summaryrefslogtreecommitdiff
path: root/system-profiles/nfsroot.nix
blob: 1cd930d968fd43570073a5ed29573eca49dca630 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
{ config, options, pkgs, lib, flake, flakeInputs, ... }:

with lib;

let
  cfg = config.nfsroot;
in {
  imports = with flake.nixosModules.systemProfiles; [
    tmpfs-root
  ];

  options = {
    nfsroot = {
      storeDevice = mkOption {
        type = types.str;
        default = "nfsroot:nix-store";
        description = "Nix store device";
      };

      registrationUrl = mkOption {
        type = types.str;
        default = "http://nfsroot/nix-registration";
        description = "Url of nix store registrations";
      };
    };

    system.build = {
      storeContents = mkOption {
        description = "Contents of nix store";
      };
    };
  };

  config = foldr recursiveUpdate {} ([
    {
      # Don't build the GRUB menu builder script, since we don't need it
      # here and it causes a cyclic dependency.
      boot.loader.grub.enable = false;

      # !!! Hack - attributes expected by other modules.
      environment.systemPackages = [ pkgs.grub2_efi ]
        ++ (if pkgs.stdenv.hostPlatform.system == "aarch64-linux"
            then []
            else [ pkgs.grub2 pkgs.syslinux ]);

      # In stage 1, mount a tmpfs on top of /nix/store (the squashfs
      # image) to make this a live CD.
      fileSystems."/nix/.ro-store" = mkImageMediaOverride
        { fsType = "nfs4";
          device = cfg.storeDevice;
          options = [ "ro" ];
          neededForBoot = true;
        };

      fileSystems."/nix/.rw-store" = mkImageMediaOverride
        { fsType = "tmpfs";
          options = [ "mode=0755" ];
          neededForBoot = true;
        };

      fileSystems."/nix/store" = mkImageMediaOverride
        { fsType = "overlay";
          device = "overlay";
          options = [
            "lowerdir=/nix/.ro-store"
            "upperdir=/nix/.rw-store/store"
            "workdir=/nix/.rw-store/work"
          ];

          depends = [
            "/nix/.ro-store"
            "/nix/.rw-store/store"
            "/nix/.rw-store/work"
          ];
        };

      nix.settings.use-sqlite-wal = false;

      boot.initrd.availableKernelModules = [ "nfs" "nfsv4" "overlay" ];
      boot.initrd.supportedFilesystems = [ "nfs" "nfsv4" "overlay" ];
      services.rpcbind.enable = mkImageMediaOverride false;

      boot.initrd.network.enable = true;
      boot.initrd.network.flushBeforeStage2 = false; # otherwise nfs doesn't work
      boot.initrd.postMountCommands = ''
        mkdir -p /mnt-root/etc/
        cp /etc/resolv.conf /mnt-root/etc/resolv.conf
      '';
      networking.useDHCP = true;
      networking.resolvconf.enable = false;
      networking.dhcpcd.persistent = true;


      system.build.storeContents = [config.system.build.toplevel];

      system.build.netbootIpxeScript = pkgs.writeTextDir "netboot.ipxe" ''
        #!ipxe
        # Use the cmdline variable to allow the user to specify custom kernel params
        # when chainloading this script from other iPXE scripts like netboot.xyz
        kernel ${pkgs.stdenv.hostPlatform.linux-kernel.target} init=${config.system.build.toplevel}/init initrd=initrd ${toString config.boot.kernelParams} ''${cmdline}
        initrd initrd
        boot
      '';

      boot.postBootCommands =
        ''
          # After booting, register the contents of the Nix store on NFS
          # in the Nix database in the tmpfs.
          ${pkgs.curl}/bin/curl ${escapeShellArg cfg.registrationUrl} | ${config.nix.package.out}/bin/nix-store --load-db

          # nixos-rebuild also requires a "system" profile and an
          # /etc/NIXOS tag.
          touch /etc/NIXOS
          ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
        '';

      boot.initrd.systemd.enable = false;
    }
  ] ++ (optional (options ? system.etc) {
    system.etc.overlay.enable = false;
  }) ++ (optional (options ? system.sysusers) {
    systemd.sysusers.enable = false;
  }));
}