From f150afec0a9b3213a732775ede36f720cadd91c8 Mon Sep 17 00:00:00 2001 From: eric Date: Wed, 18 Mar 2026 03:21:10 +0100 Subject: [PATCH] fix: probe correct value --- hosts/lab/configuration.nix | 30 ----------- hosts/lab/disko.nix | 47 ------------------ hosts/lab/hardware-configuration.nix | 5 -- pkgs/helpers/__pycache__/cli.cpython-313.pyc | Bin 70382 -> 70098 bytes pkgs/helpers/cli.py | 35 ++++++------- .../__pycache__/test_cli.cpython-313.pyc | Bin 6652 -> 7628 bytes pkgs/helpers/tests/test_cli.py | 13 +++++ 7 files changed, 29 insertions(+), 101 deletions(-) delete mode 100644 hosts/lab/configuration.nix delete mode 100644 hosts/lab/disko.nix delete mode 100644 hosts/lab/hardware-configuration.nix diff --git a/hosts/lab/configuration.nix b/hosts/lab/configuration.nix deleted file mode 100644 index f0de599..0000000 --- a/hosts/lab/configuration.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ lib, ... }: -{ - # Generated by nodeiwest host init. - imports = [ - ./disko.nix - ./hardware-configuration.nix - ]; - - networking.hostName = "lab"; - networking.useDHCP = lib.mkDefault true; - - time.timeZone = "UTC"; - - boot.loader.efi.canTouchEfiVariables = true; - boot.loader.grub = { - enable = true; - efiSupport = true; - device = "nodev"; - }; - - nodeiwest.ssh.userCAPublicKeys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE6c2oMkM7lLg9qWHVgbrFaFBDrrFyynFlPviiydQdFi openbao-user-ca" - ]; - - nodeiwest.tailscale.openbao = { - enable = true; - }; - - system.stateVersion = "25.05"; -} diff --git a/hosts/lab/disko.nix b/hosts/lab/disko.nix deleted file mode 100644 index 377830e..0000000 --- a/hosts/lab/disko.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ - lib, - ... -}: -{ - # Generated by nodeiwest host init. - # Replace the disk only if the provider exposes a different primary device. - disko.devices = { - disk.main = { - type = "disk"; - device = lib.mkDefault "/dev/sda 11"; - content = { - type = "gpt"; - partitions = { - ESP = { - priority = 1; - name = "ESP"; - start = "1MiB"; - end = "512MiB"; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = [ "umask=0077" ]; - }; - }; - swap = { - size = "4GiB"; - content = { - type = "swap"; - resumeDevice = true; - }; - }; - root = { - size = "100%"; - content = { - type = "filesystem"; - format = "ext4"; - mountpoint = "/"; - }; - }; - }; - }; - }; - }; -} diff --git a/hosts/lab/hardware-configuration.nix b/hosts/lab/hardware-configuration.nix deleted file mode 100644 index 3f6bc7b..0000000 --- a/hosts/lab/hardware-configuration.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ ... }: -{ - # Placeholder generated by nodeiwest host init. - # nixos-anywhere will replace this with the generated hardware config. -} diff --git a/pkgs/helpers/__pycache__/cli.cpython-313.pyc b/pkgs/helpers/__pycache__/cli.cpython-313.pyc index 4a14814e469cc1633b8515ab751b45246d9079b0..b6559c56458f4b1c9df30ff9e07dace7117a37ee 100644 GIT binary patch delta 3506 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 LQFS9Na8UdYt_Gi* delta 3837 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 b?leLcJbfT!q?=3?3z3&^I}jZK@ACfxVSNdU diff --git a/pkgs/helpers/cli.py b/pkgs/helpers/cli.py index 486cd3f..0276e4f 100644 --- a/pkgs/helpers/cli.py +++ b/pkgs/helpers/cli.py @@ -584,7 +584,7 @@ def validate_host_name(name: str) -> None: def probe_host(ip: str, user: str) -> ProbeFacts: - lsblk_cmd = "lsblk -o NAME,SIZE,TYPE,MODEL,FSTYPE,PTTYPE,MOUNTPOINTS" + lsblk_cmd = "lsblk -P -o NAME,SIZE,TYPE,MODEL,FSTYPE,PTTYPE,MOUNTPOINTS" boot_cmd = "test -d /sys/firmware/efi && echo UEFI || echo BIOS" root_cmd = "findmnt -no SOURCE /" swap_cmd = "cat /proc/swaps" @@ -635,28 +635,25 @@ def probe_host(ip: str, user: str) -> ProbeFacts: def parse_lsblk_output(output: str) -> list[dict[str, str]]: - lines = [line.rstrip("\n") for line in output.splitlines() if line.strip()] - if len(lines) < 2: + lines = [line.strip() for line in output.splitlines() if line.strip()] + if not lines: raise NodeiwestError("Unexpected lsblk output: not enough lines to parse.") - header = lines[0] columns = ["NAME", "SIZE", "TYPE", "MODEL", "FSTYPE", "PTTYPE", "MOUNTPOINTS"] - starts = [] - for column in columns: - index = header.find(column) - if index == -1: - raise NodeiwestError(f"Unexpected lsblk output: missing {column} column.") - starts.append(index) - starts.append(len(header) + 20) - rows: list[dict[str, str]] = [] - for line in lines[1:]: - row: dict[str, str] = {} - for idx, column in enumerate(columns): - start = starts[idx] - end = starts[idx + 1] if idx + 1 < len(columns) else len(line) - row[column] = line[start:end].strip() - row["NAME"] = re.sub(r"^[^0-9A-Za-z]+", "", row["NAME"]) + for line in lines: + tokens = shlex.split(line) + row = {} + for token in tokens: + if "=" not in token: + continue + key, value = token.split("=", 1) + row[key] = value + missing = [column for column in columns if column not in row] + if missing: + raise NodeiwestError( + f"Unexpected lsblk output: missing columns {', '.join(missing)} in line {line!r}." + ) rows.append(row) return rows diff --git a/pkgs/helpers/tests/__pycache__/test_cli.cpython-313.pyc b/pkgs/helpers/tests/__pycache__/test_cli.cpython-313.pyc index dba937d410b2bd7fec1b8e7769e3c7c721c8b560..eb5ac18fce1e03661393ecadd9d105e13f1326a7 100644 GIT binary patch delta 1202 zcma)5OH30{6rDGnDbsdJ`L)Bx&t#I4bOBfmiHcw_6e*v!IIVmnj)j)eQd)ddBsLn{ z;X)IW7ZrA_4DK`}nz(c0%EUBcFcTNJF}lOR%4p(yuY3xLiL*F4@7#OOJu@%!`^@{c z@@>1_%HZdL?M?ED<7IhF*C+MpfZqE0W_(i%GNU}4sw{8DC05XC^KWmQ&xtV znKA*hGRiEN36xnevruMJtx!zZJodFO>|0wkhxeHn25c*UELK4Vpl<64F#=k#K%NYX zHbqxOgjHD{A5{}Y4*e441Cghq`LI|`U(?Nj7#wb-M` zp>UBUW^<%D5(tNa{yG;K1|NWE9JLzDG=3#I43794CLG`3NPNSD;~PAUoVO497D_VzAYa?yaIe>}mE_Fx)Y4;u6{MjGhtlI( zS|3kOYuUNn>|72yZ~@n=NZnl23=U@Jbsb+UBg-AJW7BDo86*q0X~?`1&{{j5+x2-Q^HHTU7na1cGM%!7`#s;Y0S zlPdj04iE?u2qC-E-5cINM+m!$Az!}xb(?0h>Ey(17$TJ+0>c=kRXP6*LNI!a4rHr8ggv{J31=`Z9SxCg1{7dC^di- zdM+IU&FGz^@HYPZPW{?<$pXX~;=;{DlNp#oe`;&NB68Kea&~|r@Mw6$*;sHk?l9!E Lb%{k^>l*$7`ZPcl delta 470 zcmX}o%S!@59Ki9NbywYo7UqOc0wG}!9;6OIPYrt5yDf?^Hj~H=QyJHTLg%i<;2$DF zMYryChz`Y`I(ZiA7}5NeY7Za2zuykbvX7HrWBw1HPv+QDlJCu+uj8-qM+ag;n#|Kf+(PN@8}9Mg+04Lt4#)sm`Vt!5S@@q9p_Ujef2!KB zY7Hw@tCr1TlVst|GLU0vDiNSpfK^}(SO*3fHm3bB9w!s9*aWtK0brY4E#wO8%EtKSZ2{ESQasl8`eqPFi0K_3 None: + output = ( + 'NAME="sda" SIZE="11G" TYPE="disk" MODEL="QEMU HARDDISK" FSTYPE="" PTTYPE="gpt" MOUNTPOINTS=""\n' + 'NAME="sda1" SIZE="512M" TYPE="part" MODEL="" FSTYPE="vfat" PTTYPE="" MOUNTPOINTS="/boot"\n' + ) + rows = cli.parse_lsblk_output(output) + + self.assertEqual(rows[0]["NAME"], "sda") + self.assertEqual(rows[0]["SIZE"], "11G") + self.assertEqual(rows[0]["MODEL"], "QEMU HARDDISK") + self.assertEqual(rows[1]["NAME"], "sda1") + self.assertEqual(rows[1]["MOUNTPOINTS"], "/boot") + def test_bao_kv_get_uses_explicit_kv_mount(self) -> None: completed = mock.Mock() completed.stdout = '{"data": {"data": {"CLIENT_ID": "x"}}}'