morph icon indicating copy to clipboard operation
morph copied to clipboard

suggestion: make evalConfig configurable

Open leotaku opened this issue 5 years ago • 9 comments

PR #96 has already greatly improved working with machines that have differing requirements/architecture, however there is still one use-case that is largely unsupported: Multiple nixpkgs versions.

From what I understand the issue lies with nixpkgs/nixos/lib/eval-config.nix, as evaluating a configuration that uses a differing nixpkgs version seems to be unsupported.

I propose this problem could be fixed by making the new evalConfig option a function with the ability to inspect either the deployment name, or the value of the deployment. I suppose the former would be easier to understand and implement, while the later would potentially be more extensible.

Of course, I would also be happy with any alternative solution.

Example code (name)

let
  sources = import ../sources/nix/sources.nix;
  pinned-stable = import sources.nixos-19_09-small { };
  pinned-unstable = import sources.nixos-unstable { };
in {
  network = {
    description = "Home network";
    overlays = [ ];
    config = {
      allowUnfree = true;
      allowBroken = false;
    };
    # NOTE: evalConfig also passes nixpkgs.pkgs
    lib = pinned-stable.lib;
    evalConfig = name:
      if (name == "nixos-laptop.local") then
        pinned-stable.path + "/nixos/lib/eval-config.nix"
      else
        pinned-unstable.path + "/nixos/lib/eval-config.nix";
    runCommand = pinned-stable.runCommand;
  };
} // {
  "nixos-laptop.local" = import ./laptop/configuration.nix;
  "nixos-fujitsu.local" = import ./fujitsu.nix;
  "nixos-rpi.local" = import ./rpi.nix;
}

leotaku avatar Jan 23 '20 15:01 leotaku

It seems that the 20.03 gnupg module have an eval-dependency on pkgs.pinentry.flavors which doesn't exist in the 19.09 package-set. This effectively mean that you cannot eval 19.09-nixpkgs with 20.03 NixOS-modules and eval'ing 20.03-packages with 19.09-modules is not possible either, which... in turn leads to the conclusion that..: Currently morph cannot have 19.09 and 20.03 machines in the same deployment/network. :(

I don't know if there are any upstream opinions about backward compatibility or at least opinions about not having strict eval dependencies to packages in the first place? I tried to "complain" here: https://logs.nix.samueldr.com/nixos/2020-02-21#3093582;

I was about to create a new issue for making evalConfig - or the entire "buildTime-nixpkgs" - configurable at per-host level in morph, but realized it was already here :) :+1:

johanot avatar Feb 21 '20 16:02 johanot

@johanot Right, but it definitely seems to be possible to eval both nixos 20.03 with evalConfig 20.03 and nixos 19.09 with evalConfig 19.09, in the same file. I also think that use-case is more interesting than the mixing of versions you describe. Maybe I'm missing what exact problem you are trying to describe?

I just patched morph, adapted my deployment and everything seems to be working.

Morph Patch

diff --git a/data/eval-machines.nix b/data/eval-machines.nix
index 86ba52d..4cdc426 100644
--- a/data/eval-machines.nix
+++ b/data/eval-machines.nix
@@ -5,7 +5,7 @@ let
   network      = import networkExpr;
   nwPkgs       = network.network.pkgs or {};
   lib          = network.network.lib or nwPkgs.lib or (import <nixpkgs/lib>);
-  evalConfig   = network.network.evalConfig or "${nwPkgs.path or <nixpkgs>}/nixos/lib/eval-config.nix";
+  evalConfig   = network.network.evalConfig or (_: "${nwPkgs.path or <nixpkgs>}/nixos/lib/eval-config.nix");
   runCommand   = network.network.runCommand or nwPkgs.runCommand or ((import <nixpkgs> {}).runCommand);
 in
   with lib;
@@ -21,7 +21,7 @@ rec {
         modules = [ { imports = [ network.${machineName} ]; } { inherit (network) _file; } ];
       in
       { name = machineName;
-        value = import evalConfig {
+        value = import (evalConfig machineName) {
           modules =
             modules ++
             [ ({ config, lib, options, ... }: {

My Deployment

let
  sources = import ../sources/nix/sources.nix;
  pinned = import sources.nixos-19_09-small { };
  unstable = import sources.nixos-unstable { };
in {
  network = {
    description = "Home network";
    overlays = [ ];
    config = {
      allowUnfree = true;
      allowBroken = false;
    };
    # NOTE: evalConfig also passes nixpkgs.pkgs
    lib = pinned.lib;
    evalConfig = name:
      if name == "nixos-laptop.local" then
        unstable.path + "/nixos/lib/eval-config.nix"
      else
        pinned.path + "/nixos/lib/eval-config.nix";
    runCommand = pinned.runCommand;
  };
} // {
  "nixos-laptop.local" = import ./laptop/configuration.nix;
  "nixos-fujitsu.local" = import ./fujitsu.nix;
  "nixos-rpi.local" = import ./rpi.nix;
}

leotaku avatar Feb 22 '20 13:02 leotaku

@leotaku For the record, this demonstrates the nixpkgs/nixos-modules conflict I was referring to:

let
  common = { pkgs, ... }: {
    environment.systemPackages = [ pkgs.hello ];

    fileSystems."/" = {
      fsType = "ext4";
      label = "root";
    };
    boot.loader.grub.devices = [ "/dev/sda" ];
  };

  loris = import (builtins.fetchTarball {
      url = "https://github.com/NixOS/nixpkgs-channels/archive/c2c5dcc00b05f0f6007d7a997dc9d90aefb49f28.tar.gz";
      sha256 = "1sjy9b1jh7k4bhww42zyjjim4c1nn8r4fdbqmyqy4hjyfrh9z6jc";
   }) { config = {}; overlays = []; };

  markhor = import (builtins.fetchTarball {
      url = "https://github.com/NixOS/nixpkgs-channels/archive/153baa2674010416bed78f797f8239e1cbfed956.tar.gz";
      sha256 = "0kf6xx5lawhlkxwk8j3qb7x4bvn1snpixmw4y9qxa2glbgk5h9zr";
   }) { config = {}; overlays = []; };

in
{
  network = {
    inherit (markhor) runCommand lib;
    evalConfig = "${markhor.path}/nixos/lib/eval-config.nix"; # try changing this to "loris.path"
    description = "test";
  };

  loris = { config, pkgs, ... }: {
    imports = [ common ];
    nixpkgs.pkgs = loris;
  };

  markhor = { config, pkgs, ... }: {
    imports = [ common ];
    nixpkgs.pkgs = markhor;
  };
}

"markhor"-pkgs don't build with "loris"-nixos (eval-config), and vice versa.

johanot avatar Feb 23 '20 18:02 johanot

I am running into a similar issue. I have most of my machines follow the latest stable channel but some machines (currently just one) is following nixos-unstable due to changes in there that I require for it to operate at all. While I could continue backporting those changes manually (i.e. rebasing my custom branch on the latest channel) that becomes tedious.

I am currently tempted to use something as described in https://github.com/DBCDK/morph/issues/104#issuecomment-589954838.

andir avatar May 23 '20 14:05 andir

I've ran into the same issue. Mainly due to the fact that few servers I run use a service which changed in unstable (different module options/config) so now it won't eval. I could use a separate machine for building the machines using unstable, but almost all of my infra is in stable so I don't want to make exceptions just for a few servers. And this seems like a nice and wonderful fix.

1000101 avatar May 24 '20 11:05 1000101

Yeah, I went ahead and just apllied that patch to morph in my packages: https://github.com/andir/infra/blob/master/nix/packages/morph-evalConfig-machinename.patch

I am still not entirely happy about that approach as now you have to specify the nixpkgs for a machine twice.

On Sun, May 24, 2020, 1:44 PM 1000101 [email protected] wrote:

I've ran into the same issue. Mainly due to the fact that few servers I run use a service which changed in unstable (different module options/config) so now it won't eval. I could use a separate machine for deployment of the machines using unstable, but almost all of my infra is in stable so I don't want to make exceptions for a few servers. And this seems like a nice and wonderful fix.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/DBCDK/morph/issues/104#issuecomment-633218674, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAE365EHELPDVAW3V2FG5SLRTECBNANCNFSM4KKYLFHQ .

andir avatar May 24 '20 11:05 andir

I'm also rolling with the approach in https://github.com/DBCDK/morph/issues/104#issuecomment-589954838, although with a different take on my entrypoint, that allows me to set defaults and overwrite them when needed.

let
  sources = import ../nix/sources.nix;

  defaultArch = "x86_64-linux";
  defaultPkgs = sources."nixos-20.09";

  lib = import (defaultPkgs + "/lib");

  machines = {
    "a.local" = {
      system = "aarch64-linux";
      packages = sources.nixos-unstable;
    };
    "g.local" = {};
    "j.local" = {};
    "h.local" = {};
  };

  mkMachine = hostName: { system ? defaultArch, packages ? defaultPkgs }:
    let
      pkgs = import packages {
        inherit system;
      };
    in
      { config, ... }: {
        imports = [
          (./machines + "/${hostName}")
        ];
        nixpkgs.pkgs = pkgs;
        deployment = {
          substituteOnDestination = true;
          tags = [ system ];
        };
      };
in
{
  network = {
    inherit lib;
    description = "local";

    evalConfig = machineName:
      (machines."${machineName}".packages or defaultPkgs) + "/nixos/lib/eval-config.nix";
  };
} // (lib.mapAttrs mkMachine machines)

mweinelt avatar May 24 '21 01:05 mweinelt

The patch above no longer applies. This seems to work:

diff --git a/data/eval-machines.nix b/data/eval-machines.nix
index 86ba52d..4cdc426 100644
--- a/data/eval-machines.nix
+++ b/data/eval-machines.nix
@@ -5,7 +5,7 @@ let
   network      = import networkExpr;
   nwPkgs       = network.network.pkgs or {};
   lib          = network.network.lib or nwPkgs.lib or (import <nixpkgs/lib>);
-  evalConfig   = network.network.evalConfig or ((nwPkgs.path or <nixpkgs>) + "/nixos/lib/eval-config.nix");
+  evalConfig   = network.network.evalConfig or (_: (nwPkgs.path or <nixpkgs>) + "/nixos/lib/eval-config.nix");
   runCommand   = network.network.runCommand or nwPkgs.runCommand or ((import <nixpkgs> {}).runCommand);
 in
   with lib;
@@ -42,7 +42,7 @@ rec {
   uncheckedNodes =
     listToAttrs (map (machineName:
       { name = machineName;
-        value = import evalConfig {
+        value = import (evalConfig machineName) {
           modules = modules machineName;
           extraArgs = { nodes = uncheckedNodes; name = machineName; };
           check = false;
@@ -54,7 +54,7 @@ rec {
   nodes =
     listToAttrs (map (machineName:
       { name = machineName;
-        value = import evalConfig {
+        value = import (evalConfig machineName) {
           modules = modules machineName;
           extraArgs = { nodes = uncheckedNodes ; name = machineName; };
         };

piegamesde avatar Sep 11 '21 00:09 piegamesde

I think this might be related:

trace: warning: The extraArgs argument to eval-config.nix is deprecated. Please set config._module.args instead.

mweinelt avatar May 27 '22 14:05 mweinelt