Skip to content

Commit

Permalink
Merge pull request #206951 from MercuryTechnologies/gabriella/macos-b…
Browse files Browse the repository at this point in the history
…uilder

darwin.builder: init
  • Loading branch information
domenkozar authored Dec 21, 2022
2 parents e9b218c + 13bd327 commit bcc8d11
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/builders/special.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
</para>
<xi:include href="special/fhs-environments.section.xml" />
<xi:include href="special/mkshell.section.xml" />
<xi:include href="special/darwin-builder.section.xml" />
</chapter>
60 changes: 60 additions & 0 deletions doc/builders/special/darwin-builder.section.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# darwin.builder {#sec-darwin-builder}

`darwin.builder` provides a way to bootstrap a Linux builder on a macOS machine.

This requires macOS version 12.4 or later.

This also requires that port 22 on your machine is free (since Nix does not
permit specifying a non-default SSH port for builders).

You will also need to be a trusted user for your Nix installation. In other
words, your `/etc/nix/nix.conf` should have something like:

```
extra-trusted-users = <your username goes here>
```

To launch the builder, run the following flake:

```ShellSession
$ nix run nixpkgs#darwin.builder
```

That will prompt you to enter your `sudo` password:

```
+ sudo --reset-timestamp /nix/store/…-install-credentials.sh ./keys
Password:
```

… so that it can install a private key used to `ssh` into the build server.
After that the script will launch the virtual machine:

```
<<< Welcome to NixOS 22.11.20220901.1bd8d11 (aarch64) - ttyAMA0 >>>
Run 'nixos-help' for the NixOS manual.
nixos login:
```

> Note: When you need to stop the VM, type `Ctrl`-`a` + `c` to open the `qemu`
> prompt and then type `quit` followed by `Enter`
To delegate builds to the remote builder, add the following options to your
`nix.conf` file:

```
# - Replace ${ARCH} with either aarch64 or x86_64 to match your host machine
# - Replace ${MAX_JOBS} with the maximum number of builds (pick 4 if you're not sure)
builders = ssh-ng://builder@localhost ${ARCH}-linux /etc/nix/builder_ed25519 ${MAX_JOBS} - - - c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUpCV2N4Yi9CbGFxdDFhdU90RStGOFFVV3JVb3RpQzVxQkorVXVFV2RWQ2Igcm9vdEBuaXhvcwo='
# Not strictly necessary, but this will reduce your disk utilization
builders-use-substitutes = true
```

… and then restart your Nix daemon to apply the change:

```ShellSession
$ sudo launchctl kickstart -k system/org.nixos.nix-daemon
```
7 changes: 7 additions & 0 deletions nixos/modules/profiles/keys/ssh_host_ed25519_key
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCQVnMW/wZWqrdWrjrRPhfEFFq1KLYguagSflLhFnVQmwAAAJASuMMnErjD
JwAAAAtzc2gtZWQyNTUxOQAAACCQVnMW/wZWqrdWrjrRPhfEFFq1KLYguagSflLhFnVQmw
AAAEDIN2VWFyggtoSPXcAFy8dtG1uAig8sCuyE21eMDt2GgJBWcxb/Blaqt1auOtE+F8QU
WrUotiC5qBJ+UuEWdVCbAAAACnJvb3RAbml4b3MBAgM=
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions nixos/modules/profiles/keys/ssh_host_ed25519_key.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJBWcxb/Blaqt1auOtE+F8QUWrUotiC5qBJ+UuEWdVCb root@nixos
134 changes: 134 additions & 0 deletions nixos/modules/profiles/macos-builder.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{ config, pkgs, ... }:

let
keysDirectory = "/var/keys";

user = "builder";

keyType = "ed25519";

in

{ imports = [
../virtualisation/qemu-vm.nix
];

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

"ssh/ssh_host_ed25519_key.pub" = {
mode = "0644";

source = ./keys/ssh_host_ed25519_key.pub;
};
};

# 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" ];

nix.settings = {
auto-optimise-store = true;

min-free = 1024 * 1024 * 1024;

max-free = 3 * 1024 * 1024 * 1024;

trusted-users = [ "root" user ];
};

services.openssh = {
enable = true;

authorizedKeysFiles = [ "${keysDirectory}/%u_${keyType}.pub" ];
};

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 = pkgs.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;

in
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
'';

system.stateVersion = "22.05";

users.users."${user}"= {
isNormalUser = true;
};

virtualisation = {
diskSize = 20 * 1024;

memorySize = 3 * 1024;

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;

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;
};
}
19 changes: 19 additions & 0 deletions pkgs/top-level/darwin-packages.nix
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,23 @@ impure-cmds // appleSourcePackages // chooseLibs // {

discrete-scroll = callPackage ../os-specific/darwin/discrete-scroll { };

# See doc/builders/special/darwin-builder.section.md
builder =
let
toGuest = builtins.replaceStrings [ "darwin" ] [ "linux" ];

nixos = import ../../nixos {
configuration = {
imports = [
../../nixos/modules/profiles/macos-builder.nix
];

virtualisation.host = { inherit pkgs; };
};

system = toGuest stdenv.hostPlatform.system;
};

in
nixos.config.system.build.macos-builder-installer;
})

0 comments on commit bcc8d11

Please sign in to comment.