diff --git a/flake.lock b/flake.lock index fdcffd0db..fed839373 100644 --- a/flake.lock +++ b/flake.lock @@ -74,11 +74,11 @@ ] }, "locked": { - "lastModified": 1747365160, - "narHash": "sha256-4ZVr0x+ry6ybym/VhVYACj0HlJo44YxAaPGOxiS88Hg=", + "lastModified": 1747521943, + "narHash": "sha256-GMAJcB8oB9cC+TbYTE7QDfw9fwHZyloxUWnUpHnQRko=", "owner": "nix-darwin", "repo": "nix-darwin", - "rev": "8817b00b0011750381d0d44bb94d61087349b6ba", + "rev": "b9b927dd1f24094b271e8ec5277a672dc4fc860d", "type": "github" }, "original": { diff --git a/pkgs/clan-cli/clan_cli/machines/machines.py b/pkgs/clan-cli/clan_cli/machines/machines.py index 3ac2019bf..71a725f57 100644 --- a/pkgs/clan-cli/clan_cli/machines/machines.py +++ b/pkgs/clan-cli/clan_cli/machines/machines.py @@ -9,10 +9,9 @@ from functools import cached_property from pathlib import Path from typing import TYPE_CHECKING, Any -from clan_lib.cmd import Log, RunOpts, run from clan_lib.errors import ClanCmdError, ClanError from clan_lib.flake import Flake -from clan_lib.nix import nix_config, nix_eval, nix_test_store +from clan_lib.nix import nix_config, nix_test_store from clan_cli.facts import public_modules as facts_public_modules from clan_cli.facts import secret_modules as facts_secret_modules @@ -179,27 +178,6 @@ class Machine: ) as build_host: yield build_host - @cached_property - def deploy_as_root(self) -> bool: - if self._class_ == "nixos": - return True - - # Currently nix-darwin HEAD requires you to deploy as a non-root user - # however there is a soon to be merged PR that requires deployment - # as root to match NixOS: https://github.com/nix-darwin/nix-darwin/pull/1341 - return json.loads( - run( - nix_eval( - [ - f"{self.flake}#darwinConfigurations.{self.name}.options.system", - "--apply", - "system: system ? primaryUser", - ] - ), - RunOpts(log=Log.NONE), - ).stdout.strip() - ) - def nix( self, attr: str, diff --git a/pkgs/clan-cli/clan_cli/machines/update.py b/pkgs/clan-cli/clan_cli/machines/update.py index ea2e99eb0..a32d55deb 100644 --- a/pkgs/clan-cli/clan_cli/machines/update.py +++ b/pkgs/clan-cli/clan_cli/machines/update.py @@ -58,11 +58,18 @@ def upload_sources(machine: Machine, host: Host) -> str: if not has_path_inputs: # Just copy the flake to the remote machine, we can substitute other inputs there. path = flake_data["path"] + + remote_url = f"ssh-ng://{host.target}" + + # 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'" + cmd = nix_command( [ "copy", "--to", - f"ssh://{host.target}", + remote_url, "--no-check-sigs", path, ] @@ -109,11 +116,6 @@ def deploy_machine(machine: Machine) -> None: target_host = stack.enter_context(machine.target_host()) build_host = stack.enter_context(machine.build_host()) - if machine._class_ == "darwin": - if not machine.deploy_as_root and target_host.user == "root": - msg = f"'targetHost' should be set to a non-root user for deploying to nix-darwin on machine '{machine.name}'" - raise ClanError(msg) - host = build_host or target_host generate_facts([machine], service=None, regenerate=False) @@ -138,9 +140,10 @@ def deploy_machine(machine: Machine) -> None: f"{path}#{machine.name}", ] - become_root = machine.deploy_as_root + become_root = True if machine._class_ == "nixos": + switch_cmd = ["nixos-rebuild", "switch", *nix_options] nix_options += [ "--fast", "--build-host", @@ -153,9 +156,13 @@ def deploy_machine(machine: Machine) -> None: if target_host.user != "root": nix_options += ["--use-remote-sudo"] - - switch_cmd = [f"{machine._class_}-rebuild", "switch", *nix_options] - test_cmd = [f"{machine._class_}-rebuild", "test", *nix_options] + elif machine._class_ == "darwin": + # use absolute path to darwin-rebuild + switch_cmd = [ + "/run/current-system/sw/bin/darwin-rebuild", + "switch", + *nix_options, + ] remote_env = host.nix_ssh_env(None, local_ssh=False) ret = host.run( @@ -182,7 +189,7 @@ def deploy_machine(machine: Machine) -> None: "Mobile machine detected, applying workaround deployment method" ) ret = host.run( - test_cmd if is_mobile else switch_cmd, + ["nixos--rebuild", "test", *nix_options] if is_mobile else switch_cmd, RunOpts( log=Log.BOTH, msg_color=MsgColor(stderr=AnsiColor.DEFAULT), diff --git a/pkgs/clan-cli/clan_cli/ssh/host.py b/pkgs/clan-cli/clan_cli/ssh/host.py index eda9866fd..39acea75f 100644 --- a/pkgs/clan-cli/clan_cli/ssh/host.py +++ b/pkgs/clan-cli/clan_cli/ssh/host.py @@ -140,16 +140,16 @@ class Host: if opts is None: opts = RunOpts() - # If we are not root and we need to become root, prepend sudo - sudo = "" - if become_root and self.user != "root": - sudo = "sudo -- " - # Quote all added environment variables env_vars = [] for k, v in extra_env.items(): env_vars.append(f"{shlex.quote(k)}={shlex.quote(v)}") + sudo = [] + if become_root and self.user != "root": + # If we are not root and we need to become root, prepend sudo + sudo = ["sudo", "--"] + if opts.prefix is None: opts.prefix = self.command_prefix # always set needs_user_terminal to True because ssh asks for passwords @@ -185,7 +185,12 @@ class Host: ssh_cmd = [ *self.ssh_cmd(verbose_ssh=verbose_ssh, tty=tty), "--", - f"{sudo}bash -c {quote(bash_cmd)} -- {' '.join(map(quote, cmd))}", + *sudo, + "bash", + "-c", + quote(bash_cmd), + "--", + " ".join(map(quote, cmd)), ] # Run the ssh command