Rework and cleanup provisioning script

This commit is contained in:
Nicolas Jeannerod 2024-11-14 13:12:06 +01:00
parent 95389bb615
commit 56d125a5b0
Signed by untrusted user: Niols
GPG key ID: 35DB9EC8886E1CB8

View file

@ -1,32 +1,42 @@
#!/usr/bin/env sh #!/usr/bin/env sh
set -euC set -euC
################################################################################
## Constants
readonly apiurl=https://192.168.51.81:8006/api2/json
## FIXME: There seems to be a problem with file upload where the task is
## registered to `node051` no matter what node we are actually uploading to? For
## now, let us just use `node051` everywhere.
readonly node=node051
readonly tmpdir=/tmp/proxmox-provision-$RANDOM$RANDOM
mkdir $tmpdir
################################################################################ ################################################################################
## Parse arguments ## Parse arguments
username= username=
password= password=
iso=result/iso/installer.iso
sockets=1 sockets=1
cores=1 cores=1
memory=2048 memory=2048
vmid= vmids=
help () { help () {
cat <<EOF cat <<EOF
Usage: $0 [OPTION...] Usage: $0 [OPTION...] [ID...]
Required: Authentication options:
--username STR Username, with provider (eg. niols@pve) --username STR Username, with provider (eg. niols@pve)
--password STR Password --password STR Password
--vmid INT Identifier of the VM
If not provided via the command line, username and password will be looked for If not provided via the command line, username and password will be looked for
in a '.proxmox' file in the current working directory, the username on the in a '.proxmox' file in the current working directory, the username on the
first line, and the password on the second. first line, and the password on the second.
Optional: Other options:
--iso PATH Installer ISO (default: $iso)
--sockets INT Number of sockets (default: $sockets) --sockets INT Number of sockets (default: $sockets)
--cores INT Number of cores (default: $cores) --cores INT Number of cores (default: $cores)
--memory INT Memory (default: $memory) --memory INT Memory (default: $memory)
@ -44,15 +54,16 @@ while [ $# -gt 0 ]; do
case $argument in case $argument in
--username) readonly username=$1; shift ;; --username) readonly username=$1; shift ;;
--password) readonly password=$1; shift ;; --password) readonly password=$1; shift ;;
--vmid) readonly vmid=$1; shift ;;
--iso) iso=$1; shift ;;
--sockets) sockets=$1; shift ;; --sockets) sockets=$1; shift ;;
--cores) cores=$1; shift ;; --cores) cores=$1; shift ;;
--memory) memory=$1; shift ;; --memory) memory=$1; shift ;;
-h|-\?|--help) help; exit 0 ;; -h|-\?|--help) help; exit 0 ;;
*) die 'Unknown argument: `%s`.' "$argument" ;;
-*) die 'Unknown argument: `%s`.' "$argument" ;;
*) vmids="$vmids $argument" ;;
esac esac
done done
@ -64,32 +75,22 @@ if [ -z "$username" ] || [ -z "$password" ]; then
fi fi
fi fi
[ -z "$vmid" ] && die 'Required: `--vmid`.\n'
printf 'Provisioning VM %d with:\n' $vmid
readonly iso
readonly sockets readonly sockets
readonly cores readonly cores
readonly memory readonly memory
printf ' iso: %s\n' $iso ## FIXME: When we figure out how to use other nodes than node051.
printf ' sockets: %d\n' $sockets # if [ -z "$node" ]; then
printf ' cores: %d\n' $cores # printf 'Picking random node...'
printf ' memory: %d\n' $memory # proxmox GET $apiurl/nodes
# node=$(from_response .data[].node | sort -R | head -n 1)
# printf ' done. Picked `%s`.\n' "$node"
# fi
# readonly node
################################################################################ ################################################################################
## Getting started ## Getting started
readonly apiurl=https://192.168.51.81:8006/api2/json
## FIXME: There seems to be a problem with file upload where the task is
## registered to `node051` no matter what node we are actually uploading to? For
## now, let us just use `node051` everywhere.
node=node051
from_response () { echo "$response" | jq -r "$1"; }
printf 'Authenticating...' printf 'Authenticating...'
response=$( response=$(
http \ http \
@ -98,68 +99,84 @@ response=$(
"username=$username" \ "username=$username" \
"password=$password" "password=$password"
) )
readonly csrfToken=$(from_response .data.CSRFPreventionToken) readonly ticket=$(echo "$response" | jq -r .data.ticket)
readonly ticket=$(from_response .data.ticket) readonly csrfToken=$(echo "$response" | jq -r .data.CSRFPreventionToken)
printf ' done.\n' printf ' done.\n'
http_ () { proxmox () {
response=$(
http \ http \
--form \
--verify no \ --verify no \
"$@" \ "$@" \
"Cookie:PVEAuthCookie=$ticket" \ "Cookie:PVEAuthCookie=$ticket" \
"CSRFPreventionToken:$csrfToken" "CSRFPreventionToken:$csrfToken"
)
} }
wait_ () { ## Synchronous variant for when the `proxmox` function would just respond an
upid=$1 ## UPID in the `data` JSON field.
proxmox_sync () {
response=$(proxmox "$@")
upid=$(echo "$response" | jq -r .data)
while :; do while :; do
http_ GET $apiurl/nodes/$node/tasks/$upid/status response=$(proxmox GET $apiurl/nodes/$node/tasks/$upid/status)
status=$(from_response .data.status) status=$(echo "$response" | jq -r .data.status)
case $status in case $status in
running) printf '.'; sleep 1 ;; running) sleep 1 ;;
stopped) break ;; stopped) break ;;
*) printf ' unexpected status: `%s`\n' "$status"; exit 2 ;; *) die 'unexpected status: `%s`' "$status" ;;
esac esac
done done
} }
################################################################################
## Build ISO
build_iso () {
printf 'Building ISO for VM %d...\n' $1
nix build \
.#isoInstallers.provisioning.fedi$1 \
--log-format raw --quiet \
--out-link $tmpdir/installer-fedi$1
ln -sf $tmpdir/installer-fedi$1/iso/installer.iso $tmpdir/installer-fedi$1.iso
printf 'done building ISO for VM %d.\n' $1
}
################################################################################ ################################################################################
## Upload ISO ## Upload ISO
if [ -z "$node" ]; then upload_iso () {
printf 'Picking random node...' printf 'Uploading ISO for VM %d...\n' $1
http_ GET $apiurl/nodes
node=$(from_response .data[].node | sort -R | head -n 1)
printf ' done. Picked `%s`.\n' "$node"
fi
readonly node
absiso=$(cd "$(dirname "$iso")"; pwd)/$(basename "$iso") proxmox_sync POST $apiurl/nodes/$node/storage/local/upload \
readonly isoname=installer-$vmid.iso filename@$tmpdir/installer-fedi$1.iso \
printf 'Uploading ISO...'
ln -sf $absiso /tmp/$isoname
http_ --form POST $apiurl/nodes/$node/storage/local/upload \
filename@/tmp/$isoname \
content==iso content==iso
rm /tmp/$isoname
wait_ $(from_response .data) printf 'done uploading ISO for VM %d.\n' $1
printf ' done.\n' }
################################################################################
## Remove ISO
remove_iso () {
printf 'Removing ISO for VM %d... unsupported for now. (FIXME)\n' $1
}
################################################################################ ################################################################################
## Create VM ## Create VM
printf 'Creating VM...' create_vm () {
printf 'Creating VM %d...\n' $1
http_ --form POST $apiurl/nodes/$node/qemu \ proxmox_sync POST $apiurl/nodes/$node/qemu \
\ \
vmid==$vmid \ vmid==$1 \
name==$(printf 'fedi%03d' $vmid) \ name=="fedi$1" \
pool==Fediversity \ pool==Fediversity \
\ \
ide2=="local:iso/$isoname,media=cdrom" \ ide2=="local:iso/installer-fedi$1.iso,media=cdrom" \
ostype==l26 \ ostype==l26 \
\ \
bios==ovmf \ bios==ovmf \
@ -178,40 +195,69 @@ http_ --form POST $apiurl/nodes/$node/qemu \
\ \
net0=='virtio,bridge=vnet1306' net0=='virtio,bridge=vnet1306'
wait_ $(from_response .data) printf 'done creating VM %d.\n' $1
printf ' done.\n' }
################################################################################ ################################################################################
## Install VM ## Install VM
printf 'Installing VM...' install_vm () {
printf 'Installing VM %d...\n' $1
http_ POST $apiurl/nodes/$node/qemu/$vmid/status/start proxmox_sync POST $apiurl/nodes/$node/qemu/$1/status/start
wait_ $(from_response .data)
while :; do while :; do
http_ GET $apiurl/nodes/$node/qemu/$vmid/status/current response=$(proxmox GET $apiurl/nodes/$node/qemu/$1/status/current)
status=$(from_response .data.status) status=$(echo "$response" | jq -r .data.status)
case $status in case $status in
running) printf '.'; sleep 1 ;; running) sleep 1 ;;
stopped) break ;; stopped) break ;;
*) printf ' unexpected status: `%s`\n' "$status"; exit 2 ;; *) printf ' unexpected status: `%s`\n' "$status"; exit 2 ;;
esac esac
done done
printf ' done.\n' printf 'done installing VM %d.\n' $1
}
################################################################################ ################################################################################
## Start VM ## Start VM
printf 'Starting VM...' start_vm () {
printf 'Starting VM %d...\n' $1
http_ --form POST $apiurl/nodes/$node/qemu/$vmid/config \ proxmox_sync POST $apiurl/nodes/$node/qemu/$1/config \
ide2=='none,media=cdrom' \ ide2=='none,media=cdrom' \
net0=='virtio,bridge=vnet1305' net0=='virtio,bridge=vnet1305'
wait_ $(from_response .data)
http_ POST $apiurl/nodes/$node/qemu/$vmid/status/start proxmox_sync POST $apiurl/nodes/$node/qemu/$1/status/start
wait_ $(from_response .data)
printf ' done.\n' printf 'done starting VM %d.\n' $1
}
################################################################################
## Main loop
printf 'Provisioning VMs%s with:\n' "$vmids"
printf ' sockets: %d\n' $sockets
printf ' cores: %d\n' $cores
printf ' memory: %d\n' $memory
provision_vm () {
build_iso $1
upload_iso $1
create_vm $1
install_vm $1
start_vm $1
remove_iso $1
}
for vmid in $vmids; do
provision_vm $vmid
done
printf 'done provisioning VMs%s.\n' "$vmids"
################################################################################
## Cleanup
rm -Rf $tmpdir