Propagate nixpkgs checkout to NixOps machines

685 views Asked by At

I'm maintaining my personal changes on nixpkgs, which I use both for system rebuilds (via NixOps) and for development on my workstation (mostly via nix-shell). The changes are commits rebased ontop of the nixos-17.09 channel and are stored on a private git server. All of the machines in the deployment have read access to that git server.

When using nix-shell on a remote machine, I get old packages originating from the install time of the machine (in my case nixos-17.03).

Is there any way to have the exact same revision of nixpkgs which is used for deployment available at the remote machine?

2

There are 2 answers

2
Emmanuel Rosa On BEST ANSWER

The problem your having is due to the fact that because NixOps builds locally and then copies the closure to the remote machines, and as such does not run nix-channel --update on the remote machines, the Nix Packages Collection (nixpkgs) is not updated on the remote machines.

Commands such as nix-env and nix-shell rely on the nixpkgs pointed to by $NIX_PATH (or whichever path you provide via the -I argument).

Solution

The solution is to get your version of nixpkgs into the remote machines and ensure $NIX_PATH points to it. By default, $NIX_PATH looks like this:

nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels

So the idea is to make it look like something like this:

nixpkgs=/nix/store/blah-blah-blah:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels

where blah-blah-blah is your nixpkgs Git repo inserted into the Nix store. Here's an example of how to do that:

let
    # This will point to whatever NIX_PATH states on the local machine,
    # unless overwritten with -I.
    hostNixpkgs = import <nixpkgs> {};

    # Some other nixpkgs from a GitHub repo
    romildo = hostNixpkgs.pkgs.fetchFromGitHub {
         owner = "romildo";
         repo = "nixpkgs";
         rev = "b167ba35987c2e69dc1bb91d5c245a04421ee7ed";
         sha256 = "02d8dfvginz45h2zhq745kynzygnsy760qh7yy152wpfhczag180";
    };
in
{
    network.description = "My NixOS VMs";

    vm0 = { config, lib, pkgs, ... }:
    {
      ...

      # This is really hacky, but it works.
      # I'd prefer to set environment.etc.NIX_PATH, but that's not allowed,
      # because that value is "read-only".
      environment.extraInit = "export NIX_PATH=nixpkgs=${romildo}:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels";
    };
}

How it works

Nix creates /nix/store/BLAH-set-environment which exports a bunch of environment variables, among other things. This file is made available in all shell sessions. environment.extraInit makes it possible to append whatever shell-neutral (sh) code you want to this environment. Because this arbitrary code is inserted at the end of the script, it can be used to override the environment variables, such as NIX_PATH.

The caveat is that you must log back in after deployment in order for the change to take affect. But the resulting NIX_PATH will look something like this: nixpkgs=/nix/store/mzxkszfv05np2f6rgdi2kwxd937f0sxa-source:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels. So in this example, nix-shell will look for nixpkgs at /nix/store/mzxkszfv05np2f6rgdi2kwxd937f0sxa-source.

0
Peter Hoeg On

Set this in configuration.nix (or however you structure your configuration):

{
  nix.nixPath = [ "nixpkgs=${pkgs.path}:/other/custom/paths/you/need" ];
}