How to create a /etc file, only when it's not available

I know how to create a file, but the file can only be created. Never should the file be overwritten on a nixos-rebuild boot/switch.

environment.etc."foo.env" = {
	text = ''
		bar = 1
		# bar = 2
	'';
	mode = "0770";
};

I’ve solved it with a systemd service.

Please share if you find a better solution.

    systemd.services.create-foo-conf = {
      script = ''
        cat > /etc/foo.conf << EOF
        bar = 1
        # bar = 2
        EOF
        chown 1000:100 /etc/foo.conf
        chmod 770 /etc/foo.conf
      '';
      wantedBy = [ "multi-user.target" ];
      after = [ "network-online.target" ];
      wants = [ "network-online.target" ];
      unitConfig.ConditionPathExists = "!/etc/foo.conf";
      serviceConfig.Type = "oneshot";
    };

I’m curious why you don’t want the file to be over-written? Feels like there is part of the story you didn’t share.

I do agree, that your systemd service approach is a solution to the problem “create /etc/file, but only if it is not present”

This really seems like a strange thing to want, yes. However, assuming it really is what you want, I can’t really think of a better solution than the systemd service.

I have 3 kiosks in a production environment, which run the same nixos config (except static ip, disk id)
I want a 4th pc to function as a spare. When needed someone can swap them.

I can map a keybinding to change it in the file
or I could access remotely and change the value in the file.(currently the system doesn’t have internet access)

I gave each kiosk a numpad keyboard

Sounds like a job for specializations. I’d map the keybind to switch specializations instead, then you can declare the file differently in the specialization.

good idea

I’ll lookup how to change default specialization and reboot.

Can this work on a system without the config?
I build the config on my laptop and push it nixos-rebuild ... target

you can tell systemd-tmpfiles to link a file if and only if the target doesn’t exist - this might be the simplest and cleanest solution

specialisation work, but it will only allow to switch once?

ls /run/current-system/specialisation/
foo1  foo2
sudo /run/current-system/specialisation/foo2/bin/switch-to-configuration switch

When I try to run it a second time, the folder is empty:

ls /run/current-system/specialisation/

    environment.etc."foo.conf" = lib.mkDefault {
      mode = "0777";
      text = ''
        bar = 1
      '';
    };
    specialisation = {
      foo1.configuration = {
        system.nixos.tags = [ "foo1" ];
        environment.etc."foo.conf" = lib.mkForce {
          mode = "0777";
          text = ''
            bar = 1
          '';
        };
      };
      foo2.configuration = {
        system.nixos.tags = [ "foo2" ];
        environment.etc."foo.conf" = lib.mkForce {
          mode = "0777";
          text = ''
            bar = 2
          '';
        };
      };
    };

sudo /nix/var/nix/profiles/system/specialisation/foo2/bin/switch-to-configuration switch

This works

Assuming you don’t update the system without rebooting it, getting it from /run/booted-system would work. Or you could grab it from /nix/var/nix/profiles/system, I suppose.

I understand why it can’t just link them all together circularly… even though that’s a bit annoying here.

Incidentally, you should probably use switch-to-configuration test, so it doesn’t bother recreating boot menus and such.

After a reboot the specialisation isn’t active anymore.
tried with switch & boot

Is this a bug or normal behavior?

I believe that’s normal. You boot into the non-specialized config unless you choose otherwise in the bootloader. There’s no state tracking across reboots for which specialization you’re in.

1 Like