Merge pull request 'update/flake-upload: use ssh-ng:// for nix copy' (#4597) from local-build into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4597
This commit is contained in:
Mic92
2025-08-05 20:47:23 +00:00
3 changed files with 30 additions and 22 deletions

View File

@@ -236,7 +236,7 @@
"--debug",
"--flake", "/flake",
"--host-key-check", "none",
"--fetch-local", # Use local store instead of fetching from network
"--upload-inputs", # Use local store instead of fetching from network
"--build-host", "local",
"test-update-machine",
"--target-host", f"root@localhost",
@@ -247,12 +247,12 @@
##############
print("TEST: update with --fetch-local")
print("TEST: update with --target-host")
with open(machine_config_path, "w") as f:
f.write("""
{
environment.etc."update-fetch-local-successful".text = "ok";
environment.etc."target-host-update-successful".text = "ok";
}
""")
@@ -264,17 +264,17 @@
"--debug",
"--flake", flake_dir,
"--host-key-check", "none",
"--fetch-local", # Use local store instead of fetching from network
"--upload-inputs", # Use local store instead of fetching from network
"test-update-machine",
"--target-host", f"root@192.168.1.1:{ssh_conn.host_port}",
], check=True)
# Verify the update was successful
machine.succeed("test -f /etc/update-fetch-local-successful")
machine.succeed("test -f /etc/target-host-update-successful")
##############
print("TEST: update with --build-host 192.168.1.1")
print("TEST: update with --build-host")
# Update configuration again
with open(machine_config_path, "w") as f:
f.write("""
@@ -291,7 +291,7 @@
"--debug",
"--flake", flake_dir,
"--host-key-check", "none",
"--fetch-local", # Use local store instead of fetching from network
"--upload-inputs", # Use local store instead of fetching from network
"--build-host", f"root@192.168.1.1:{ssh_conn.host_port}",
"test-update-machine",
"--target-host", f"root@192.168.1.1:{ssh_conn.host_port}",

View File

@@ -162,7 +162,7 @@ def update_command(args: argparse.Namespace) -> None:
machine=machine,
target_host=target_host,
build_host=build_host,
force_fetch_local=args.fetch_local,
upload_inputs=args.upload_inputs,
)
runtime.join_all()
runtime.check_all()
@@ -211,10 +211,10 @@ def register_update_parser(parser: argparse.ArgumentParser) -> None:
),
)
parser.add_argument(
"--fetch-local",
"--upload-inputs",
action="store_true",
help=(
"Prefetch flake inputs locally, then upload them to the build-host.\n"
"Upload all flake inputs from the local machine instead of the build host/target host.\n"
"This is useful if downloading the inputs requires authentication "
"which is only available to the local machine"
),

View File

@@ -37,7 +37,7 @@ def is_local_input(node: dict[str, dict[str, str]]) -> bool:
return local
def upload_sources(machine: Machine, ssh: Host, force_fetch_local: bool) -> str:
def upload_sources(machine: Machine, ssh: Host, upload_inputs: bool) -> str:
env = ssh.nix_ssh_env(os.environ.copy())
flake_url = (
@@ -49,16 +49,16 @@ def upload_sources(machine: Machine, ssh: Host, force_fetch_local: bool) -> str:
)
# Construct the remote URL with proper parameters for Darwin
# Dont use ssh-ng here. It makes `flake archive` fail, despite root@..., with:
# cannot add path '/nix/store/...' because it lacks a signature by a trusted key
remote_url = f"ssh://{ssh.target}"
remote_url_base = ssh.target
remote_program_params = ""
# MacOS doesn't come with a proper login shell for ssh and therefore doesn't have nix in $PATH as it doesn't source /etc/profile
if machine._class_ == "darwin":
remote_url += "?remote-program=bash -lc 'exec nix-daemon --stdio'"
if not has_path_inputs and not force_fetch_local:
if not has_path_inputs and not upload_inputs:
# Just copy the flake to the remote machine, we can substitute other inputs there.
path = flake_data["path"]
if machine._class_ == "darwin":
remote_program_params = "?remote-program=bash -lc 'exec nix-daemon --stdio'"
remote_url = f"ssh-ng://{remote_url_base}{remote_program_params}"
cmd = nix_command(
[
"copy",
@@ -80,6 +80,14 @@ def upload_sources(machine: Machine, ssh: Host, force_fetch_local: bool) -> str:
return path
# Slow path: we need to upload all sources to the remote machine
# Don't use ssh-ng here. It makes `flake archive` fail, despite root@..., with:
# cannot add path '/nix/store/...' because it lacks a signature by a trusted key
# The issue is the missing `--no-check-sigs` option in `nix flake archive`.
if machine._class_ == "darwin":
remote_program_params = (
"?remote-program=bash -lc 'exec nix-store --serve --write'"
)
remote_url = f"ssh://{remote_url_base}{remote_program_params}"
cmd = nix_command(
[
"flake",
@@ -112,14 +120,14 @@ def run_machine_update(
machine: Machine,
target_host: Host,
build_host: Host | None,
force_fetch_local: bool = False,
upload_inputs: bool = False,
) -> None:
"""Update an existing machine using nixos-rebuild or darwin-rebuild.
Args:
machine: The Machine instance to deploy.
target_host: Remote object representing the target host for deployment.
build_host: Optional Remote object representing the build host.
force_fetch_local: Whether to fetch flake inputs locally before uploading.
upload_inputs: Whether to upload flake inputs from the local.
Raises:
ClanError: If the machine is not found in the inventory or if there are issues with
generating facts or variables.
@@ -145,7 +153,7 @@ def run_machine_update(
upload_secret_vars(machine, target_host_root)
# Upload the flake's source to the build host.
path = upload_sources(machine, build_host, force_fetch_local)
path = upload_sources(machine, build_host, upload_inputs)
nix_options = machine.flake.nix_options if machine.flake.nix_options else []
@@ -207,11 +215,11 @@ def run_machine_update(
# retry nixos-rebuild switch if the first attempt failed
if ret.returncode != 0:
# Hint user to --fetch-local on issues with flake inputs
# Hint user to --upload-inputs on issues with flake inputs
if "… while fetching the input" in ret.stderr:
msg = (
"Detected potential issue when fetching flake inputs on remote."
"\nTry running the update with --fetch-local to prefetch inputs "
"\nTry running the update with --update-inputs to prefetch inputs "
"locally and upload them instead."
)
raise ClanError(msg)