From cd47d884f78fc629050264d08706f41cb16b9879 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicolas=20=E2=80=9CNiols=E2=80=9D=20Jeannerod?=
 <nicolas.jeannerod@moduscreate.com>
Date: Mon, 24 Feb 2025 17:18:49 +0100
Subject: [PATCH] Cleaner grabing of options

---
 infra/proxmox-provision.sh | 145 ++++++++++++++++++++++---------------
 1 file changed, 86 insertions(+), 59 deletions(-)

diff --git a/infra/proxmox-provision.sh b/infra/proxmox-provision.sh
index be433849..b92097f2 100755
--- a/infra/proxmox-provision.sh
+++ b/infra/proxmox-provision.sh
@@ -158,34 +158,65 @@ proxmox_sync () (
 )
 
 ################################################################################
-## Grab VM option
+## Grab VM options
 ##
-## Takes the name of the VM and an option and grabs `vmOptions.<name>.<option>`
-## in the flake.
+## Takes the name of the VM, grabs `.#vmOptions.<name>` and defines a bunch of
+## global variables corresponding to all the options.
 
-grab_vm_option () {
-  nix eval \
-    --impure --raw --expr "
-      builtins.toJSON (builtins.getFlake (builtins.toString ./.)).vmOptions.$1
-    " | jq -r ."$2"
+grab_vm_options () {
+  local options
+
+  vm_name=$1
+
+  printf 'Grabing VM options for VM %s...\n' "$vm_name"
+
+  options=$(
+    nix eval \
+      --impure --raw --expr "
+        builtins.toJSON (builtins.getFlake (builtins.toString ./.)).vmOptions.$vm_name
+      " \
+    --log-format raw --quiet
+  )
+
+  proxmox=$(echo "$options" | jq -r .proxmox)
+  vm_id=$(echo "$options" | jq -r .vmId)
+
+  if [ "$proxmox" != fediversity ]; then
+    die "I do not know how to provision things that are not Fediversity VMs,
+but I got proxmox = '%s' for VM %s." "$proxmox" "$vm_name"
+  fi
+
+  sockets=$(echo "$options" | jq -r .sockets)
+  cores=$(echo "$options" | jq -r .cores)
+  memory=$(echo "$options" | jq -r .memory)
+
+  host_public_key=$(echo "$options" | jq -r .hostPublicKey)
+  host_private_key=$(echo "$options" | jq -r .unsafeHostPrivateKey)
+
+  if [ "$host_private_key" != null ] && [ "$host_public_key" = null ]; then
+    die 'I do not know what to do with a private key but no public key.'
+  fi
+
+  printf 'done grabing VM options for VM %s. Got:\n  id: %d\n  sockets: %d\n  cores: %d\n  memory: %d MiB\n' \
+    "$vm_name" "$vm_id" "$sockets" "$cores" "$memory"
 }
 
 ################################################################################
 ## Build ISO
 
 build_iso () {
-  acquire_lock build
-  printf 'Building ISO for VM %s...\n' "$2"
+  local nix_host_keys
 
-  host_public_key=$(grab_vm_option "$2" hostPublicKey)
-  host_private_key=$(grab_vm_option "$2" unsafeHostPrivateKey)
-  if [ "$host_public_key" != null ] && [ "$host_private_key" != null ]; then
-    echo "$host_public_key" > "$tmpdir"/"$2"_host_key.pub
-    echo "$host_private_key" > "$tmpdir"/"$2"_host_key
+  acquire_lock build
+  printf 'Building ISO for VM %s...\n' "$vm_name"
+
+  if [ "$host_private_key" != null ]; then
+    echo "$host_public_key" > "$tmpdir"/"$vm_name"_host_key.pub
+    echo "$host_private_key" > "$tmpdir"/"$vm_name"_host_key
     nix_host_keys="
       hostKeys.ed25519 = {
-        public = $tmpdir/$2_host_key.pub;
-        private = $tmpdir/$2_host_key;
+        public = $tmpdir/${vm_name}_host_key.pub;
+        private = $tmpdir/${vm_name}_host_key;
       };
     "
   else
@@ -196,23 +227,23 @@ build_iso () {
     --impure --expr "
       let flake = builtins.getFlake (builtins.toString ./.); in
       flake.lib.makeInstallerIso {
-        nixosConfiguration = flake.nixosConfigurations.$2;
+        nixosConfiguration = flake.nixosConfigurations.$vm_name;
         nixpkgs = flake.inputs.nixpkgs;
         $nix_host_keys
       }
     " \
     --log-format raw --quiet \
-    --out-link "$tmpdir/installer-$2"
+    --out-link "$tmpdir/installer-$vm_name"
 
   if [ $? -ne 0 ]; then
     die 'Something went wrong when building ISO for VM %s.
 Check the Nix logs and fix things. Possibly there just is no NixOS configuration by that name?' \
-      "$2"
+      "$vm_name"
   fi
 
-  ln -sf "$tmpdir/installer-$2/iso/installer.iso" "$tmpdir/installer-$2.iso"
+  ln -sf "$tmpdir/installer-$vm_name/iso/installer.iso" "$tmpdir/installer-$vm_name.iso"
 
-  printf 'done building ISO for VM %s.\n' "$2"
+  printf 'done building ISO for VM %s.\n' "$vm_name"
   release_lock build
 }
 
@@ -221,13 +252,13 @@ Check the Nix logs and fix things. Possibly there just is no NixOS configuration
 
 upload_iso () {
   acquire_lock upload
-  printf 'Uploading ISO for VM %s...\n' "$2"
+  printf 'Uploading ISO for VM %s...\n' "$vm_name"
 
   proxmox_sync POST "$api_url/nodes/$node/storage/local/upload" \
-    "filename@$tmpdir/installer-$2.iso" \
+    "filename@$tmpdir/installer-$vm_name.iso" \
     content==iso
 
-  printf 'done uploading ISO for VM %s.\n' "$2"
+  printf 'done uploading ISO for VM %s.\n' "$vm_name"
   release_lock upload
 }
 
@@ -235,26 +266,26 @@ upload_iso () {
 ## Remove ISO
 
 remove_iso () {
-  printf 'Removing ISO for VM %s...\n' "$2"
+  printf 'Removing ISO for VM %s...\n' "$vm_name"
 
-  proxmox_sync DELETE "$api_url/nodes/$node/storage/local/content/local:iso/installer-$2.iso"
+  proxmox_sync DELETE "$api_url/nodes/$node/storage/local/content/local:iso/installer-$vm_name.iso"
 
-  printf 'done removing ISO for VM %s.\n' "$2"
+  printf 'done removing ISO for VM %s.\n' "$vm_name"
 }
 
 ################################################################################
 ## Create VM
 
 create_vm () {
-  printf 'Creating VM %s with id %d...\n' "$2" "$1"
+  printf 'Creating VM %s...\n' "$vm_name"
 
   proxmox_sync POST "$api_url/nodes/$node/qemu" \
     \
-    vmid=="$1" \
-    name=="$2" \
+    vmid=="$vm_id" \
+    name=="$vm_name" \
     pool==Fediversity \
     \
-    ide2=="local:iso/installer-$2.iso,media=cdrom" \
+    ide2=="local:iso/installer-$vm_name.iso,media=cdrom" \
     ostype==l26 \
     \
     bios==ovmf \
@@ -264,28 +295,28 @@ create_vm () {
     scsihw==virtio-scsi-single \
     scsi0=='linstor_storage:32,discard=on,ssd=on,iothread=on' \
     \
-    sockets=="$(grab_vm_option "$2" sockets)" \
-    cores=="$(grab_vm_option "$2" cores)" \
+    sockets=="$sockets" \
+    cores=="$cores" \
     cpu==x86-64-v2-AES \
     numa==1 \
     \
-    memory=="$(grab_vm_option "$2" memory)" \
+    memory=="$memory" \
     \
     net0=='virtio,bridge=vnet1306'
 
-  printf 'done creating VM %s.\n' "$2"
+  printf 'done creating VM %s.\n' "$vm_name"
 }
 
 ################################################################################
 ## Install VM
 
 install_vm () (
-  printf 'Installing VM %s...\n' "$2"
+  printf 'Installing VM %s...\n' "$vm_name"
 
-  proxmox_sync POST "$api_url/nodes/$node/qemu/$1/status/start"
+  proxmox_sync POST "$api_url/nodes/$node/qemu/$vm_id/status/start"
 
   while :; do
-    response=$(proxmox GET "$api_url/nodes/$node/qemu/$1/status/current")
+    response=$(proxmox GET "$api_url/nodes/$node/qemu/$vm_id/status/current")
     status=$(echo "$response" | jq -r .data.status)
     case $status in
       running) sleep 1 ;;
@@ -294,22 +325,22 @@ install_vm () (
     esac
   done
 
-  printf 'done installing VM %s.\n' "$2"
+  printf 'done installing VM %s.\n' "$vm_name"
 )
 
 ################################################################################
 ## Start VM
 
 start_vm () {
-  printf 'Starting VM %s...\n' "$2"
+  printf 'Starting VM %s...\n' "$vm_name"
 
-  proxmox_sync POST "$api_url/nodes/$node/qemu/$1/config" \
+  proxmox_sync POST "$api_url/nodes/$node/qemu/$vm_id/config" \
     ide2=='none,media=cdrom' \
     net0=='virtio,bridge=vnet1305'
 
-  proxmox_sync POST "$api_url/nodes/$node/qemu/$1/status/start"
+  proxmox_sync POST "$api_url/nodes/$node/qemu/$vm_id/status/start"
 
-  printf 'done starting VM %s.\n' "$2"
+  printf 'done starting VM %s.\n' "$vm_name"
 }
 
 ################################################################################
@@ -318,24 +349,20 @@ start_vm () {
 printf 'Provisioning VMs%s...\n' "$vm_names"
 
 provision_vm () (
-  ## NOTE: Mind the fact that we now run in a sub-shell, allowing the following
-  ## functions to define global variables without clashing with concurrent VMs
-  ## provisioning.
-
-  build_iso "$@"
-  upload_iso "$@"
-  create_vm "$@"
-  install_vm "$@"
-  start_vm "$@"
-  remove_iso "$@"
+  ## Grab VM options and put them in global variables. NOTE: Mind the fact that
+  ## we now run in a sub-shell, allowing us to define global variables without
+  ## clashing with concurrent executions of `provision_vm`.
+  grab_vm_options "$1"
+  build_iso
+  upload_iso
+  create_vm
+  install_vm
+  start_vm
+  remove_iso
 )
 
 for vm_name in $vm_names; do
-  vm_id=$(grab_vm_option "$vm_name" vmId)
-  if [ "$(grab_vm_option "$vm_name" proxmox)" != fediversity ]; then
-    die 'This script does not know how to provision things that are not Fediversity VMs'
-  fi
-  provision_vm "$vm_id" "$vm_name" &
+  provision_vm "$vm_name" &
 done
 wait