Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running nixos-rebuild switch twice can produce different results due to dependence on current system state #65803

Open
Thra11 opened this issue Aug 2, 2019 · 5 comments

Comments

@Thra11
Copy link
Member

Thra11 commented Aug 2, 2019

Describe the bug
Quoting from the NixOS homepage

NixOS has a completely declarative approach to configuration management: you write a specification of the desired configuration of your system in NixOS’s modular language, and NixOS takes care of making it happen.

The problem is that the system/environment in which nixos-rebuild is run can have a huge effect on the result. This is especially noticeable when setting Nix configuration options such as the nixPath. The first nixos-rebuild will use the existing /etc/nix/nix.conf. If the build + switch results in changes to /etc/nix/nix.conf, then the next nixos-rebuild will potentially produce a completely different result.

I am wondering whether:

  1. Is it possible to detect changes to the configuration which could affect the output in this way?
  2. Is it possible to avoid the issue by e.g. first building things like /etc/nix/nix.conf, then using them in subsequent stages instead of the current generation's.
  3. I think that it's converging (hopefully) on some sort of 'fixed point'? However, is it guaranteed to converge, or is there enough freedom that it might flip-flop between two states or diverge?

To Reproduce
As an example, on a fresh system set to use a channel:

  1. Edit /etc/nixos/configuration.nix to set nix.nixPath to include something like nixpkgs=/path/to/local/nixpkgs
  2. Run nixos-rebuild: It will rebuild everything using the channel
  3. Run nixos-rebuild again: It will rebuild everything using the local nixpkgs in /path/to/local/nixpkgs

Note that I am aware that you can override various nix options on the command line or by setting environment variables. What I am interested in, is whether we can get closer to the idea of a simple "define the system" -> "realise the system".

Expected behavior
It would be nice to be able to define your system configuration, run nixos-rebuild once, and be fairly sure that the result was what you defined.

@arcnmx
Copy link
Member

arcnmx commented Aug 3, 2019

Setting things up in such a way that building your system config relies on the environment (NIX_PATH, nix-channel, etc) is certainly going to be fragile. This is hopefully one of the problems that flakes have set out to solve? I believe the usual advice is to pin nixpkgs, which can be a pain to maintain but as far as I know is the best way to make things reasonably reproducible.

I suppose there's a balance here to weigh against overloading new users with unfamiliar concepts, being able to guide them to certain techniques while still offering more familiar workflows like nix-channel, nix-env, /etc config files, etc. without the cost of losing some of the advantages of nix? A large part of it is just improved tooling, like replacing nix-channel with something that's both easy to use and doesn't make a mess of things - either by making declarative configuration easier or having imperative tools that modify your declarations/config rather than directly affecting the environment.

(I don't even like the idea of keeping the config on the same system in /etc, my own approach to pinning is to use git to pin nixpkgs as a submodule, so that it can be tied to config changes and git submodule update --remote can be used to update it easily enough)

(also note: I'm sidestepping the topic of nix.conf because that topic's a bit more nuanced, though the hope is that any changes a typical user makes to that file won't meaningfully affect the output of any derivations)

@danbst
Copy link
Contributor

danbst commented Aug 6, 2019

Yes, you are right, nix.nixPath is a naughty child in our family. But this is more a problem of setup.

The core reason is that nixos-rebuild tool takes a few things from environment. See https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/impure.nix and https://github.com/NixOS/nixpkgs/blob/master/nixos/default.nix#L1-L3. We call these "impure variables", because they are quite implicit.

If you want true reproducibility, you should manage all impurities on your own. Luckily, the ones I've listed above are all of them: NIX_PATH (nixpkgs and <nixos-config>), nixpkgs config, nixpkgs overlays.

BTW, what you have described is already implemented for nix.package option - before building system we fetch the correct Nix package (whatever is defined in configuration.nix) and build system using that. But this method is fragile in some edge cases.

I'll change issue type to "question" then. People tried to fix the issue previously but failed #30399

PS. You can also make nixos-rebuild produce different results on each rebuild simply by inserting builtins.currentTime anywhere in derivation. I'm not sure if there is any Nix option which disables this builtin. Also, system.activationScripts can do any file I/O, even change /etc/nixos/configuration.nix.

@Thra11
Copy link
Member Author

Thra11 commented Aug 6, 2019

When installing NixOS on a device for the first time. I usually switch from the nix channel to a local git checkout of nixpkgs. For me at least, this is the best option because:

  • It uses concepts and tools which I know and understand: files on a filesystem, git, branches, etc.
  • I can make experimental changes to nixpkgs and test them without having to commit and push them anywhere.

So with the current state of affairs, I have to run nixos-rebuild switch a couple of times to get from a fresh install to a useable system. I've been experimenting with installing NixOS on a few different devices recently, which probably means I am running into this issue more often than most people might.

I believe the usual advice is to pin nixpkgs

Do you know if it's possible to use pinning to import a local nixpkgs checkout, thus effectively ignoring nix.nixPath, but still using a local nixpkgs?

If you want true reproducibility, you should manage all impurities on your own.

I think this is basically what I'm trying to do: I'm pointing nixPath at a local checkout so that I can 'manage' it, but as you say, it's a setup problem which happens while transitioning into the managed state.

I'll change issue type to "question" then. People tried to fix the issue previously but failed #30399

Slightly offtopic: I originally wanted to tag this as a question, but it wouldn't let me.

@stale
Copy link

stale bot commented Jun 2, 2020

Thank you for your contributions.

This has been automatically marked as stale because it has had no activity for 180 days.

If this is still important to you, we ask that you leave a comment below. Your comment can be as simple as "still important to me". This lets people see that at least one person still cares about this. Someone will have to do this at most twice a year if there is no other activity.

Here are suggestions that might help resolve this more quickly:

  1. Search for maintainers and people that previously touched the related code and @ mention them in a comment.
  2. Ask on the NixOS Discourse.
  3. Ask on the #nixos channel on irc.freenode.net.

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jun 2, 2020
@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Apr 22, 2024
@samueldr
Copy link
Member

See also: #8160

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants