From 4154a492b0035f7b8bdc8a06d5f431f302815b5b Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Wed, 15 Apr 2026 16:30:33 +0200 Subject: [PATCH] Add runvm function with IP detection for libvirt VMs --- dotfiles/desktop/.bashrc.d/30-runvm.sh | 94 ++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100755 dotfiles/desktop/.bashrc.d/30-runvm.sh diff --git a/dotfiles/desktop/.bashrc.d/30-runvm.sh b/dotfiles/desktop/.bashrc.d/30-runvm.sh new file mode 100755 index 0000000..31e6f87 --- /dev/null +++ b/dotfiles/desktop/.bashrc.d/30-runvm.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +runvm() { + local vm state choice count i ip + + if ! command -v virsh >/dev/null 2>&1; then + printf '%s\n' "runvm: virsh is required (libvirt)" >&2 + return 1 + fi + + sudo -v + + local line + vms=() + while IFS= read -r line; do + [ -n "$line" ] && vms+=("$line") + done < <(sudo virsh list --all --name) + + if [ ${#vms[@]} -eq 0 ]; then + printf '%s\n' "runvm: no VMs found" >&2 + return 1 + fi + + printf '\n%s\n' "VMs:" + count=1 + for i in "${!vms[@]}"; do + state=$(sudo virsh dominfo "${vms[$i]}" 2>/dev/null | awk '/^State:/ {print $2}') + printf ' %d) %-30s [%s]\n' "$((count++))" "${vms[$i]}" "${state:-unknown}" + done + printf '\n' + + read -p "Select VM (1-${#vms[@]}) or 'q' to quit: " choice + + if [ "$choice" = "q" ] || [ -z "$choice" ]; then + return 0 + fi + + if ! [[ "$choice" =~ ^[0-9]+$ ]] || [ "$choice" -lt 1 ] || [ "$choice" -gt "${#vms[@]}" ]; then + printf '%s\n' "runvm: invalid choice" >&2 + return 1 + fi + + vm="${vms[$((choice - 1))]}" + state=$(sudo virsh dominfo "$vm" 2>/dev/null | awk '/^State:/ {print $2}') + + printf '\nSelected: %s\n' "$vm" + + if [ "$state" = "running" ]; then + printf ' VM is already running.\n' + ip=$(_runvm_get_ip "$vm") + if [ -n "$ip" ] && [ "$ip" != "" ]; then + printf ' IP: %s\n' "$ip" + fi + return 0 + fi + + printf 'Starting %s...\n' "$vm" + if ! sudo virsh start "$vm"; then + printf ' failed to start %s\n' "$vm" >&2 + return 1 + fi + + printf ' %s started.\n' "$vm" + printf ' Waiting for IP...\n' + ip=$(_runvm_get_ip "$vm") + + if [ -n "$DISPLAY" ] && command -v notify-send >/dev/null 2>&1; then + notify-send "$vm started" "IP: $ip" 2>/dev/null + fi + + printf ' IP: %s\n' "$ip" + + return 0 +} + +_runvm_get_ip() { + local vm="$1" + local mac network ip i + + mac=$(sudo virsh dumpxml "$vm" | awk -F"'" '/mac address/ {print $2}') + [ -z "$mac" ] && return 1 + + network=$(sudo virsh dumpxml "$vm" | awk -F"'" '/source network/ {print $2}') + [ -z "$network" ] && return 1 + + for i in $(seq 15); do + ip=$(sudo virsh net-dhcp-leases "$network" 2>/dev/null | \ + awk -v m="$mac" '$3 == m {print $5}' | cut -d/ -f1) + [ -n "$ip" ] && break + sleep 2 + done + + printf '%s' "${ip:-}" +}