Use SCRIPT_DIR, add sshpass and auto-mount workspaces, update flakes
This commit is contained in:
parent
8534f7efb9
commit
9aa72fade7
8 changed files with 292 additions and 413 deletions
7
bin/qvm
7
bin/qvm
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
54
bin/qvm-run
54
bin/qvm-run
|
|
@ -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"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -32,10 +32,16 @@
|
|||
# Create output directories
|
||||
mkdir -p $out/bin
|
||||
mkdir -p $out/lib/qvm
|
||||
mkdir -p $out/share/qvm
|
||||
|
||||
# Install library files
|
||||
install -Dm755 lib/common.sh $out/lib/qvm/common.sh
|
||||
|
||||
# Install default VM flake template
|
||||
if [ -d "flake/default-vm" ]; then
|
||||
cp -r flake/default-vm $out/share/qvm/default-vm
|
||||
fi
|
||||
|
||||
# Install all scripts from bin/
|
||||
for script in bin/*; do
|
||||
if [ -f "$script" ]; then
|
||||
|
|
@ -57,6 +63,7 @@
|
|||
pkgs.netcat-gnu
|
||||
pkgs.bc
|
||||
pkgs.procps
|
||||
pkgs.sshpass
|
||||
]} \
|
||||
--set QVM_LIB_DIR "$out/lib/qvm"
|
||||
done
|
||||
|
|
@ -104,6 +111,7 @@
|
|||
netcat-gnu
|
||||
bc
|
||||
procps
|
||||
sshpass
|
||||
|
||||
# Development tools
|
||||
shellcheck
|
||||
|
|
|
|||
|
|
@ -3,210 +3,234 @@
|
|||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
nixos-generators = {
|
||||
url = "github:nix-community/nixos-generators";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
opencode.url = "github:anomalyco/opencode";
|
||||
common.url = "git+https://git.joshuabell.xyz/ringofstorms/dotfiles?dir=flakes/common";
|
||||
ros_neovim.url = "git+https://git.joshuabell.xyz/ringofstorms/nvim";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
nixos-generators,
|
||||
home-manager,
|
||||
opencode,
|
||||
...
|
||||
}: let
|
||||
system = "x86_64-linux";
|
||||
stateVersion = "24.11";
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
nixos-generators,
|
||||
...
|
||||
}@inputs:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
stateVersion = "26.05";
|
||||
|
||||
vmModule = { config, pkgs, lib, ... }: {
|
||||
imports = [
|
||||
home-manager.nixosModules.home-manager
|
||||
];
|
||||
vmModule =
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
inputs.home-manager.nixosModules.home-manager
|
||||
|
||||
nixpkgs.config = {
|
||||
allowUnfree = true;
|
||||
allowUnfreePredicate = (_: true);
|
||||
};
|
||||
inputs.ros_neovim.nixosModules.default
|
||||
inputs.common.nixosModules.essentials
|
||||
inputs.common.nixosModules.git
|
||||
inputs.common.nixosModules.zsh
|
||||
inputs.common.nixosModules.tmux
|
||||
];
|
||||
|
||||
# Distinctive hostname for easy identification
|
||||
networking.hostName = "qvm-dev";
|
||||
nixpkgs.config = {
|
||||
allowUnfree = true;
|
||||
allowUnfreePredicate = (_: true);
|
||||
};
|
||||
|
||||
# SSH enabled with password auth for root
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PasswordAuthentication = true;
|
||||
settings.PermitRootLogin = "yes";
|
||||
};
|
||||
# Distinctive hostname for easy identification
|
||||
networking.hostName = "qvm-dev";
|
||||
|
||||
# Root user with password and zsh
|
||||
users.users.root = {
|
||||
password = "root";
|
||||
shell = pkgs.zsh;
|
||||
};
|
||||
|
||||
programs.zsh.enable = true;
|
||||
|
||||
# Home manager configuration for nice shell
|
||||
home-manager = {
|
||||
useUserPackages = true;
|
||||
useGlobalPkgs = true;
|
||||
backupFileExtension = "bak";
|
||||
|
||||
users.root = {
|
||||
home.stateVersion = stateVersion;
|
||||
programs.home-manager.enable = true;
|
||||
|
||||
# Starship prompt that shows we're in qvm-dev
|
||||
programs.starship = {
|
||||
# SSH enabled with password auth for root
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
add_newline = false;
|
||||
format = lib.concatStrings [
|
||||
"[┌─](bold green)"
|
||||
"[$hostname](bold red)"
|
||||
"[$directory](bold blue)"
|
||||
"$git_branch"
|
||||
"$git_status"
|
||||
"\n"
|
||||
"[└─>](bold green) "
|
||||
settings.PasswordAuthentication = true;
|
||||
settings.PermitRootLogin = "yes";
|
||||
};
|
||||
|
||||
# Root user with password and zsh
|
||||
users.users.root = {
|
||||
password = "root";
|
||||
shell = pkgs.zsh;
|
||||
};
|
||||
|
||||
programs.zsh.enable = true;
|
||||
|
||||
# Home manager configuration for nice shell
|
||||
home-manager = {
|
||||
useUserPackages = true;
|
||||
useGlobalPkgs = true;
|
||||
backupFileExtension = "bak";
|
||||
|
||||
users.root = {
|
||||
home.stateVersion = stateVersion;
|
||||
programs.home-manager.enable = true;
|
||||
|
||||
sharedModules = [
|
||||
inputs.common.homeManagerModules.atuin
|
||||
inputs.common.homeManagerModules.git
|
||||
inputs.common.homeManagerModules.postgres_cli_options
|
||||
inputs.common.homeManagerModules.starship
|
||||
inputs.common.homeManagerModules.zoxide
|
||||
inputs.common.homeManagerModules.zsh
|
||||
inputs.common.homeManagerModules.tmux
|
||||
inputs.common.homeManagerModules.direnv
|
||||
];
|
||||
hostname = {
|
||||
ssh_only = false;
|
||||
format = "[@$hostname](bold red) ";
|
||||
disabled = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
enableCompletion = true;
|
||||
autosuggestion.enable = true;
|
||||
syntaxHighlighting.enable = true;
|
||||
# Avoid slow boots due to wait-online
|
||||
systemd.network.wait-online.enable = false;
|
||||
systemd.services.NetworkManager-wait-online.enable = lib.mkForce false;
|
||||
systemd.services.systemd-networkd-wait-online.enable = lib.mkForce false;
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 22 ];
|
||||
|
||||
# Enable flakes
|
||||
nix.settings.experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
|
||||
# Josh's timezone
|
||||
time.timeZone = "America/Chicago";
|
||||
|
||||
# Git safe.directory for 9p ownership issues
|
||||
environment.etc."gitconfig".text = ''
|
||||
[safe]
|
||||
directory = *
|
||||
'';
|
||||
|
||||
# 9p mount points for caches (must match qvm-start mount tags)
|
||||
fileSystems."/cache/cargo" = {
|
||||
device = "cargo_home";
|
||||
fsType = "9p";
|
||||
options = [
|
||||
"trans=virtio"
|
||||
"version=9p2000.L"
|
||||
"msize=104857600"
|
||||
"_netdev"
|
||||
"nofail"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems."/cache/target" = {
|
||||
device = "cargo_target";
|
||||
fsType = "9p";
|
||||
options = [
|
||||
"trans=virtio"
|
||||
"version=9p2000.L"
|
||||
"msize=104857600"
|
||||
"_netdev"
|
||||
"nofail"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems."/cache/pnpm" = {
|
||||
device = "pnpm_store";
|
||||
fsType = "9p";
|
||||
options = [
|
||||
"trans=virtio"
|
||||
"version=9p2000.L"
|
||||
"msize=104857600"
|
||||
"_netdev"
|
||||
"nofail"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems."/cache/sccache" = {
|
||||
device = "sccache";
|
||||
fsType = "9p";
|
||||
options = [
|
||||
"trans=virtio"
|
||||
"version=9p2000.L"
|
||||
"msize=104857600"
|
||||
"_netdev"
|
||||
"nofail"
|
||||
];
|
||||
};
|
||||
|
||||
# Environment variables for cache directories
|
||||
environment.variables = {
|
||||
CARGO_HOME = "/cache/cargo";
|
||||
CARGO_TARGET_DIR = "/cache/target";
|
||||
PNPM_HOME = "/cache/pnpm";
|
||||
SCCACHE_DIR = "/cache/sccache";
|
||||
};
|
||||
|
||||
# Ensure workspace directory exists
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /workspace 0755 root root -"
|
||||
];
|
||||
|
||||
# Essential packages for development
|
||||
environment.systemPackages = with pkgs; [
|
||||
git
|
||||
vim
|
||||
tmux
|
||||
htop
|
||||
curl
|
||||
jq
|
||||
ripgrep
|
||||
fd
|
||||
inputs.opencode.packages.${system}.default
|
||||
];
|
||||
|
||||
# Opencode aliases without proxy interference
|
||||
environment.shellAliases = {
|
||||
"oc" = "all_proxy='' http_proxy='' https_proxy='' opencode";
|
||||
"occ" = "oc -c";
|
||||
};
|
||||
|
||||
# MOTD to clearly show this is qvm-dev
|
||||
users.motd = ''
|
||||
╔════════════════════════════════════════╗
|
||||
║ ║
|
||||
║ QVM Development VM ║
|
||||
║ Hostname: qvm-dev ║
|
||||
║ ║
|
||||
║ Caches: /cache/{cargo,target,...} ║
|
||||
║ Workspace: /workspace ║
|
||||
║ ║
|
||||
╚════════════════════════════════════════╝
|
||||
'';
|
||||
|
||||
# 20GB disk size
|
||||
virtualisation.diskSize = 20 * 1024;
|
||||
|
||||
system.stateVersion = stateVersion;
|
||||
};
|
||||
|
||||
in
|
||||
let
|
||||
qcow2Image = nixos-generators.nixosGenerate {
|
||||
inherit system;
|
||||
format = "qcow";
|
||||
modules = [ vmModule ];
|
||||
};
|
||||
in
|
||||
{
|
||||
# Export the qcow2 image
|
||||
packages.${system} = {
|
||||
qcow2 = qcow2Image;
|
||||
default = qcow2Image;
|
||||
};
|
||||
|
||||
# Avoid slow boots due to wait-online
|
||||
systemd.network.wait-online.enable = false;
|
||||
systemd.services.NetworkManager-wait-online.enable = lib.mkForce false;
|
||||
systemd.services.systemd-networkd-wait-online.enable = lib.mkForce false;
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 22 ];
|
||||
|
||||
# Enable flakes
|
||||
nix.settings.experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
|
||||
# Josh's timezone
|
||||
time.timeZone = "America/Chicago";
|
||||
|
||||
# Git safe.directory for 9p ownership issues
|
||||
environment.etc."gitconfig".text = ''
|
||||
[safe]
|
||||
directory = *
|
||||
'';
|
||||
|
||||
# 9p mount points for caches (must match qvm-start mount tags)
|
||||
fileSystems."/cache/cargo" = {
|
||||
device = "cargo_home";
|
||||
fsType = "9p";
|
||||
options = [ "trans=virtio" "version=9p2000.L" "msize=104857600" "_netdev" "nofail" ];
|
||||
};
|
||||
|
||||
fileSystems."/cache/target" = {
|
||||
device = "cargo_target";
|
||||
fsType = "9p";
|
||||
options = [ "trans=virtio" "version=9p2000.L" "msize=104857600" "_netdev" "nofail" ];
|
||||
};
|
||||
|
||||
fileSystems."/cache/pnpm" = {
|
||||
device = "pnpm_store";
|
||||
fsType = "9p";
|
||||
options = [ "trans=virtio" "version=9p2000.L" "msize=104857600" "_netdev" "nofail" ];
|
||||
};
|
||||
|
||||
fileSystems."/cache/sccache" = {
|
||||
device = "sccache";
|
||||
fsType = "9p";
|
||||
options = [ "trans=virtio" "version=9p2000.L" "msize=104857600" "_netdev" "nofail" ];
|
||||
};
|
||||
|
||||
# Environment variables for cache directories
|
||||
environment.variables = {
|
||||
CARGO_HOME = "/cache/cargo";
|
||||
CARGO_TARGET_DIR = "/cache/target";
|
||||
PNPM_HOME = "/cache/pnpm";
|
||||
SCCACHE_DIR = "/cache/sccache";
|
||||
};
|
||||
|
||||
# Ensure workspace directory exists
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /workspace 0755 root root -"
|
||||
];
|
||||
|
||||
# Essential packages for development
|
||||
environment.systemPackages = with pkgs; [
|
||||
git
|
||||
vim
|
||||
tmux
|
||||
htop
|
||||
curl
|
||||
jq
|
||||
ripgrep
|
||||
fd
|
||||
opencode.packages.${system}.default
|
||||
];
|
||||
|
||||
# Opencode aliases without proxy interference
|
||||
environment.shellAliases = {
|
||||
"oc" = "all_proxy='' http_proxy='' https_proxy='' opencode";
|
||||
"occ" = "oc -c";
|
||||
};
|
||||
|
||||
# MOTD to clearly show this is qvm-dev
|
||||
users.motd = ''
|
||||
╔════════════════════════════════════════╗
|
||||
║ ║
|
||||
║ QVM Development VM ║
|
||||
║ Hostname: qvm-dev ║
|
||||
║ ║
|
||||
║ Caches: /cache/{cargo,target,...} ║
|
||||
║ Workspace: /workspace ║
|
||||
║ ║
|
||||
╚════════════════════════════════════════╝
|
||||
'';
|
||||
|
||||
# 20GB disk size
|
||||
virtualisation.diskSize = 20 * 1024;
|
||||
|
||||
system.stateVersion = stateVersion;
|
||||
# Export the module for reuse
|
||||
nixosModules.default = vmModule;
|
||||
};
|
||||
|
||||
in {
|
||||
# Export the qcow2 image
|
||||
packages.${system}.qcow2 = nixos-generators.nixosGenerate {
|
||||
inherit system;
|
||||
format = "qcow";
|
||||
modules = [ vmModule ];
|
||||
};
|
||||
|
||||
# Also export a default package
|
||||
packages.${system}.default = self.packages.${system}.qcow2;
|
||||
|
||||
# Export the module for reuse
|
||||
nixosModules.default = vmModule;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,210 +0,0 @@
|
|||
{
|
||||
description = "Qai base NixOS VM image";
|
||||
|
||||
inputs = {
|
||||
home-manager = {
|
||||
url = "github:rycee/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
flake-utils = {
|
||||
url = "github:numtide/flake-utils";
|
||||
};
|
||||
nixos-generators = {
|
||||
url = "github:nix-community/nixos-generators";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
common.url = "git+https://git.joshuabell.xyz/ringofstorms/dotfiles?dir=flakes/common";
|
||||
opencode.url = "github:anomalyco/opencode?ref=ad4bdd9f0fb7670949b5c47917bb656247ac60ac";
|
||||
ros_neovim.url = "git+https://git.joshuabell.xyz/ringofstorms/nvim";
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
nixos-generators,
|
||||
...
|
||||
}:
|
||||
let
|
||||
baseModule =
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
stateVersion = "26.05";
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
inputs."home-manager".nixosModules.default
|
||||
|
||||
inputs.ros_neovim.nixosModules.default
|
||||
|
||||
inputs.common.nixosModules.essentials
|
||||
inputs.common.nixosModules.git
|
||||
inputs.common.nixosModules.zsh
|
||||
inputs.common.nixosModules.tmux
|
||||
|
||||
(
|
||||
{
|
||||
...
|
||||
}:
|
||||
{
|
||||
home-manager = {
|
||||
useUserPackages = true;
|
||||
useGlobalPkgs = true;
|
||||
backupFileExtension = "bak";
|
||||
|
||||
users.root = {
|
||||
home.stateVersion = stateVersion;
|
||||
programs.home-manager.enable = true;
|
||||
};
|
||||
|
||||
sharedModules = [
|
||||
inputs.common.homeManagerModules.atuin
|
||||
inputs.common.homeManagerModules.git
|
||||
inputs.common.homeManagerModules.postgres_cli_options
|
||||
inputs.common.homeManagerModules.starship
|
||||
inputs.common.homeManagerModules.zoxide
|
||||
inputs.common.homeManagerModules.zsh
|
||||
inputs.common.homeManagerModules.tmux
|
||||
inputs.common.homeManagerModules.direnv
|
||||
];
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
nixpkgs.config = {
|
||||
allowUnfree = true;
|
||||
allowUnfreePredicate = (_: true);
|
||||
};
|
||||
|
||||
networking.hostName = "qai-base";
|
||||
|
||||
# SSH enabled for terminal access via WebSocket proxy.
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.PasswordAuthentication = true;
|
||||
settings.PermitRootLogin = "yes";
|
||||
};
|
||||
|
||||
users.users.root.password = "root";
|
||||
|
||||
# Avoid slow boots due to wait-online.
|
||||
systemd.network.wait-online.enable = false;
|
||||
systemd.services.NetworkManager-wait-online.enable = false;
|
||||
systemd.services.systemd-networkd-wait-online.enable = false;
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
22
|
||||
];
|
||||
|
||||
# Needed so `nix develop` works inside the VM.
|
||||
nix.settings.experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
|
||||
# Host binary cache (QEMU user-net host is reachable at 10.0.2.2).
|
||||
# Only effective at runtime, not during image build.
|
||||
networking.hosts."10.0.2.2" = [ "lio" ];
|
||||
|
||||
# Note: These substituters are for runtime use. The build VM can't reach them.
|
||||
nix.settings.substituters = lib.mkAfter [ "http://lio:5000" ];
|
||||
nix.settings.trusted-public-keys = lib.mkAfter [
|
||||
"lio:9jKQ2xJyZjD0AWFzMcLe5dg3s8vOJ3uffujbUkBg4ms="
|
||||
];
|
||||
# Fallback timeout so nix doesn't hang if lio is unreachable
|
||||
nix.settings.connect-timeout = 5;
|
||||
|
||||
time.timeZone = "America/Chicago";
|
||||
|
||||
# Git 2.35+ blocks repos owned by different uid; 9p shares can trip this.
|
||||
# Use wildcard to allow all subdirectories under /workspace (task-1, task-2, etc.)
|
||||
environment.etc."gitconfig".text = ''
|
||||
[safe]
|
||||
directory = *
|
||||
'';
|
||||
|
||||
programs.zsh.enable = true;
|
||||
users.users.root.shell = pkgs.zsh;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
zsh
|
||||
git
|
||||
htop
|
||||
vim
|
||||
inputs.opencode.packages.${pkgs.system}.default
|
||||
];
|
||||
|
||||
environment.shellAliases = {
|
||||
"oc" = "all_proxy='' http_proxy='' https_proxy='' opencode";
|
||||
"occ" = "oc -c";
|
||||
};
|
||||
|
||||
# Default disk is too small for `nix develop` / direnv.
|
||||
virtualisation.diskSize = 20 * 1024;
|
||||
|
||||
virtualisation.vmVariant = {
|
||||
virtualisation = {
|
||||
memorySize = 4096;
|
||||
cores = 2;
|
||||
graphics = false;
|
||||
};
|
||||
|
||||
virtualisation.forwardPorts = [
|
||||
{
|
||||
from = "host";
|
||||
host.port = 2221;
|
||||
guest.port = 22;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
system.stateVersion = stateVersion;
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
nixosModules.default = baseModule;
|
||||
}
|
||||
// flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
baseVm = nixpkgs.lib.nixosSystem {
|
||||
inherit system;
|
||||
modules = [ baseModule ];
|
||||
};
|
||||
in
|
||||
{
|
||||
nixosConfigurations.base = baseVm;
|
||||
|
||||
# Runnable VM (./result/bin/run-nixos-vm)
|
||||
packages.vm = baseVm.config.system.build.vm;
|
||||
|
||||
# Bootable qcow2 disk image (./result/nixos.qcow2)
|
||||
packages.qcow2 = nixos-generators.nixosGenerate {
|
||||
inherit system;
|
||||
format = "qcow";
|
||||
modules = [ baseModule ];
|
||||
};
|
||||
|
||||
apps.default = {
|
||||
type = "app";
|
||||
program = "${baseVm.config.system.build.vm}/bin/run-nixos-vm";
|
||||
};
|
||||
|
||||
devShells.default = pkgs.mkShellNoCC {
|
||||
QEMU_NET_OPTS = "hostfwd=tcp::2221-:22";
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue