Skip to content

Instantly share code, notes, and snippets.

@jirutka
Last active May 16, 2023 20:02
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jirutka/836f3bd37c582fb3e0bc953091df7154 to your computer and use it in GitHub Desktop.
Replace disk in the specified VM template in Proxmox with the given image.
#!/bin/sh
# SPDX-FileCopyrightText: 2023 Jakub Jirutka <jakub@jirutka.cz>
# SPDX-License-Identifier: MIT
set -eu
PROGNAME='qm-replace-disk'
VERSION='0.1.0'
# Defaults
DISK='scsi0'
die() {
printf "$PROGNAME: %s\n" "$@" >&2
exit 2
}
help() {
cat <<-EOF
Usage: $PROGNAME [options] <vmid> <image>
Replace disk in the specified VM template in Proxmox with the given image.
Arguments:
<vmid> ID of the VM template.
<image> Path to the image file to import or "-" for stdin.
Options:
-d --disk <diskid> The disk to replace (default is "$DISK").
-V --version Show script name & version and exit.
-h --help Show this message and exit.
EOF
}
parse_args() {
local opts
opts="$(getopt -n $PROGNAME -o d:hV -l disk:,help,version -- "$@")" || exit 1
eval set -- "$opts"
while [ $# -gt 0 ]; do
case "$1" in
-d | --disk) DISK=$2;;
-h | --help) help; exit 0;;
-V | --version) echo "$PROGNAME $VERSION"; exit 0;;
--) shift; break;;
esac
shift 2
done
[ $# -eq 2 ] || die 'invalid number of arguments (try --help)'
VMID=$1
IMAGE_FILE=$2
}
parse_args "$@"
if [ "$(id -u)" -ne 0 ]; then
echo 'Re-executing as root'
exec sudo -u root "$0" "$@"
fi
config=$(qm config "$VMID") || exit 2
if ! echo "$config" | grep -qFx 'template: 1'; then
die "VM $VMID is not a template!" >&2
fi
# Example: "scsi0: zfs_main:vm-1317-disk-1,iothread=1,size=5G".
storageid=$(echo "$config" | sed -En "s/^$DISK: ([^:]+).*/\1/p")
[ "$storageid" ] || die "VM $VMID does not have disk $DISK!"
diskopts="$(echo "$config" \
| sed -En "s/^$DISK: [^,]+,?(.*)/\1/p" \
| tr ',' '\n' \
| grep -v '^size=' \
| tr '\n' ',')"
diskopts="${diskopts%,}"
tmpfile=
if [ "$IMAGE_FILE" = '-' ]; then
printf 'Reading image from stdin...'
tmpfile="$(mktemp -t -p /var/tmp "$PROGNAME.XXXXXX")"
IMAGE_FILE="$tmpfile"
cat > "$tmpfile"
size=$(stat -c %s "$IMAGE_FILE")
echo " $(( $size >>20 )) MiB done." >&2
fi
[ -f "$IMAGE_FILE" ] || die "File $IMAGE_FILE does not exist or not readable!"
qm set "$VMID" -$DISK "$storageid:0,$diskopts,import-from=$IMAGE_FILE"
[ -f "$tmpfile" ] && rm "$tmpfile"
unused="$(qm config "$VMID" | grep -o '^unused[0-9]' | tail -n1)"
[ "$unused" ] && qm disk unlink "$VMID" --idlist "$unused"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment