aboutsummaryrefslogtreecommitdiff
path: root/bin/vm
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2022-10-10 18:11:06 -0300
committerEuAndreh <eu@euandre.org>2022-10-10 18:11:09 -0300
commit26158ce2ebcf1f91abd4dcd43ff8aa7185754a0f (patch)
tree1295270a7aad8f5f9e154b5542550ccdf43c8f8f /bin/vm
parentbin/wms: Add new working binary, and integrate it with i3 (diff)
downloaddotfiles-26158ce2ebcf1f91abd4dcd43ff8aa7185754a0f.tar.gz
dotfiles-26158ce2ebcf1f91abd4dcd43ff8aa7185754a0f.tar.xz
bin/vm: Add VM management script
etc/guix/system.scm: Include myself in the "kvm" group so that the QEMU commands can be given the "--enable-kvm" flag; etc/ssh/config: Include the generated SSH config file
Diffstat (limited to 'bin/vm')
-rwxr-xr-xbin/vm176
1 files changed, 176 insertions, 0 deletions
diff --git a/bin/vm b/bin/vm
new file mode 100755
index 0000000..f4ba093
--- /dev/null
+++ b/bin/vm
@@ -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