Skip to content

Commit eb32dcf

Browse files
authored
nixos-rebuild-ng: add systemd-run to switch-to-configuration (#380918)
2 parents 914507b + 6725c12 commit eb32dcf

File tree

4 files changed

+178
-15
lines changed

4 files changed

+178
-15
lines changed

pkgs/by-name/ni/nixos-rebuild-ng/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,6 @@ not possible to fix, please open an issue and we can discuss a solution.
148148

149149
## TODON'T
150150

151-
- Reimplement `systemd-run` logic: will be moved to the new
152-
[`apply`](https://github.com/NixOS/nixpkgs/pull/344407) script
153151
- Nix bootstrap: it is only used for non-Flake paths and it is basically
154152
useless nowadays. It was created at a time when Nix was changing frequently
155153
and there was a need to bootstrap a new version of Nix before evaluating the

pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@
2929

3030
FLAKE_FLAGS: Final = ["--extra-experimental-features", "nix-command flakes"]
3131
FLAKE_REPL_TEMPLATE: Final = "repl.nix.template"
32+
SWITCH_TO_CONFIGURATION_CMD_PREFIX: Final = [
33+
"systemd-run",
34+
"-E",
35+
# Will be set to new value early in switch-to-configuration script,
36+
# but interpreter starts out with old value
37+
"LOCALE_ARCHIVE",
38+
"-E",
39+
"NIXOS_INSTALL_BOOTLOADER",
40+
"--collect",
41+
"--no-ask-password",
42+
"--pipe",
43+
"--quiet",
44+
"--same-dir",
45+
"--service-type=exec",
46+
"--unit=nixos-rebuild-switch-to-configuration",
47+
]
3248
logger = logging.getLogger(__name__)
3349

3450

@@ -628,8 +644,21 @@ def switch_to_configuration(
628644
if not path_to_config.exists():
629645
raise NRError(f"specialisation not found: {specialisation}")
630646

647+
r = run_wrapper(
648+
["test", "-d", "/run/systemd/system"],
649+
remote=target_host,
650+
check=False,
651+
)
652+
cmd = SWITCH_TO_CONFIGURATION_CMD_PREFIX
653+
if r.returncode:
654+
logger.debug(
655+
"skipping systemd-run to switch configuration since systemd is "
656+
+ "not working in target host"
657+
)
658+
cmd = []
659+
631660
run_wrapper(
632-
[path_to_config / "bin/switch-to-configuration", str(action)],
661+
[*cmd, path_to_config / "bin/switch-to-configuration", str(action)],
633662
extra_env={"NIXOS_INSTALL_BOOTLOADER": "1" if install_bootloader else "0"},
634663
remote=target_host,
635664
sudo=sudo,

pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
234234

235235
nr.execute(["nixos-rebuild", "boot", "--no-flake", "-vvv", "--no-reexec"])
236236

237-
assert mock_run.call_count == 6
237+
assert mock_run.call_count == 7
238238
mock_run.assert_has_calls(
239239
[
240240
call(
@@ -279,7 +279,16 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
279279
**DEFAULT_RUN_KWARGS,
280280
),
281281
call(
282-
[config_path / "bin/switch-to-configuration", "boot"],
282+
["test", "-d", "/run/systemd/system"],
283+
check=False,
284+
**DEFAULT_RUN_KWARGS,
285+
),
286+
call(
287+
[
288+
*nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX,
289+
config_path / "bin/switch-to-configuration",
290+
"boot",
291+
],
283292
check=True,
284293
**(DEFAULT_RUN_KWARGS | {"env": {"NIXOS_INSTALL_BOOTLOADER": "0"}}),
285294
),
@@ -442,7 +451,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
442451
]
443452
)
444453

445-
assert mock_run.call_count == 3
454+
assert mock_run.call_count == 4
446455
mock_run.assert_has_calls(
447456
[
448457
call(
@@ -476,7 +485,17 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
476485
**DEFAULT_RUN_KWARGS,
477486
),
478487
call(
479-
["sudo", config_path / "bin/switch-to-configuration", "switch"],
488+
["test", "-d", "/run/systemd/system"],
489+
check=False,
490+
**DEFAULT_RUN_KWARGS,
491+
),
492+
call(
493+
[
494+
"sudo",
495+
*nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX,
496+
config_path / "bin/switch-to-configuration",
497+
"switch",
498+
],
480499
check=True,
481500
**(DEFAULT_RUN_KWARGS | {"env": {"NIXOS_INSTALL_BOOTLOADER": "1"}}),
482501
),
@@ -535,7 +554,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
535554
]
536555
)
537556

538-
assert mock_run.call_count == 10
557+
assert mock_run.call_count == 11
539558
mock_run.assert_has_calls(
540559
[
541560
call(
@@ -661,6 +680,19 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
661680
check=True,
662681
**DEFAULT_RUN_KWARGS,
663682
),
683+
call(
684+
[
685+
"ssh",
686+
*nr.process.SSH_DEFAULT_OPTS,
687+
"user@target-host",
688+
"--",
689+
"test",
690+
"-d",
691+
"/run/systemd/system",
692+
],
693+
check=False,
694+
**DEFAULT_RUN_KWARGS,
695+
),
664696
call(
665697
[
666698
"ssh",
@@ -670,6 +702,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
670702
"sudo",
671703
"env",
672704
"NIXOS_INSTALL_BOOTLOADER=0",
705+
*nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX,
673706
str(config_path / "bin/switch-to-configuration"),
674707
"switch",
675708
],
@@ -712,7 +745,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
712745
]
713746
)
714747

715-
assert mock_run.call_count == 4
748+
assert mock_run.call_count == 5
716749
mock_run.assert_has_calls(
717750
[
718751
call(
@@ -750,6 +783,19 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
750783
check=True,
751784
**DEFAULT_RUN_KWARGS,
752785
),
786+
call(
787+
[
788+
"ssh",
789+
*nr.process.SSH_DEFAULT_OPTS,
790+
"user@localhost",
791+
"--",
792+
"test",
793+
"-d",
794+
"/run/systemd/system",
795+
],
796+
check=False,
797+
**DEFAULT_RUN_KWARGS,
798+
),
753799
call(
754800
[
755801
"ssh",
@@ -759,6 +805,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
759805
"sudo",
760806
"env",
761807
"NIXOS_INSTALL_BOOTLOADER=0",
808+
*nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX,
762809
str(config_path / "bin/switch-to-configuration"),
763810
"switch",
764811
],
@@ -802,7 +849,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
802849
]
803850
)
804851

805-
assert mock_run.call_count == 6
852+
assert mock_run.call_count == 7
806853
mock_run.assert_has_calls(
807854
[
808855
call(
@@ -863,7 +910,16 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
863910
**DEFAULT_RUN_KWARGS,
864911
),
865912
call(
866-
[config_path / "bin/switch-to-configuration", "switch"],
913+
["test", "-d", "/run/systemd/system"],
914+
check=False,
915+
**DEFAULT_RUN_KWARGS,
916+
),
917+
call(
918+
[
919+
*nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX,
920+
config_path / "bin/switch-to-configuration",
921+
"switch",
922+
],
867923
check=True,
868924
**DEFAULT_RUN_KWARGS,
869925
),
@@ -881,6 +937,8 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
881937
return CompletedProcess([], 0, str(nixpkgs_path))
882938
elif args[0] == "git":
883939
return CompletedProcess([], 0, "")
940+
elif args[0] == "test":
941+
return CompletedProcess([], 1)
884942
else:
885943
return CompletedProcess([], 0)
886944

@@ -897,7 +955,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
897955
]
898956
)
899957

900-
assert mock_run.call_count == 4
958+
assert mock_run.call_count == 5
901959
mock_run.assert_has_calls(
902960
[
903961
call(
@@ -929,6 +987,11 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
929987
check=True,
930988
**DEFAULT_RUN_KWARGS,
931989
),
990+
call(
991+
["test", "-d", "/run/systemd/system"],
992+
check=False,
993+
**DEFAULT_RUN_KWARGS,
994+
),
932995
call(
933996
[
934997
Path("/nix/var/nix/profiles/system/bin/switch-to-configuration"),
@@ -978,6 +1041,8 @@ def test_execute_test_flake(mock_run: Mock, tmp_path: Path) -> None:
9781041
def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
9791042
if args[0] == "nix":
9801043
return CompletedProcess([], 0, str(config_path))
1044+
elif args[0] == "test":
1045+
return CompletedProcess([], 1)
9811046
else:
9821047
return CompletedProcess([], 0)
9831048

@@ -987,7 +1052,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
9871052
["nixos-rebuild", "test", "--flake", "github:user/repo#hostname", "--no-reexec"]
9881053
)
9891054

990-
assert mock_run.call_count == 2
1055+
assert mock_run.call_count == 3
9911056
mock_run.assert_has_calls(
9921057
[
9931058
call(
@@ -1003,6 +1068,11 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
10031068
stdout=PIPE,
10041069
**DEFAULT_RUN_KWARGS,
10051070
),
1071+
call(
1072+
["test", "-d", "/run/systemd/system"],
1073+
check=False,
1074+
**DEFAULT_RUN_KWARGS,
1075+
),
10061076
call(
10071077
[config_path / "bin/switch-to-configuration", "test"],
10081078
check=True,
@@ -1031,6 +1101,8 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
10311101
2084 2024-11-07 23:54:17 (current)
10321102
"""),
10331103
)
1104+
elif args[0] == "test":
1105+
return CompletedProcess([], 1)
10341106
else:
10351107
return CompletedProcess([], 0)
10361108

@@ -1040,7 +1112,7 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
10401112
["nixos-rebuild", "test", "--rollback", "--profile-name", "foo", "--no-reexec"]
10411113
)
10421114

1043-
assert mock_run.call_count == 2
1115+
assert mock_run.call_count == 3
10441116
mock_run.assert_has_calls(
10451117
[
10461118
call(
@@ -1054,6 +1126,11 @@ def run_side_effect(args: list[str], **kwargs: Any) -> CompletedProcess[str]:
10541126
stdout=PIPE,
10551127
**DEFAULT_RUN_KWARGS,
10561128
),
1129+
call(
1130+
["test", "-d", "/run/systemd/system"],
1131+
check=False,
1132+
**DEFAULT_RUN_KWARGS,
1133+
),
10571134
call(
10581135
[
10591136
Path(

pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,9 +689,12 @@ def test_set_profile(mock_run: Mock) -> None:
689689

690690

691691
@patch(get_qualified_name(n.run_wrapper, n), autospec=True)
692-
def test_switch_to_configuration(mock_run: Mock, monkeypatch: MonkeyPatch) -> None:
692+
def test_switch_to_configuration_without_systemd_run(
693+
mock_run: Any, monkeypatch: MonkeyPatch
694+
) -> None:
693695
profile_path = Path("/path/to/profile")
694696
config_path = Path("/path/to/config")
697+
mock_run.return_value = CompletedProcess([], 1)
695698

696699
with monkeypatch.context() as mp:
697700
mp.setenv("LOCALE_ARCHIVE", "")
@@ -749,6 +752,62 @@ def test_switch_to_configuration(mock_run: Mock, monkeypatch: MonkeyPatch) -> No
749752
)
750753

751754

755+
@patch(get_qualified_name(n.run_wrapper, n), autospec=True)
756+
def test_switch_to_configuration_with_systemd_run(
757+
mock_run: Mock, monkeypatch: MonkeyPatch
758+
) -> None:
759+
profile_path = Path("/path/to/profile")
760+
config_path = Path("/path/to/config")
761+
mock_run.return_value = CompletedProcess([], 0)
762+
763+
with monkeypatch.context() as mp:
764+
mp.setenv("LOCALE_ARCHIVE", "")
765+
766+
n.switch_to_configuration(
767+
profile_path,
768+
m.Action.SWITCH,
769+
sudo=False,
770+
target_host=None,
771+
specialisation=None,
772+
install_bootloader=False,
773+
)
774+
mock_run.assert_called_with(
775+
[
776+
*n.SWITCH_TO_CONFIGURATION_CMD_PREFIX,
777+
profile_path / "bin/switch-to-configuration",
778+
"switch",
779+
],
780+
extra_env={"NIXOS_INSTALL_BOOTLOADER": "0"},
781+
sudo=False,
782+
remote=None,
783+
)
784+
785+
target_host = m.Remote("user@localhost", [], None)
786+
with monkeypatch.context() as mp:
787+
mp.setenv("LOCALE_ARCHIVE", "/path/to/locale")
788+
mp.setenv("PATH", "/path/to/bin")
789+
mp.setattr(Path, Path.exists.__name__, lambda self: True)
790+
791+
n.switch_to_configuration(
792+
Path("/path/to/config"),
793+
m.Action.TEST,
794+
sudo=True,
795+
target_host=target_host,
796+
install_bootloader=True,
797+
specialisation="special",
798+
)
799+
mock_run.assert_called_with(
800+
[
801+
*n.SWITCH_TO_CONFIGURATION_CMD_PREFIX,
802+
config_path / "specialisation/special/bin/switch-to-configuration",
803+
"test",
804+
],
805+
extra_env={"NIXOS_INSTALL_BOOTLOADER": "1"},
806+
sudo=True,
807+
remote=target_host,
808+
)
809+
810+
752811
@patch(
753812
get_qualified_name(n.Path.glob, n),
754813
autospec=True,

0 commit comments

Comments
 (0)