!UKDpaKNNsBpOPfLWfX:zhaofeng.li

Colmena

320 Members
A simple, stateless NixOS deployment tool - https://github.com/zhaofengli/colmena108 Servers

Load older messages


SenderMessageTime
26 May 2022
@blaggacao:matrix.org@blaggacao:matrix.org* In my opinion, maintaining legacy nix support in-tree is a bit of a stretch and reduces the ability to innovate. Maby there can be a 2-tree solution that is not 100% mutually compatible .19:24:05
@blaggacao:matrix.org@blaggacao:matrix.org

Looks like this iface should be enough, we could yants-ify it as it may become a (semi-public) contract:

in rec {
  deploymentConfig = l.mapAttrs (name: eval: eval.config.deployment) nodes;
  deploymentConfigSelected = names: listToAttrs (map (name: { inherit name; value = nodes.${name}.config.deployment; }) names);
  evalAll = evalSelected nodeNames;
  evalSelectedDrvPaths = names: l.mapAttrs (k: v: v.drvPath) (evalSelected names);
  evalSelected = names: let selected = l.filterAttrs (name: _: elem name names) toplevel; in selected;
  introspect = function: function { inherit nixpkgs lib; nodes = uncheckedNodes; };
  nodes = listToAttrs (map (name: { inherit name; value = evalNode name (configsFor name); }) nodeNames);
  toplevel = l.mapAttrs (name: eval: eval.config.system.build.toplevel) nodes;
}
21:46:33
@blaggacao:matrix.org@blaggacao:matrix.org

The actual inteface seems even less:

❯ rg 'hive\.(deploymentConfig|evalSelected|evalAll|nodes|toplevel|introspect)' src/nix/hive/mod.rs
257:        self.nix_instantiate("attrNames hive.nodes").eval()
263:        let configs: HashMap<NodeName, NodeConfig> = self.nix_instantiate("hive.deploymentConfig").eval_with_builders().await?
278:        let expr = format!("hive.nodes.\"{}\".config.deployment or null", node.as_str());
287:        let configs: HashMap<NodeName, NodeConfig> = self.nix_instantiate(&format!("hive.deploymentConfigSelected {}", nodes_expr.expression()))
309:        let expr = format!("hive.evalSelectedDrvPaths {}", nodes_expr.expression());
339:            let expression = format!("hive.introspect ({})", expression);
343:            let expression = format!("toJSON (hive.introspect ({}))", expression);
480:            "{} hive.evalSelected {}",
21:55:35
@blaggacao:matrix.org@blaggacao:matrix.org I reduced the iface surface a little which seems to be pure cleanup refactoring since it doesn't break any tests...
https://github.com/zhaofengli/colmena/pull/89
22:28:04
@blaggacao:matrix.org@blaggacao:matrix.org ( the guiding principle has been: nothing except src/nix/hive/* should be allowed to consume the eval.nix contract) 22:29:28
27 May 2022
@blaggacao:matrix.org@blaggacao:matrix.orgquick question: is unchecked module evaluation lazy?00:32:58
@blaggacao:matrix.org@blaggacao:matrix.org

Not sure if anyone noticed and I don't know how to explain properly due to the spaghetti, but this is actually the only place where the invoking system would bleed into the nixosConfiguration other than that, I beleive that system can be completely encapsulated into the configuration.

https://github.com/NixOS/nixpkgs/pull/174829

01:02:23
@blaggacao:matrix.org@blaggacao:matrix.org And that would be the final cleanup to completely encapsulate instantiating nixpkgs within the config and would make things like meta.nixpkgs et al. not needed any more... 01:03:31
@blaggacao:matrix.org@blaggacao:matrix.org

So I hope this new eval.nix would work, testing tomorrow, let me know if you have comments / ideas:

{ flakeUri                     # Nix Flake URI with `outputs.colmena`
, hermetic ? true              # Whether we are allowed to use <nixpkgs>
, colmenaOptions
, colmenaModules
}: let
  flake = builtins.getFlake flakeUri;
  nixpkgs =
  if builtins.hasAttr "nixpkgs" flake.inputs
  then inputs.nixpkgs
  else throw ''
    In order to be able to use 'colmena', an input
    named 'nixpkgs' must be defined in the flake.
  '';

  l = nixpkgs.lib // builtins;
in

  # The final hive will always have the meta key instead of network.
  # system.name.colmenaConfigurations.target
  hive = let
    op1 = l.filterAttrs (_: v: v ? colmenaConfigurations ); # contains colmena configs?
    op2 = l.mapAttrs (n: v: v.colmenaConfigurations); # lift colmena configs one level up
    op3 = l.mapAttrsToList (n: l.mapAttrs' (t: c: l.nameValuePair "${n}-${t}" c)); # prefix with cell name -> unique names
  in
    l.listToAttrs (l.flatten (op3 (op2 (op1 flake.x86_64-linux))));

  evalPkgs = name: config: nixpkgs.lib.evalModules {
    modules = [ config {_module.check = false;} {imports = [ "${nixpkgs}/nixos/misc/nixpkgs.nix" ];} ];
  }.config.nixpkgs.pkgs;

  evalNode = check: name: config: let
    pkgs = evalPkgs name config;
    evalConfig = import "${pkgs.path}/nixos/lib/eval-config.nix";
  in evalConfig {
    inherit (pkgs) system;

    modules = [
      colmenaModules.assertionModule
      colmenaModules.keyChownModule
      colmenaModules.keyServiceModule
      colmenaOptions.deploymentOptions
      config
      {_module.check = check;}
    ];
    specialArgs = {
      inherit name;
      nodes = evalNode false hive;
    };
  };

in rec {
  # Exported attributes
  #
  # Functions are intended to be called with `nix-instantiate --eval --json`
  nodes =            l.mapAttrs (evalNode true) hive;
  toplevel =         l.mapAttrs (_: v: v.config.system.build.toplevel) nodes;
  deploymentConfig = l.mapAttrs (_: v: v.config.deployment)            nodes;
  deploymentConfigSelected = names: l.filterAttrs (name: _: l.elem name names) deploymentConfig;
  evalSelected =             names: l.filterAttrs (name: _: l.elem name names) toplevel;
  evalSelectedDrvPaths =     names: l.mapAttrs    (_: v: v.drvPath)            (evalSelected names);
  introspect = f: f { inherit nixpkgs; inherit (nixpkgs) lib; nodes = evalNode false hive; };
  machinesFile = null;
}


01:23:51
@blaggacao:matrix.org@blaggacao:matrix.org *

So I hope this new eval.nix would work, testing tomorrow, let me know if you have comments / ideas:

{ flakeUri                     # Nix Flake URI with `outputs.colmena`
, hermetic ? true              # Whether we are allowed to use <nixpkgs>
, colmenaOptions
, colmenaModules
}: let
  flake = builtins.getFlake flakeUri;
  nixpkgs =
  if builtins.hasAttr "nixpkgs" flake.inputs
  then inputs.nixpkgs
  else throw ''
    In order to be able to use 'colmena', an input
    named 'nixpkgs' must be defined in the flake.
  '';

  l = nixpkgs.lib // builtins;
in

  # The final hive will always have the meta key instead of network.
  # system.name.colmenaConfigurations.target
  hive = let
    op1 = l.filterAttrs (_: v: v ? colmenaConfigurations ); # contains colmena configs?
    op2 = l.mapAttrs (n: v: v.colmenaConfigurations); # lift colmena configs one level up
    op3 = l.mapAttrsToList (n: l.mapAttrs' (t: c: l.nameValuePair "${n}-${t}" c)); # prefix with cell name -> unique names
  in
    l.listToAttrs (l.flatten (op3 (op2 (op1 flake.x86_64-linux))));

  evalPkgs = name: config: nixpkgs.lib.nixos.evalModules {
    modules = [ config {_module.check = false;} {imports = [ "${nixpkgs}/nixos/misc/nixpkgs.nix" ];} ];
  }.config.nixpkgs.pkgs;

  evalNode = check: name: config: let
    pkgs = evalPkgs name config;
    evalConfig = import "${pkgs.path}/nixos/lib/eval-config.nix";
  in evalConfig {
    inherit (pkgs) system;

    modules = [
      colmenaModules.assertionModule
      colmenaModules.keyChownModule
      colmenaModules.keyServiceModule
      colmenaOptions.deploymentOptions
      config
      {_module.check = check;}
    ];
    specialArgs = {
      inherit name;
      nodes = evalNode false hive;
    };
  };

in rec {
  # Exported attributes
  #
  # Functions are intended to be called with `nix-instantiate --eval --json`
  nodes =            l.mapAttrs (evalNode true) hive;
  toplevel =         l.mapAttrs (_: v: v.config.system.build.toplevel) nodes;
  deploymentConfig = l.mapAttrs (_: v: v.config.deployment)            nodes;
  deploymentConfigSelected = names: l.filterAttrs (name: _: l.elem name names) deploymentConfig;
  evalSelected =             names: l.filterAttrs (name: _: l.elem name names) toplevel;
  evalSelectedDrvPaths =     names: l.mapAttrs    (_: v: v.drvPath)            (evalSelected names);
  introspect = f: f { inherit nixpkgs; inherit (nixpkgs) lib; nodes = evalNode false hive; };
  machinesFile = null;
}


01:24:37
@blaggacao:matrix.org@blaggacao:matrix.org If it's not hermetically defined in the config, I think this would then fall back to inputs.nixpkgs which is roughly what we want anyways. 01:26:06
@blaggacao:matrix.org@blaggacao:matrix.org *

So I hope this new eval.nix would work, testing tomorrow, let me know if you have comments / ideas:

{ flakeUri                     # Nix Flake URI with `outputs.colmena`
, hermetic ? true              # Whether we are allowed to use <nixpkgs>
, colmenaOptions
, colmenaModules
}: let
  flake = builtins.getFlake flakeUri;
  nixpkgs =
  if builtins.hasAttr "nixpkgs" flake.inputs
  then inputs.nixpkgs
  else throw ''
    In order to be able to use 'colmena', an input
    named 'nixpkgs' must be defined in the flake.
  '';

  l = nixpkgs.lib // builtins;
in
  # system.name.colmenaConfigurations.target
  hive = let
    op1 = l.filterAttrs (_: v: v ? colmenaConfigurations ); # contains colmena configs?
    op2 = l.mapAttrs (n: v: v.colmenaConfigurations); # lift colmena configs one level up
    op3 = l.mapAttrsToList (n: l.mapAttrs' (t: c: l.nameValuePair "${n}-${t}" c)); # prefix with cell name -> unique names
  in
    l.listToAttrs (l.flatten (op3 (op2 (op1 flake.x86_64-linux))));

  evalPkgs = name: config: nixpkgs.lib.nixos.evalModules {
    modules = [ config {_module.check = false;} {imports = [ "${nixpkgs}/nixos/misc/nixpkgs.nix" ];} ];
  }.config.nixpkgs.pkgs;

  evalNode = check: name: config: let
    pkgs = evalPkgs name config;
    evalConfig = import "${pkgs.path}/nixos/lib/eval-config.nix";
  in evalConfig {
    inherit (pkgs) system;

    modules = [
      colmenaModules.assertionModule
      colmenaModules.keyChownModule
      colmenaModules.keyServiceModule
      colmenaOptions.deploymentOptions
      config
      {_module.check = check;}
    ];
    specialArgs = {
      inherit name;
      nodes = evalNode false hive;
    };
  };

in rec {
  # Exported attributes
  #
  # Functions are intended to be called with `nix-instantiate --eval --json`
  nodes =            l.mapAttrs (evalNode true) hive;
  toplevel =         l.mapAttrs (_: v: v.config.system.build.toplevel) nodes;
  deploymentConfig = l.mapAttrs (_: v: v.config.deployment)            nodes;
  deploymentConfigSelected = names: l.filterAttrs (name: _: l.elem name names) deploymentConfig;
  evalSelected =             names: l.filterAttrs (name: _: l.elem name names) toplevel;
  evalSelectedDrvPaths =     names: l.mapAttrs    (_: v: v.drvPath)            (evalSelected names);
  introspect = f: f { inherit nixpkgs; inherit (nixpkgs) lib; nodes = evalNode false hive; };
  machinesFile = null;
}


01:26:50
@blaggacao:matrix.org@blaggacao:matrix.org

Zhaofeng Li: the collateral benefit to have this in-tree downstream (with hidden --eval flag):

  • it's easy enough to read
  • therefore, it's self documenting
01:31:15
@blaggacao:matrix.org@blaggacao:matrix.org *

Zhaofeng Li: the collateral benefit to have this in-tree downstream (with hidden --eval flag):

  • it's easy enough to read
  • therefore, it's self documenting (the magic parts of colmena)
01:31:34
@blaggacao:matrix.org@blaggacao:matrix.org nixpkgs.lib.nixos.evalModules is relatively recent so inputs.nixpkgs would have to satisfy that contract, ofc. 01:35:58
@hexa:lossy.networkhexa
❯ colmena build
[INFO ] Using configuration: /home/hexa/git/hexa/nixos-servers/config/hive.nix
[INFO ] Enumerating nodes...
error: attribute 'lib' missing

       at /run/user/1000/.tmpaIJWby:388:9:

          387|
          388|   lib = pkgs.lib;
             |         ^
          389|   reservedNames = [ "defaults" "network" "meta" ];
(use '--show-trace' to show detailed location information)
[ERROR] -----
[ERROR] Operation failed with error: Child process exited with error code: 1
14:59:50
@hexa:lossy.networkhexa(...)15:02:39
@hexa:lossy.networkhexa
let
  # niv sources
  sources = import ../nix/sources.nix;

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

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

  machines = {
    "foo.example.com" = {
    };
    "bar.example.com" = {
      packages = source."nixos-21.11";
    };
  };

  mkMachine = hostName: { system ? defaultArch, packages ? defaultPkgs, tags ? [] }:
    {
      imports = [
        (./machines + "/${hostName}")
      ];

      nixpkgs = {
        inherit system;
      };
    };
in
{
  meta = {
    nixpkgs = defaultPkgs;

    nodeNixpkgs = lib.mapAttrs
      (hostName: { packages? defaultPkgs, ... }: packages)
    machines;
  };
} // (lib.mapAttrs mkMachine machines)
15:03:29
@hexa:lossy.networkhexacan anybody shed some light on that error?15:04:00
@hexa:lossy.networkhexaI'm slowly trying to migrate from morph, so some of the boilerplate is from that era15:04:27
@linus:schreibt.jetzt@linus:schreibt.jetztmeta.nixpkgs should be an imported nixpkgs, not the path to a nixpkgs15:04:57
@hexa:lossy.networkhexaaccording to https://colmena.cli.rs/unstable/tutorial/index.html it can be … everything?15:05:15
@hexa:lossy.networkhexaalthough that may be something new from "unstable"15:05:25
@hexa:lossy.networkhexa
{
  meta = {
    # Override to pin the Nixpkgs version (recommended). This option
    # accepts one of the following:
    # - A path to a Nixpkgs checkout
    # - The Nixpkgs lambda (e.g., import <nixpkgs>)
    # - An initialized Nixpkgs attribute set
    nixpkgs = <nixpkgs>;
15:05:44
@hexa:lossy.networkhexafrom the 0.3 docs15:06:01
@linus:schreibt.jetzt@linus:schreibt.jetztoh, hm. Might have been broken accidentally?15:06:06
@linus:schreibt.jetzt@linus:schreibt.jetztIt definitely doesn't support passing a path when using flakes15:06:55
@linus:schreibt.jetzt@linus:schreibt.jetztTry using an imported nixpkgs anyway maybe15:07:31
@hexa:lossy.networkhexa passed nixpkgs = import defaultPkgs {}; 15:08:45
@hexa:lossy.networkhexa
error: attribute 'path' missing

       at /run/user/1000/.tmpsGzWiX:396:26:

          395|       else pkgs;
          396|     evalConfig = import (npkgs.path + "/nixos/lib/eval-config.nix");
             |                          ^
          397|     assertionModule = { config, ... }: {
(use '--show-trace' to show detailed location information)
15:08:50

Show newer messages


Back to Room ListRoom Version: 6