fix(create-proxmox-resource): fix VM disk never attaching after import #67

Merged
beatzaplenty merged 2 commits from worktree-warm-discovering-moon into main 2026-07-25 22:57:22 +00:00
Owner

Three bugs combined to leave every VM build with a shell but no boot disk:

  1. The remote build script moved the raw image to /var/lib/vz/import/ before
    qm importdisk could use it. If the mv failed (cross-filesystem copy, sudo
    path, or any other reason) the remote script exited non-zero -- but the
    local script's set -e handling of the SSH heredoc was inconsistent, so
    qm create sometimes ran anyway, leaving a diskless VM shell.

    Fix: skip the mv entirely. The diskoImagesScript writes .raw into
    its CWD (the remote repo dir, $out = $PWD at invocation). Import directly
    from that path; clean it up after a successful import.

  2. The qm importdisk output regex expected "Successfully imported disk as '...'"
    but current Proxmox emits "unusedN: successfully imported disk '...'"
    (lowercase, no "as"). The grep returned no match and exited 1.

  3. The disk_id assignment used $(... | grep ...) without || true inside the
    substitution. With set -euo pipefail, a non-zero grep exit aborts the
    script before the fallback could run -- so the VM was always left with an
    unattached unused0 disk.

    Fix: update the primary regex to match the actual PVE format; add || true
    inside the substitution so set -e never fires on a grep miss; add a qm
    config fallback (scan for unusedN: lines) that works regardless of PVE
    output format changes.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_011uRcikkTp3D5VbXj2DwNpQ

Three bugs combined to leave every VM build with a shell but no boot disk: 1. The remote build script moved the raw image to /var/lib/vz/import/ before qm importdisk could use it. If the mv failed (cross-filesystem copy, sudo path, or any other reason) the remote script exited non-zero -- but the local script's set -e handling of the SSH heredoc was inconsistent, so qm create sometimes ran anyway, leaving a diskless VM shell. Fix: skip the mv entirely. The diskoImagesScript writes <hostname>.raw into its CWD (the remote repo dir, $out = $PWD at invocation). Import directly from that path; clean it up after a successful import. 2. The qm importdisk output regex expected "Successfully imported disk as '...'" but current Proxmox emits "unusedN: successfully imported disk '...'" (lowercase, no "as"). The grep returned no match and exited 1. 3. The disk_id assignment used $(... | grep ...) without || true inside the substitution. With set -euo pipefail, a non-zero grep exit aborts the script before the fallback could run -- so the VM was always left with an unattached unused0 disk. Fix: update the primary regex to match the actual PVE format; add || true inside the substitution so set -e never fires on a grep miss; add a qm config fallback (scan for unusedN: lines) that works regardless of PVE output format changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011uRcikkTp3D5VbXj2DwNpQ
beatzaplenty added 2 commits 2026-07-25 22:57:04 +00:00
Three bugs combined to leave every VM build with a shell but no boot disk:

1. The remote build script moved the raw image to /var/lib/vz/import/ before
   qm importdisk could use it. If the mv failed (cross-filesystem copy, sudo
   path, or any other reason) the remote script exited non-zero -- but the
   local script's set -e handling of the SSH heredoc was inconsistent, so
   qm create sometimes ran anyway, leaving a diskless VM shell.

   Fix: skip the mv entirely. The diskoImagesScript writes <hostname>.raw into
   its CWD (the remote repo dir, $out = $PWD at invocation). Import directly
   from that path; clean it up after a successful import.

2. The qm importdisk output regex expected "Successfully imported disk as '...'"
   but current Proxmox emits "unusedN: successfully imported disk '...'"
   (lowercase, no "as"). The grep returned no match and exited 1.

3. The disk_id assignment used $(... | grep ...) without || true inside the
   substitution. With set -euo pipefail, a non-zero grep exit aborts the
   script before the fallback could run -- so the VM was always left with an
   unattached unused0 disk.

   Fix: update the primary regex to match the actual PVE format; add || true
   inside the substitution so set -e never fires on a grep miss; add a qm
   config fallback (scan for unusedN: lines) that works regardless of PVE
   output format changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uRcikkTp3D5VbXj2DwNpQ
fix(proxmox): embed SSH host key via NIXOS_HOST_KEYS_DIR so sops can decrypt on first boot
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m30s
6e1e992652
--pre-format-files placed the key on the QEMU builder VM's rootfs, not the
target disk. nixos-install chroots into the target and runs sshd-keygen, which
found no key in the chroot and generated a fresh (unregistered) one. sops then
could not decrypt on first boot because the key didn't match .sops.yaml, leaving
both root and nixos with '!' in /etc/shadow even after mutableUsers = false was
set (hashedPasswordFile pointed to paths sops never wrote).

Fix modules/platforms/proxmox.nix to embed the clan SSH host key in
environment.etc via NIXOS_HOST_KEYS_DIR at eval time -- the same pattern
lxc.nix uses. nixos-install's own activation places the key on the target disk,
sshd-keygen finds it already present and skips generation, and sops decrypts
correctly on first boot. Includes the same preserveSshHostKey/restoreSshHostKey
activation scripts as lxc.nix so subsequent nixos-rebuild switch calls (without
NIXOS_HOST_KEYS_DIR) don't remove the key as "obsolete" from environment.etc.

Update create-proxmox-resource.sh: switch VM builds from
  ./result-<target> --pre-format-files ... --build-memory 2048
to
  NIXOS_HOST_KEYS_DIR=$(pwd)/host-keys nix build --impure ... diskoImagesScript
  ./result-<target> --build-memory 2048
matching the LXC build path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uRcikkTp3D5VbXj2DwNpQ
beatzaplenty force-pushed worktree-warm-discovering-moon from 928646f7d0 to 6e1e992652 2026-07-25 22:57:04 +00:00 Compare
beatzaplenty merged commit 89d506180d into main 2026-07-25 22:57:22 +00:00
This repo is archived. You cannot comment on pull requests.
No Reviewers
No labels
1 Participants
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: beatzaplenty/nixos#67