clan-cli: clan machiens update-hardware-config now uses kexec, and supports non NixOS targets
This commit is contained in:
@@ -302,7 +302,8 @@
|
|||||||
"test-install-machine-without-system",
|
"test-install-machine-without-system",
|
||||||
"-i", ssh_conn.ssh_key,
|
"-i", ssh_conn.ssh_key,
|
||||||
"--option", "store", os.environ['CLAN_TEST_STORE'],
|
"--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)
|
result = subprocess.run(clan_cmd, capture_output=True, cwd=flake_dir)
|
||||||
@@ -326,7 +327,9 @@
|
|||||||
"test-install-machine-without-system",
|
"test-install-machine-without-system",
|
||||||
"-i", ssh_conn.ssh_key,
|
"-i", ssh_conn.ssh_key,
|
||||||
"--option", "store", os.environ['CLAN_TEST_STORE'],
|
"--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)
|
result = subprocess.run(clan_cmd, capture_output=True, cwd=flake_dir)
|
||||||
|
|||||||
@@ -92,16 +92,21 @@ Examples:
|
|||||||
"update-hardware-config",
|
"update-hardware-config",
|
||||||
help="Generate hardware specifics for a machine",
|
help="Generate hardware specifics for a machine",
|
||||||
description="""
|
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@<ip> -i ~/.config/clan/nixos-anywhere/keys/id_ed25519`
|
||||||
|
|
||||||
|
|
||||||
The target must be a Linux based system reachable via SSH.
|
The target must be a Linux based system reachable via SSH.
|
||||||
|
|
||||||
|
|
||||||
""",
|
""",
|
||||||
epilog=(
|
epilog=(
|
||||||
"""
|
"""
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
$ clan machines update-hardware-config [MACHINE] [TARGET_HOST]
|
$ clan machines update-hardware-config [MACHINE] --target-host root@<ip>
|
||||||
Will generate hardware specifics for the the specified `[TARGET_HOST]` and place the result in hardware.nix for the given machine `[MACHINE]`.
|
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
|
For more detailed information, visit: https://docs.clan.lol/guides/getting-started/configure/#machine-configuration
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,18 @@ def update_hardware_config_command(args: argparse.Namespace) -> None:
|
|||||||
private_key=args.identity_file,
|
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)
|
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)
|
add_dynamic_completer(machine_parser, complete_machines)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"target_host",
|
"--target-host",
|
||||||
type=str,
|
type=str,
|
||||||
nargs="?",
|
|
||||||
help="ssh address to install to in the form of user@host:2222",
|
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(
|
parser.add_argument(
|
||||||
"--host-key-check",
|
"--host-key-check",
|
||||||
choices=list(get_args(HostKeyCheck)),
|
choices=list(get_args(HostKeyCheck)),
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ from pathlib import Path
|
|||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
|
|
||||||
from clan_lib.api import API
|
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.dirs import specific_machine_dir
|
||||||
from clan_lib.errors import ClanCmdError, ClanError
|
from clan_lib.errors import ClanCmdError, ClanError
|
||||||
from clan_lib.git import commit_file
|
from clan_lib.git import commit_file
|
||||||
from clan_lib.machines.machines import Machine
|
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
|
from clan_lib.ssh.remote import Remote
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@@ -79,41 +80,45 @@ def run_machine_hardware_info(
|
|||||||
hw_file = opts.backend.config_path(opts.machine)
|
hw_file = opts.backend.config_path(opts.machine)
|
||||||
hw_file.parent.mkdir(parents=True, exist_ok=True)
|
hw_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
if opts.backend == HardwareConfig.NIXOS_FACTER:
|
cmd = [
|
||||||
config_command = ["nixos-facter"]
|
"nixos-anywhere",
|
||||||
else:
|
"--flake",
|
||||||
config_command = [
|
f"{machine.flake}#{machine.name}",
|
||||||
"nixos-generate-config",
|
"--phases",
|
||||||
# Filesystems are managed by disko
|
"kexec",
|
||||||
"--no-filesystems",
|
"--generate-hardware-config",
|
||||||
"--show-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:
|
if target_host.private_key:
|
||||||
out = sudo_ssh.run(config_command, opts=RunOpts(check=False))
|
cmd += ["--ssh-option", f"IdentityFile={target_host.private_key}"]
|
||||||
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)
|
|
||||||
|
|
||||||
machine.error(str(out))
|
if target_host.port:
|
||||||
msg = f"Failed to inspect {opts.machine}. Address: {target_host.target}"
|
cmd += ["--ssh-port", str(target_host.port)]
|
||||||
raise ClanError(msg)
|
|
||||||
|
key_pair = create_secret_key_nixos_anywhere()
|
||||||
|
cmd += ["-i", str(key_pair.private)]
|
||||||
|
|
||||||
backup_file = None
|
backup_file = None
|
||||||
if hw_file.exists():
|
if hw_file.exists():
|
||||||
backup_file = hw_file.with_suffix(".bak")
|
backup_file = hw_file.with_suffix(".bak")
|
||||||
hw_file.replace(backup_file)
|
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}")
|
print(f"Successfully generated: {hw_file}")
|
||||||
|
|
||||||
# try to evaluate the machine
|
# try to evaluate the machine
|
||||||
# If it fails, the hardware-configuration.nix file is invalid
|
# If it fails, the hardware-configuration.nix file is invalid
|
||||||
|
|
||||||
commit_file(
|
commit_file(
|
||||||
hw_file,
|
hw_file,
|
||||||
opts.machine.flake.path,
|
opts.machine.flake.path,
|
||||||
|
|||||||
Reference in New Issue
Block a user