Use SCRIPT_DIR, add sshpass and auto-mount workspaces, update flakes

This commit is contained in:
Joshua Bell 2026-01-26 08:41:33 -06:00
parent 8534f7efb9
commit 9aa72fade7
8 changed files with 292 additions and 413 deletions

View file

@ -8,8 +8,11 @@
set -euo pipefail
# Determine script directory for locating sibling scripts
readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# Source common library (use QVM_LIB_DIR from wrapper or relative path for dev)
source "${QVM_LIB_DIR:-$(dirname "$0")/../lib}/common.sh"
source "${QVM_LIB_DIR:-${SCRIPT_DIR}/../lib}/common.sh"
readonly VERSION="0.1.0"
@ -72,7 +75,7 @@ main() {
start|stop|run|ssh|status|rebuild|reset)
# Route to the appropriate qvm-* script
# Use exec to replace this process with the subcommand
exec "qvm-${subcommand}" "$@"
exec "${SCRIPT_DIR}/qvm-${subcommand}" "$@"
;;
help|--help|-h)
show_help

View file

@ -28,9 +28,17 @@ ensure_user_flake() {
log_info "User flake not found, copying default template..."
# Determine default flake location
# In installed version: $QVM_LIB_DIR/../flake/default-vm/
# In installed version: $QVM_LIB_DIR/../share/qvm/default-vm/
# In development: $(dirname "$0")/../flake/default-vm/
local default_flake_dir="$QVM_LIB_DIR/../flake/default-vm"
local default_flake_dir
# Try installed location first
if [[ -d "$QVM_LIB_DIR/../share/qvm/default-vm" ]]; then
default_flake_dir="$QVM_LIB_DIR/../share/qvm/default-vm"
else
# Fall back to development location
default_flake_dir="$(dirname "$(readlink -f "$0")")/../flake/default-vm"
fi
if [[ ! -d "$default_flake_dir" ]]; then
die "Default flake template not found at: $default_flake_dir"

View file

@ -95,6 +95,34 @@ register_workspace() {
return 1 # Indicate new workspace added
}
#
# ensure_workspace_mounted - Mount workspace in VM if not already mounted
# Args: $1 - SSH port
# $2 - mount tag (e.g., ws_abc123)
# $3 - guest path (e.g., /workspace/abc123)
# Returns: 0 on success
#
ensure_workspace_mounted() {
local ssh_port="$1"
local mount_tag="$2"
local guest_path="$3"
# SSH into VM and mount the workspace
# - mkdir creates the mount point if missing
# - mount attempts to mount the 9p virtfs
# - || true ensures we don't fail if already mounted
sshpass -p root ssh -o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o LogLevel=ERROR \
-o PubkeyAuthentication=no \
-o PasswordAuthentication=yes \
-p "$ssh_port" \
root@localhost \
"mkdir -p '$guest_path' && mount -t 9p -o trans=virtio,version=9p2000.L,msize=104857600 '$mount_tag' '$guest_path' 2>/dev/null || true" >/dev/null 2>&1
return 0
}
#
# is_workspace_mounted - Check if workspace is actually mounted in VM
# Args: $1 - SSH port
@ -106,9 +134,11 @@ is_workspace_mounted() {
local guest_path="$2"
# SSH into VM and check if guest path exists and is a directory
if ssh -o StrictHostKeyChecking=no \
if sshpass -p root ssh -o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o LogLevel=ERROR \
-o PubkeyAuthentication=no \
-o PasswordAuthentication=yes \
-p "$ssh_port" \
root@localhost \
"test -d '$guest_path'" 2>/dev/null; then
@ -169,14 +199,22 @@ main() {
local ssh_port
ssh_port=$(get_ssh_port)
# Check if workspace is actually mounted in VM
# Get mount tag from workspaces.json
local mount_tag
mount_tag=$(jq -r --arg path "$workspace_path" '.[] | select(.host_path == $path) | .mount_tag' "$QVM_WORKSPACES_FILE")
# Ensure workspace is mounted (auto-mount if not)
log_info "Ensuring workspace is mounted..."
ensure_workspace_mounted "$ssh_port" "$mount_tag" "$guest_path"
# Verify workspace is actually mounted
if ! is_workspace_mounted "$ssh_port" "$guest_path"; then
log_error "Workspace not mounted in VM"
log_error "Failed to mount workspace in VM"
echo ""
echo "This workspace was just registered but is not mounted in the VM."
echo "Workspaces must be mounted at VM start time."
echo "The workspace could not be mounted automatically."
echo "This may indicate the VM was started before this workspace was registered."
echo ""
echo "Please restart the VM to mount this workspace:"
echo "Please restart the VM to properly configure the workspace:"
echo " qvm stop"
echo " qvm start"
echo ""
@ -185,14 +223,18 @@ main() {
fi
# Build SSH command
# - Use sshpass for automated password auth (password: root)
# - Use -t if stdin is a TTY (for interactive commands)
# - Suppress SSH warnings (ephemeral VM, host keys change)
# - cd to guest path and execute command
local ssh_cmd=(
sshpass -p root
ssh
-o StrictHostKeyChecking=no
-o UserKnownHostsFile=/dev/null
-o LogLevel=ERROR
-o PubkeyAuthentication=no
-o PasswordAuthentication=yes
-p "$ssh_port"
)

View file

@ -85,12 +85,15 @@ main() {
local port
port=$(get_ssh_port)
# Build SSH command
# Build SSH command with sshpass for automated password auth
local ssh_cmd=(
sshpass -p root
ssh
-o StrictHostKeyChecking=no
-o UserKnownHostsFile=/dev/null
-o LogLevel=ERROR # Suppress host key warnings
-o PubkeyAuthentication=no # Use password auth (password: root)
-o PasswordAuthentication=yes
-p "$port"
root@localhost
)

View file

@ -76,7 +76,7 @@ mount_workspaces() {
local i=0
while (( i < workspace_count )); do
local path mount_tag
path=$(jq -r ".[$i].path" "$QVM_WORKSPACES_FILE")
path=$(jq -r ".[$i].host_path" "$QVM_WORKSPACES_FILE")
mount_tag=$(jq -r ".[$i].mount_tag" "$QVM_WORKSPACES_FILE")
if [[ -z "$path" || -z "$mount_tag" || "$path" == "null" || "$mount_tag" == "null" ]]; then
@ -93,9 +93,9 @@ mount_workspaces() {
fi
log_info " - $path -> $mount_tag"
cmd_array+=(-virtfs "local,path=$path,mount_tag=$mount_tag,security_model=mapped-xattr,trans=virtio,version=9p2000.L,msize=104857600")
cmd_array+=(-virtfs "local,path=$path,mount_tag=$mount_tag,security_model=mapped-xattr")
(( i++ ))
(( i++ )) || true # Prevent set -e from exiting when i was 0
done
}
@ -173,10 +173,11 @@ main() {
-device "virtio-net-pci,netdev=net0"
# 9p mounts for shared caches (security_model=mapped-xattr for proper permissions)
-virtfs "local,path=$QVM_CARGO_HOME,mount_tag=cargo_home,security_model=mapped-xattr,trans=virtio,version=9p2000.L,msize=104857600"
-virtfs "local,path=$QVM_CARGO_TARGET,mount_tag=cargo_target,security_model=mapped-xattr,trans=virtio,version=9p2000.L,msize=104857600"
-virtfs "local,path=$QVM_PNPM_STORE,mount_tag=pnpm_store,security_model=mapped-xattr,trans=virtio,version=9p2000.L,msize=104857600"
-virtfs "local,path=$QVM_SCCACHE,mount_tag=sccache,security_model=mapped-xattr,trans=virtio,version=9p2000.L,msize=104857600"
# Note: trans, version, msize are kernel-side mount options (in NixOS flake), not QEMU options
-virtfs "local,path=$QVM_CARGO_HOME,mount_tag=cargo_home,security_model=mapped-xattr"
-virtfs "local,path=$QVM_CARGO_TARGET,mount_tag=cargo_target,security_model=mapped-xattr"
-virtfs "local,path=$QVM_PNPM_STORE,mount_tag=pnpm_store,security_model=mapped-xattr"
-virtfs "local,path=$QVM_SCCACHE,mount_tag=sccache,security_model=mapped-xattr"
)
# Add workspace mounts from registry
@ -187,8 +188,8 @@ main() {
# Serial console to log file
-serial "file:$QVM_SERIAL_LOG"
# No graphics
-nographic
# No graphics (use -display none for daemonized mode)
-display none
# Daemonize with PID file
-daemonize