nix-community / disko

Declarative disk partitioning and formatting using nix [maintainers=@Lassulus @Enzime @iFreilicht]
MIT License
1.89k stars 201 forks source link

disko-install: error: infinite recursion encountered #613

Open bam80 opened 7 months ago

bam80 commented 7 months ago

When I add this snippet as a file (installer.nix) to the flake, I get the infinite recursion error while generating the image with nixos-generate: https://github.com/nix-community/disko/blob/dea314155a9b8a4de242bdd4c005ba8a5dce8385/docs/disko-install.md?plain=1#L186-L213

# in the flake's dir
$ nixos-generate --flake . -f iso
...
error:
       … while calling the 'derivationStrict' builtin
         at <nix/derivation-internal.nix>:9:12:
            8|
            9|   strict = derivationStrict drvAttrs;
             |            ^
           10|

       … while evaluating derivation 'nixos.iso'
         whose name attribute is located at /nix/store/cc0ribc27c349w1v2anrby7z8kigy5pq-source/pkgs/stdenv/generic/make-derivation.nix:331:7

       … while evaluating attribute 'sources' of derivation 'nixos.iso'
         at /nix/store/cc0ribc27c349w1v2anrby7z8kigy5pq-source/nixos/lib/make-iso9660-image.nix:76:3:
           75|
           76|   sources = map (x: x.source) contents;
             |   ^
           77|   targets = map (x: x.target) contents;

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: infinite recursion encountered
       at /nix/store/cc0ribc27c349w1v2anrby7z8kigy5pq-source/lib/modules.nix:809:9:
          808|     in warnDeprecation opt //
          809|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          810|         inherit (res.defsFinal') highestPrio;
$

I added installer.nix to the flake like this:


{                                                                                                                              
  inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";                                                              
  inputs.disko.url = "github:nix-community/disko";                                                                             
  inputs.disko.inputs.nixpkgs.follows = "nixpkgs";                                                                             

  outputs = { self, disko, nixpkgs }@inputs: {                                                                                 
  nixosConfigurations.i7 = inputs.nixpkgs.lib.nixosSystem {                                                                    
    system = "x86_64-linux";                                                                                                   
    # to pass this flake into your configuration (see the example below)                                                       
    specialArgs = {inherit self;};                                                                                             
    modules = [                                                                                                                
      ./installer.nix                                                                                                          

      {                                                                                                                        
        # TODO: add your NixOS configuration here, don't forget your hardware-configuration.nix as well!                       
        boot.loader.systemd-boot.enable = true;
        imports = [ self.inputs.disko.nixosModules.disko ];                                                                    
        disko.devices = {
...
nixos-discourse commented 7 months ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/disko-install-how-to-to-pass-flake-self-using-specialargs/43920/6

Mic92 commented 7 months ago

Does it work if you replace self with ${./.}?

bam80 commented 7 months ago

@Mic92 The problem seem to be not with ${self}, but with the dependencies block:

Thoughts?

nixos-discourse commented 7 months ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/infinite-recursion-encountered-by-making-module-configurable/23508/11

bam80 commented 7 months ago

Does it work if you replace self with ${./.}?

Where should I do that?

bam80 commented 7 months ago

So I tried to insert the Example module for a NixOS installer to the flake itself, so it got direct access to the self flake variable and no specialArgs = {inherit self;}; trick is needed.

Still, the same infinite recursion error.

@Mic92 how it worked on your side, did you test the code?

bam80 commented 7 months ago

So I debugged it even more and apparently I was wrong about the reason is related to "self".

The problem seems to be in this line instead: self.nixosConfigurations.your-machine.config.system.build.toplevel , if I remove it the error goes away.

At the same time, the next line is all OK: self.nixosConfigurations.your-machine.config.system.build.diskoScript

Any ideas what can be wrong with the toplevel?

Mic92 commented 7 months ago

Do you have a complete example that leads to the said infinite recursion?

bam80 commented 7 months ago

Please see the full reproducible sample:


# command to run:
# $ nix build .\#nixosConfigurations.i7.config.system.build.diskoImagesScript --show-trace

# flake.nix
{
  inputs.disko.url = "github:nix-community/disko";
  inputs.disko.inputs.nixpkgs.follows = "nixpkgs";

  outputs = { self, disko, nixpkgs }: {
    nixosConfigurations.i7 = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ({ pkgs, ... }:
        let
          dependencies = [
            pkgs.stdenv.drvPath
# "error: infinite recursion encountered" with this line!
            self.nixosConfigurations.i7.config.system.build.toplevel

            self.nixosConfigurations.i7.config.system.build.diskoScript
          ] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);

          closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
        in
        {
          environment.etc."install-closure".source = "${closureInfo}/store-paths";

          environment.systemPackages = [
            (pkgs.writeShellScriptBin "install-nixos-unattended" ''
              set -eux
              # Replace "/dev/disk/by-id/some-disk-id" with your actual disk ID
              exec ${pkgs.disko}/bin/disko-install --flake "${self}#your-machine" --disk vdb "/dev/disk/by-id/some-disk-id"
            '')
          ];
        })

        {
          boot.loader.systemd-boot.enable = true;
          imports = [ self.inputs.disko.nixosModules.disko ];
          disko.devices = {
            disk = {
              vdb = {
                device = "/dev/disk/by-id/some-disk-id";
                type = "disk";
                content = {
                  type = "gpt";
                  partitions = {
                    ESP = {
                      type = "EF00";
                      size = "500M";
                      content = {
                        type = "filesystem";
                        format = "vfat";
                        mountpoint = "/boot";
                      };
                    };
                    root = {
                      size = "100%";
                      content = {
                        type = "filesystem";
                        format = "ext4";
                        mountpoint = "/";
                      };
                    };
                  };
                };
              };
            };
          };
        }

      ];
    };
  };
}
Lassulus commented 7 months ago

you can't reference the systems own top-level in it's own dependencies (that's also unnecessary, because the system usually has itself available :)) what you need to do instead is create a new system which represents the installer you boot into and reference the system you want to install in there.

bam80 commented 7 months ago

@Lassulus thank you for your answer.

Could you be more specific? I really new to Nix and didn't quite understand what you just said. I just followed the docs here, could you provide concrete code I should try?

Thanks.

bam80 commented 7 months ago

Also, please note I'm chasing the fully unattended installer here. Can I do that?

If I need to do something manually on the system running the generated installer, this is not quite what I need.

Please reply so I wouldn't spent even more time on that, if my goal is unachievable currently.

bam80 commented 7 months ago

This is the flake I come up with.

iFreilicht commented 2 months ago

So it seems to me like you've found the perfect solution. I agree the documentation could be slightly better here, but I'd say the basic example is very close already. The only missing piece is how to incorporate it into a flake.