about summary refs log tree commit diff
path: root/nixos/modules/profiles
diff options
context:
space:
mode:
authorGeraint Ballinger <G3zz@users.noreply.github.com>2023-04-07 04:10:49 +0100
committerGitHub <noreply@github.com>2023-04-07 05:10:49 +0200
commit8b2521bdae89126497fa6f139fb9d030d5d13184 (patch)
tree9a7f20e258bc1b67f3053e3d1b1e9ffc47f2f3d6 /nixos/modules/profiles
parent772d05f31d5169f414659217b98907916f5f14fa (diff)
nixos/darwin-builder: add disk space options (#224480)
Diffstat (limited to 'nixos/modules/profiles')
-rw-r--r--nixos/modules/profiles/macos-builder.nix306
1 files changed, 183 insertions, 123 deletions
diff --git a/nixos/modules/profiles/macos-builder.nix b/nixos/modules/profiles/macos-builder.nix
index 4a5359582bce0..768c673e7f377 100644
--- a/nixos/modules/profiles/macos-builder.nix
+++ b/nixos/modules/profiles/macos-builder.nix
@@ -7,6 +7,8 @@ let
 
   keyType = "ed25519";
 
+  cfg = config.virtualisation.darwin-builder;
+
 in
 
 {
@@ -24,156 +26,214 @@ in
     }
   ];
 
-  # The builder is not intended to be used interactively
-  documentation.enable = false;
-
-  environment.etc = {
-    "ssh/ssh_host_ed25519_key" = {
-      mode = "0600";
-
-      source = ./keys/ssh_host_ed25519_key;
+  options.virtualisation.darwin-builder = with lib; {
+    diskSize = mkOption {
+      default = 20 * 1024;
+      type = types.int;
+      example = 30720;
+      description = "The maximum disk space allocated to the runner in MB";
     };
-
-    "ssh/ssh_host_ed25519_key.pub" = {
-      mode = "0644";
-
-      source = ./keys/ssh_host_ed25519_key.pub;
+    memorySize = mkOption {
+      default = 3 * 1024;
+      type = types.int;
+      example = 8192;
+      description = "The runner's memory in MB";
+    };
+    min-free = mkOption {
+      default = 1024 * 1024 * 1024;
+      type = types.int;
+      example = 1073741824;
+      description = ''
+        The threshold (in bytes) of free disk space left at which to
+        start garbage collection on the runner
+      '';
+    };
+    max-free = mkOption {
+      default = 3 * 1024 * 1024 * 1024;
+      type = types.int;
+      example = 3221225472;
+      description = ''
+        The threshold (in bytes) of free disk space left at which to
+        stop garbage collection on the runner
+      '';
+    };
+    workingDirectory = mkOption {
+       default = ".";
+       type = types.str;
+       example = "/var/lib/darwin-builder";
+       description = ''
+         The working directory to use to run the script. When running
+         as part of a flake will need to be set to a non read-only filesystem.
+       '';
+    };
+    hostPort = mkOption {
+      default = 22;
+      type = types.int;
+      example = 31022;
+      description = ''
+        The localhost host port to forward TCP to the guest port.
+      '';
     };
   };
 
-  # DNS fails for QEMU user networking (SLiRP) on macOS.  See:
-  #
-  # https://github.com/utmapp/UTM/issues/2353
-  #
-  # This works around that by using a public DNS server other than the DNS
-  # server that QEMU provides (normally 10.0.2.3)
-  networking.nameservers = [ "8.8.8.8" ];
+  config = {
+    # The builder is not intended to be used interactively
+    documentation.enable = false;
 
-  nix.settings = {
-    auto-optimise-store = true;
+    environment.etc = {
+      "ssh/ssh_host_ed25519_key" = {
+        mode = "0600";
 
-    min-free = 1024 * 1024 * 1024;
+        source = ./keys/ssh_host_ed25519_key;
+      };
 
-    max-free = 3 * 1024 * 1024 * 1024;
+      "ssh/ssh_host_ed25519_key.pub" = {
+        mode = "0644";
 
-    trusted-users = [ "root" user ];
-  };
+        source = ./keys/ssh_host_ed25519_key.pub;
+      };
+    };
 
-  services = {
-    getty.autologinUser = user;
+    # DNS fails for QEMU user networking (SLiRP) on macOS.  See:
+    #
+    # https://github.com/utmapp/UTM/issues/2353
+    #
+    # This works around that by using a public DNS server other than the DNS
+    # server that QEMU provides (normally 10.0.2.3)
+    networking.nameservers = [ "8.8.8.8" ];
 
-    openssh = {
-      enable = true;
+    nix.settings = {
+      auto-optimise-store = true;
 
-      authorizedKeysFiles = [ "${keysDirectory}/%u_${keyType}.pub" ];
-    };
-  };
+      min-free = cfg.min-free;
 
-  system.build.macos-builder-installer =
-    let
-      privateKey = "/etc/nix/${user}_${keyType}";
+      max-free = cfg.max-free;
 
-      publicKey = "${privateKey}.pub";
+      trusted-users = [ "root" user ];
+    };
 
-      # This installCredentials script is written so that it's as easy as
-      # possible for a user to audit before confirming the `sudo`
-      installCredentials = hostPkgs.writeShellScript "install-credentials" ''
-        KEYS="''${1}"
-        INSTALL=${hostPkgs.coreutils}/bin/install
-        "''${INSTALL}" -g nixbld -m 600 "''${KEYS}/${user}_${keyType}" ${privateKey}
-        "''${INSTALL}" -g nixbld -m 644 "''${KEYS}/${user}_${keyType}.pub" ${publicKey}
-      '';
+    services = {
+      getty.autologinUser = user;
 
-      hostPkgs = config.virtualisation.host.pkgs;
-
-      script = hostPkgs.writeShellScriptBin "create-builder" ''
-        KEYS="''${KEYS:-./keys}"
-        ${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}"
-        PRIVATE_KEY="''${KEYS}/${user}_${keyType}"
-        PUBLIC_KEY="''${PRIVATE_KEY}.pub"
-        if [ ! -e "''${PRIVATE_KEY}" ] || [ ! -e "''${PUBLIC_KEY}" ]; then
-            ${hostPkgs.coreutils}/bin/rm --force -- "''${PRIVATE_KEY}" "''${PUBLIC_KEY}"
-            ${hostPkgs.openssh}/bin/ssh-keygen -q -f "''${PRIVATE_KEY}" -t ${keyType} -N "" -C 'builder@localhost'
-        fi
-        if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then
-          (set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}")
-        fi
-        KEYS="$(nix-store --add "$KEYS")" ${config.system.build.vm}/bin/run-nixos-vm
-      '';
+      openssh = {
+        enable = true;
 
-    in
-    script.overrideAttrs (old: {
-      meta = (old.meta or { }) // {
-        platforms = lib.platforms.darwin;
+        authorizedKeysFiles = [ "${keysDirectory}/%u_${keyType}.pub" ];
       };
-    });
-
-  system = {
-    # To prevent gratuitous rebuilds on each change to Nixpkgs
-    nixos.revision = null;
+    };
 
-    stateVersion = lib.mkDefault (throw ''
-      The macOS linux builder should not need a stateVersion to be set, but a module
-      has accessed stateVersion nonetheless.
-      Please inspect the trace of the following command to figure out which module
-      has a dependency on stateVersion.
+    system.build.macos-builder-installer =
+      let
+        privateKey = "/etc/nix/${user}_${keyType}";
+
+        publicKey = "${privateKey}.pub";
+
+        # This installCredentials script is written so that it's as easy as
+        # possible for a user to audit before confirming the `sudo`
+        installCredentials = hostPkgs.writeShellScript "install-credentials" ''
+          KEYS="''${1}"
+          INSTALL=${hostPkgs.coreutils}/bin/install
+          "''${INSTALL}" -g nixbld -m 600 "''${KEYS}/${user}_${keyType}" ${privateKey}
+          "''${INSTALL}" -g nixbld -m 644 "''${KEYS}/${user}_${keyType}.pub" ${publicKey}
+        '';
+
+        hostPkgs = config.virtualisation.host.pkgs;
+
+  script = hostPkgs.writeShellScriptBin "create-builder" (
+          # When running as non-interactively as part of a DarwinConfiguration the working directory
+          # must be set to a writeable directory.
+        (if cfg.workingDirectory != "." then ''
+          ${hostPkgs.coreutils}/bin/mkdir --parent "${cfg.workingDirectory}"
+          cd "${cfg.workingDirectory}"
+  '' else "") + ''
+          KEYS="''${KEYS:-./keys}"
+          ${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}"
+          PRIVATE_KEY="''${KEYS}/${user}_${keyType}"
+          PUBLIC_KEY="''${PRIVATE_KEY}.pub"
+          if [ ! -e "''${PRIVATE_KEY}" ] || [ ! -e "''${PUBLIC_KEY}" ]; then
+              ${hostPkgs.coreutils}/bin/rm --force -- "''${PRIVATE_KEY}" "''${PUBLIC_KEY}"
+              ${hostPkgs.openssh}/bin/ssh-keygen -q -f "''${PRIVATE_KEY}" -t ${keyType} -N "" -C 'builder@localhost'
+          fi
+          if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then
+            (set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}")
+          fi
+          KEYS="$(${hostPkgs.nix}/bin/nix-store --add "$KEYS")" ${config.system.build.vm}/bin/run-nixos-vm
+        '');
+
+      in
+      script.overrideAttrs (old: {
+        meta = (old.meta or { }) // {
+          platforms = lib.platforms.darwin;
+        };
+      });
+
+    system = {
+      # To prevent gratuitous rebuilds on each change to Nixpkgs
+      nixos.revision = null;
+
+      stateVersion = lib.mkDefault (throw ''
+        The macOS linux builder should not need a stateVersion to be set, but a module
+        has accessed stateVersion nonetheless.
+        Please inspect the trace of the following command to figure out which module
+        has a dependency on stateVersion.
+
+          nix-instantiate --attr darwin.builder --show-trace
+      '');
+    };
 
-        nix-instantiate --attr darwin.builder --show-trace
-    '');
-  };
+    users.users."${user}" = {
+      isNormalUser = true;
+    };
 
-  users.users."${user}" = {
-    isNormalUser = true;
-  };
+    security.polkit.enable = true;
 
-  security.polkit.enable = true;
+    security.polkit.extraConfig = ''
+      polkit.addRule(function(action, subject) {
+        if (action.id === "org.freedesktop.login1.power-off" && subject.user === "${user}") {
+          return "yes";
+        } else {
+          return "no";
+        }
+      })
+    '';
 
-  security.polkit.extraConfig = ''
-    polkit.addRule(function(action, subject) {
-      if (action.id === "org.freedesktop.login1.power-off" && subject.user === "${user}") {
-        return "yes";
-      } else {
-        return "no";
-      }
-    })
-  '';
+    virtualisation = {
+      diskSize = cfg.diskSize;
 
-  virtualisation = {
-    diskSize = 20 * 1024;
+      memorySize = cfg.memorySize;
 
-    memorySize = 3 * 1024;
+      forwardPorts = [
+        { from = "host"; guest.port = 22; host.port = cfg.hostPort; }
+      ];
 
-    forwardPorts = [
-      { from = "host"; guest.port = 22; host.port = 22; }
-    ];
+      # Disable graphics for the builder since users will likely want to run it
+      # non-interactively in the background.
+      graphics = false;
 
-    # Disable graphics for the builder since users will likely want to run it
-    # non-interactively in the background.
-    graphics = false;
+      sharedDirectories.keys = {
+        source = "\"$KEYS\"";
+        target = keysDirectory;
+      };
 
-    sharedDirectories.keys = {
-      source = "\"$KEYS\"";
-      target = keysDirectory;
+      # If we don't enable this option then the host will fail to delegate builds
+      # to the guest, because:
+      #
+      # - The host will lock the path to build
+      # - The host will delegate the build to the guest
+      # - The guest will attempt to lock the same path and fail because
+      #   the lockfile on the host is visible on the guest
+      #
+      # Snapshotting the host's /nix/store as an image isolates the guest VM's
+      # /nix/store from the host's /nix/store, preventing this problem.
+      useNixStoreImage = true;
+
+      # Obviously the /nix/store needs to be writable on the guest in order for it
+      # to perform builds.
+      writableStore = true;
+
+      # This ensures that anything built on the guest isn't lost when the guest is
+      # restarted.
+      writableStoreUseTmpfs = false;
     };
-
-    # If we don't enable this option then the host will fail to delegate builds
-    # to the guest, because:
-    #
-    # - The host will lock the path to build
-    # - The host will delegate the build to the guest
-    # - The guest will attempt to lock the same path and fail because
-    #   the lockfile on the host is visible on the guest
-    #
-    # Snapshotting the host's /nix/store as an image isolates the guest VM's
-    # /nix/store from the host's /nix/store, preventing this problem.
-    useNixStoreImage = true;
-
-    # Obviously the /nix/store needs to be writable on the guest in order for it
-    # to perform builds.
-    writableStore = true;
-
-    # This ensures that anything built on the guest isn't lost when the guest is
-    # restarted.
-    writableStoreUseTmpfs = false;
   };
 }