1
0
Fork 0
mirror of https://github.com/ciderale/nixos-utm.git synced 2024-12-14 11:37:37 +00:00
nixos-utm/flake.nix

274 lines
10 KiB
Nix
Raw Normal View History

2023-10-06 19:43:38 +00:00
{
description = "Description for the project";
inputs = {
2024-11-30 22:15:59 +00:00
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11-small";
2023-10-06 19:43:38 +00:00
devenv.url = "github:cachix/devenv";
2023-10-16 20:45:28 +00:00
devenv.inputs.nixpkgs.follows = "nixpkgs";
2024-10-11 10:58:32 +00:00
disko.url = "github:nix-community/disko";
disko.inputs.nixpkgs.follows = "nixpkgs";
2023-10-06 19:43:38 +00:00
};
outputs = inputs @ {flake-parts, ...}:
flake-parts.lib.mkFlake {inherit inputs;} {
imports = [
inputs.devenv.flakeModule
];
2024-08-01 15:46:56 +00:00
systems = inputs.nixpkgs.lib.systems.flakeExposed;
2023-10-06 19:43:38 +00:00
perSystem = {
config,
self',
inputs',
pkgs,
system,
...
}: {
2024-11-30 22:20:46 +00:00
packages.nixosInstallerImg = pkgs.fetchurl {
# the image is only used for bootstrapping. It will be overwritten by nixos-anywhere
# the final version is defined by the configuration you provide in `nixosCreate`
# Build 280619599 of job nixos:release-24.11:nixos.iso_minimal.aarch64-linux
url = "https://hydra.nixos.org/build/280619599/download/1/nixos-minimal-24.11.710050.62c435d93bf0-aarch64-linux.iso";
sha256 = "sha256-BUYqZLwpeSda+wjRvDsYL/AP+KE653ymLuyKUlSGe7A=";
2023-10-06 19:43:38 +00:00
};
2024-08-01 15:23:15 +00:00
packages.utm = pkgs.utm;
2023-10-06 19:43:38 +00:00
packages.nixosCmd = pkgs.writeShellApplication {
name = "nixosCmd";
runtimeInputs = [self'.packages.utm];
text = ''
2023-10-15 20:24:00 +00:00
TT=
while [ -z "$TT" ]; do
TT=$(utmctl attach "$VM_NAME" | sed -n -e 's/PTTY: //p')
2023-10-15 21:29:10 +00:00
echo -n "."
2023-10-15 20:24:00 +00:00
sleep 1
done
2023-10-09 20:39:45 +00:00
echo "TTY IS: $TT"
2023-10-06 19:43:38 +00:00
DAT=/tmp/ttyDump.dat.''$''$
trap 'rm "$DAT"' EXIT
exec 3<"$TT" #REDIRECT SERIAL OUTPUT TO FD 3
cat <&3 > "$DAT" & #REDIRECT SERIAL OUTPUT TO FILE
PID=$! #SAVE PID TO KILL CAT
echo -e "$@" > "$TT";
sleep 0.3s #WAIT FOR RESPONSE
kill $PID #KILL CAT PROCESS
wait $PID 2>/dev/null || true #SUPRESS "Terminated" output
exec 3<&-
cat $DAT
'';
};
packages.nixosSetRootPW = pkgs.writeShellApplication {
name = "nixosSetRootPW";
runtimeInputs = [self'.packages.nixosCmd];
2023-10-15 16:29:23 +00:00
text = ''NIXOS_PW=$1; nixosCmd "echo -e '$NIXOS_PW\n$NIXOS_PW' | sudo passwd" '';
2023-10-06 19:43:38 +00:00
};
packages.sshNixos = pkgs.writeShellApplication {
name = "sshNixos";
runtimeInputs = [self'.packages.utmConfiguration pkgs.openssh self'.packages.utm];
2023-10-06 19:43:38 +00:00
text = ''
2023-10-15 21:39:41 +00:00
utmctl start "$VM_NAME" || true # be sure it is started, or start it
VM_IP=$(utmConfiguration ip)
2023-10-06 19:43:38 +00:00
# shellcheck disable=SC2029
ssh "root@$VM_IP" "$@"
2023-10-06 19:43:38 +00:00
'';
};
2023-10-15 16:00:17 +00:00
packages.killUTM = pkgs.writeShellApplication {
name = "killUTM";
2023-10-15 17:25:47 +00:00
runtimeInputs = [
self'.packages.utm
pkgs.coreutils
pkgs.gnused
pkgs.ps
];
2023-10-15 16:00:17 +00:00
text = ''
# shellcheck disable=SC2009
if ps aux | grep '/[U]TM'; then
2023-10-15 17:25:47 +00:00
UTM_PID=$(ps ax -o pid,command | grep '/[U]TM'| sed -ne 's/^[ ]*\([[:digit:]]*\) .*/\1/p')
2023-10-15 16:00:17 +00:00
read -r -e -p "Running at $UTM_PID. Kill? (y/N)" -i "n" answer
case "$answer" in
y | Y | yes ) kill "$UTM_PID" ;;
*) echo "don't stop UTM. abort."; exit ;;
esac
fi
'';
};
2023-10-06 21:03:45 +00:00
packages.nixosCreate = pkgs.writeShellApplication {
name = "nixosCreate";
runtimeInputs = [
pkgs.util-linux.bin
pkgs.coreutils
pkgs.gnused
pkgs.openssh
2023-10-09 20:39:45 +00:00
pkgs.ps
self'.packages.utm
self'.packages.nixosCmd
2023-10-15 16:00:17 +00:00
self'.packages.killUTM
self'.packages.utmConfiguration
2024-10-11 10:58:32 +00:00
pkgs.nixos-anywhere
];
2023-10-06 21:03:45 +00:00
text = ''
2023-10-15 17:51:21 +00:00
set -x
2023-10-15 19:18:56 +00:00
FLAKE_CONFIG=''${1:-".#utm"}
2023-10-18 22:09:28 +00:00
shift 1
# define UTM_CONFIG -- or fallback to provided default
: "''${UTM_CONFIG:=${./utm.config.nix}}"
2023-10-15 19:18:56 +00:00
echo "## Check that the provided nixosConfiguration $FLAKE_CONFIG exists"
2023-10-15 19:27:30 +00:00
nix eval "''${FLAKE_CONFIG/'#'/'#'nixosConfigurations.}.config.system.stateVersion"
2023-10-15 16:29:23 +00:00
2024-10-10 23:26:42 +00:00
# deterministically generate mac address from VM_NAME
2023-10-15 17:40:46 +00:00
MAC_ADDR=$(md5sum <<< "$VM_NAME" | head -c 10 | sed -r 's/(..)/\1:/g;s/:$//;s/^/02:/')
2023-10-06 21:03:45 +00:00
2023-10-15 17:40:46 +00:00
if utmctl list | grep "$VM_NAME" ; then
read -r -e -p "The VM [$VM_NAME] exists: should the VM be deleted (y/N)" -i "n" answer
2023-10-09 20:39:45 +00:00
case "$answer" in
2023-10-15 17:40:46 +00:00
y | Y | yes ) utmctl stop "$VM_NAME"; utmctl delete "$VM_NAME" ;;
2023-10-09 20:39:45 +00:00
*) echo "keep existing VM. abort."; exit ;;
esac
fi
2023-10-06 21:03:45 +00:00
2023-10-15 19:18:56 +00:00
echo "create the VM [$VM_NAME] from $FLAKE_CONFIG with applescript"
2024-11-30 22:20:46 +00:00
osascript ${./setupVM.osa} "$VM_NAME" "$MAC_ADDR" ${self'.packages.nixosInstallerImg}
2023-10-09 20:39:45 +00:00
2023-10-15 16:00:17 +00:00
echo "configure the VM with plutil"
utmConfiguration update "$UTM_CONFIG"
2023-10-15 17:51:21 +00:00
echo -e "\n\n## refresh UTMs view of the configuration requires restarting UTM"
2023-10-15 16:00:17 +00:00
killUTM
2023-10-15 17:40:46 +00:00
utmctl start "$VM_NAME"
2023-10-06 21:03:45 +00:00
while ! nixosCmd ls | grep nixos ; do
2023-10-15 17:40:46 +00:00
echo "VM $VM_NAME not yet running"
2023-10-06 21:03:45 +00:00
sleep 2;
done
nixosCmd uname
2023-10-15 17:40:46 +00:00
echo "VM $VM_NAME is running"
2023-10-06 21:03:45 +00:00
2023-10-15 17:51:21 +00:00
echo "## configure ad-hoc authorized key for nixos-anywhere"
INSTALL_KEY_FILE=$(mktemp -u)
ssh-keygen -t ed25519 -N "" -f "$INSTALL_KEY_FILE"
INSTALL_KEY_PUB=$(cat "$INSTALL_KEY_FILE.pub")
nixosCmd "sudo mkdir -p /root/.ssh; echo '$INSTALL_KEY_PUB' | sudo tee -a /root/.ssh/authorized_keys"
2023-10-15 20:04:40 +00:00
sleep 0.5;
2023-10-15 17:51:21 +00:00
echo "## start the actuall installation"
NIXOS_IP=$(utmConfiguration ip)
nixos-anywhere --flake "''${FLAKE_CONFIG}" "root@$NIXOS_IP" --build-on-remote -i "$INSTALL_KEY_FILE" "$@"
rm "$INSTALL_KEY_FILE" "$INSTALL_KEY_FILE".pub
2023-10-15 17:40:46 +00:00
utmctl stop "$VM_NAME"
osascript ${./removeIso.osa} "$VM_NAME"
utmctl start "$VM_NAME"
while ! ssh-keyscan "$NIXOS_IP"; do sleep 2; done
ssh-keygen -R "$NIXOS_IP"
2023-10-06 21:03:45 +00:00
'';
};
packages.utmConfiguration = pkgs.writeShellApplication {
name = "utmConfiguration";
runtimeInputs = [pkgs.jq pkgs.coreutils pkgs.gnused];
text = ''
# INPUTS: VM_NAME
UTM_DATA_DIR="$HOME/Library/Containers/com.utmapp.UTM/Data/Documents";
VM_FOLDER="$UTM_DATA_DIR/$VM_NAME.utm"
PLIST_FILE="$VM_FOLDER"/config.plist
case "''${1:-usage}" in
show)
plutil -convert json -o - "$PLIST_FILE" | jq .
;;
mac)
$0 show | jq '.Network[0].MacAddress' -r
;;
ip)
MAC=$($0 mac)
# shellcheck disable=SC2001
MAC1=$(sed -e 's/0\([[:digit:]]\)/\1/g' <<< "$MAC")
IP=
while [ -z "$IP" ]; do
IP=$(arp -a | sed -ne "s/.*(\([0-9.]*\)) at $MAC1.*/\1/p")
sleep 1
done
echo "$IP"
;;
update)
shift
NIX_PATCH=$1
# CREATE TEMPORARY FILES
PLIST_JSON=$(mktemp -u)
PLIST_JSON_PLIST=$(mktemp -u)
JSON_PATCH=$(mktemp -u)
trap 'rm $PLIST_JSON $PLIST_JSON_PLIST $JSON_PATCH' EXIT
# EXECUTE UPDATE
nix eval -f "$NIX_PATCH" --json > "$JSON_PATCH"
plutil -convert json -o "$PLIST_JSON" "$PLIST_FILE"
jq -s 'reduce .[] as $item ({}; . * $item)' "$PLIST_JSON" "$JSON_PATCH" > "$PLIST_JSON_PLIST"
plutil -convert binary1 "$PLIST_JSON_PLIST"
# WRITE UPDATE TO CONFIG
cp "$PLIST_JSON_PLIST" "$PLIST_FILE"
;;
usage | *)
SCRIPT=$(basename "$0")
echo "usage: VM_NAME=your-vm $SCRIPT show"
echo "usage: VM_NAME=your-vm $SCRIPT mac"
echo "usage: VM_NAME=your-vm $SCRIPT ip"
echo "usage: VM_NAME=your-vm $SCRIPT update patch-config.nix"
;;
esac
'';
};
2023-10-16 20:44:19 +00:00
packages.nixosDeploy = pkgs.writeShellApplication {
name = "nixosDeploy";
runtimeInputs = [
self'.packages.utmConfiguration
2023-10-16 20:44:19 +00:00
pkgs.nixos-rebuild
];
text = ''
2023-10-16 21:35:25 +00:00
set -x
2023-10-16 20:44:19 +00:00
FLAKE_CONFIG=$1
2023-10-18 22:09:28 +00:00
shift
THE_TARGET="root@$(utmConfiguration ip)"
2023-10-16 21:35:25 +00:00
echo "Deploying $FLAKE_CONFIG to $THE_TARGET"
2023-10-16 20:44:19 +00:00
export NIX_SSHOPTS="-o ControlPath=/tmp/ssh-utm-vm-%n"
2023-10-18 22:09:28 +00:00
nixos-rebuild \
--fast --target-host "$THE_TARGET" --build-host "$THE_TARGET" \
switch --flake "$FLAKE_CONFIG" "$@"
2023-10-16 21:35:25 +00:00
# experiment with copying flake manually
# FLAKE="''${FLAKE_CONFIG/'#'*}"
# REF=$(nix flake metadata "$FLAKE" --json | jq .path -r)
# nix copy "$REF" --to "ssh://$THE_TARGET"
#
# CFG="''${FLAKE_CONFIG/*'#'}"
# sshNixos "nixos-rebuild switch --flake $REF#$CFG"
2023-10-16 20:44:19 +00:00
'';
};
2024-08-01 15:46:56 +00:00
devenv.shells.default = {lib, ...}: {
2023-10-15 17:40:46 +00:00
env.VM_NAME = "MyNixOS2";
2024-08-01 15:46:56 +00:00
containers = lib.mkForce {};
2023-10-06 21:03:45 +00:00
enterShell = ''
export UTM_DATA_DIR="$HOME/Library/Containers/com.utmapp.UTM/Data/Documents";
'';
2023-10-06 19:43:38 +00:00
packages = builtins.attrValues {
inherit (self'.packages) nixosCreate sshNixos utm nixosCmd utmConfiguration;
2024-10-11 10:58:32 +00:00
inherit (pkgs) coreutils nixos-rebuild nixos-anywhere;
2023-10-06 19:43:38 +00:00
};
};
};
flake = {
nixosConfigurations.utm = import ./example/default.nix inputs;
2023-10-15 21:11:53 +00:00
templates.default = {
path = ./example;
description = "A basic UTM VM configuration";
};
2023-10-06 19:43:38 +00:00
};
};
}