install: let nixos-anywhere determine where to build automatically

This fixes installing machines that don't have `system` defined i.e.
when running `clan machines install` with `--update-hardware-config`.
This commit is contained in:
Michael Hoang
2025-02-26 16:38:50 +07:00
parent 7608bab20a
commit d79d1811d6
2 changed files with 16 additions and 48 deletions

View File

@@ -3,6 +3,7 @@ import logging
import os import os
import sys import sys
from dataclasses import dataclass, field from dataclasses import dataclass, field
from enum import Enum
from pathlib import Path from pathlib import Path
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
@@ -25,6 +26,12 @@ from clan_cli.vars.generate import generate_vars
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
class BuildOn(Enum):
AUTO = "auto"
LOCAL = "local"
REMOTE = "remote"
@dataclass @dataclass
class InstallOptions: class InstallOptions:
machine: Machine machine: Machine
@@ -33,7 +40,7 @@ class InstallOptions:
debug: bool = False debug: bool = False
no_reboot: bool = False no_reboot: bool = False
phases: str | None = None phases: str | None = None
build_on_remote: bool = False build_on: BuildOn | None = None
nix_options: list[str] = field(default_factory=list) nix_options: list[str] = field(default_factory=list)
update_hardware_config: HardwareConfig = HardwareConfig.NONE update_hardware_config: HardwareConfig = HardwareConfig.NONE
password: str | None = None password: str | None = None
@@ -122,10 +129,8 @@ def install_machine(opts: InstallOptions) -> None:
if opts.identity_file: if opts.identity_file:
cmd += ["-i", str(opts.identity_file)] cmd += ["-i", str(opts.identity_file)]
if opts.build_on_remote: if opts.build_on:
cmd.extend(["--build-on", "remote"]) cmd += ["--build-on", opts.build_on.value]
else:
cmd.extend(["--build-on", "auto"])
if h.port: if h.port:
cmd += ["--ssh-port", str(h.port)] cmd += ["--ssh-port", str(h.port)]
@@ -210,7 +215,7 @@ def install_command(args: argparse.Namespace) -> None:
debug=args.debug, debug=args.debug,
no_reboot=args.no_reboot, no_reboot=args.no_reboot,
nix_options=args.option, nix_options=args.option,
build_on_remote=args.build_on_remote, build_on=BuildOn(args.build_on) if args.build_on is not None else None,
update_hardware_config=HardwareConfig(args.update_hardware_config), update_hardware_config=HardwareConfig(args.update_hardware_config),
password=password, password=password,
identity_file=args.identity_file, identity_file=args.identity_file,
@@ -241,10 +246,10 @@ def register_install_parser(parser: argparse.ArgumentParser) -> None:
help="Host key (.ssh/known_hosts) check mode.", help="Host key (.ssh/known_hosts) check mode.",
) )
parser.add_argument( parser.add_argument(
"--build-on-remote", "--build-on",
action="store_true", choices=[x.value for x in BuildOn],
help="build the NixOS configuration on the remote machine", default=None,
default=False, help="where to build the NixOS configuration",
) )
parser.add_argument( parser.add_argument(
"--yes", "--yes",

View File

@@ -4,15 +4,13 @@ import logging
from dataclasses import dataclass, field from dataclasses import dataclass, field
from functools import cached_property from functools import cached_property
from pathlib import Path from pathlib import Path
from time import time
from typing import TYPE_CHECKING, Any, Literal from typing import TYPE_CHECKING, Any, Literal
from clan_cli.cmd import RunOpts, run_no_stdout
from clan_cli.errors import ClanError from clan_cli.errors import ClanError
from clan_cli.facts import public_modules as facts_public_modules from clan_cli.facts import public_modules as facts_public_modules
from clan_cli.facts import secret_modules as facts_secret_modules from clan_cli.facts import secret_modules as facts_secret_modules
from clan_cli.flake import Flake from clan_cli.flake import Flake
from clan_cli.nix import nix_build, nix_config, nix_eval, nix_test_store from clan_cli.nix import nix_config, nix_test_store
from clan_cli.ssh.host import Host from clan_cli.ssh.host import Host
from clan_cli.ssh.host_key import HostKeyCheck from clan_cli.ssh.host_key import HostKeyCheck
from clan_cli.ssh.parse import parse_deployment_address from clan_cli.ssh.parse import parse_deployment_address
@@ -64,41 +62,6 @@ class Machine:
f"nixosConfigurations.{self.name}.pkgs.hostPlatform.system" f"nixosConfigurations.{self.name}.pkgs.hostPlatform.system"
) )
@property
def can_build_locally(self) -> bool:
config = nix_config()
if self.system == config["system"] or self.system in config["extra-platforms"]:
return True
nix_code = f"""
let
flake = builtins.getFlake("path:{self.flake.store_path}?narHash={self.flake.hash}");
in
(flake.inputs.nixpkgs.legacyPackages.{self.system}.runCommandNoCC "clan-can-build-{int(time())}" {{ }} "touch $out").drvPath
"""
unsubstitutable_drv = json.loads(
run_no_stdout(
nix_eval(
[
"--expr",
nix_code,
]
),
opts=RunOpts(prefix=self.name),
).stdout.strip()
)
try:
run_no_stdout(
nix_build([f"{unsubstitutable_drv}^*"]), opts=RunOpts(prefix=self.name)
)
except Exception as e:
self.debug("failed to build test derivation", exc_info=e)
return False
else:
return True
@property @property
def deployment(self) -> dict: def deployment(self) -> dict:
if self.cached_deployment is not None: if self.cached_deployment is not None: