diff --git a/bin/qvm b/bin/qvm index 16514c0..537858e 100755 --- a/bin/qvm +++ b/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 diff --git a/bin/qvm-rebuild b/bin/qvm-rebuild index 7ae02f5..8ff9ec3 100755 --- a/bin/qvm-rebuild +++ b/bin/qvm-rebuild @@ -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" diff --git a/bin/qvm-run b/bin/qvm-run index a1e5d1f..1beead7 100755 --- a/bin/qvm-run +++ b/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" ) diff --git a/bin/qvm-ssh b/bin/qvm-ssh index 5efa668..4489657 100755 --- a/bin/qvm-ssh +++ b/bin/qvm-ssh @@ -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 ) diff --git a/bin/qvm-start b/bin/qvm-start index bc25d57..5dc5620 100755 --- a/bin/qvm-start +++ b/bin/qvm-start @@ -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 diff --git a/flake.nix b/flake.nix index f5699d4..a5f146d 100644 --- a/flake.nix +++ b/flake.nix @@ -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 diff --git a/flake/default-vm/flake.nix b/flake/default-vm/flake.nix index c414b38..bf437f0 100644 --- a/flake/default-vm/flake.nix +++ b/flake/default-vm/flake.nix @@ -3,210 +3,234 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - - nixos-generators = { - url = "github:nix-community/nixos-generators"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - home-manager = { url = "github:nix-community/home-manager"; inputs.nixpkgs.follows = "nixpkgs"; }; + nixos-generators = { + url = "github:nix-community/nixos-generators"; + 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; - }; } diff --git a/vm_base/flake.nix b/vm_base/flake.nix deleted file mode 100644 index 6127ca2..0000000 --- a/vm_base/flake.nix +++ /dev/null @@ -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"; - }; - } - ); -}