mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-07-20 15:41:16 +00:00
nixos-rebuild-ng: allow overriding default ssh opts via environment (#538973)
This commit is contained in:
@@ -379,6 +379,11 @@ NIX_PATH
|
||||
NIX_SSHOPTS
|
||||
Additional options to be passed to ssh on the command line.
|
||||
|
||||
NIXOS_REBUILD_SSH_DEFAULT_OPTS
|
||||
Replaces the built-in default ssh options (connection sharing via a
|
||||
private _ControlMaster_ that is closed on exit). If empty, no
|
||||
default options are added.
|
||||
|
||||
NIX_SUDOOPTS
|
||||
Additional options to be passed to sudo on the command line.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ from .models import (
|
||||
Profile,
|
||||
Remote,
|
||||
)
|
||||
from .process import SSH_DEFAULT_OPTS, run_wrapper
|
||||
from .process import run_wrapper, ssh_default_opts
|
||||
from .utils import Args, dict_to_flags
|
||||
|
||||
FLAKE_FLAGS: Final = ["--extra-experimental-features", "nix-command flakes"]
|
||||
@@ -193,7 +193,7 @@ def copy_closure(
|
||||
Also supports copying a closure from a remote to another remote."""
|
||||
|
||||
sshopts = os.getenv("NIX_SSHOPTS", "")
|
||||
env = {"NIX_SSHOPTS": " ".join(filter(lambda x: x, [sshopts, *SSH_DEFAULT_OPTS]))}
|
||||
env = {"NIX_SSHOPTS": " ".join(filter(lambda x: x, [sshopts, *ssh_default_opts()]))}
|
||||
|
||||
def nix_copy_closure(host: Remote, to: bool) -> None:
|
||||
run_wrapper(
|
||||
|
||||
@@ -31,6 +31,14 @@ SSH_DEFAULT_OPTS: Final = [
|
||||
]
|
||||
|
||||
|
||||
def ssh_default_opts() -> list[str]:
|
||||
"Default ssh options appended after NIX_SSHOPTS."
|
||||
env = os.getenv("NIXOS_REBUILD_SSH_DEFAULT_OPTS")
|
||||
if env is None:
|
||||
return SSH_DEFAULT_OPTS
|
||||
return shlex.split(env)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Remote:
|
||||
host: str
|
||||
@@ -133,7 +141,7 @@ def run_wrapper(
|
||||
ssh_args: list[Arg] = [
|
||||
"ssh",
|
||||
*remote.opts,
|
||||
*SSH_DEFAULT_OPTS,
|
||||
*ssh_default_opts(),
|
||||
remote.ssh_host(),
|
||||
"--",
|
||||
*[_quote_remote_arg(a) for a in remote_run_args],
|
||||
@@ -282,7 +290,7 @@ def _kill_long_running_ssh_process(args: Args, remote: Remote) -> None:
|
||||
[
|
||||
"ssh",
|
||||
*remote.opts,
|
||||
*SSH_DEFAULT_OPTS,
|
||||
*ssh_default_opts(),
|
||||
remote.ssh_host(),
|
||||
"--",
|
||||
"pkill",
|
||||
|
||||
@@ -275,6 +275,17 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None:
|
||||
},
|
||||
)
|
||||
|
||||
# NIXOS_REBUILD_SSH_DEFAULT_OPTS replaces the ControlMaster defaults
|
||||
monkeypatch.setenv("NIX_SSHOPTS", "-oControlPath=/run/user/1000/%C")
|
||||
monkeypatch.setenv("NIXOS_REBUILD_SSH_DEFAULT_OPTS", "")
|
||||
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
|
||||
n.copy_closure(closure, target_host)
|
||||
mock_run.assert_called_with(
|
||||
["nix-copy-closure", "--to", "user@target.host", closure],
|
||||
append_local_env={"NIX_SSHOPTS": "-oControlPath=/run/user/1000/%C"},
|
||||
)
|
||||
monkeypatch.delenv("NIXOS_REBUILD_SSH_DEFAULT_OPTS")
|
||||
|
||||
monkeypatch.setenv("NIX_SSHOPTS", "--ssh build-target-opt")
|
||||
env = {"NIX_SSHOPTS": " ".join(["--ssh build-target-opt", *p.SSH_DEFAULT_OPTS])}
|
||||
with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run:
|
||||
|
||||
@@ -234,6 +234,52 @@ def test_remote_from_name(monkeypatch: MonkeyPatch) -> None:
|
||||
)
|
||||
|
||||
|
||||
def test_ssh_default_opts(monkeypatch: MonkeyPatch) -> None:
|
||||
monkeypatch.delenv("NIXOS_REBUILD_SSH_DEFAULT_OPTS", raising=False)
|
||||
assert p.ssh_default_opts() == p.SSH_DEFAULT_OPTS
|
||||
|
||||
monkeypatch.setenv(
|
||||
"NIXOS_REBUILD_SSH_DEFAULT_OPTS", "-o ControlPath=/run/user/1000/%C"
|
||||
)
|
||||
assert p.ssh_default_opts() == ["-o", "ControlPath=/run/user/1000/%C"]
|
||||
|
||||
monkeypatch.setenv("NIXOS_REBUILD_SSH_DEFAULT_OPTS", "")
|
||||
assert p.ssh_default_opts() == []
|
||||
|
||||
|
||||
@patch.dict(
|
||||
p.os.environ,
|
||||
{"PATH": "/path/to/bin", "NIXOS_REBUILD_SSH_DEFAULT_OPTS": ""},
|
||||
clear=True,
|
||||
)
|
||||
@patch("subprocess.run", autospec=True)
|
||||
def test_run_wrapper_ssh_default_opts_override(mock_run: Any) -> None:
|
||||
p.run_wrapper(
|
||||
["test"],
|
||||
check=True,
|
||||
remote=m.Remote("user@localhost", ["-p", "2222"], "ssh"),
|
||||
)
|
||||
mock_run.assert_called_with(
|
||||
[
|
||||
"ssh",
|
||||
"-p",
|
||||
"2222",
|
||||
"user@localhost",
|
||||
"--",
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"""'exec /usr/bin/env -i PATH="${PATH-}" "$@"'""",
|
||||
"sh",
|
||||
"test",
|
||||
],
|
||||
check=True,
|
||||
text=True,
|
||||
errors="surrogateescape",
|
||||
env=None,
|
||||
input=None,
|
||||
)
|
||||
|
||||
|
||||
def test_ssh_host() -> None:
|
||||
ssh_remotes = {
|
||||
"user@[fe80::1%25eth0]": "user@fe80::1%eth0",
|
||||
|
||||
Reference in New Issue
Block a user