Print flake system configuration as JSON

Hello,

I’d like to print the configuration of my systems as JSON. I’m using flakes to define them and figured out this works to get individual parameters:

$  nix eval -v -L '.#nixosConfigurations.kartoffel.config.networking.hostName'
"kartoffel"

It print’s the hostname (“kartoffel” in this case) as expected and I can use that output for further processing and scripting with other tools.

However, if I try to get all values I get an error:

$ nix eval -v -L '.#nixosConfigurations.kartoffel.config'
error: anonymous function at /nix/store/q3cfrfrwfv4d5v72i81kmjxa753y558h-source/pkgs/build-support/fetchurl/boot.nix:5:1 called with unexpected argument 'meta'

       at /nix/store/q3cfrfrwfv4d5v72i81kmjxa753y558h-source/pkgs/build-support/fetchzip/default.nix:18:2:

           17|
           18| (fetchurl (let
             |  ^
           19|   basename = baseNameOf (if url != "" then url else builtins.head urls);(use '--show-trace' to show detailed location information)

How can I get the complete configuration of a system?

Due to laziness, the config set cannot be evaluated in general, since there will be many options that trigger evaluation errors (e.g. in disabled modules) or are unprintable (like functions).

However, this specific error is caused by an attempt to print a derivation, which nix eval doesn’t do very well, because derivations contain a lot of unprintable, circular or aborting values (like stdenv.lib). Try adding --json:

# nix eval nix#defaultPackage.x86_64-linux 
trace: Warning: `stdenv.lib` is deprecated and will be removed in the next release. Please use `lib` instead. For more information see https://github.com/NixOS/nixpkgs/issues/108938
...
/pkgs/build-support/fetchurl/boot.nix:5:1 called with unexpected argument 'meta'

       at /nix/store/mk4x3mhmgmzx0j0dda26ay19x22yxbyj-source/pkgs/build-support/fetchzip/default.nix:18:2:

           17|
           18| (fetchurl (let
             |  ^
           19|   basename = baseNameOf (if url != "" then url else builtins.head urls);
(use '--show-trace' to show detailed location information)

vs.

# nix eval --json nix#defaultPackage.x86_64-linux 
"/nix/store/34bysvl4kzi79z7bj7b0dsnk8c2rwkg2-nix-2.4pre20210722_96c62fb"

This works for packages but still does not allow to evaluate config directly. In my case I get this error:

error: attribute 'cycle' missing

       at /nix/store/g2g13rv513i8z8rav2imcfk49fm8bac1-source/nixos/modules/tasks/filesystems.nix:230:119:

          229|       { assertion = ! (fileSystems' ? cycle);
          230|         message = "The ‘fileSystems’ option can't be topologically sorted: mountpoint dependency path ${ls " -> " fileSystems'.cycle} loops to ${ls ", " fileSystems'.loops}";             |                                                                                                                       ^
          231|       }
sage":"Setting a MAC Address for tun device vboxnet0 isn't supported.\n"},{"assertion":true,"message":"Invalid value given to the networking.hostId option."},{"assertion":true,"message":}]}

Is there any possibility to at least get the options/configuration that has been explicitely defined in nixosConfigurations.<hostname> ?

The goal would be to render a “overview” of my hosts from the flake, showing some of the options like the hostname, ip address and more. I could run nix eval -v -L '.#nixosConfigurations.<hostname>.config.networking.hostName' for each of the values I want to get and each of the hosts, but that seems rather inefficient and unflexible. A solution that just prints all the defined values of the configuration to some common format like json would be great (if it’s possible)!

You would need to do something like this. Create an attribute set that contains the attributes that interest you, attribute values don’t matter:

hostInfo = { networking = { hostName = null; useDHCP = null; }; 
             fileSystems = null; };

Be aware that, when you pick a attribute that is also an attribute set in config (e.g. fileSystems), all its attributes must evaluate to something sensible, or you end up in the same situation in which you are now.

Now, the magic filter function that you would apply to each host in turn looks like this:

with (import <nixpkgs/lib>);
mapAttrsRecursive (path: _: getAttrFromPath path config)
  hostInfo

Where config is the config attribute set for the particular host (e.g. nixosConfigurations.kartoffel.config). The result has the same structure as hostInfo but with filled values.

Hope it’s okay to revive this old thread :slight_smile:

It should be possible to recursively serialize all attributes which can be evaluated, while skipping functions and errors. Maybe with mapAttrsRecursive and tryEval? Maybe there’s a way to skip i.e. disabled Modules entirely?

A quick way to get a best-effort dump of as much of the configuration as possible could be useful for debugging (i.e. grepping).

1 Like