diff options
Diffstat (limited to 'bin/vm')
-rwxr-xr-x | bin/vm | 176 |
1 files changed, 176 insertions, 0 deletions
@@ -0,0 +1,176 @@ +#!/bin/sh +set -eu + + +usage() { + cat <<-'EOF' + Usage: + vm ACTION [OS] + vm -h + EOF +} + +help() { + cat <<-'EOF' + + + Options: + -h, --help show this message + + ACTION one of: + - up + - down + - status + OS the name of the OS to be acted upon + + + Manage the state of known virtual machines. + + The VM QCOW2 images are stored under + $XDG_STATE_HOME/euandreh/qemu/, as "$OS.qcow2" files. The PIDs + of the running images are stored in individual files under + $XDG_RUNTIME_DIR/vm-pids/, as "$OS.pid" files. + + It also generates an SSH configuration file to bu `Included` + by the main $XDG_CONFIG_HOME/ssh/config file, which contains + one alias entry for each VM, so that one can do a combination + of `vm up alpine && ssh alpine`. + + + Examples: + + Start the VM for Alpine: + + $ vm up alpine + + + Stop the VM for Slackware, which was already down + + $ vm down slackware + The VM for "slackware" is not running, already. + + + List the available VMs, and their current state: + + $ vm status + alpine:up + slackware:down + freebsd:up + EOF +} + + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + + +ACTION="${1:-}" +OS="${2:-}" + +eval "$(assert-arg "$ACTION" 'ACTION')" + + +VMS=' +alpine:60022 +' + +for vm in $VMS; do + NAME="$(echo "$vm" | cut -d: -f1)" + PORT="$(echo "$vm" | cut -d: -f2)" + cat <<-EOF + Host $NAME + HostName localhost + Port $PORT + + EOF +done > "$XDG_DATA_HOME"/euandreh/vm-ssh.conf + +PIDS_DIR="${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/vm-pids" +PID_F="$PIDS_DIR/$OS.pid" +mkdir -p "$PIDS_DIR" + + +port_for_os() { + _OS="$1" + _PORT="$(echo "$VMS" | awk -F: -vOS="$_OS" '$1 == OS { print $2 }')" + if [ -z "$_PORT" ]; then + printf 'Unknown OS: "%s".\n\n' "$_OS" >&2 + usage >&2 + exit 2 + fi + printf '%s' "$_PORT" +} + +case "$ACTION" in + status) + echo "$VMS" | awk -F: '$0=$1' | while read -r vm; do + if [ -e "$PIDS_DIR/$vm.pid" ]; then + STATUS=up + else + STATUS=down + fi + printf '%s:%s\n' "$vm" "$STATUS" + done + ;; + up) + eval "$(assert-arg "$OS" 'OS')" + PORT="$(port_for_os "$OS")" + + if [ -e "$PID_F" ]; then + printf 'The VM for "%s" is already running with PID %s.\n' \ + "$OS" "$(cat "$PID_F")" >&2 + else + QCOW="$XDG_STATE_HOME"/euandreh/qemu/"$OS".qcow2 + qemu-system-x86_64 \ + -m 1G \ + -nic user,model=virtio,hostfwd=tcp::"$PORT"-:22 \ + -drive file="$QCOW",media=disk,if=virtio \ + -enable-kvm \ + -nographic 1>/dev/null 2>&1 & + printf '%s' $! > "$PID_F.pid" + fi + ;; + down) + eval "$(assert-arg "$OS" 'OS')" + PORT="$(port_for_os "$OS")" + + if [ ! -e "$PID_F" ]; then + printf 'The VM for "%s" is not running, already.\n' "$OS" >&2 + else + # shellcheck disable=2064 + trap "rm -f $PID_F" EXIT + kill "$(cat "$PID_F")" + fi + ;; + *) + printf 'Unrecognized action: "%s".\n\n' "$ACTION" >&2 + usage >&2 + exit 2 +esac |