aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2022-12-02 22:22:27 -0300
committerEuAndreh <eu@euandre.org>2022-12-02 22:24:54 -0300
commit5f981d9fbe486e37e90ee18d8c959a7be7616558 (patch)
treec5a6b6d24ae70e23d592381ebda3d1b117e2636e
parentbin/serve: Find a port instead of having a hard-coded fallback (diff)
downloaddotfiles-5f981d9fbe486e37e90ee18d8c959a7be7616558.tar.gz
dotfiles-5f981d9fbe486e37e90ee18d8c959a7be7616558.tar.xz
bin/vm: v2
- support -S flag for toggling snapshot mode; - support -G flag for toggling GUI mode; - dynamically discover available images; - dynamically find available ports to map to 22.
-rwxr-xr-xbin/vm169
-rw-r--r--etc/ssh/config.tmpl2
-rw-r--r--etc/ssh/known_hosts6
3 files changed, 120 insertions, 57 deletions
diff --git a/bin/vm b/bin/vm
index 813f1e6..52bcce5 100755
--- a/bin/vm
+++ b/bin/vm
@@ -5,7 +5,7 @@ set -eu
usage() {
cat <<-'EOF'
Usage:
- vm ACTION [OS]
+ vm [-G] [-S] [-v] ACTION [OS]
vm -h
EOF
}
@@ -15,6 +15,9 @@ help() {
Options:
+ -G use graphics
+ -S don't write to VM image (snapshot on)
+ -v verbose mode
-h, --help show this message
ACTION one of:
@@ -27,14 +30,14 @@ help() {
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
+ $XDG_STATE_HOME/vm/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.
+ $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`.
+ It also generates an SSH configuration file under
+ $XDG_DATA_HOME/vm/ssh.conf to be `Included` by the main
+ ~/.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:
@@ -53,8 +56,8 @@ help() {
List the available VMs, and their current state:
$ vm status
- alpine:up
- slackware:down
+ alpine up
+ slackware down
freebsd:up
EOF
}
@@ -75,8 +78,20 @@ for flag in "$@"; do
esac
done
-while getopts 'h' flag; do
+GRAPHICS=false
+SNAPSHOT=false
+VERBOSE=false
+while getopts 'GSvh' flag; do
case "$flag" in
+ G)
+ GRAPHICS=true
+ ;;
+ S)
+ SNAPSHOT=true
+ ;;
+ v)
+ VERBOSE=true
+ ;;
h)
usage
help
@@ -91,83 +106,125 @@ done
shift $((OPTIND - 1))
-ACTION="${1:-}"
-OS="${2:-}"
-eval "$(assert-arg "$ACTION" 'ACTION')"
+QCOW_DIR="${XDG_STATE_HOME:-$HOME/.local/state}"/vm/qemu
+RUNDIR="${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}}/vm"
+LOGS="$RUNDIR"/logs
+mkdir -p "$RUNDIR" "$QCOW_DIR" "$XDG_DATA_HOME"/vm
+guess_name() {
+ PREFIX="$1"
+ IMAGES="$(find "$QCOW_DIR" -type f -name "${PREFIX}*")"
+ COUNT="$(echo "$IMAGES" | wc -l)"
+ if [ "$COUNT" != 1 ]; then
+ printf 'Cannot guess name with the given prefix: "%s".\n' "$PREFIX" >&2
+ printf '\nThe possibilities are:\n' >&2
+ printf '%s\n' "$IMAGES" |
+ xargs -I% basename % .qcow2 |
+ sed 's/^/- /' >&2
+ exit 2
+ fi
+ printf '%s\n' "$(basename "$IMAGES" .qcow2)"
+}
-VMS='
-alpine:60022
-'
+write_ssh_config() {
+ for port in "$RUNDIR"/*.port; do
+ if [ ! -e "$port" ]; then
+ break
+ fi
+ NAME="$(basename "$port" .port)"
+ PORT="$(cat "$port")"
+ cat <<-EOF
+ Host $NAME
+ HostName localhost
+ Port $PORT
+
+ EOF
+ done > "$XDG_DATA_HOME"/vm/ssh.conf
+}
-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
+write_ssh_config
- 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"
+ACTION="${1:-}"
+OS="${2:-}"
+eval "$(assert-arg "$ACTION" 'ACTION')"
+
+
+FLAGS=''
+if [ "$GRAPHICS" = false ]; then
+ FLAGS="$FLAGS -nographic"
+else
+ FLAGS="$FLAGS -display sdl"
+fi
+if [ "$SNAPSHOT" = true ]; then
+ FLAGS="$FLAGS -snapshot"
+fi
-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
+ for img in "$QCOW_DIR"/*.qcow2; do
+ if [ ! -e "$img" ]; then
+ break
+ fi
+ NAME="$(basename "$img" .qcow2)"
+ if [ -e "$RUNDIR/$NAME.pid" ]; then
STATUS=up
else
STATUS=down
fi
- printf '%s:%s\n' "$vm" "$STATUS"
+ printf '%s\t%s\n' "$NAME" "$STATUS"
done
;;
up)
eval "$(assert-arg "$OS" 'OS')"
- PORT="$(port_for_os "$OS")"
+ OS="$(guess_name "$OS")"
+ PID_F="$RUNDIR/$OS.pid"
+ PORT_F="$RUNDIR/$OS.port"
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"
+ exit 1
+ fi
+
+ PORT="$(free-port)"
+ QCOW="$QCOW_DIR"/"$OS".qcow2
+ if [ "$VERBOSE" = true ]; then
+ set -x
fi
+ # shellcheck disable=2086
+ qemu-system-x86_64 \
+ -m 1G \
+ -nic user,model=virtio,hostfwd=tcp::"$PORT"-:22 \
+ -drive file="$QCOW",media=disk,if=virtio \
+ -enable-kvm \
+ $FLAGS 1>>"$LOGS" 2>&1 &
+ PID=$!
+ set +x
+ printf '%s' "$PID" > "$PID_F"
+ printf '%s' "$PORT" > "$PORT_F"
+
+ write_ssh_config
;;
down)
eval "$(assert-arg "$OS" 'OS')"
- PORT="$(port_for_os "$OS")"
+ OS="$(guess_name "$OS")"
+ PID_F="$RUNDIR/$OS.pid"
+ PORT_F="$RUNDIR/$OS.port"
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")"
+ exit 1
fi
+
+ PID="$(cat "$PID_F")"
+ rm -f "$PID_F" "$PORT_F"
+ kill "$PID"
+
+ write_ssh_config
;;
*)
printf 'Unrecognized action: "%s".\n\n' "$ACTION" >&2
diff --git a/etc/ssh/config.tmpl b/etc/ssh/config.tmpl
index fd4b8a3..4a9ba86 100644
--- a/etc/ssh/config.tmpl
+++ b/etc/ssh/config.tmpl
@@ -3,4 +3,4 @@ Host *
Include ~/dev/libre/servers/src/infrastructure/ssh.conf
Include ~/dev/others/lawtech/src/infrastructure/ssh.conf
-Include ${XDG_DATA_HOME}/euandreh/vm-ssh.conf
+Include ${XDG_DATA_HOME}/vm/ssh.conf
diff --git a/etc/ssh/known_hosts b/etc/ssh/known_hosts
index f567da3..67bc095 100644
--- a/etc/ssh/known_hosts
+++ b/etc/ssh/known_hosts
@@ -34,3 +34,9 @@ euandre.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKF5klRzMiaDhfFv7vj6nIT2Bdjbcgps
localhost ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII9jxIXM2FSYeZmY2uLWkQUJQLNIQQJyJdc7P4eEPhEU
velhinho ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII9jxIXM2FSYeZmY2uLWkQUJQLNIQQJyJdc7P4eEPhEU
+
+
+
+# QEMU VMs, managed by vm(1)
+
+alpine-amd64-headless ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEuoUWqrJ8WLBDWwWG7zCyYVYz1upMlg1mSXMGMHIVzY