diff --git a/checks/installation/flake-module.nix b/checks/installation/flake-module.nix index f1284c94f..7d3cfd65b 100644 --- a/checks/installation/flake-module.nix +++ b/checks/installation/flake-module.nix @@ -302,7 +302,8 @@ "test-install-machine-without-system", "-i", ssh_conn.ssh_key, "--option", "store", os.environ['CLAN_TEST_STORE'], - f"nonrootuser@localhost:{ssh_conn.host_port}" + "--target-host", f"nonrootuser@localhost:{ssh_conn.host_port}", + "--yes" ] result = subprocess.run(clan_cmd, capture_output=True, cwd=flake_dir) @@ -326,7 +327,9 @@ "test-install-machine-without-system", "-i", ssh_conn.ssh_key, "--option", "store", os.environ['CLAN_TEST_STORE'], - f"nonrootuser@localhost:{ssh_conn.host_port}" + "--target-host", + f"nonrootuser@localhost:{ssh_conn.host_port}", + "--yes" ] result = subprocess.run(clan_cmd, capture_output=True, cwd=flake_dir) diff --git a/pkgs/clan-cli/clan_cli/machines/cli.py b/pkgs/clan-cli/clan_cli/machines/cli.py index e3575638d..f5b6c7401 100644 --- a/pkgs/clan-cli/clan_cli/machines/cli.py +++ b/pkgs/clan-cli/clan_cli/machines/cli.py @@ -92,16 +92,21 @@ Examples: "update-hardware-config", help="Generate hardware specifics for a machine", description=""" -Generates hardware specifics for a machine. Such as the host platform, available kernel modules, etc. + +This command will use kexec to boot the target into a minimal NixOS environment to gather the hardware information. +If you want to manually ssh into the target after this command use `ssh root@ -i ~/.config/clan/nixos-anywhere/keys/id_ed25519` + The target must be a Linux based system reachable via SSH. + + """, epilog=( """ Examples: - $ clan machines update-hardware-config [MACHINE] [TARGET_HOST] - Will generate hardware specifics for the the specified `[TARGET_HOST]` and place the result in hardware.nix for the given machine `[MACHINE]`. + $ clan machines update-hardware-config [MACHINE] --target-host root@ + Will generate the facter.json hardware report for `[TARGET_HOST]` and place the result in facter.json for the given machine `[MACHINE]`. For more detailed information, visit: https://docs.clan.lol/guides/getting-started/configure/#machine-configuration diff --git a/pkgs/clan-cli/clan_cli/machines/hardware.py b/pkgs/clan-cli/clan_cli/machines/hardware.py index b84576ba6..8c5887f7e 100644 --- a/pkgs/clan-cli/clan_cli/machines/hardware.py +++ b/pkgs/clan-cli/clan_cli/machines/hardware.py @@ -44,6 +44,18 @@ def update_hardware_config_command(args: argparse.Namespace) -> None: private_key=args.identity_file, ) + if not args.yes: + confirm = ( + input( + f"Update hardware configuration for machine '{machine.name}' at '{target_host.target}'? [y/N]: " + ) + .strip() + .lower() + ) + if confirm not in ("y", "yes"): + log.info("Aborted.") + return + run_machine_hardware_info(opts, target_host) @@ -56,11 +68,16 @@ def register_update_hardware_config(parser: argparse.ArgumentParser) -> None: ) add_dynamic_completer(machine_parser, complete_machines) parser.add_argument( - "target_host", + "--target-host", type=str, - nargs="?", help="ssh address to install to in the form of user@host:2222", ) + parser.add_argument( + "-y", + "--yes", + action="store_true", + help="Automatic yes to prompts; assume 'yes' as answer to all prompts and run non-interactively.", + ) parser.add_argument( "--host-key-check", choices=list(get_args(HostKeyCheck)), diff --git a/pkgs/clan-cli/clan_lib/machines/hardware.py b/pkgs/clan-cli/clan_lib/machines/hardware.py index 61f6cc632..057e2ef50 100644 --- a/pkgs/clan-cli/clan_lib/machines/hardware.py +++ b/pkgs/clan-cli/clan_lib/machines/hardware.py @@ -6,12 +6,13 @@ from pathlib import Path from typing import TypedDict from clan_lib.api import API -from clan_lib.cmd import RunOpts, run +from clan_lib.cmd import Log, RunOpts, run from clan_lib.dirs import specific_machine_dir from clan_lib.errors import ClanCmdError, ClanError from clan_lib.git import commit_file from clan_lib.machines.machines import Machine -from clan_lib.nix import nix_config, nix_eval +from clan_lib.nix import nix_config, nix_eval, nix_shell +from clan_lib.ssh.create import create_secret_key_nixos_anywhere from clan_lib.ssh.remote import Remote log = logging.getLogger(__name__) @@ -79,41 +80,45 @@ def run_machine_hardware_info( hw_file = opts.backend.config_path(opts.machine) hw_file.parent.mkdir(parents=True, exist_ok=True) - if opts.backend == HardwareConfig.NIXOS_FACTER: - config_command = ["nixos-facter"] - else: - config_command = [ - "nixos-generate-config", - # Filesystems are managed by disko - "--no-filesystems", - "--show-hardware-config", - ] + cmd = [ + "nixos-anywhere", + "--flake", + f"{machine.flake}#{machine.name}", + "--phases", + "kexec", + "--generate-hardware-config", + str(opts.backend.value), + str(opts.backend.config_path(machine)), + ] - with target_host.host_connection() as ssh, ssh.become_root() as sudo_ssh: - out = sudo_ssh.run(config_command, opts=RunOpts(check=False)) - if out.returncode != 0: - if "nixos-facter" in out.stderr and "not found" in out.stderr: - machine.error(str(out.stderr)) - msg = ( - "Please use our custom nixos install images from https://github.com/nix-community/nixos-images/releases/tag/nixos-unstable. " - "nixos-factor only works on nixos / clan systems currently." - ) - raise ClanError(msg) + if target_host.private_key: + cmd += ["--ssh-option", f"IdentityFile={target_host.private_key}"] - machine.error(str(out)) - msg = f"Failed to inspect {opts.machine}. Address: {target_host.target}" - raise ClanError(msg) + if target_host.port: + cmd += ["--ssh-port", str(target_host.port)] + + key_pair = create_secret_key_nixos_anywhere() + cmd += ["-i", str(key_pair.private)] backup_file = None if hw_file.exists(): backup_file = hw_file.with_suffix(".bak") hw_file.replace(backup_file) - hw_file.write_text(out.stdout) + + cmd += [target_host.target] + cmd = nix_shell( + ["nixos-anywhere"], + cmd, + ) + + run( + cmd, + RunOpts(log=Log.BOTH, prefix=machine.name, needs_user_terminal=True), + ) print(f"Successfully generated: {hw_file}") # try to evaluate the machine # If it fails, the hardware-configuration.nix file is invalid - commit_file( hw_file, opts.machine.flake.path,