nixos/etc-overlay: ship empty /etc/machine-id placeholder on immutable /etc - #529950
Conversation
0b89cff to
7c94f36
Compare
You're right, I missed that in the previous PR. The symlink setup requires modifying environment.etc."machine-id" = {
source = "/var/lib/nixos/etc/machine-id";
mode = "direct-symlink";
};
boot.initrd.systemd.tmpfiles.settings.machine-id."/sysroot/var/lib/nixos/etc/machine-id".f = {
argument = "uninitialized";
};
systemd.services.systemd-machine-id-commit = {
unitConfig.ConditionPathIsMountPoint = [
""
"/var/lib/nixos/etc/machine-id"
];
serviceConfig.ExecStart = [
""
"systemd-machine-id-setup --commit --root /var/lib/nixos"
];
};
That makes sense. Though personally, I still slightly prefer the symlink approach for consistency with how we handle |
|
Yeah, I would prefer to make minimal changes to upstream services though, and stay closer to what upstream expects, to lower the maintenance burden. |
|
@WilliButz might be able to give more context on how this used to work with symlinks and why now it doesn't. |
|
There is a bunch of context for this in this upstream issue: systemd/systemd#39438 The underlying change mentioned there breaks a couple of setups that do not seem to be supported/intended by upstream (which I gathered from discussions in person after the issue stalled), i.e. any setup that tries to persist only the machine-id outside The two explicitly supported options seem to be limited to persisting all of Anything that does not fit with how upstream expects a system to be set up could break just like the symlink setup did. So I think the correct thing to do would be to find some way to align our and upstream's expectations on this. The linked issue above was an attempt to communicate an actual use case that is not "just" a niche NixOS thing, but could be valuable to other platforms/setups as well (as shown by others that commented there) and then for example simply going back to resolving symlinks again, but with explicit support. Unfortunately the discussion on the issue stalled, but I don't think it's entirely hopeless. |
|
I guess the question remains though, what do we do right now? Because what we currently have on master is not working. Do we ship this PR as a solution for now that's at least workable, until upstream comes with a better fix? Or does anyone have another suggestion? |
rebmit
left a comment
There was a problem hiding this comment.
Do we ship this PR as a solution for now that's at least workable, until upstream comes with a better fix?
I agree.
|
Sorry for not catching this in the original PR. It's unfortunate that systemd does not consider symlinked /etc/machine-id to be supported.
I think it would be useful to document this in the |
The symlink to /var/lib/nixos/machine-id never persists the ID, systemd-machine-id-commit.service requires a writable /etc, and machine_id_commit() does not follow symlinks for its mountpoint check. So the backing file stays "uninitialized", every boot is ConditionFirstBoot=yes, and the machine-id is random per boot. Ship an empty regular file instead, systemd then overlays /run/machine-id for the session, ConditionFirstBoot is correctly "no", commit is cleanly condition-skipped, and the file is a usable bind target for users that want persistence. Fixes NixOS#523878
The upstream unit has ConditionPathIsReadWrite=/etc, which is always false on the read-only overlay, so the previous commit alone requires users that want persistence to override the conditions themselves before the generated ID can be written back. Use ConditionFirstBoot instead, with the empty placeholder first-boot is "no" and commit stays skipped, but when a writable file containing "uninitialized" is bind-mounted over /etc/machine-id, first-boot is "yes" once and commit writes the ID through the bind.
7c94f36 to
f438cd8
Compare
#523894 made
/etc/machine-ida symlink to/var/lib/nixos/machine-idandcreated the target with content
uninitialized.Unfortunately the generated id is never committed, because:
systemd-machine-id-commit.servicehasConditionPathIsReadWrite=/etc,which is always false on the read-only overlay, so the unit is skipped.
machine_id_commit()checks whether/etc/machine-iditself is a mountpoint (no symlink following), finds thesymlink isn't, and exits without writing.
So
/var/lib/nixos/machine-idstaysuninitializedforever, every boot isConditionFirstBoot=yes, and the machine-id is random on every boot.I think it's more correct to have an empty regular file in the etc image so that:
/run/machine-idover it for the session.ConditionFirstBootisno, which is the only logical default for a filethat can never change. The previous behaviour fired first-boot units on every boot.
systemd-machine-id-commitis cleanly condition-skipped, no failed unit.and have commit write through it, which does not work with a symlink.
The whole attrset is
mkDefault, so any user definition ofenvironment.etc.machine-idoverrides it.For users who need a persistent ID, there are two main options:
systemd.machine_id=/systemd.machine_id=firmwareon the kernel command line.cc @anglesideangle @rebmit @nikstur
Things done
passthru.tests.nixpkgs-reviewon this PR. See nixpkgs-review usage../result/bin/.