diff --git a/cli.nix b/cli.nix index d32e492..6a45937 100644 --- a/cli.nix +++ b/cli.nix @@ -1,12 +1,13 @@ -{ pkgs ? import { } -, lib ? pkgs.lib -, mode ? "mount" -, flake ? null -, flakeAttr ? null -, diskoFile ? null -, rootMountPoint ? "/mnt" -, noDeps ? false -, ... +{ + pkgs ? import { }, + lib ? pkgs.lib, + mode ? "mount", + flake ? null, + flakeAttr ? null, + diskoFile ? null, + rootMountPoint ? "/mnt", + noDeps ? false, + ... }@args: let disko = import ./. { @@ -17,66 +18,77 @@ let hasDiskoFile = diskoFile != null; diskoAttr = - (if noDeps then - (if hasDiskoFile then - { - destroy = "_cliDestroyNoDeps"; - format = "_cliFormatNoDeps"; - mount = "_cliMountNoDeps"; - unmount = "_cliUnmountNoDeps"; + ( + if noDeps then + ( + if hasDiskoFile then + { + destroy = "_cliDestroyNoDeps"; + format = "_cliFormatNoDeps"; + mount = "_cliMountNoDeps"; + unmount = "_cliUnmountNoDeps"; - "format,mount" = "_cliFormatMountNoDeps"; - "destroy,format,mount" = "_cliDestroyFormatMountNoDeps"; + "format,mount" = "_cliFormatMountNoDeps"; + "destroy,format,mount" = "_cliDestroyFormatMountNoDeps"; + } + else + { + destroy = "destroyNoDeps"; + format = "formatNoDeps"; + mount = "mountNoDeps"; + unmount = "unmountNoDeps"; + + "format,mount" = "formatMountNoDeps"; + "destroy,format,mount" = "destroyFormatMountNoDeps"; + } + ) + // { + # legacy aliases + disko = "diskoScriptNoDeps"; + create = "createScriptNoDeps"; + zap_create_mount = "diskoScriptNoDeps"; } else - { - destroy = "destroyNoDeps"; - format = "formatNoDeps"; - mount = "mountNoDeps"; - unmount = "unmountNoDeps"; + ( + if hasDiskoFile then + { + destroy = "_cliDestroy"; + format = "_cliFormat"; + mount = "_cliMount"; + unmount = "_cliUnmount"; - "format,mount" = "formatMountNoDeps"; - "destroy,format,mount" = "destroyFormatMountNoDeps"; - }) // { - # legacy aliases - disko = "diskoScriptNoDeps"; - create = "createScriptNoDeps"; - zap_create_mount = "diskoScriptNoDeps"; - } - else - (if hasDiskoFile then - { - destroy = "_cliDestroy"; - format = "_cliFormat"; - mount = "_cliMount"; - unmount = "_cliUnmount"; + "format,mount" = "_cliFormatMount"; + "destroy,format,mount" = "_cliDestroyFormatMount"; + } + else + { + destroy = "destroy"; + format = "format"; + mount = "mount"; + unmount = "unmount"; - "format,mount" = "_cliFormatMount"; - "destroy,format,mount" = "_cliDestroyFormatMount"; + "format,mount" = "formatMount"; + "destroy,format,mount" = "destroyFormatMount"; + } + ) + // { + # legacy aliases + disko = "diskoScript"; + create = "createScript"; + zap_create_mount = "diskoScript"; } - else - { - destroy = "destroy"; - format = "format"; - mount = "mount"; - unmount = "unmount"; - - "format,mount" = "formatMount"; - "destroy,format,mount" = "destroyFormatMount"; - }) // { - # legacy aliases - disko = "diskoScript"; - create = "createScript"; - zap_create_mount = "diskoScript"; - } ).${mode}; hasDiskoConfigFlake = hasDiskoFile || lib.hasAttrByPath [ "diskoConfigurations" flakeAttr ] (builtins.getFlake flake); - hasDiskoModuleFlake = - lib.hasAttrByPath [ "nixosConfigurations" flakeAttr "config" "disko" "devices" ] (builtins.getFlake flake); - + hasDiskoModuleFlake = lib.hasAttrByPath [ + "nixosConfigurations" + flakeAttr + "config" + "disko" + "devices" + ] (builtins.getFlake flake); diskFormat = let @@ -86,20 +98,16 @@ let else (builtins.getFlake flake).diskoConfigurations.${flakeAttr}; in - if builtins.isFunction diskoConfig then - diskoConfig ({ inherit lib; } // args) - else - diskoConfig; + if builtins.isFunction diskoConfig then diskoConfig ({ inherit lib; } // args) else diskoConfig; - diskoEval = - disko.${diskoAttr} diskFormat pkgs; + diskoEval = disko.${diskoAttr} diskFormat pkgs; diskoScript = if hasDiskoConfigFlake then diskoEval else if hasDiskoModuleFlake then - (builtins.getFlake flake).nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr} or ( - pkgs.writeShellScriptBin "disko-compat-error" '' + (builtins.getFlake flake).nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr} + or (pkgs.writeShellScriptBin "disko-compat-error" '' echo 'Error: Attribute `nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr}` >&2 echo ' not found in flake `${flake}`!' >&2 echo ' This is probably caused by the locked version of disko in the flake' >&2 @@ -107,8 +115,7 @@ let echo 'EITHER set the `disko` input of your flake to `github:nix-community/disko/latest`,' >&2 echo ' run `nix flake update disko` in the flake directory and then try again,' >&2 echo 'OR run `nix run github:nix-community/disko/v1.9.0 -- --help` and use one of its modes.' >&2 - exit 1;'' - ) + exit 1;'') else (builtins.abort "couldn't find `diskoConfigurations.${flakeAttr}` or `nixosConfigurations.${flakeAttr}.config.disko.devices`"); diff --git a/default.nix b/default.nix index 02f429c..5bc1151 100644 --- a/default.nix +++ b/default.nix @@ -1,64 +1,107 @@ -{ lib ? import -, rootMountPoint ? "/mnt" -, checked ? false -, diskoLib ? import ./lib { inherit lib rootMountPoint; } +{ + lib ? import , + rootMountPoint ? "/mnt", + checked ? false, + diskoLib ? import ./lib { inherit lib rootMountPoint; }, }: let - eval = cfg: lib.evalModules { - modules = lib.singleton { - # _file = toString input; - imports = lib.singleton { disko.devices = cfg.disko.devices; }; - options = { - disko.devices = lib.mkOption { - type = diskoLib.toplevel; + eval = + cfg: + lib.evalModules { + modules = lib.singleton { + # _file = toString input; + imports = lib.singleton { disko.devices = cfg.disko.devices; }; + options = { + disko.devices = lib.mkOption { + type = diskoLib.toplevel; + }; }; }; }; - }; # We might instead reuse some of the deprecated output names to refer to the values the _cli* outputs currently do, # but this warning allows us to get feedback from users early in case they have a use case we haven't considered. - warnDeprecated = name: lib.warn "the ${name} output is deprecated and will be removed, please open an issue if you're using it!"; + warnDeprecated = + name: + lib.warn "the ${name} output is deprecated and will be removed, please open an issue if you're using it!"; in { lib = warnDeprecated ".lib.lib" diskoLib; - _cliDestroy = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroy; - _cliDestroyNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyNoDeps; + _cliDestroy = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroy; + _cliDestroyNoDeps = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyNoDeps; _cliFormat = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).format; - _cliFormatNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatNoDeps; + _cliFormatNoDeps = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatNoDeps; _cliMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mount; - _cliMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountNoDeps; + _cliMountNoDeps = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountNoDeps; - _cliUnmount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmount; - _cliUnmountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmountNoDeps; + _cliUnmount = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmount; + _cliUnmountNoDeps = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmountNoDeps; - _cliFormatMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMount; - _cliFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMountNoDeps; + _cliFormatMount = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMount; + _cliFormatMountNoDeps = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMountNoDeps; - _cliDestroyFormatMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMount; - _cliDestroyFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMountNoDeps; + _cliDestroyFormatMount = + cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMount; + _cliDestroyFormatMountNoDeps = + cfg: pkgs: + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMountNoDeps; # legacy aliases create = cfg: warnDeprecated "create" (eval cfg).config.disko.devices._create; - createScript = cfg: pkgs: warnDeprecated "createScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript; - createScriptNoDeps = cfg: pkgs: warnDeprecated "createScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps; + createScript = + cfg: pkgs: + warnDeprecated "createScript" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript; + createScriptNoDeps = + cfg: pkgs: + warnDeprecated "createScriptNoDeps" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps; format = cfg: warnDeprecated "format" (eval cfg).config.disko.devices._create; - formatScript = cfg: pkgs: warnDeprecated "formatScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript; - formatScriptNoDeps = cfg: pkgs: warnDeprecated "formatScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps; + formatScript = + cfg: pkgs: + warnDeprecated "formatScript" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript; + formatScriptNoDeps = + cfg: pkgs: + warnDeprecated "formatScriptNoDeps" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps; mount = cfg: warnDeprecated "mount" (eval cfg).config.disko.devices._mount; - mountScript = cfg: pkgs: warnDeprecated "mountScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScript; - mountScriptNoDeps = cfg: pkgs: warnDeprecated "mountScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScriptNoDeps; + mountScript = + cfg: pkgs: + warnDeprecated "mountScript" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScript; + mountScriptNoDeps = + cfg: pkgs: + warnDeprecated "mountScriptNoDeps" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScriptNoDeps; disko = cfg: warnDeprecated "disko" (eval cfg).config.disko.devices._disko; - diskoScript = cfg: pkgs: warnDeprecated "diskoScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScript; - diskoScriptNoDeps = cfg: pkgs: warnDeprecated "diskoScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps; + diskoScript = + cfg: pkgs: + warnDeprecated "diskoScript" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScript; + diskoScriptNoDeps = + cfg: pkgs: + warnDeprecated "diskoScriptNoDeps" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps; # we keep this old output for backwards compatibility - diskoNoDeps = cfg: pkgs: warnDeprecated "diskoNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps; + diskoNoDeps = + cfg: pkgs: + warnDeprecated "diskoNoDeps" + ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps; config = cfg: (eval cfg).config.disko.devices._config; packages = cfg: (eval cfg).config.disko.devices._packages; diff --git a/doc.nix b/doc.nix index d07f8f3..a57abe2 100644 --- a/doc.nix +++ b/doc.nix @@ -1,4 +1,10 @@ -{ lib, nixosOptionsDoc, runCommand, fetchurl, pandoc }: +{ + lib, + nixosOptionsDoc, + runCommand, + fetchurl, + pandoc, +}: let diskoLib = import ./lib { @@ -21,16 +27,18 @@ let options = nixosOptionsDoc { options = eval.options; }; - md = (runCommand "disko-options.md" { } '' - cat >$out <$out <>$out - '').overrideAttrs (_o: { - # Work around https://github.com/hercules-ci/hercules-ci-agent/issues/168 - allowSubstitutes = true; - }); + EOF + cat ${options.optionsCommonMark} >>$out + '').overrideAttrs + (_o: { + # Work around https://github.com/hercules-ci/hercules-ci-agent/issues/168 + allowSubstitutes = true; + }); css = fetchurl { url = "https://gist.githubusercontent.com/killercup/5917178/raw/40840de5352083adb2693dc742e9f75dbb18650f/pandoc.css"; sha256 = "sha256-SzSvxBIrylxBF6B/mOImLlZ+GvCfpWNLzGFViLyOeTk="; diff --git a/example/btrfs-only-root-subvolume.nix b/example/btrfs-only-root-subvolume.nix index 46e7334..4688838 100644 --- a/example/btrfs-only-root-subvolume.nix +++ b/example/btrfs-only-root-subvolume.nix @@ -26,7 +26,10 @@ type = "btrfs"; extraArgs = [ "-f" ]; # Override existing partition mountpoint = "/"; - mountOptions = [ "compress=zstd" "noatime" ]; + mountOptions = [ + "compress=zstd" + "noatime" + ]; }; }; }; @@ -35,4 +38,3 @@ }; }; } - diff --git a/example/btrfs-subvolumes.nix b/example/btrfs-subvolumes.nix index 8f36443..1d18ef8 100644 --- a/example/btrfs-subvolumes.nix +++ b/example/btrfs-subvolumes.nix @@ -41,7 +41,10 @@ "/home/user" = { }; # Parent is not mounted so the mountpoint must be set "/nix" = { - mountOptions = [ "compress=zstd" "noatime" ]; + mountOptions = [ + "compress=zstd" + "noatime" + ]; mountpoint = "/nix"; }; # This subvolume will be created but not mounted @@ -74,4 +77,3 @@ }; }; } - diff --git a/example/legacy-table.nix b/example/legacy-table.nix index 7eccfdd..ad27534 100644 --- a/example/legacy-table.nix +++ b/example/legacy-table.nix @@ -38,4 +38,3 @@ }; }; } - diff --git a/example/luks-btrfs-subvolumes.nix b/example/luks-btrfs-subvolumes.nix index eb1b6c0..4b434a5 100644 --- a/example/luks-btrfs-subvolumes.nix +++ b/example/luks-btrfs-subvolumes.nix @@ -35,15 +35,24 @@ subvolumes = { "/root" = { mountpoint = "/"; - mountOptions = [ "compress=zstd" "noatime" ]; + mountOptions = [ + "compress=zstd" + "noatime" + ]; }; "/home" = { mountpoint = "/home"; - mountOptions = [ "compress=zstd" "noatime" ]; + mountOptions = [ + "compress=zstd" + "noatime" + ]; }; "/nix" = { mountpoint = "/nix"; - mountOptions = [ "compress=zstd" "noatime" ]; + mountOptions = [ + "compress=zstd" + "noatime" + ]; }; "/swap" = { mountpoint = "/.swapvol"; diff --git a/example/luks-on-mdadm.nix b/example/luks-on-mdadm.nix index c8cc691..2c79b5a 100644 --- a/example/luks-on-mdadm.nix +++ b/example/luks-on-mdadm.nix @@ -56,4 +56,3 @@ }; }; } - diff --git a/example/stand-alone/configuration.nix b/example/stand-alone/configuration.nix index 6161cea..2e0889a 100644 --- a/example/stand-alone/configuration.nix +++ b/example/stand-alone/configuration.nix @@ -1,6 +1,7 @@ -{ pkgs -, lib -, ... +{ + pkgs, + lib, + ... }: let # We just import from the repository for testing here: diff --git a/example/with-lib.nix b/example/with-lib.nix index 5558fac..a6099d9 100644 --- a/example/with-lib.nix +++ b/example/with-lib.nix @@ -1,5 +1,10 @@ # Example to create a bios compatible gpt partition -{ disks ? [ "/dev/vdb" ], lib, ... }: { +{ + disks ? [ "/dev/vdb" ], + lib, + ... +}: +{ disko.devices = { disk = lib.genAttrs disks (device: { name = lib.replaceStrings [ "/" ] [ "_" ] device; diff --git a/example/xfs-with-quota.nix b/example/xfs-with-quota.nix index f4b0fab..e123b3e 100644 --- a/example/xfs-with-quota.nix +++ b/example/xfs-with-quota.nix @@ -23,7 +23,10 @@ type = "filesystem"; format = "xfs"; mountpoint = "/"; - mountOptions = [ "defaults" "pquota" ]; + mountOptions = [ + "defaults" + "pquota" + ]; }; }; }; diff --git a/example/zfs-with-vdevs.nix b/example/zfs-with-vdevs.nix index effe53e..d824e23 100644 --- a/example/zfs-with-vdevs.nix +++ b/example/zfs-with-vdevs.nix @@ -251,14 +251,20 @@ } { mode = "mirror"; - members = [ "data2" "data3" ]; + members = [ + "data2" + "data3" + ]; } ]; spare = [ "spare" ]; log = [ { mode = "mirror"; - members = [ "log1" "log2" ]; + members = [ + "log1" + "log2" + ]; } { members = [ "log3" ]; @@ -267,7 +273,10 @@ dedup = [ { mode = "mirror"; - members = [ "dedup1" "dedup2" ]; + members = [ + "dedup1" + "dedup2" + ]; } { members = [ "dedup3" ]; @@ -276,7 +285,10 @@ special = [ { mode = "mirror"; - members = [ "special1" "special2" ]; + members = [ + "special1" + "special2" + ]; } { members = [ "special3" ]; diff --git a/flake.nix b/flake.nix index 237c58b..4c732d9 100644 --- a/flake.nix +++ b/flake.nix @@ -6,7 +6,8 @@ #inputs.nixpkgs.url = "nixpkgs"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; - outputs = { self, nixpkgs, ... }: + outputs = + { self, nixpkgs, ... }: let lib = nixpkgs.lib; supportedSystems = [ @@ -28,7 +29,8 @@ nixosModules.default = self.nixosModules.disko; # convention nixosModules.disko = ./module.nix; lib = diskoLib; - packages = forAllSystems (system: + packages = forAllSystems ( + system: let pkgs = nixpkgs.legacyPackages.${system}; in @@ -41,27 +43,35 @@ default = self.packages.${system}.disko; create-release = pkgs.callPackage ./scripts/create-release.nix { }; - } // pkgs.lib.optionalAttrs (!pkgs.stdenv.buildPlatform.isRiscV64) { + } + // pkgs.lib.optionalAttrs (!pkgs.stdenv.buildPlatform.isRiscV64) { disko-doc = pkgs.callPackage ./doc.nix { }; - }); + } + ); # TODO: disable bios-related tests on aarch64... # Run checks: nix flake check -L - checks = forAllSystems (system: + checks = forAllSystems ( + system: let pkgs = nixpkgs.legacyPackages.${system}; # FIXME: aarch64-linux seems to hang on boot - nixosTests = lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (import ./tests { - inherit pkgs; - makeTest = import (pkgs.path + "/nixos/tests/make-test-python.nix"); - eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix"); - }); + nixosTests = lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 ( + import ./tests { + inherit pkgs; + makeTest = import (pkgs.path + "/nixos/tests/make-test-python.nix"); + eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix"); + } + ); disko-install = pkgs.callPackage ./tests/disko-install { inherit self; diskoVersion = version; }; - jsonTypes = pkgs.writeTextFile { name = "jsonTypes"; text = (builtins.toJSON diskoLib.jsonTypes); }; + jsonTypes = pkgs.writeTextFile { + name = "jsonTypes"; + text = (builtins.toJSON diskoLib.jsonTypes); + }; treefmt = pkgs.runCommand "treefmt" { } '' ${self.formatter.${system}}/bin/treefmt --ci --working-dir ${self} @@ -69,11 +79,14 @@ ''; in # FIXME: aarch64-linux seems to hang on boot - lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (nixosTests // { inherit disko-install; }) // - pkgs.lib.optionalAttrs (!pkgs.stdenv.buildPlatform.isRiscV64 && !pkgs.stdenv.hostPlatform.isx86_32) { - inherit jsonTypes treefmt; - inherit (self.packages.${system}) disko-doc; - }); + lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (nixosTests // { inherit disko-install; }) + // + pkgs.lib.optionalAttrs (!pkgs.stdenv.buildPlatform.isRiscV64 && !pkgs.stdenv.hostPlatform.isx86_32) + { + inherit jsonTypes treefmt; + inherit (self.packages.${system}) disko-doc; + } + ); nixosConfigurations.testmachine = lib.nixosSystem { system = "x86_64-linux"; @@ -83,7 +96,8 @@ ./module.nix ]; }; - formatter = forAllSystems (system: + formatter = forAllSystems ( + system: let pkgs = nixpkgs.legacyPackages.${system}; in @@ -104,6 +118,6 @@ self.formatter.${system} ]; }; - }); + }); }; } diff --git a/install-cli.nix b/install-cli.nix index 955670f..578ecc2 100644 --- a/install-cli.nix +++ b/install-cli.nix @@ -1,10 +1,10 @@ -{ flake -, flakeAttr -, diskMappings -, extraSystemConfig ? "{}" -, writeEfiBootEntries ? false -, rootMountPoint ? "/mnt" -, +{ + flake, + flakeAttr, + diskMappings, + extraSystemConfig ? "{}", + writeEfiBootEntries ? false, + rootMountPoint ? "/mnt", }: let originalSystem = (builtins.getFlake "${flake}").nixosConfigurations."${flakeAttr}"; @@ -17,21 +17,19 @@ let else throw "No device passed for disk '${name}'. Pass `--disk ${name} /dev/name` via commandline"; - modifiedDisks = builtins.mapAttrs - ( - name: value: - let - dev = deviceName name; - in - value - // { - device = dev; - content = value.content // { - device = dev; - }; - } - ) - originalSystem.config.disko.devices.disk; + modifiedDisks = builtins.mapAttrs ( + name: value: + let + dev = deviceName name; + in + value + // { + device = dev; + content = value.content // { + device = dev; + }; + } + ) originalSystem.config.disko.devices.disk; # filter all nixos module internal attributes cleanedDisks = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) modifiedDisks; diff --git a/lib/binfmt.nix b/lib/binfmt.nix index 4e3ef9f..9a367fc 100644 --- a/lib/binfmt.nix +++ b/lib/binfmt.nix @@ -1,25 +1,33 @@ -{ lib, diskoLib, pkgs, imagePkgs, ... }: +{ + lib, + diskoLib, + pkgs, + imagePkgs, + ... +}: let # from https://github.com/NixOS/nixpkgs/blob/851f7fc119e9597c26cc43e10938ce7272d0af9d/nixos/modules/system/boot/binfmt.nix makeBinfmtLine = - { name - , recognitionType - , offset - , magicOrExtension - , mask - , preserveArgvZero - , openBinary - , matchCredentials - , fixBinary - , interpreter - , ... + { + name, + recognitionType, + offset, + magicOrExtension, + mask, + preserveArgvZero, + openBinary, + matchCredentials, + fixBinary, + interpreter, + ... }: let type = if recognitionType == "magic" then "M" else "E"; offset' = toString offset; mask' = toString mask; - flags = with lib; + flags = + with lib; if !(matchCredentials -> openBinary) then throw "boot.binfmt.registrations.${name}: you can't specify openBinary = false when matchCredentials = true." else @@ -144,29 +152,30 @@ let in { binfmtRegistration = - let - system = imagePkgs.stdenv.hostPlatform.system; - enabled = system != pkgs.stdenv.hostPlatform.system; - elaborated = lib.systems.elaborate { inherit system; }; - useStaticEmulator = true; # needed for chroot - interpreter = elaborated.emulator (if useStaticEmulator then pkgs.pkgsStatic else pkgs); + let + system = imagePkgs.stdenv.hostPlatform.system; + enabled = system != pkgs.stdenv.hostPlatform.system; + elaborated = lib.systems.elaborate { inherit system; }; + useStaticEmulator = true; # needed for chroot + interpreter = elaborated.emulator (if useStaticEmulator then pkgs.pkgsStatic else pkgs); - inherit (elaborated) qemuArch; - isQemu = "qemu-${qemuArch}" == baseNameOf interpreter; - in makeBinfmtLine ( - { - name = system; - inherit interpreter; - recognitionType = "magic"; - offset = null; - openBinary = false; - matchCredentials = false; + inherit (elaborated) qemuArch; + isQemu = "qemu-${qemuArch}" == baseNameOf interpreter; + in + makeBinfmtLine ( + { + name = system; + inherit interpreter; + recognitionType = "magic"; + offset = null; + openBinary = false; + matchCredentials = false; - preserveArgvZero = isQemu; + preserveArgvZero = isQemu; - fixBinary = useStaticEmulator; - } - // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}")) - ); + fixBinary = useStaticEmulator; + } + // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}")) + ); systemsAreDifferent = imagePkgs.stdenv.hostPlatform.system != pkgs.stdenv.hostPlatform.system; } diff --git a/lib/default.nix b/lib/default.nix index 17f6177..d0328b9 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -1,7 +1,8 @@ -{ lib ? import -, rootMountPoint ? "/mnt" -, makeTest ? import -, eval-config ? import +{ + lib ? import , + rootMountPoint ? "/mnt", + makeTest ? import , + eval-config ? import , }: let outputs = import ../default.nix { inherit lib diskoLib; }; @@ -9,91 +10,148 @@ let testLib = import ./tests.nix { inherit lib makeTest eval-config; }; # like lib.types.oneOf but instead of a list takes an attrset # uses the field "type" to find the correct type in the attrset - subType = { types, extraArgs ? { parent = { type = "rootNode"; name = "root"; }; } }: lib.mkOptionType { - name = "subType"; - description = "one of ${lib.concatStringsSep "," (lib.attrNames types)}"; - check = x: if x ? type then types.${x.type}.check x else throw "No type option set in:\n${lib.generators.toPretty {} x}"; - merge = loc: lib.foldl' - (_res: def: types.${def.value.type}.merge loc [ - # we add a dummy root parent node to render documentation - (lib.recursiveUpdate { value._module.args = extraArgs; } def) - ]) - { }; - nestedTypes = types; - }; + subType = + { + types, + extraArgs ? { + parent = { + type = "rootNode"; + name = "root"; + }; + }, + }: + lib.mkOptionType { + name = "subType"; + description = "one of ${lib.concatStringsSep "," (lib.attrNames types)}"; + check = + x: + if x ? type then + types.${x.type}.check x + else + throw "No type option set in:\n${lib.generators.toPretty { } x}"; + merge = + loc: + lib.foldl' ( + _res: def: + types.${def.value.type}.merge loc [ + # we add a dummy root parent node to render documentation + (lib.recursiveUpdate { value._module.args = extraArgs; } def) + ] + ) { }; + nestedTypes = types; + }; # option for valid contents of partitions (basically like devices, but without tables) - _partitionTypes = { inherit (diskoLib.types) btrfs filesystem zfs mdraid luks lvm_pv swap; }; - partitionType = extraArgs: lib.mkOption { - type = lib.types.nullOr (diskoLib.subType { - types = diskoLib._partitionTypes; - inherit extraArgs; - }); - default = null; - description = "The type of partition"; + _partitionTypes = { + inherit (diskoLib.types) + btrfs + filesystem + zfs + mdraid + luks + lvm_pv + swap + ; }; + partitionType = + extraArgs: + lib.mkOption { + type = lib.types.nullOr ( + diskoLib.subType { + types = diskoLib._partitionTypes; + inherit extraArgs; + } + ); + default = null; + description = "The type of partition"; + }; # option for valid contents of devices - _deviceTypes = { inherit (diskoLib.types) table gpt btrfs filesystem zfs mdraid luks lvm_pv swap; }; - deviceType = extraArgs: lib.mkOption { - type = lib.types.nullOr (diskoLib.subType { - types = diskoLib._deviceTypes; - inherit extraArgs; - }); - default = null; - description = "The type of device"; + _deviceTypes = { + inherit (diskoLib.types) + table + gpt + btrfs + filesystem + zfs + mdraid + luks + lvm_pv + swap + ; }; + deviceType = + extraArgs: + lib.mkOption { + type = lib.types.nullOr ( + diskoLib.subType { + types = diskoLib._deviceTypes; + inherit extraArgs; + } + ); + default = null; + description = "The type of device"; + }; + /** + like lib.recursiveUpdate but supports merging of lists - /** - like lib.recursiveUpdate but supports merging of lists + # Inputs: - # Inputs: + `left` - `left` + : Left attribute set of the merge - : Left attribute set of the merge + `right` - `right` + : Right attribute set of the merge - : Right attribute set of the merge + recursiveUpdate :: AttrSet -> AttrSet -> AttrSet - recursiveUpdate :: AttrSet -> AttrSet -> AttrSet + # Examples + :::{.example} + ```nix + recursiveUpdate { + boot.loader.grub.enable = true; + boot.loader.grub.devices = [ "/dev/hda" ]; + } { + boot.loader.grub.devices = [ "/dev/hdb" ]; + } - # Examples - :::{.example} - ```nix - recursiveUpdate { - boot.loader.grub.enable = true; - boot.loader.grub.devices = [ "/dev/hda" ]; - } { - boot.loader.grub.devices = [ "/dev/hdb" ]; - } - - returns: { - boot.loader.grub.enable = true; - boot.loader.grub.devices = [ "/dev/hda" "/dev/hdb" ]; - } - ``` - **/ - recursiveUpdate = left: right: + returns: { + boot.loader.grub.enable = true; + boot.loader.grub.devices = [ "/dev/hda" "/dev/hdb" ]; + } + ``` + * + */ + recursiveUpdate = + left: right: let - inherit (lib) zipAttrsWith length elemAt head isAttrs isList concatLists all reverseList; + inherit (lib) + zipAttrsWith + length + elemAt + head + isAttrs + isList + concatLists + all + reverseList + ; recursiveMergeUntil = - pred: - lhs: - rhs: + pred: lhs: rhs: let - f = attrPath: - zipAttrsWith (n: values: - let here = attrPath ++ [ n ]; in - if length values == 1 - || pred here (elemAt values 1) (head values) then - ( - if all isList values then concatLists (reverseList values) - else head values - ) + f = + attrPath: + zipAttrsWith ( + n: values: + let + here = attrPath ++ [ n ]; + in + if length values == 1 || pred here (elemAt values 1) (head values) then + (if all isList values then concatLists (reverseList values) else head values) else f here values ); @@ -101,43 +159,45 @@ let f [ ] [ rhs lhs ]; recursiveMerge = - lhs: - rhs: - recursiveMergeUntil - (_path: lhs: rhs: - !(isAttrs lhs && isAttrs rhs)) - lhs - rhs; - + lhs: rhs: + recursiveMergeUntil ( + _path: lhs: rhs: + !(isAttrs lhs && isAttrs rhs) + ) lhs rhs; in recursiveMerge left right; - /* deepMergeMap takes a function and a list of attrsets and deep merges them + /* + deepMergeMap takes a function and a list of attrsets and deep merges them - deepMergeMap :: (AttrSet -> AttrSet ) -> [ AttrSet ] -> Attrset + deepMergeMap :: (AttrSet -> AttrSet ) -> [ AttrSet ] -> Attrset - Example: - deepMergeMap (x: x.t = "test") [ { x = { y = 1; z = 3; }; } { x = { bla = 234; }; } ] - => { x = { y = 1; z = 3; bla = 234; t = "test"; }; } + Example: + deepMergeMap (x: x.t = "test") [ { x = { y = 1; z = 3; }; } { x = { bla = 234; }; } ] + => { x = { y = 1; z = 3; bla = 234; t = "test"; }; } */ deepMergeMap = f: lib.foldr (attr: acc: (diskoLib.recursiveUpdate acc (f attr))) { }; - /* get a device and an index to get the matching device name + /* + get a device and an index to get the matching device name - deviceNumbering :: str -> int -> str + deviceNumbering :: str -> int -> str - Example: - deviceNumbering "/dev/sda" 3 - => "/dev/sda3" + Example: + deviceNumbering "/dev/sda" 3 + => "/dev/sda3" - deviceNumbering "/dev/disk/by-id/xxx" 2 - => "/dev/disk/by-id/xxx-part2" + deviceNumbering "/dev/disk/by-id/xxx" 2 + => "/dev/disk/by-id/xxx-part2" */ - deviceNumbering = dev: index: - let inherit (lib) match; in + deviceNumbering = + dev: index: + let + inherit (lib) match; + in if match "/dev/([vs]|(xv)d).+" dev != null then - dev + toString index # /dev/{s,v,xv}da style + dev + toString index # /dev/{s,v,xv}da style else if match "/dev/(disk|zvol)/.+" dev != null then "${dev}-part${toString index}" # /dev/disk/by-id/xxx style, also used by zfs's zvolumes else if match "/dev/((nvme|mmcblk).+|md/.*[[:digit:]])" dev != null then @@ -146,14 +206,15 @@ let "${dev}${toString index}" # /dev/md/raid1 style else if match "/dev/mapper/.+" dev != null then "${dev}${toString index}" # /dev/mapper/vg-lv1 style - else if match "/dev/loop[[:digit:]]+" dev != null - then "${dev}p${toString index}" # /dev/mapper/vg-lv1 style + else if match "/dev/loop[[:digit:]]+" dev != null then + "${dev}p${toString index}" # /dev/mapper/vg-lv1 style else abort '' ${dev} seems not to be a supported disk format. Please add this to disko in https://github.com/nix-community/disko/blob/master/lib/default.nix ''; - /* Escape a string as required to be used in udev symlinks + /* + Escape a string as required to be used in udev symlinks The allowed characters are "0-9A-Za-z#+-.:=@_/", valid UTF-8 character sequences, and "\x00" hex encoding. Everything else is escaped as "\xXX" where XX is the hex value of the character. @@ -181,23 +242,27 @@ let allowedChars = "[0-9A-Za-z#+-.:=@_/]"; charToHex = c: lib.toHexString (lib.strings.charToInt c); in - lib.stringAsChars - (c: if lib.match allowedChars c != null || c == "" then c else "\\x" + charToHex c); + lib.stringAsChars ( + c: if lib.match allowedChars c != null || c == "" then c else "\\x" + charToHex c + ); - /* get the index an item in a list + /* + get the index an item in a list - indexOf :: (a -> bool) -> [a] -> int -> int + indexOf :: (a -> bool) -> [a] -> int -> int - Example: - indexOf (x: x == 2) [ 1 2 3 ] 0 - => 2 + Example: + indexOf (x: x == 2) [ 1 2 3 ] 0 + => 2 - indexOf (x: x == "x") [ 1 2 3 ] 0 - => 0 - */ - indexOf = f: list: fallback: + indexOf (x: x == "x") [ 1 2 3 ] 0 + => 0 + */ + indexOf = + f: list: fallback: let - iter = index: list: + iter = + index: list: if list == [ ] then fallback else if f (lib.head list) then @@ -207,44 +272,48 @@ let in iter 1 list; + /* + indent takes a multiline string and indents it by 2 spaces starting on the second line - /* indent takes a multiline string and indents it by 2 spaces starting on the second line + indent :: str -> str - indent :: str -> str - - Example: - indent "test\nbla" - => "test\n bla" + Example: + indent "test\nbla" + => "test\n bla" */ indent = lib.replaceStrings [ "\n" ] [ "\n " ]; - /* A nix option type representing a json datastructure, vendored from nixpkgs to avoid dependency on pkgs */ + # A nix option type representing a json datastructure, vendored from nixpkgs to avoid dependency on pkgs jsonType = let - valueType = lib.types.nullOr - (lib.types.oneOf [ - lib.types.bool - lib.types.int - lib.types.float - lib.types.str - lib.types.path - (lib.types.attrsOf valueType) - (lib.types.listOf valueType) - ]) // { - description = "JSON value"; - }; + valueType = + lib.types.nullOr ( + lib.types.oneOf [ + lib.types.bool + lib.types.int + lib.types.float + lib.types.str + lib.types.path + (lib.types.attrsOf valueType) + (lib.types.listOf valueType) + ] + ) + // { + description = "JSON value"; + }; in valueType; - /* Given a attrset of deviceDependencies and a devices attrset - returns a sorted list by deviceDependencies. aborts if a loop is found + /* + Given a attrset of deviceDependencies and a devices attrset + returns a sorted list by deviceDependencies. aborts if a loop is found - sortDevicesByDependencies :: AttrSet -> AttrSet -> [ [ str str ] ] + sortDevicesByDependencies :: AttrSet -> AttrSet -> [ [ str str ] ] */ - sortDevicesByDependencies = deviceDependencies: devices: + sortDevicesByDependencies = + deviceDependencies: devices: let - dependsOn = a: b: - lib.elem a (lib.attrByPath b [ ] deviceDependencies); + dependsOn = a: b: lib.elem a (lib.attrByPath b [ ] deviceDependencies); maybeSortedDevices = lib.toposort dependsOn (diskoLib.deviceList devices); in if (lib.hasAttr "cycle" maybeSortedDevices) then @@ -252,81 +321,116 @@ let else maybeSortedDevices.result; - /* Takes a devices attrSet and returns it as a list + /* + Takes a devices attrSet and returns it as a list - deviceList :: AttrSet -> [ [ str str ] ] + deviceList :: AttrSet -> [ [ str str ] ] - Example: - deviceList { zfs.pool1 = {}; zfs.pool2 = {}; mdadm.raid1 = {}; } - => [ [ "zfs" "pool1" ] [ "zfs" "pool2" ] [ "mdadm" "raid1" ] ] + Example: + deviceList { zfs.pool1 = {}; zfs.pool2 = {}; mdadm.raid1 = {}; } + => [ [ "zfs" "pool1" ] [ "zfs" "pool2" ] [ "mdadm" "raid1" ] ] */ - deviceList = devices: - lib.concatLists (lib.mapAttrsToList (n: v: (map (x: [ n x ]) (lib.attrNames v))) devices); + deviceList = + devices: + lib.concatLists ( + lib.mapAttrsToList ( + n: v: + (map (x: [ + n + x + ]) (lib.attrNames v)) + ) devices + ); - /* Takes either a string or null and returns the string or an empty string + /* + Takes either a string or null and returns the string or an empty string - maybeStr :: Either (str null) -> str + maybeStr :: Either (str null) -> str - Example: - maybeStr null - => "" - maybeSTr "hello world" - => "hello world" + Example: + maybeStr null + => "" + maybeSTr "hello world" + => "hello world" */ maybeStr = x: lib.optionalString (x != null) x; - /* Takes a Submodules config and options argument and returns a serializable - subset of config variables as a shell script snippet. + /* + Takes a Submodules config and options argument and returns a serializable + subset of config variables as a shell script snippet. */ - defineHookVariables = { options }: + defineHookVariables = + { options }: let sanitizeName = lib.replaceStrings [ "-" ] [ "_" ]; isAttrsOfSubmodule = o: o.type.name == "attrsOf" && o.type.nestedTypes.elemType.name == "submodule"; - isSerializable = n: o: !( - lib.hasPrefix "_" n + isSerializable = + n: o: + !( + lib.hasPrefix "_" n || lib.hasSuffix "Hook" n || isAttrsOfSubmodule o # TODO don't hardcode diskoLib.subType options. - || n == "content" || n == "partitions" || n == "datasets" || n == "swap" + || n == "content" + || n == "partitions" + || n == "datasets" + || n == "swap" || n == "mode" - ); + ); in - lib.toShellVars - (lib.mapAttrs' - (n: o: lib.nameValuePair (sanitizeName n) o.value) - (lib.filterAttrs isSerializable options)); + lib.toShellVars ( + lib.mapAttrs' (n: o: lib.nameValuePair (sanitizeName n) o.value) ( + lib.filterAttrs isSerializable options + ) + ); - mkHook = description: lib.mkOption { - inherit description; - type = lib.types.lines; - default = ""; - }; + mkHook = + description: + lib.mkOption { + inherit description; + type = lib.types.lines; + default = ""; + }; - mkSubType = module: lib.types.submodule [ - module + mkSubType = + module: + lib.types.submodule [ + module + { + options = { + preCreateHook = diskoLib.mkHook "shell commands to run before create"; + postCreateHook = diskoLib.mkHook "shell commands to run after create"; + preMountHook = diskoLib.mkHook "shell commands to run before mount"; + postMountHook = diskoLib.mkHook "shell commands to run after mount"; + preUnmountHook = diskoLib.mkHook "shell commands to run before unmount"; + postUnmountHook = diskoLib.mkHook "shell commands to run after unmount"; + }; + config._module.args = { + inherit diskoLib rootMountPoint; + }; + } + ]; + + mkCreateOption = { - options = { - preCreateHook = diskoLib.mkHook "shell commands to run before create"; - postCreateHook = diskoLib.mkHook "shell commands to run after create"; - preMountHook = diskoLib.mkHook "shell commands to run before mount"; - postMountHook = diskoLib.mkHook "shell commands to run after mount"; - preUnmountHook = diskoLib.mkHook "shell commands to run before unmount"; - postUnmountHook = diskoLib.mkHook "shell commands to run after unmount"; - }; - config._module.args = { - inherit diskoLib rootMountPoint; - }; - } - ]; - - mkCreateOption = { config, options, default }@attrs: + config, + options, + default, + }@attrs: lib.mkOption { internal = true; readOnly = true; type = lib.types.str; default = '' - ( # ${config.type} ${lib.concatMapStringsSep " " (n: toString (config.${n} or "")) ["name" "device" "format" "mountpoint"]} # + ( # ${config.type} ${ + lib.concatMapStringsSep " " (n: toString (config.${n} or "")) [ + "name" + "device" + "format" + "mountpoint" + ] + } # ${diskoLib.indent (diskoLib.defineHookVariables { inherit options; })} ${diskoLib.indent config.preCreateHook} ${diskoLib.indent attrs.default} @@ -336,98 +440,131 @@ let description = "Creation script"; }; - mkMountOption = { config, options, default }@attrs: + mkMountOption = + { + config, + options, + default, + }@attrs: lib.mkOption { internal = true; readOnly = true; type = diskoLib.jsonType; - default = lib.mapAttrsRecursive - (_name: value: - if builtins.isString value then '' + default = lib.mapAttrsRecursive ( + _name: value: + if builtins.isString value then + '' ( ${diskoLib.indent (diskoLib.defineHookVariables { inherit options; })} ${diskoLib.indent config.preMountHook} ${diskoLib.indent value} ${diskoLib.indent config.postMountHook} ) - '' else value) - attrs.default; + '' + else + value + ) attrs.default; description = "Mount script"; }; - mkUnmountOption = { config, options, default }@attrs: + mkUnmountOption = + { + config, + options, + default, + }@attrs: lib.mkOption { internal = true; readOnly = true; type = diskoLib.jsonType; - default = lib.mapAttrsRecursive - (_name: value: - if builtins.isString value then '' + default = lib.mapAttrsRecursive ( + _name: value: + if builtins.isString value then + '' ( ${diskoLib.indent (diskoLib.defineHookVariables { inherit options; })} ${diskoLib.indent config.preUnmountHook} ${diskoLib.indent value} ${diskoLib.indent config.postUnmountHook} ) - '' else value) - attrs.default; + '' + else + value + ) attrs.default; description = "Unmount script"; }; - /* Writer for optionally checking bash scripts before writing them to the store + /* + Writer for optionally checking bash scripts before writing them to the store - writeCheckedBash :: AttrSet -> str -> str -> derivation + writeCheckedBash :: AttrSet -> str -> str -> derivation */ - writeCheckedBash = { pkgs, checked ? false, noDeps ? false }: pkgs.writers.makeScriptWriter { - interpreter = if noDeps then "/usr/bin/env bash" else "${pkgs.bash}/bin/bash"; - check = lib.optionalString (checked && !pkgs.stdenv.hostPlatform.isRiscV64 && !pkgs.stdenv.hostPlatform.isx86_32) (pkgs.writeScript "check" '' - set -efu - # SC2054: our toShellVars function doesn't quote list elements with commas - # SC2034: We don't use all variables exported by hooks. - ${pkgs.shellcheck}/bin/shellcheck -e SC2034,SC2054 "$1" - ''); - }; + writeCheckedBash = + { + pkgs, + checked ? false, + noDeps ? false, + }: + pkgs.writers.makeScriptWriter { + interpreter = if noDeps then "/usr/bin/env bash" else "${pkgs.bash}/bin/bash"; + check = + lib.optionalString + (checked && !pkgs.stdenv.hostPlatform.isRiscV64 && !pkgs.stdenv.hostPlatform.isx86_32) + ( + pkgs.writeScript "check" '' + set -efu + # SC2054: our toShellVars function doesn't quote list elements with commas + # SC2034: We don't use all variables exported by hooks. + ${pkgs.shellcheck}/bin/shellcheck -e SC2034,SC2054 "$1" + '' + ); + }; + /* + Takes a disko device specification, returns an attrset with metadata - /* Takes a disko device specification, returns an attrset with metadata - - meta :: lib.types.devices -> AttrSet + meta :: lib.types.devices -> AttrSet */ meta = toplevel: toplevel._meta; - /* Takes a disko device specification and returns a string which formats the disks + /* + Takes a disko device specification and returns a string which formats the disks - create :: lib.types.devices -> str + create :: lib.types.devices -> str */ create = toplevel: toplevel._create; - /* Takes a disko device specification and returns a string which mounts the disks + /* + Takes a disko device specification and returns a string which mounts the disks - mount :: lib.types.devices -> str + mount :: lib.types.devices -> str */ mount = toplevel: toplevel._mount; - /* takes a disko device specification and returns a string which unmounts, destroys all disks and then runs create and mount + /* + takes a disko device specification and returns a string which unmounts, destroys all disks and then runs create and mount - zapCreateMount :: lib.types.devices -> str + zapCreateMount :: lib.types.devices -> str */ - zapCreateMount = toplevel: - '' - set -efux - ${toplevel._disko} - ''; - /* Takes a disko device specification and returns a nixos configuration + zapCreateMount = toplevel: '' + set -efux + ${toplevel._disko} + ''; + /* + Takes a disko device specification and returns a nixos configuration - config :: lib.types.devices -> nixosConfig + config :: lib.types.devices -> nixosConfig */ config = toplevel: toplevel._config; - /* Takes a disko device specification and returns a function to get the needed packages to format/mount the disks + /* + Takes a disko device specification and returns a function to get the needed packages to format/mount the disks - packages :: lib.types.devices -> pkgs -> [ derivation ] + packages :: lib.types.devices -> pkgs -> [ derivation ] */ packages = toplevel: toplevel._packages; - /* Checks whether nixpkgs is recent enough for vmTools to support the customQemu argument. + /* + Checks whether nixpkgs is recent enough for vmTools to support the customQemu argument. Returns false, which is technically incorrect, for a few commits on 2024-07-08, but we can't be more accurate. Make sure to pass lib, not pkgs.lib! See https://github.com/nix-community/disko/issues/904 @@ -453,8 +590,10 @@ let pathname = lib.mkOptionType { name = "pathname"; - check = x: - with lib; let + check = + x: + with lib; + let # The filter is used to normalize paths, i.e. to remove duplicated and # trailing slashes. It also removes leading slashes, thus we have to # check for "/" explicitly below. @@ -466,11 +605,19 @@ let }; }; - /* topLevel type of the disko config, takes attrsets of disks, mdadms, zpools, nodevs, and lvm vgs. - */ - toplevel = lib.types.submodule (cfg: + # topLevel type of the disko config, takes attrsets of disks, mdadms, zpools, nodevs, and lvm vgs. + toplevel = lib.types.submodule ( + cfg: let - devices = { inherit (cfg.config) disk mdadm zpool lvm_vg nodev; }; + devices = { + inherit (cfg.config) + disk + mdadm + zpool + lvm_vg + nodev + ; + }; in { options = { @@ -505,7 +652,9 @@ let meta informationen generated by disko currently used for building a dependency list so we know in which order to create the devices ''; - default = diskoLib.deepMergeMap (dev: dev._meta) (lib.flatten (map lib.attrValues (lib.attrValues devices))); + default = diskoLib.deepMergeMap (dev: dev._meta) ( + lib.flatten (map lib.attrValues (lib.attrValues devices)) + ); }; _packages = lib.mkOption { internal = true; @@ -513,16 +662,31 @@ let packages required by the disko configuration coreutils is always included ''; - default = pkgs: with lib; unique ((flatten (map (dev: dev._pkgs pkgs) (flatten (map attrValues (attrValues devices))))) ++ [ pkgs.coreutils-full ]); + default = + pkgs: + with lib; + unique ( + (flatten (map (dev: dev._pkgs pkgs) (flatten (map attrValues (attrValues devices))))) + ++ [ pkgs.coreutils-full ] + ); }; _scripts = lib.mkOption { internal = true; description = '' The scripts generated by disko ''; - default = { pkgs, checked ? false }: + default = + { + pkgs, + checked ? false, + }: let - throwIfNoDisksDetected = _: v: if devices.disk == { } then throw "No disks defined, did you forget to import your disko config?" else v; + throwIfNoDisksDetected = + _: v: + if devices.disk == { } then + throw "No disks defined, did you forget to import your disko config?" + else + v; destroyDependencies = with pkgs; [ util-linux e2fsprogs @@ -557,31 +721,70 @@ let export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ])}:$PATH ${cfg.config._formatMount} ''; - destroyFormatMount = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-destroy-format-mount" '' - export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ] ++ destroyDependencies)}:$PATH - ${cfg.config._destroyFormatMount} - ''; + destroyFormatMount = + (diskoLib.writeCheckedBash { inherit pkgs checked; }) "/bin/disko-destroy-format-mount" + '' + export PATH=${ + lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ] ++ destroyDependencies) + }:$PATH + ${cfg.config._destroyFormatMount} + ''; # These are useful to skip copying executables uploading a script to an in-memory installer - destroyNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-destroy" '' - ${cfg.config._destroy} - ''; - formatNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-format" '' - ${cfg.config._create} - ''; - mountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-mount" '' - ${cfg.config._mount} - ''; - unmountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-unmount" '' - ${cfg.config._unmount} - ''; - formatMountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-format-mount" '' - ${cfg.config._formatMount} - ''; - destroyFormatMountNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "/bin/disko-destroy-format-mount" '' - ${cfg.config._destroyFormatMount} - ''; - + destroyNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "/bin/disko-destroy" + '' + ${cfg.config._destroy} + ''; + formatNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "/bin/disko-format" + '' + ${cfg.config._create} + ''; + mountNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "/bin/disko-mount" + '' + ${cfg.config._mount} + ''; + unmountNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "/bin/disko-unmount" + '' + ${cfg.config._unmount} + ''; + formatMountNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "/bin/disko-format-mount" + '' + ${cfg.config._formatMount} + ''; + destroyFormatMountNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "/bin/disko-destroy-format-mount" + '' + ${cfg.config._destroyFormatMount} + ''; # Legacy scripts, to be removed in version 2.0.0 # They are generally less useful, because the scripts are directly written to their $out path instead of @@ -604,26 +807,52 @@ let ''; diskoScript = (diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko" '' - export PATH=${lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ] ++ destroyDependencies)}:$PATH + export PATH=${ + lib.makeBinPath ((cfg.config._packages pkgs) ++ [ pkgs.bash ] ++ destroyDependencies) + }:$PATH ${cfg.config._disko} ''; # These are useful to skip copying executables uploading a script to an in-memory installer - destroyScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-destroy" '' - ${cfg.config._legacyDestroy} - ''; + destroyScriptNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "disko-destroy" + '' + ${cfg.config._legacyDestroy} + ''; - formatScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-format" '' - ${cfg.config._create} - ''; + formatScriptNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "disko-format" + '' + ${cfg.config._create} + ''; - mountScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-mount" '' - ${cfg.config._mount} - ''; + mountScriptNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "disko-mount" + '' + ${cfg.config._mount} + ''; - diskoScriptNoDeps = (diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko" '' - ${cfg.config._disko} - ''; + diskoScriptNoDeps = + (diskoLib.writeCheckedBash { + inherit pkgs checked; + noDeps = true; + }) + "disko" + '' + ${cfg.config._disko} + ''; }; }; _legacyDestroy = lib.mkOption { @@ -687,8 +916,10 @@ let The script to create all devices defined by disko.devices ''; default = - with lib; let - sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { }) devices; + with lib; + let + sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { } + ) devices; in '' set -efux @@ -697,7 +928,7 @@ let trap 'rm -rf "$disko_devices_dir"' EXIT mkdir -p "$disko_devices_dir" - ${concatMapStrings (dev: (attrByPath (dev ++ [ "_create" ]) {} devices)) sortedDeviceList} + ${concatMapStrings (dev: (attrByPath (dev ++ [ "_create" ]) { } devices)) sortedDeviceList} ''; }; _mount = lib.mkOption { @@ -707,14 +938,18 @@ let The script to mount all devices defined by disko.devices ''; default = - with lib; let - fsMounts = diskoLib.deepMergeMap (dev: dev._mount.fs or { }) (flatten (map attrValues (attrValues devices))); - sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { }) devices; + with lib; + let + fsMounts = diskoLib.deepMergeMap (dev: dev._mount.fs or { }) ( + flatten (map attrValues (attrValues devices)) + ); + sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { } + ) devices; in '' set -efux # first create the necessary devices - ${concatMapStrings (dev: (attrByPath (dev ++ [ "_mount" ]) {} devices).dev or "") sortedDeviceList} + ${concatMapStrings (dev: (attrByPath (dev ++ [ "_mount" ]) { } devices).dev or "") sortedDeviceList} # and then mount the filesystems in alphabetical order ${concatStrings (attrValues fsMounts)} @@ -727,9 +962,13 @@ let The script to unmount all devices defined by disko.devices ''; default = - with lib; let - fsMounts = diskoLib.deepMergeMap (dev: dev._unmount.fs or { }) (flatten (map attrValues (attrValues devices))); - sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { }) devices; + with lib; + let + fsMounts = diskoLib.deepMergeMap (dev: dev._unmount.fs or { }) ( + flatten (map attrValues (attrValues devices)) + ); + sortedDeviceList = diskoLib.sortDevicesByDependencies (cfg.config._meta.deviceDependencies or { } + ) devices; in '' set -efux @@ -737,7 +976,9 @@ let ${concatStrings (lib.reverseList (attrValues fsMounts))} # Than close the devices - ${concatMapStrings (dev: (attrByPath (dev ++ [ "_unmount" ]) {} devices).dev or "") (lib.reverseList sortedDeviceList)} + ${concatMapStrings (dev: (attrByPath (dev ++ [ "_unmount" ]) { } devices).dev or "") ( + lib.reverseList sortedDeviceList + )} ''; }; _disko = lib.mkOption { @@ -782,39 +1023,33 @@ let The NixOS config generated by disko ''; default = - with lib; let - configKeys = flatten (map attrNames (flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices)))))); + with lib; + let + configKeys = flatten ( + map attrNames (flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices))))) + ); collectedConfigs = flatten (map (dev: dev._config) (flatten (map attrValues (attrValues devices)))); in genAttrs configKeys (key: mkMerge (catAttrs key collectedConfigs)); }; }; - }); + } + ); # import all the types from the types directory types = lib.listToAttrs ( - map - (file: lib.nameValuePair - (lib.removeSuffix ".nix" file) - (diskoLib.mkSubType (./types + "/${file}")) - ) - (lib.attrNames (builtins.readDir ./types)) + map ( + file: lib.nameValuePair (lib.removeSuffix ".nix" file) (diskoLib.mkSubType (./types + "/${file}")) + ) (lib.attrNames (builtins.readDir ./types)) ); - # render types into an json serializable format - serializeType = type: + serializeType = + type: let options = lib.filter (x: !lib.hasPrefix "_" x) (lib.attrNames type.options); in - lib.listToAttrs ( - map - (option: lib.nameValuePair - option - type.options.${option} - ) - options - ); + lib.listToAttrs (map (option: lib.nameValuePair option type.options.${option}) options); typesSerializerLib = { rootMountPoint = ""; @@ -855,7 +1090,10 @@ let }; either = t1: t2: { type = "oneOf"; - types = [ t1 t2 ]; + types = [ + t1 + t2 + ]; }; enum = choices: { type = "enum"; @@ -867,10 +1105,12 @@ let str = "str"; bool = "bool"; int = "int"; - submodule = x: x { - inherit (diskoLib.typesSerializerLib) lib config options; - name = ""; - }; + submodule = + x: + x { + inherit (diskoLib.typesSerializerLib) lib config options; + name = ""; + }; }; }; diskoLib = { @@ -878,32 +1118,35 @@ let # Spoof these types to avoid infinite recursion deviceType = _: ""; partitionType = _: ""; - subType = { types, ... }: { - type = "oneOf"; - types = lib.attrNames types; - }; + subType = + { types, ... }: + { + type = "oneOf"; + types = lib.attrNames types; + }; mkCreateOption = option: "_create"; }; }; - jsonTypes = lib.listToAttrs - ( - map - (file: lib.nameValuePair - (lib.removeSuffix ".nix" file) - (diskoLib.serializeType (import (./types + "/${file}") diskoLib.typesSerializerLib)) + jsonTypes = + lib.listToAttrs ( + map ( + file: + lib.nameValuePair (lib.removeSuffix ".nix" file) ( + diskoLib.serializeType (import (./types + "/${file}") diskoLib.typesSerializerLib) ) - (lib.filter (name: lib.hasSuffix ".nix" name) (lib.attrNames (builtins.readDir ./types))) - ) // { - partitionType = { - type = "oneOf"; - types = lib.attrNames diskoLib._partitionTypes; + ) (lib.filter (name: lib.hasSuffix ".nix" name) (lib.attrNames (builtins.readDir ./types))) + ) + // { + partitionType = { + type = "oneOf"; + types = lib.attrNames diskoLib._partitionTypes; + }; + deviceType = { + type = "oneOf"; + types = lib.attrNames diskoLib._deviceTypes; + }; }; - deviceType = { - type = "oneOf"; - types = lib.attrNames diskoLib._deviceTypes; - }; - }; binfmt = import ./binfmt.nix; } // outputs; diff --git a/lib/interactive-vm.nix b/lib/interactive-vm.nix index 67d5eb8..361a383 100644 --- a/lib/interactive-vm.nix +++ b/lib/interactive-vm.nix @@ -1,22 +1,30 @@ -{ diskoLib, modulesPath, config, pkgs, lib, ... }: +{ + diskoLib, + modulesPath, + config, + pkgs, + lib, + ... +}: let vm_disko = (diskoLib.testLib.prepareDiskoConfig config diskoLib.testLib.devices).disko; - cfg_ = (lib.evalModules { - modules = lib.singleton { - # _file = toString input; - imports = lib.singleton { disko.devices = vm_disko.devices; }; - options = { - disko.devices = lib.mkOption { - type = diskoLib.toplevel; - }; - disko.testMode = lib.mkOption { - type = lib.types.bool; - default = true; + cfg_ = + (lib.evalModules { + modules = lib.singleton { + # _file = toString input; + imports = lib.singleton { disko.devices = vm_disko.devices; }; + options = { + disko.devices = lib.mkOption { + type = diskoLib.toplevel; + }; + disko.testMode = lib.mkOption { + type = lib.types.bool; + default = true; + }; }; }; - }; - }).config; + }).config; disks = lib.attrValues cfg_.disko.devices.disk; rootDisk = { name = "root"; @@ -26,13 +34,11 @@ let deviceExtraOpts.bootindex = "1"; deviceExtraOpts.serial = "root"; }; - otherDisks = map - (disk: { - name = disk.name; - file = ''"$tmp"/${lib.escapeShellArg disk.name}.qcow2''; - driveExtraOpts.werror = "report"; - }) - (builtins.tail disks); + otherDisks = map (disk: { + name = disk.name; + file = ''"$tmp"/${lib.escapeShellArg disk.name}.qcow2''; + driveExtraOpts.werror = "report"; + }) (builtins.tail disks); diskoBasedConfiguration = { # generated from disko config diff --git a/lib/make-disk-image.nix b/lib/make-disk-image.nix index b4a0b7d..c5bcf76 100644 --- a/lib/make-disk-image.nix +++ b/lib/make-disk-image.nix @@ -1,10 +1,11 @@ -{ config -, diskoLib -, lib -, extendModules -, options -, imagePkgs -, ... +{ + config, + diskoLib, + lib, + extendModules, + options, + imagePkgs, + ... }: let diskoCfg = config.disko; @@ -13,33 +14,45 @@ let checked = diskoCfg.checkScripts; configSupportsZfs = config.boot.supportedFilesystems.zfs or false; - binfmt = diskoLib.binfmt { inherit diskoLib lib pkgs imagePkgs; }; + binfmt = diskoLib.binfmt { + inherit + diskoLib + lib + pkgs + imagePkgs + ; + }; binfmtSetup = lib.optionalString (cfg.enableBinfmt && binfmt.systemsAreDifferent) '' mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc ${pkgs.systemdMinimal}/lib/systemd/systemd-binfmt <(echo ${lib.strings.escapeShellArg binfmt.binfmtRegistration}) ''; - vmTools = pkgs.vmTools.override - ({ - rootModules = [ - "9p" "9pnet_virtio" # we can drop those in future if we stop supporting 24.11 + vmTools = pkgs.vmTools.override ( + { + rootModules = + [ + "9p" + "9pnet_virtio" # we can drop those in future if we stop supporting 24.11 - "virtiofs" - "virtio_pci" - "virtio_blk" - "virtio_balloon" - "virtio_rng" - ] + "virtiofs" + "virtio_pci" + "virtio_blk" + "virtio_balloon" + "virtio_rng" + ] ++ (lib.optional configSupportsZfs "zfs") ++ cfg.extraRootModules; - kernel = pkgs.aggregateModules - ([ cfg.kernelPackages.kernel ] - ++ lib.optional (lib.elem "zfs" cfg.extraRootModules || configSupportsZfs) cfg.kernelPackages.${config.boot.zfs.package.kernelModuleAttribute}); + kernel = pkgs.aggregateModules ( + [ cfg.kernelPackages.kernel ] + ++ lib.optional ( + lib.elem "zfs" cfg.extraRootModules || configSupportsZfs + ) cfg.kernelPackages.${config.boot.zfs.package.kernelModuleAttribute} + ); } - // lib.optionalAttrs (diskoLib.vmToolsSupportsCustomQemu lib) - { + // lib.optionalAttrs (diskoLib.vmToolsSupportsCustomQemu lib) { customQemu = cfg.qemu; - }); + } + ); cleanedConfig = diskoLib.testLib.prepareDiskoConfig config diskoLib.testLib.devices; systemToInstall = extendModules { modules = [ @@ -51,34 +64,41 @@ let } ]; }; - systemToInstallNative = if binfmt.systemsAreDifferent then extendModules { - modules = [ - cfg.extraConfig - { - disko.testMode = true; - disko.devices = lib.mkForce cleanedConfig.disko.devices; - boot.loader.grub.devices = lib.mkForce cleanedConfig.boot.loader.grub.devices; - nixpkgs.hostPlatform = lib.mkForce pkgs.stdenv.hostPlatform; + systemToInstallNative = + if binfmt.systemsAreDifferent then + extendModules { + modules = [ + cfg.extraConfig + { + disko.testMode = true; + disko.devices = lib.mkForce cleanedConfig.disko.devices; + boot.loader.grub.devices = lib.mkForce cleanedConfig.boot.loader.grub.devices; + nixpkgs.hostPlatform = lib.mkForce pkgs.stdenv.hostPlatform; + } + ]; } - ]; - } - else systemToInstall; - dependencies = with pkgs; [ - bash - coreutils - gnused - parted # for partprobe - systemdMinimal - nix - util-linux - findutils - kmod - ] ++ cfg.extraDependencies; + else + systemToInstall; + dependencies = + with pkgs; + [ + bash + coreutils + gnused + parted # for partprobe + systemdMinimal + nix + util-linux + findutils + kmod + ] + ++ cfg.extraDependencies; preVM = '' # shellcheck disable=SC2154 mkdir -p "$out" - ${lib.concatMapStringsSep "\n" (disk: - # shellcheck disable=SC2154 + ${lib.concatMapStringsSep "\n" ( + disk: + # shellcheck disable=SC2154 "${pkgs.qemu}/bin/qemu-img create -f ${imageFormat} \"$out/${disk.imageName}.${imageFormat}\" ${disk.imageSize}" ) (lib.attrValues diskoCfg.devices.disk)} # This makes disko work, when canTouchEfiVariables is set to true. @@ -127,24 +147,26 @@ let umount -Rv ${systemToInstall.config.disko.rootMountPoint} ''; - QEMU_OPTS = lib.concatStringsSep " " ([ - "-drive if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}" - "-drive if=pflash,format=raw,unit=1,file=efivars.fd" - ] ++ builtins.map - (disk: + QEMU_OPTS = lib.concatStringsSep " " ( + [ + "-drive if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}" + "-drive if=pflash,format=raw,unit=1,file=efivars.fd" + ] + ++ builtins.map ( + disk: "-drive file=\"$out\"/${disk.imageName}.${imageFormat},if=virtio,cache=unsafe,werror=report,format=${imageFormat}" - ) - (lib.attrValues diskoCfg.devices.disk)); + ) (lib.attrValues diskoCfg.devices.disk) + ); in { - system.build.diskoImages = vmTools.runInLinuxVM (pkgs.runCommand cfg.name - { + system.build.diskoImages = vmTools.runInLinuxVM ( + pkgs.runCommand cfg.name { buildInputs = dependencies; inherit preVM QEMU_OPTS; postVM = cfg.extraPostVM; inherit (diskoCfg) memSize; - } - (binfmtSetup + partitioner + installer)); + } (binfmtSetup + partitioner + installer) + ); system.build.diskoImagesScript = diskoLib.writeCheckedBash { inherit checked pkgs; } cfg.name '' set -efu @@ -209,32 +231,34 @@ in shift done - export preVM=${diskoLib.writeCheckedBash { inherit pkgs checked; } "preVM.sh" '' - set -efu - mv copy_before_disko copy_after_disko xchg/ - origBuilder=${pkgs.writeScript "disko-builder" '' - set -eu - export PATH=${lib.makeBinPath dependencies} - for src in /tmp/xchg/copy_before_disko/*; do - [ -e "$src" ] || continue - dst=$(basename "$src" | base64 -d) - mkdir -p "$(dirname "$dst")" - cp -r "$src" "$dst" - done - set -f - ${partitioner} - set +f - for src in /tmp/xchg/copy_after_disko/*; do - [ -e "$src" ] || continue - dst=/mnt/$(basename "$src" | base64 -d) - mkdir -p "$(dirname "$dst")" - cp -r "$src" "$dst" - done - ${installer} - ''} - echo "export origBuilder=$origBuilder" >> xchg/saved-env - ${preVM} - ''} + export preVM=${ + diskoLib.writeCheckedBash { inherit pkgs checked; } "preVM.sh" '' + set -efu + mv copy_before_disko copy_after_disko xchg/ + origBuilder=${pkgs.writeScript "disko-builder" '' + set -eu + export PATH=${lib.makeBinPath dependencies} + for src in /tmp/xchg/copy_before_disko/*; do + [ -e "$src" ] || continue + dst=$(basename "$src" | base64 -d) + mkdir -p "$(dirname "$dst")" + cp -r "$src" "$dst" + done + set -f + ${partitioner} + set +f + for src in /tmp/xchg/copy_after_disko/*; do + [ -e "$src" ] || continue + dst=/mnt/$(basename "$src" | base64 -d) + mkdir -p "$(dirname "$dst")" + cp -r "$src" "$dst" + done + ${installer} + ''} + echo "export origBuilder=$origBuilder" >> xchg/saved-env + ${preVM} + '' + } export postVM=${diskoLib.writeCheckedBash { inherit pkgs checked; } "postVM.sh" cfg.extraPostVM} build_memory=''${build_memory:-${builtins.toString diskoCfg.memSize}} diff --git a/lib/tests.nix b/lib/tests.nix index 3cef657..fcdefbb 100644 --- a/lib/tests.nix +++ b/lib/tests.nix @@ -1,37 +1,48 @@ -{ lib -, makeTest -, eval-config -, ... +{ + lib, + makeTest, + eval-config, + ... }: let testLib = { # this takes a nixos config and changes the disk devices so we can run them inside the qemu test runner # basically changes all the disk.*.devices to something like /dev/vda or /dev/vdb etc. - prepareDiskoConfig = cfg: devices: + prepareDiskoConfig = + cfg: devices: let cleanedTopLevel = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) cfg; - preparedDisks = lib.foldlAttrs - (acc: n: v: { - devices = lib.tail acc.devices; - grub-devices = acc.grub-devices ++ (lib.optional (lib.any (part: (part.type or "") == "EF02") (lib.attrValues (v.content.partitions or { }))) (lib.head acc.devices)); - disks = acc.disks // { - "${n}" = v // { - device = lib.head acc.devices; - content = v.content // { device = lib.head acc.devices; }; + preparedDisks = + lib.foldlAttrs + (acc: n: v: { + devices = lib.tail acc.devices; + grub-devices = + acc.grub-devices + ++ (lib.optional (lib.any (part: (part.type or "") == "EF02") ( + lib.attrValues (v.content.partitions or { }) + )) (lib.head acc.devices)); + disks = acc.disks // { + "${n}" = v // { + device = lib.head acc.devices; + content = v.content // { + device = lib.head acc.devices; + }; + }; }; - }; - }) - { - inherit devices; - grub-devices = [ ]; - disks = { }; - } - cleanedTopLevel.disko.devices.disk; + }) + { + inherit devices; + grub-devices = [ ]; + disks = { }; + } + cleanedTopLevel.disko.devices.disk; in - cleanedTopLevel // { - boot.loader.grub.devices = if (preparedDisks.grub-devices != [ ]) then preparedDisks.grub-devices else [ "nodev" ]; + cleanedTopLevel + // { + boot.loader.grub.devices = + if (preparedDisks.grub-devices != [ ]) then preparedDisks.grub-devices else [ "nodev" ]; disko.devices = cleanedTopLevel.disko.devices // { disk = preparedDisks.disks; }; @@ -58,33 +69,31 @@ let # This is the test generator for a disko test makeDiskoTest = - { name - , disko-config - , extendModules ? null - , pkgs ? import { } - , extraTestScript ? "" - , bootCommands ? "" - , extraInstallerConfig ? { } - , extraSystemConfig ? { } - , efi ? !pkgs.stdenv.hostPlatform.isRiscV64 - , postDisko ? "" - , testMode ? "module" # can be one of direct module cli - , testBoot ? true # if we actually want to test booting or just create/mount - , enableOCR ? false + { + name, + disko-config, + extendModules ? null, + pkgs ? import { }, + extraTestScript ? "", + bootCommands ? "", + extraInstallerConfig ? { }, + extraSystemConfig ? { }, + efi ? !pkgs.stdenv.hostPlatform.isRiscV64, + postDisko ? "", + testMode ? "module", # can be one of direct module cli + testBoot ? true, # if we actually want to test booting or just create/mount + enableOCR ? false, }: let - makeTest' = args: + makeTest' = + args: makeTest args { inherit pkgs; inherit (pkgs) system; }; # for installation we skip /dev/vda because it is the test runner disk - importedDiskoConfig = - if builtins.isPath disko-config then - import disko-config - else - disko-config; + importedDiskoConfig = if builtins.isPath disko-config then import disko-config else disko-config; diskoConfigWithArgs = if builtins.isFunction importedDiskoConfig then @@ -104,79 +113,93 @@ let tsp-config = tsp-generator.config testConfigBooted; num-disks = builtins.length (lib.attrNames testConfigBooted.disko.devices.disk); - installed-system = { config, ... }: { - imports = [ - (lib.optionalAttrs (testMode == "direct") tsp-config) - (lib.optionalAttrs (testMode == "module") { - disko.enableConfig = true; - imports = [ - ../module.nix - testConfigBooted - ]; - }) - ]; + installed-system = + { config, ... }: + { + imports = [ + (lib.optionalAttrs (testMode == "direct") tsp-config) + (lib.optionalAttrs (testMode == "module") { + disko.enableConfig = true; + imports = [ + ../module.nix + testConfigBooted + ]; + }) + ]; - # config for tests to make them run faster or work at all - documentation.enable = false; - hardware.enableAllFirmware = lib.mkForce false; - # FIXME: we don't have an systemd in stage-1 equialvent for this - boot.initrd.preDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) '' - echo -n 'secretsecret' > /tmp/secret.key - ''; - boot.consoleLogLevel = lib.mkForce 100; - boot.loader.systemd-boot.enable = lib.mkDefault efi; - }; + # config for tests to make them run faster or work at all + documentation.enable = false; + hardware.enableAllFirmware = lib.mkForce false; + # FIXME: we don't have an systemd in stage-1 equialvent for this + boot.initrd.preDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) '' + echo -n 'secretsecret' > /tmp/secret.key + ''; + boot.consoleLogLevel = lib.mkForce 100; + boot.loader.systemd-boot.enable = lib.mkDefault efi; + }; installed-system-eval = eval-config { modules = [ installed-system ]; inherit (pkgs) system; }; - installedTopLevel = ((if extendModules != null then extendModules else installed-system-eval.extendModules) { - modules = [ - ({ config, ... }: { - imports = [ - extraSystemConfig - ({ modulesPath, ... }: { - imports = [ - (modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests - (modulesPath + "/profiles/qemu-guest.nix") - ]; - disko.devices = lib.mkForce testConfigBooted.disko.devices; - }) - ]; - - # since we boot on a different machine, the efi payload needs to be portable - boot.loader.grub.efiInstallAsRemovable = efi; - boot.loader.grub.efiSupport = efi; - boot.loader.systemd-boot.graceful = true; - - # we always want the bind-mounted nix store. otherwise tests take forever - fileSystems."/nix/store" = lib.mkForce { - device = "nix-store"; - fsType = "9p"; - neededForBoot = true; - options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ]; - }; - boot.zfs.devNodes = "/dev/disk/by-uuid"; # needed because /dev/disk/by-id is empty in qemu-vms - - # grub will install to these devices, we need to force those or we are offset by 1 - # we use mkOveride 70, so that users can override this with mkForce in case they are testing grub mirrored boots - boot.loader.grub.devices = lib.mkOverride 70 testConfigInstall.boot.loader.grub.devices; - - assertions = [ + installedTopLevel = + ((if extendModules != null then extendModules else installed-system-eval.extendModules) { + modules = [ + ( + { config, ... }: { - assertion = builtins.length config.boot.loader.grub.mirroredBoots > 1 -> config.boot.loader.grub.devices == [ ]; - message = '' - When using `--vm-test` in combination with `mirroredBoots`, - it is necessary to configure `boot.loader.grub.devices` as an empty list by setting `boot.loader.grub.devices = lib.mkForce [];`. - This adjustment is crucial because the `--vm-test` mechanism automatically overrides the grub boot devices as part of the virtual machine test. - ''; + imports = [ + extraSystemConfig + ( + { modulesPath, ... }: + { + imports = [ + (modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests + (modulesPath + "/profiles/qemu-guest.nix") + ]; + disko.devices = lib.mkForce testConfigBooted.disko.devices; + } + ) + ]; + + # since we boot on a different machine, the efi payload needs to be portable + boot.loader.grub.efiInstallAsRemovable = efi; + boot.loader.grub.efiSupport = efi; + boot.loader.systemd-boot.graceful = true; + + # we always want the bind-mounted nix store. otherwise tests take forever + fileSystems."/nix/store" = lib.mkForce { + device = "nix-store"; + fsType = "9p"; + neededForBoot = true; + options = [ + "trans=virtio" + "version=9p2000.L" + "cache=loose" + ]; + }; + boot.zfs.devNodes = "/dev/disk/by-uuid"; # needed because /dev/disk/by-id is empty in qemu-vms + + # grub will install to these devices, we need to force those or we are offset by 1 + # we use mkOveride 70, so that users can override this with mkForce in case they are testing grub mirrored boots + boot.loader.grub.devices = lib.mkOverride 70 testConfigInstall.boot.loader.grub.devices; + + assertions = [ + { + assertion = + builtins.length config.boot.loader.grub.mirroredBoots > 1 -> config.boot.loader.grub.devices == [ ]; + message = '' + When using `--vm-test` in combination with `mirroredBoots`, + it is necessary to configure `boot.loader.grub.devices` as an empty list by setting `boot.loader.grub.devices = lib.mkForce [];`. + This adjustment is crucial because the `--vm-test` mechanism automatically overrides the grub boot devices as part of the virtual machine test. + ''; + } + ]; } - ]; - }) - ]; - }).config.system.build.toplevel; + ) + ]; + }).config.system.build.toplevel; in makeTest' { @@ -184,153 +207,177 @@ let meta.timeout = 600; # 10 minutes inherit enableOCR; - nodes.machine = { pkgs, ... }: { - imports = [ - (lib.optionalAttrs (testMode == "module") { - imports = [ - ../module.nix - ]; - disko = { - enableConfig = false; - checkScripts = true; - devices = testConfigInstall.disko.devices; - }; - }) - extraInstallerConfig + nodes.machine = + { pkgs, ... }: + { + imports = [ + (lib.optionalAttrs (testMode == "module") { + imports = [ + ../module.nix + ]; + disko = { + enableConfig = false; + checkScripts = true; + devices = testConfigInstall.disko.devices; + }; + }) + extraInstallerConfig - # from base.nix - ({ config, ... }: { - boot.supportedFilesystems = - [ "btrfs" "cifs" "f2fs" "jfs" "ntfs" "reiserfs" "vfat" "xfs" ] ++ - lib.optional (config.networking.hostId != null && lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package) "zfs"; - }) + # from base.nix + ( + { config, ... }: + { + boot.supportedFilesystems = + [ + "btrfs" + "cifs" + "f2fs" + "jfs" + "ntfs" + "reiserfs" + "vfat" + "xfs" + ] + ++ lib.optional ( + config.networking.hostId != null + && lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package + ) "zfs"; + } + ) - (if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then { - boot.swraid.enable = true; - } else { - boot.initrd.services.swraid.enable = true; - }) - ]; + ( + if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then + { + boot.swraid.enable = true; + } + else + { + boot.initrd.services.swraid.enable = true; + } + ) + ]; - systemd.services.mdmonitor.enable = false; # silence some weird warnings + systemd.services.mdmonitor.enable = false; # silence some weird warnings - environment.systemPackages = [ - pkgs.jq - ]; + environment.systemPackages = [ + pkgs.jq + ]; - # speed-up eval - documentation.enable = false; + # speed-up eval + documentation.enable = false; - nix.settings = { - substituters = lib.mkForce [ ]; - hashed-mirrors = null; - connect-timeout = 1; + nix.settings = { + substituters = lib.mkForce [ ]; + hashed-mirrors = null; + connect-timeout = 1; + }; + + networking.hostId = lib.mkIf ( + (testConfigInstall ? networking.hostId) && (testConfigInstall.networking.hostId != null) + ) testConfigInstall.networking.hostId; + + virtualisation.emptyDiskImages = builtins.genList (_: 4096) num-disks; + + # useful for debugging via repl + system.build.systemToInstall = installed-system-eval; }; - networking.hostId = lib.mkIf - ( - (testConfigInstall ? networking.hostId) && (testConfigInstall.networking.hostId != null) - ) - testConfigInstall.networking.hostId; + testScript = + { nodes, ... }: + '' + def disks(oldmachine, num_disks): + disk_flags = [] + for i in range(num_disks): + disk_flags += [ + '-drive', + f"file={oldmachine.state_dir}/empty{i}.qcow2,id=drive{i + 1},if=none,index={i + 1},werror=report", + '-device', + f"virtio-blk-pci,drive=drive{i + 1}" + ] + return disk_flags - virtualisation.emptyDiskImages = builtins.genList (_: 4096) num-disks; - - # useful for debugging via repl - system.build.systemToInstall = installed-system-eval; - }; - - testScript = { nodes, ... }: '' - def disks(oldmachine, num_disks): - disk_flags = [] - for i in range(num_disks): - disk_flags += [ - '-drive', - f"file={oldmachine.state_dir}/empty{i}.qcow2,id=drive{i + 1},if=none,index={i + 1},werror=report", - '-device', - f"virtio-blk-pci,drive=drive{i + 1}" - ] - return disk_flags - - def create_test_machine( - oldmachine=None, **kwargs - ): # taken from - start_command = [ - "${pkgs.qemu_test}/bin/qemu-kvm", - "-cpu", - "max", - "-m", - "1024", - "-virtfs", - "local,path=/nix/store,security_model=none,mount_tag=nix-store", - *disks(oldmachine, ${toString num-disks}) - ] - ${lib.optionalString efi '' - start_command += ["-drive", - "if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}", - "-drive", - "if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}" + def create_test_machine( + oldmachine=None, **kwargs + ): # taken from + start_command = [ + "${pkgs.qemu_test}/bin/qemu-kvm", + "-cpu", + "max", + "-m", + "1024", + "-virtfs", + "local,path=/nix/store,security_model=none,mount_tag=nix-store", + *disks(oldmachine, ${toString num-disks}) ] - ''} - machine = create_machine(start_command=" ".join(start_command), **kwargs) - driver.machines.append(machine) - return machine + ${lib.optionalString efi '' + start_command += ["-drive", + "if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}", + "-drive", + "if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}" + ] + ''} + machine = create_machine(start_command=" ".join(start_command), **kwargs) + driver.machines.append(machine) + return machine - machine.start() - machine.succeed("echo -n 'additionalSecret' > /tmp/additionalSecret.key") - machine.succeed("echo -n 'secretsecret' > /tmp/secret.key") - ${lib.optionalString (testMode == "direct") '' - # running direct mode - machine.succeed("${lib.getExe tsp-format}") - machine.succeed("${lib.getExe tsp-mount}") - machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent - machine.succeed("${lib.getExe tsp-unmount}") - machine.succeed("${lib.getExe tsp-unmount}") # verify that umount is idempotent - machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent - machine.succeed("${lib.getExe tsp-disko} --yes-wipe-all-disks") # verify that we can destroy and recreate - machine.succeed("mkdir -p /mnt/home") - machine.succeed("touch /mnt/home/testfile") - machine.succeed("${lib.getExe tsp-format}") # verify that format is idempotent - machine.succeed("test -e /mnt/home/testfile") - ''} - ${lib.optionalString (testMode == "module") '' - # running module mode - machine.succeed("${lib.getExe nodes.machine.system.build.format}") - machine.succeed("${lib.getExe nodes.machine.system.build.mount}") - machine.succeed("${lib.getExe nodes.machine.system.build.mount}") # verify that mount is idempotent - machine.succeed("${lib.getExe nodes.machine.system.build.destroyFormatMount} --yes-wipe-all-disks") # verify that we can destroy and recreate again - machine.succeed("mkdir -p /mnt/home") - machine.succeed("touch /mnt/home/testfile") - machine.succeed("${lib.getExe nodes.machine.system.build.format}") # verify that format is idempotent - machine.succeed("test -e /mnt/home/testfile") - ''} - - ${postDisko} - - ${lib.optionalString testBoot '' - # mount nix-store in /mnt - machine.succeed("mkdir -p /mnt/nix/store") - machine.succeed("mount --bind /nix/store /mnt/nix/store") - - machine.succeed("nix-store --load-db < ${pkgs.closureInfo {rootPaths = [installedTopLevel];}}/registration") - - # fix "this is not a NixOS installation" - machine.succeed("mkdir -p /mnt/etc") - machine.succeed("touch /mnt/etc/NIXOS") - - machine.succeed("mkdir -p /mnt/nix/var/nix/profiles") - machine.succeed("nix-env -p /mnt/nix/var/nix/profiles/system --set ${installedTopLevel}") - machine.succeed("NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root /mnt -- ${installedTopLevel}/bin/switch-to-configuration boot") - machine.succeed("sync") - machine.shutdown() - - machine = create_test_machine(oldmachine=machine, name="booted_machine") machine.start() - ${bootCommands} - machine.wait_for_unit("local-fs.target") - ''} + machine.succeed("echo -n 'additionalSecret' > /tmp/additionalSecret.key") + machine.succeed("echo -n 'secretsecret' > /tmp/secret.key") + ${lib.optionalString (testMode == "direct") '' + # running direct mode + machine.succeed("${lib.getExe tsp-format}") + machine.succeed("${lib.getExe tsp-mount}") + machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent + machine.succeed("${lib.getExe tsp-unmount}") + machine.succeed("${lib.getExe tsp-unmount}") # verify that umount is idempotent + machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent + machine.succeed("${lib.getExe tsp-disko} --yes-wipe-all-disks") # verify that we can destroy and recreate + machine.succeed("mkdir -p /mnt/home") + machine.succeed("touch /mnt/home/testfile") + machine.succeed("${lib.getExe tsp-format}") # verify that format is idempotent + machine.succeed("test -e /mnt/home/testfile") + ''} + ${lib.optionalString (testMode == "module") '' + # running module mode + machine.succeed("${lib.getExe nodes.machine.system.build.format}") + machine.succeed("${lib.getExe nodes.machine.system.build.mount}") + machine.succeed("${lib.getExe nodes.machine.system.build.mount}") # verify that mount is idempotent + machine.succeed("${lib.getExe nodes.machine.system.build.destroyFormatMount} --yes-wipe-all-disks") # verify that we can destroy and recreate again + machine.succeed("mkdir -p /mnt/home") + machine.succeed("touch /mnt/home/testfile") + machine.succeed("${lib.getExe nodes.machine.system.build.format}") # verify that format is idempotent + machine.succeed("test -e /mnt/home/testfile") + ''} - ${extraTestScript} - ''; + ${postDisko} + + ${lib.optionalString testBoot '' + # mount nix-store in /mnt + machine.succeed("mkdir -p /mnt/nix/store") + machine.succeed("mount --bind /nix/store /mnt/nix/store") + + machine.succeed("nix-store --load-db < ${ + pkgs.closureInfo { rootPaths = [ installedTopLevel ]; } + }/registration") + + # fix "this is not a NixOS installation" + machine.succeed("mkdir -p /mnt/etc") + machine.succeed("touch /mnt/etc/NIXOS") + + machine.succeed("mkdir -p /mnt/nix/var/nix/profiles") + machine.succeed("nix-env -p /mnt/nix/var/nix/profiles/system --set ${installedTopLevel}") + machine.succeed("NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root /mnt -- ${installedTopLevel}/bin/switch-to-configuration boot") + machine.succeed("sync") + machine.shutdown() + + machine = create_test_machine(oldmachine=machine, name="booted_machine") + machine.start() + ${bootCommands} + machine.wait_for_unit("local-fs.target") + ''} + + ${extraTestScript} + ''; }; }; in diff --git a/lib/types/btrfs.nix b/lib/types/btrfs.nix index d9cff2c..858cbdd 100644 --- a/lib/types/btrfs.nix +++ b/lib/types/btrfs.nix @@ -1,60 +1,71 @@ -{ config, options, diskoLib, lib, rootMountPoint, parent, device, ... }: +{ + config, + options, + diskoLib, + lib, + rootMountPoint, + parent, + device, + ... +}: let swapType = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { - options = { - size = lib.mkOption { - type = lib.types.strMatching "^([0-9]+[KMGTP])?$"; - description = "Size of the swap file (e.g. 2G)"; - }; + type = lib.types.attrsOf ( + lib.types.submodule ( + { name, ... }: + { + options = { + size = lib.mkOption { + type = lib.types.strMatching "^([0-9]+[KMGTP])?$"; + description = "Size of the swap file (e.g. 2G)"; + }; - path = lib.mkOption { - type = lib.types.str; - default = name; - description = "Path to the swap file (relative to the mountpoint)"; - }; + path = lib.mkOption { + type = lib.types.str; + default = name; + description = "Path to the swap file (relative to the mountpoint)"; + }; - priority = lib.mkOption { - type = lib.types.nullOr lib.types.int; - default = null; - description = '' - Specify the priority of the swap file. Priority is a value between 0 and 32767. - Higher numbers indicate higher priority. - null lets the kernel choose a priority, which will show up as a negative value. - ''; - }; + priority = lib.mkOption { + type = lib.types.nullOr lib.types.int; + default = null; + description = '' + Specify the priority of the swap file. Priority is a value between 0 and 32767. + Higher numbers indicate higher priority. + null lets the kernel choose a priority, which will show up as a negative value. + ''; + }; - options = lib.mkOption { - type = lib.types.listOf lib.types.nonEmptyStr; - default = [ "defaults" ]; - example = [ "nofail" ]; - description = "Options used to mount the swap."; - }; - }; - })); + options = lib.mkOption { + type = lib.types.listOf lib.types.nonEmptyStr; + default = [ "defaults" ]; + example = [ "nofail" ]; + description = "Options used to mount the swap."; + }; + }; + } + ) + ); default = { }; description = "Swap files"; }; - swapConfig = { mountpoint, swap }: + swapConfig = + { mountpoint, swap }: { - swapDevices = builtins.map - (file: { - device = "${mountpoint}/${file.path}"; - inherit (file) priority options; - }) - (lib.attrValues swap); + swapDevices = builtins.map (file: { + device = "${mountpoint}/${file.path}"; + inherit (file) priority options; + }) (lib.attrValues swap); }; - swapCreate = mountpoint: swap: - lib.concatMapStringsSep - "\n" - (file: '' - if ! test -e "${mountpoint}/${file.path}"; then - btrfs filesystem mkswapfile --size ${file.size} "${mountpoint}/${file.path}" - fi - '') - (lib.attrValues swap); + swapCreate = + mountpoint: swap: + lib.concatMapStringsSep "\n" (file: '' + if ! test -e "${mountpoint}/${file.path}"; then + btrfs filesystem mkswapfile --size ${file.size} "${mountpoint}/${file.path}" + fi + '') (lib.attrValues swap); in { @@ -80,37 +91,42 @@ in description = "A list of options to pass to mount."; }; subvolumes = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: { - options = { - name = lib.mkOption { - type = lib.types.str; - default = config._module.args.name; - description = "Name of the BTRFS subvolume."; - }; - type = lib.mkOption { - type = lib.types.enum [ "btrfs_subvol" ]; - default = "btrfs_subvol"; - internal = true; - description = "Type"; - }; - extraArgs = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - description = "Extra arguments"; - }; - mountOptions = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ "defaults" ]; - description = "Options to pass to mount"; - }; - mountpoint = lib.mkOption { - type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname; - default = null; - description = "Location to mount the subvolume to."; - }; - swap = swapType; - }; - })); + type = lib.types.attrsOf ( + lib.types.submodule ( + { config, ... }: + { + options = { + name = lib.mkOption { + type = lib.types.str; + default = config._module.args.name; + description = "Name of the BTRFS subvolume."; + }; + type = lib.mkOption { + type = lib.types.enum [ "btrfs_subvol" ]; + default = "btrfs_subvol"; + internal = true; + description = "Type"; + }; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments"; + }; + mountOptions = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "defaults" ]; + description = "Options to pass to mount"; + }; + mountpoint = lib.mkOption { + type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname; + default = null; + description = "Location to mount the subvolume to."; + }; + swap = swapType; + }; + } + ) + ); default = { }; description = "Subvolumes to define for BTRFS."; }; @@ -138,9 +154,9 @@ in if ! (blkid "${config.device}" -o export | grep -q '^TYPE='); then mkfs.btrfs "${config.device}" ${toString config.extraArgs} fi - ${lib.optionalString (config.swap != {} || config.subvolumes != {}) '' + ${lib.optionalString (config.swap != { } || config.subvolumes != { }) '' if (blkid "${config.device}" -o export | grep -q '^TYPE=btrfs$'); then - ${lib.optionalString (config.swap != {}) '' + ${lib.optionalString (config.swap != { }) '' ( MNTPOINT=$(mktemp -d) mount ${device} "$MNTPOINT" -o subvol=/ @@ -169,79 +185,84 @@ in inherit config options; default = let - subvolMounts = lib.concatMapAttrs - (_: subvol: - lib.warnIf (subvol.mountOptions != (options.subvolumes.type.getSubOptions [ ]).mountOptions.default && subvol.mountpoint == null) - "Subvolume ${subvol.name} has mountOptions but no mountpoint. See upgrade guide (2023-07-09 121df48)." - lib.optionalAttrs - (subvol.mountpoint != null) - { - ${subvol.mountpoint} = '' - if ! findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then - mount "${config.device}" "${rootMountPoint}${subvol.mountpoint}" \ - ${lib.concatMapStringsSep " " (opt: "-o ${opt}") (subvol.mountOptions ++ [ "subvol=${subvol.name}" ])} \ - -o X-mount.mkdir - fi - ''; - } - ) - config.subvolumes; + subvolMounts = lib.concatMapAttrs ( + _: subvol: + lib.warnIf + ( + subvol.mountOptions != (options.subvolumes.type.getSubOptions [ ]).mountOptions.default + && subvol.mountpoint == null + ) + "Subvolume ${subvol.name} has mountOptions but no mountpoint. See upgrade guide (2023-07-09 121df48)." + lib.optionalAttrs + (subvol.mountpoint != null) + { + ${subvol.mountpoint} = '' + if ! findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then + mount "${config.device}" "${rootMountPoint}${subvol.mountpoint}" \ + ${ + lib.concatMapStringsSep " " (opt: "-o ${opt}") (subvol.mountOptions ++ [ "subvol=${subvol.name}" ]) + } \ + -o X-mount.mkdir + fi + ''; + } + ) config.subvolumes; in { - fs = subvolMounts // lib.optionalAttrs (config.mountpoint != null) { - ${config.mountpoint} = '' - if ! findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then - mount "${config.device}" "${rootMountPoint}${config.mountpoint}" \ - ${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \ - -o X-mount.mkdir - fi - ''; - }; + fs = + subvolMounts + // lib.optionalAttrs (config.mountpoint != null) { + ${config.mountpoint} = '' + if ! findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then + mount "${config.device}" "${rootMountPoint}${config.mountpoint}" \ + ${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \ + -o X-mount.mkdir + fi + ''; + }; }; }; _unmount = diskoLib.mkUnmountOption { inherit config options; default = let - subvolMounts = lib.concatMapAttrs - (_: subvol: - lib.optionalAttrs - (subvol.mountpoint != null) - { - ${subvol.mountpoint} = '' - if findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then - umount "${rootMountPoint}${subvol.mountpoint}" - fi - ''; - } - ) - config.subvolumes; + subvolMounts = lib.concatMapAttrs ( + _: subvol: + lib.optionalAttrs (subvol.mountpoint != null) { + ${subvol.mountpoint} = '' + if findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then + umount "${rootMountPoint}${subvol.mountpoint}" + fi + ''; + } + ) config.subvolumes; in { - fs = subvolMounts // lib.optionalAttrs (config.mountpoint != null) { - ${config.mountpoint} = '' - if findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then - umount "${rootMountPoint}${config.mountpoint}" - fi - ''; - }; + fs = + subvolMounts + // lib.optionalAttrs (config.mountpoint != null) { + ${config.mountpoint} = '' + if findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then + umount "${rootMountPoint}${config.mountpoint}" + fi + ''; + }; }; }; _config = lib.mkOption { internal = true; readOnly = true; default = [ - (map - (subvol: - lib.optional (subvol.mountpoint != null) { - fileSystems.${subvol.mountpoint} = { - device = config.device; - fsType = "btrfs"; - options = subvol.mountOptions ++ [ "subvol=${subvol.name}" ]; - }; - } - ) - (lib.attrValues config.subvolumes)) + (map ( + subvol: + lib.optional (subvol.mountpoint != null) { + fileSystems.${subvol.mountpoint} = { + device = config.device; + fsType = "btrfs"; + options = subvol.mountOptions ++ [ "subvol=${subvol.name}" ]; + }; + } + ) (lib.attrValues config.subvolumes)) (lib.optional (config.mountpoint != null) { fileSystems.${config.mountpoint} = { device = config.device; @@ -249,11 +270,12 @@ in options = config.mountOptions; }; }) - (map - (subvol: swapConfig { + (map ( + subvol: + swapConfig { inherit (subvol) mountpoint swap; - }) - (lib.attrValues config.subvolumes)) + } + ) (lib.attrValues config.subvolumes)) (swapConfig { inherit (config) mountpoint swap; }) @@ -264,8 +286,10 @@ in internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: - [ pkgs.btrfs-progs pkgs.gnugrep ]; + default = pkgs: [ + pkgs.btrfs-progs + pkgs.gnugrep + ]; description = "Packages"; }; }; diff --git a/lib/types/disk.nix b/lib/types/disk.nix index 343f968..c6c771f 100644 --- a/lib/types/disk.nix +++ b/lib/types/disk.nix @@ -1,4 +1,10 @@ -{ config, options, lib, diskoLib, ... }: +{ + config, + options, + lib, + diskoLib, + ... +}: { options = { name = lib.mkOption { @@ -32,13 +38,20 @@ ''; default = "2G"; }; - content = diskoLib.deviceType { parent = config; device = config.device; }; + content = diskoLib.deviceType { + parent = config; + device = config.device; + }; _meta = lib.mkOption { internal = true; readOnly = true; type = diskoLib.jsonType; - default = - lib.optionalAttrs (config.content != null) (config.content._meta [ "disk" config.device ]); + default = lib.optionalAttrs (config.content != null) ( + config.content._meta [ + "disk" + config.device + ] + ); description = "Metadata"; }; _create = diskoLib.mkCreateOption { @@ -56,8 +69,7 @@ _config = lib.mkOption { internal = true; readOnly = true; - default = - lib.optional (config.content != null) config.content._config; + default = lib.optional (config.content != null) config.content._config; description = "NixOS configuration"; }; _pkgs = lib.mkOption { diff --git a/lib/types/filesystem.nix b/lib/types/filesystem.nix index e59e186..b957898 100644 --- a/lib/types/filesystem.nix +++ b/lib/types/filesystem.nix @@ -1,4 +1,13 @@ -{ config, options, lib, diskoLib, rootMountPoint, parent, device, ... }: +{ + config, + options, + lib, + diskoLib, + rootMountPoint, + parent, + device, + ... +}: { options = { type = lib.mkOption { @@ -90,18 +99,32 @@ internal = true; readOnly = true; # type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: - [ pkgs.util-linux pkgs.gnugrep ] ++ ( + default = + pkgs: + [ + pkgs.util-linux + pkgs.gnugrep + ] + ++ ( # TODO add many more - if (config.format == "xfs") then [ pkgs.xfsprogs ] - else if (config.format == "btrfs") then [ pkgs.btrfs-progs ] - else if (config.format == "vfat") then [ pkgs.dosfstools ] - else if (config.format == "ext2") then [ pkgs.e2fsprogs ] - else if (config.format == "ext3") then [ pkgs.e2fsprogs ] - else if (config.format == "ext4") then [ pkgs.e2fsprogs ] - else if (config.format == "bcachefs") then [ pkgs.bcachefs-tools ] - else if (config.format == "f2fs") then [ pkgs.f2fs-tools ] - else [ ] + if (config.format == "xfs") then + [ pkgs.xfsprogs ] + else if (config.format == "btrfs") then + [ pkgs.btrfs-progs ] + else if (config.format == "vfat") then + [ pkgs.dosfstools ] + else if (config.format == "ext2") then + [ pkgs.e2fsprogs ] + else if (config.format == "ext3") then + [ pkgs.e2fsprogs ] + else if (config.format == "ext4") then + [ pkgs.e2fsprogs ] + else if (config.format == "bcachefs") then + [ pkgs.bcachefs-tools ] + else if (config.format == "f2fs") then + [ pkgs.f2fs-tools ] + else + [ ] ); description = "Packages"; }; diff --git a/lib/types/gpt.nix b/lib/types/gpt.nix index d792190..9d5305e 100644 --- a/lib/types/gpt.nix +++ b/lib/types/gpt.nix @@ -1,4 +1,12 @@ -{ config, options, lib, diskoLib, parent, device, ... }: +{ + config, + options, + lib, + diskoLib, + parent, + device, + ... +}: let sortedPartitions = lib.sort (x: y: x.priority < y.priority) (lib.attrValues config.partitions); sortedHybridPartitions = lib.filter (p: p.hybrid != null) sortedPartitions; @@ -16,171 +24,210 @@ in description = "Device to use for the partition table"; }; partitions = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({ name, ... }@partition: { - options = { - type = lib.mkOption { - type = - let - hexPattern = len: "[A-Fa-f0-9]{${toString len}}"; - in - lib.types.either - (lib.types.strMatching (hexPattern 4)) - (lib.types.strMatching (lib.concatMapStringsSep "-" hexPattern [ 8 4 4 4 12 ])); - default = if partition.config.content != null && partition.config.content.type == "swap" then "8200" else "8300"; - defaultText = ''8300 (Linux filesystem) normally, 8200 (Linux swap) if content.type is "swap"''; - description = '' - Filesystem type to use. - This can either be an sgdisk-specific short code (run sgdisk -L to see what is available), - or a fully specified GUID (see https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs). - ''; - }; - device = lib.mkOption { - type = lib.types.str; - default = - if partition.config.uuid != null then - "/dev/disk/by-partuuid/${partition.config.uuid}" - else if config._parent.type == "mdadm" then - # workaround because mdadm partlabel do not appear in /dev/disk/by-partlabel - "/dev/disk/by-id/md-name-any:${config._parent.name}-part${toString partition.config._index}" - else - "/dev/disk/by-partlabel/${diskoLib.hexEscapeUdevSymlink partition.config.label}"; - defaultText = '' - if `uuid` is provided: - /dev/disk/by-partuuid/''${partition.config.uuid} - - otherwise, if the parent is an mdadm device: - /dev/disk/by-id/md-name-any:''${config._parent.name}-part''${toString partition.config._index} - - otherwise: - /dev/disk/by-partlabel/''${diskoLib.hexEscapeUdevSymlink partition.config.label} - ''; - description = "Device to use for the partition"; - }; - priority = lib.mkOption { - type = lib.types.int; - default = - if partition.config.size or "" == "100%" then - 9001 - else if partition.config.type == "EF02" then - # Boot partition should be created first, because some BIOS implementations require it. - # Priority defaults to 100 here to support any potential use-case for placing partitions prior to EF02 - 100 - else - 1000; - defaultText = '' - 1000: normal partitions - 9001: partitions with 100% size - 100: boot partitions (EF02) - ''; - description = "Priority of the partition, smaller values are created first"; - }; - name = lib.mkOption { - type = lib.types.str; - description = "Name of the partition"; - default = name; - }; - uuid = lib.mkOption { - type = lib.types.nullOr (lib.types.strMatching "[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}"); - default = null; - defaultText = "`null` - generate a UUID when creating the partition"; - example = "809b3a2b-828a-4730-95e1-75b6343e415a"; - description = '' - The UUID (also known as GUID) of the partition. Note that this is distinct from the UUID of the filesystem. - - You can generate a UUID with the command `uuidgen -r`. - ''; - }; - label = lib.mkOption { - type = lib.types.str; - default = - let - # 72 bytes is the maximum length of a GPT partition name - # the labels seem to be in UTF-16, so 2 bytes per character - limit = 36; - label = "${config._parent.type}-${config._parent.name}-${partition.config.name}"; - in - if (lib.stringLength label) > limit then - builtins.substring 0 limit (builtins.hashString "sha256" label) - else - label; - defaultText = '' - ''${config._parent.type}-''${config._parent.name}-''${partition.config.name} - - or a truncated hash of the above if it is longer than 36 characters - ''; - }; - size = lib.mkOption { - type = lib.types.either (lib.types.enum [ "100%" ]) (lib.types.strMatching "[0-9]+[KMGTP]?"); - default = "0"; - description = '' - Size of the partition, in sgdisk format. - sets end automatically with the + prefix - can be 100% for the whole remaining disk, will be done last in that case. - ''; - }; - alignment = lib.mkOption { - type = lib.types.int; - default = if (builtins.substring (builtins.stringLength partition.config.start - 1) 1 partition.config.start == "s" || (builtins.substring (builtins.stringLength partition.config.end - 1) 1 partition.config.end == "s")) then 1 else 0; - defaultText = "1 if the unit of start or end is sectors, 0 otherwise"; - description = "Alignment of the partition, if sectors are used as start or end it can be aligned to 1"; - }; - start = lib.mkOption { - type = lib.types.str; - default = "0"; - description = "Start of the partition, in sgdisk format, use 0 for next available range"; - }; - end = lib.mkOption { - type = lib.types.str; - default = if partition.config.size == "100%" then "-0" else "+${partition.config.size}"; - defaultText = '' - if partition.config.size == "100%" then "-0" else "+''${partition.config.size}"; - ''; - description = '' - End of the partition, in sgdisk format. - Use + for relative sizes from the partitions start - or - for relative sizes from the disks end - ''; - }; - content = diskoLib.partitionType { parent = config; device = partition.config.device; }; - hybrid = lib.mkOption { - type = lib.types.nullOr (lib.types.submodule ({ ... } @ hp: { - options = { - mbrPartitionType = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "MBR type code"; - }; - mbrBootableFlag = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Set the bootable flag (aka the active flag) on any or all of your hybridized partitions"; - }; - _create = diskoLib.mkCreateOption { - inherit config options; - default = '' - ${lib.optionalString (hp.config.mbrPartitionType != null) '' - sfdisk --label-nested dos --part-type "${parent.device}" ${(toString partition.config._index)} ${hp.config.mbrPartitionType} - udevadm trigger --subsystem-match=block - udevadm settle - ''} - ${lib.optionalString hp.config.mbrBootableFlag '' - sfdisk --label-nested dos --activate "${parent.device}" ${(toString partition.config._index)} - ''} - ''; - }; + type = lib.types.attrsOf ( + lib.types.submodule ( + { name, ... }@partition: + { + options = { + type = lib.mkOption { + type = + let + hexPattern = len: "[A-Fa-f0-9]{${toString len}}"; + in + lib.types.either (lib.types.strMatching (hexPattern 4)) ( + lib.types.strMatching ( + lib.concatMapStringsSep "-" hexPattern [ + 8 + 4 + 4 + 4 + 12 + ] + ) + ); + default = + if partition.config.content != null && partition.config.content.type == "swap" then + "8200" + else + "8300"; + defaultText = ''8300 (Linux filesystem) normally, 8200 (Linux swap) if content.type is "swap"''; + description = '' + Filesystem type to use. + This can either be an sgdisk-specific short code (run sgdisk -L to see what is available), + or a fully specified GUID (see https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs). + ''; }; - })); - default = null; - description = "Entry to add to the Hybrid MBR table"; - }; - _index = lib.mkOption { - type = lib.types.int; - internal = true; - default = diskoLib.indexOf (x: x.name == partition.config.name) sortedPartitions 0; - defaultText = null; - }; - }; - })); + device = lib.mkOption { + type = lib.types.str; + default = + if partition.config.uuid != null then + "/dev/disk/by-partuuid/${partition.config.uuid}" + else if config._parent.type == "mdadm" then + # workaround because mdadm partlabel do not appear in /dev/disk/by-partlabel + "/dev/disk/by-id/md-name-any:${config._parent.name}-part${toString partition.config._index}" + else + "/dev/disk/by-partlabel/${diskoLib.hexEscapeUdevSymlink partition.config.label}"; + defaultText = '' + if `uuid` is provided: + /dev/disk/by-partuuid/''${partition.config.uuid} + + otherwise, if the parent is an mdadm device: + /dev/disk/by-id/md-name-any:''${config._parent.name}-part''${toString partition.config._index} + + otherwise: + /dev/disk/by-partlabel/''${diskoLib.hexEscapeUdevSymlink partition.config.label} + ''; + description = "Device to use for the partition"; + }; + priority = lib.mkOption { + type = lib.types.int; + default = + if partition.config.size or "" == "100%" then + 9001 + else if partition.config.type == "EF02" then + # Boot partition should be created first, because some BIOS implementations require it. + # Priority defaults to 100 here to support any potential use-case for placing partitions prior to EF02 + 100 + else + 1000; + defaultText = '' + 1000: normal partitions + 9001: partitions with 100% size + 100: boot partitions (EF02) + ''; + description = "Priority of the partition, smaller values are created first"; + }; + name = lib.mkOption { + type = lib.types.str; + description = "Name of the partition"; + default = name; + }; + uuid = lib.mkOption { + type = lib.types.nullOr ( + lib.types.strMatching "[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}" + ); + default = null; + defaultText = "`null` - generate a UUID when creating the partition"; + example = "809b3a2b-828a-4730-95e1-75b6343e415a"; + description = '' + The UUID (also known as GUID) of the partition. Note that this is distinct from the UUID of the filesystem. + + You can generate a UUID with the command `uuidgen -r`. + ''; + }; + label = lib.mkOption { + type = lib.types.str; + default = + let + # 72 bytes is the maximum length of a GPT partition name + # the labels seem to be in UTF-16, so 2 bytes per character + limit = 36; + label = "${config._parent.type}-${config._parent.name}-${partition.config.name}"; + in + if (lib.stringLength label) > limit then + builtins.substring 0 limit (builtins.hashString "sha256" label) + else + label; + defaultText = '' + ''${config._parent.type}-''${config._parent.name}-''${partition.config.name} + + or a truncated hash of the above if it is longer than 36 characters + ''; + }; + size = lib.mkOption { + type = lib.types.either (lib.types.enum [ "100%" ]) (lib.types.strMatching "[0-9]+[KMGTP]?"); + default = "0"; + description = '' + Size of the partition, in sgdisk format. + sets end automatically with the + prefix + can be 100% for the whole remaining disk, will be done last in that case. + ''; + }; + alignment = lib.mkOption { + type = lib.types.int; + default = + if + ( + builtins.substring (builtins.stringLength partition.config.start - 1) 1 partition.config.start + == "s" + || ( + builtins.substring (builtins.stringLength partition.config.end - 1) 1 partition.config.end == "s" + ) + ) + then + 1 + else + 0; + defaultText = "1 if the unit of start or end is sectors, 0 otherwise"; + description = "Alignment of the partition, if sectors are used as start or end it can be aligned to 1"; + }; + start = lib.mkOption { + type = lib.types.str; + default = "0"; + description = "Start of the partition, in sgdisk format, use 0 for next available range"; + }; + end = lib.mkOption { + type = lib.types.str; + default = if partition.config.size == "100%" then "-0" else "+${partition.config.size}"; + defaultText = '' + if partition.config.size == "100%" then "-0" else "+''${partition.config.size}"; + ''; + description = '' + End of the partition, in sgdisk format. + Use + for relative sizes from the partitions start + or - for relative sizes from the disks end + ''; + }; + content = diskoLib.partitionType { + parent = config; + device = partition.config.device; + }; + hybrid = lib.mkOption { + type = lib.types.nullOr ( + lib.types.submodule ( + { ... }@hp: + { + options = { + mbrPartitionType = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "MBR type code"; + }; + mbrBootableFlag = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Set the bootable flag (aka the active flag) on any or all of your hybridized partitions"; + }; + _create = diskoLib.mkCreateOption { + inherit config options; + default = '' + ${lib.optionalString (hp.config.mbrPartitionType != null) '' + sfdisk --label-nested dos --part-type "${parent.device}" ${(toString partition.config._index)} ${hp.config.mbrPartitionType} + udevadm trigger --subsystem-match=block + udevadm settle + ''} + ${lib.optionalString hp.config.mbrBootableFlag '' + sfdisk --label-nested dos --activate "${parent.device}" ${(toString partition.config._index)} + ''} + ''; + }; + }; + } + ) + ); + default = null; + description = "Entry to add to the Hybrid MBR table"; + }; + _index = lib.mkOption { + type = lib.types.int; + internal = true; + default = diskoLib.indexOf (x: x.name == partition.config.name) sortedPartitions 0; + defaultText = null; + }; + }; + } + ) + ); default = { }; description = "Attrs of partitions to add to the partition table"; }; @@ -197,12 +244,13 @@ in internal = true; readOnly = true; type = lib.types.functionTo diskoLib.jsonType; - default = dev: - lib.foldr lib.recursiveUpdate { } (map - (partition: - lib.optionalAttrs (partition.content != null) (partition.content._meta dev) + default = + dev: + lib.foldr lib.recursiveUpdate { } ( + map (partition: lib.optionalAttrs (partition.content != null) (partition.content._meta dev)) ( + lib.attrValues config.partitions ) - (lib.attrValues config.partitions)); + ); description = "Metadata"; }; _create = diskoLib.mkCreateOption { @@ -211,61 +259,63 @@ in if ! blkid "${config.device}" >&2; then sgdisk --clear "${config.device}" fi - ${lib.concatMapStrings (partition: + ${lib.concatMapStrings ( + partition: let args = '' - --partition-guid="${toString partition._index}:${if partition.uuid == null then "R" else partition.uuid}" \ + --partition-guid="${toString partition._index}:${ + if partition.uuid == null then "R" else partition.uuid + }" \ --change-name="${toString partition._index}:${partition.label}" \ --typecode=${toString partition._index}:${partition.type} \ "${config.device}" \ ''; createArgs = '' - --align-end ${lib.optionalString (partition.alignment != 0) ''--set-alignment=${builtins.toString partition.alignment}''} \ + --align-end ${ + lib.optionalString ( + partition.alignment != 0 + ) ''--set-alignment=${builtins.toString partition.alignment}'' + } \ --new=${toString partition._index}:${partition.start}:${partition.end} \ ''; in - '' - # try to create the partition, if it fails, try to change the type and name - if ! sgdisk ${createArgs} ${args} - then - sgdisk ${args} - fi - # ensure /dev/disk/by-path/..-partN exists before continuing - partprobe "${config.device}" || : # sometimes partprobe fails, but the partitions are still up2date - udevadm trigger --subsystem-match=block - udevadm settle - '' + '' + # try to create the partition, if it fails, try to change the type and name + if ! sgdisk ${createArgs} ${args} + then + sgdisk ${args} + fi + # ensure /dev/disk/by-path/..-partN exists before continuing + partprobe "${config.device}" || : # sometimes partprobe fails, but the partitions are still up2date + udevadm trigger --subsystem-match=block + udevadm settle + '' ) sortedPartitions} - ${ - lib.optionalString (sortedHybridPartitions != []) - ("sgdisk -h " - + (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions)) - + ( - lib.optionalString (!config.efiGptPartitionFirst) ":EE " - ) - + ''"${parent.device}"'') - } - ${lib.concatMapStrings (p: - p.hybrid._create - ) - sortedHybridPartitions - } + ${lib.optionalString (sortedHybridPartitions != [ ]) ( + "sgdisk -h " + + (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions)) + + (lib.optionalString (!config.efiGptPartitionFirst) ":EE ") + + ''"${parent.device}"'' + )} + ${lib.concatMapStrings (p: p.hybrid._create) sortedHybridPartitions} - ${lib.concatStrings (map (partition: '' - ${lib.optionalString (partition.content != null) partition.content._create} - '') sortedPartitions)} + ${lib.concatStrings ( + map (partition: '' + ${lib.optionalString (partition.content != null) partition.content._create} + '') sortedPartitions + )} ''; }; _mount = diskoLib.mkMountOption { inherit config options; default = let - partMounts = lib.foldr lib.recursiveUpdate { } (map - (partition: - lib.optionalAttrs (partition.content != null) partition.content._mount + partMounts = lib.foldr lib.recursiveUpdate { } ( + map (partition: lib.optionalAttrs (partition.content != null) partition.content._mount) ( + lib.attrValues config.partitions ) - (lib.attrValues config.partitions)); + ); in { dev = partMounts.dev or ""; @@ -276,11 +326,11 @@ in inherit config options; default = let - partMounts = lib.foldr lib.recursiveUpdate { } (map - (partition: - lib.optionalAttrs (partition.content != null) partition.content._unmount + partMounts = lib.foldr lib.recursiveUpdate { } ( + map (partition: lib.optionalAttrs (partition.content != null) partition.content._unmount) ( + lib.attrValues config.partitions ) - (lib.attrValues config.partitions)); + ); in { dev = partMounts.dev or ""; @@ -290,30 +340,31 @@ in _config = lib.mkOption { internal = true; readOnly = true; - default = (map - (partition: - lib.optional (partition.content != null) partition.content._config - ) - (lib.attrValues config.partitions)) - ++ (lib.optional (lib.any (part: part.type == "EF02") (lib.attrValues config.partitions)) { - boot.loader.grub.devices = [ config.device ]; - }); + default = + (map (partition: lib.optional (partition.content != null) partition.content._config) ( + lib.attrValues config.partitions + )) + ++ (lib.optional (lib.any (part: part.type == "EF02") (lib.attrValues config.partitions)) { + boot.loader.grub.devices = [ config.device ]; + }); description = "NixOS configuration"; }; _pkgs = lib.mkOption { internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: + default = + pkgs: [ pkgs.gptfdisk pkgs.systemdMinimal pkgs.parted # for partprobe - ] ++ lib.flatten (map - (partition: - lib.optional (partition.content != null) (partition.content._pkgs pkgs) + ] + ++ lib.flatten ( + map (partition: lib.optional (partition.content != null) (partition.content._pkgs pkgs)) ( + lib.attrValues config.partitions ) - (lib.attrValues config.partitions)); + ); description = "Packages"; }; }; diff --git a/lib/types/luks.nix b/lib/types/luks.nix index 738acd1..9a58b7f 100644 --- a/lib/types/luks.nix +++ b/lib/types/luks.nix @@ -1,20 +1,30 @@ -{ config, options, lib, diskoLib, parent, device, ... }: +{ + config, + options, + lib, + diskoLib, + parent, + device, + ... +}: let keyFile = - if config.settings ? "keyFile" - then config.settings.keyFile - else if config.askPassword - then ''<(set +x; echo -n "$password"; set -x)'' - else if config.passwordFile != null + if config.settings ? "keyFile" then + config.settings.keyFile + else if config.askPassword then + ''<(set +x; echo -n "$password"; set -x)'' + else if + config.passwordFile != null # do not print the password to the console - then ''<(set +x; echo -n "$(cat ${config.passwordFile})"; set -x)'' - else if config.keyFile != null then - lib.warn - ("The option `keyFile` is deprecated." - + "Use passwordFile instead if you want to use interactive login or settings.keyFile if you want to use key file login") - config.keyFile - else null; + ''<(set +x; echo -n "$(cat ${config.passwordFile})"; set -x)'' + else if config.keyFile != null then + lib.warn ( + "The option `keyFile` is deprecated." + + "Use passwordFile instead if you want to use interactive login or settings.keyFile if you want to use key file login" + ) config.keyFile + else + null; keyFileArgs = '' ${lib.optionalString (keyFile != null) "--key-file ${keyFile}"} \ ${lib.optionalString (lib.hasAttr "keyFileSize" config.settings) "--keyfile-size ${builtins.toString config.settings.keyFileSize}"} \ @@ -23,7 +33,10 @@ let cryptsetupOpen = '' cryptsetup open "${config.device}" "${config.name}" \ ${lib.optionalString (config.settings.allowDiscards or false) "--allow-discards"} \ - ${lib.optionalString (config.settings.bypassWorkqueues or false) "--perf-no_read_workqueue --perf-no_write_workqueue"} \ + ${ + lib.optionalString (config.settings.bypassWorkqueues or false + ) "--perf-no_read_workqueue --perf-no_write_workqueue" + } \ ${toString config.extraOpenArgs} \ ${keyFileArgs} \ ''; @@ -58,7 +71,7 @@ in }; askPassword = lib.mkOption { type = lib.types.bool; - default = config.keyFile == null && config.passwordFile == null && (! config.settings ? "keyFile"); + default = config.keyFile == null && config.passwordFile == null && (!config.settings ? "keyFile"); defaultText = "true if neither keyFile nor passwordFile are set"; description = "Whether to ask for a password for initial encryption"; }; @@ -66,13 +79,14 @@ in type = lib.types.attrsOf lib.types.anything; default = { }; description = "LUKS settings (as defined in configuration.nix in boot.initrd.luks.devices.)"; - example = ''{ - keyFile = "/tmp/disk.key"; - keyFileSize = 2048; - keyFileOffset = 1024; - fallbackToPassword = true; - allowDiscards = true; - }; + example = '' + { + keyFile = "/tmp/disk.key"; + keyFileSize = 2048; + keyFileOffset = 1024; + fallbackToPassword = true; + allowDiscards = true; + }; ''; }; additionalKeyFiles = lib.mkOption { @@ -98,7 +112,10 @@ in description = "Extra arguments to pass to `cryptsetup luksOpen` when opening"; example = [ "--timeout 10" ]; }; - content = diskoLib.deviceType { parent = config; device = "/dev/mapper/${config.name}"; }; + content = diskoLib.deviceType { + parent = config; + device = "/dev/mapper/${config.name}"; + }; _parent = lib.mkOption { internal = true; default = parent; @@ -107,8 +124,7 @@ in internal = true; readOnly = true; type = lib.types.functionTo diskoLib.jsonType; - default = dev: - lib.optionalAttrs (config.content != null) (config.content._meta dev); + default = dev: lib.optionalAttrs (config.content != null) (config.content._meta dev); description = "Metadata"; }; _create = diskoLib.mkCreateOption { @@ -136,9 +152,11 @@ in ''} cryptsetup -q luksFormat "${config.device}" ${toString config.extraFormatArgs} ${keyFileArgs} ${cryptsetupOpen} --persistent - ${toString (lib.forEach config.additionalKeyFiles (keyFile: '' - cryptsetup luksAddKey "${config.device}" ${keyFile} ${keyFileArgs} - ''))} + ${toString ( + lib.forEach config.additionalKeyFiles (keyFile: '' + cryptsetup luksAddKey "${config.device}" ${keyFile} ${keyFileArgs} + '') + )} fi ${lib.optionalString (config.content != null) config.content._create} ''; @@ -176,34 +194,42 @@ in let contentUnmount = config.content._unmount; in - { - dev = '' - ${lib.optionalString (config.content != null) contentUnmount.dev or ""} - if cryptsetup status "${config.name}" >/dev/null 2>/dev/null; then - cryptsetup close "${config.name}" - fi - ''; - }; + { + dev = '' + ${lib.optionalString (config.content != null) contentUnmount.dev or ""} + if cryptsetup status "${config.name}" >/dev/null 2>/dev/null; then + cryptsetup close "${config.name}" + fi + ''; + }; }; _config = lib.mkOption { internal = true; readOnly = true; - default = [ ] + default = + [ ] # If initrdUnlock is true, then add a device entry to the initrd.luks.devices config. ++ (lib.optional config.initrdUnlock [ - { - boot.initrd.luks.devices.${config.name} = { - inherit (config) device; - } // config.settings; - } - ]) ++ (lib.optional (config.content != null) config.content._config); + { + boot.initrd.luks.devices.${config.name} = { + inherit (config) device; + } // config.settings; + } + ]) + ++ (lib.optional (config.content != null) config.content._config); description = "NixOS configuration"; }; _pkgs = lib.mkOption { internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: [ pkgs.gnugrep pkgs.cryptsetup ] ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs)); + default = + pkgs: + [ + pkgs.gnugrep + pkgs.cryptsetup + ] + ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs)); description = "Packages"; }; }; diff --git a/lib/types/lvm_pv.nix b/lib/types/lvm_pv.nix index 6b0ae41..350482c 100644 --- a/lib/types/lvm_pv.nix +++ b/lib/types/lvm_pv.nix @@ -1,4 +1,12 @@ -{ config, options, lib, diskoLib, parent, device, ... }: +{ + config, + options, + lib, + diskoLib, + parent, + device, + ... +}: { options = { type = lib.mkOption { @@ -55,7 +63,10 @@ internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: [ pkgs.gnugrep pkgs.lvm2 ]; + default = pkgs: [ + pkgs.gnugrep + pkgs.lvm2 + ]; description = "Packages"; }; }; diff --git a/lib/types/lvm_vg.nix b/lib/types/lvm_vg.nix index b396fee..f40d0ed 100644 --- a/lib/types/lvm_vg.nix +++ b/lib/types/lvm_vg.nix @@ -1,14 +1,22 @@ -{ config, options, lib, diskoLib, ... }: +{ + config, + options, + lib, + diskoLib, + ... +}: let # Load kernel modules to ensure device mapper types are available kernelModules = [ # Prevent unbootable systems if LVM snapshots are present at boot time. "dm-snapshot" - ] ++ - lib.filter (x: x != "") (map - (lv: lib.optionalString (lv.lvm_type != null && lv.lvm_type != "thinlv") "dm-${lv.lvm_type}") - (lib.attrValues config.lvs)); + ] + ++ lib.filter (x: x != "") ( + map (lv: lib.optionalString (lv.lvm_type != null && lv.lvm_type != "thinlv") "dm-${lv.lvm_type}") ( + lib.attrValues config.lvs + ) + ); in { options = { @@ -23,44 +31,65 @@ in description = "Type"; }; lvs = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({ name, ... }@lv: { - options = { - name = lib.mkOption { - type = lib.types.str; - default = name; - description = "Name of the logical volume"; - }; - priority = lib.mkOption { - type = lib.types.int; - default = (if lv.config.lvm_type == "thin-pool" then 501 else 1000) + (if lib.hasInfix "100%" lv.config.size then 251 else 0); - defaultText = lib.literalExpression '' - if (lib.hasInfix "100%" lv.config.size) then 9001 else 1000 - ''; - description = "Priority of the logical volume, smaller values are created first"; - }; - size = lib.mkOption { - type = lib.types.str; # TODO lvm size type - description = "Size of the logical volume"; - }; - lvm_type = lib.mkOption { - # TODO: add raid10 - type = lib.types.nullOr (lib.types.enum [ "mirror" "raid0" "raid1" "raid4" "raid5" "raid6" "thin-pool" "thinlv" ]); # TODO add all lib.types - default = null; # maybe there is always a default type? - description = "LVM type"; - }; - extraArgs = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - description = "Extra arguments"; - }; - pool = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Name of pool LV that this LV belongs to"; - }; - content = diskoLib.partitionType { parent = config; device = "/dev/${config.name}/${lv.config.name}"; }; - }; - })); + type = lib.types.attrsOf ( + lib.types.submodule ( + { name, ... }@lv: + { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + description = "Name of the logical volume"; + }; + priority = lib.mkOption { + type = lib.types.int; + default = + (if lv.config.lvm_type == "thin-pool" then 501 else 1000) + + (if lib.hasInfix "100%" lv.config.size then 251 else 0); + defaultText = lib.literalExpression '' + if (lib.hasInfix "100%" lv.config.size) then 9001 else 1000 + ''; + description = "Priority of the logical volume, smaller values are created first"; + }; + size = lib.mkOption { + type = lib.types.str; # TODO lvm size type + description = "Size of the logical volume"; + }; + lvm_type = lib.mkOption { + # TODO: add raid10 + type = lib.types.nullOr ( + lib.types.enum [ + "mirror" + "raid0" + "raid1" + "raid4" + "raid5" + "raid6" + "thin-pool" + "thinlv" + ] + ); # TODO add all lib.types + default = null; # maybe there is always a default type? + description = "LVM type"; + }; + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Extra arguments"; + }; + pool = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "Name of pool LV that this LV belongs to"; + }; + content = diskoLib.partitionType { + parent = config; + device = "/dev/${config.name}/${lv.config.name}"; + }; + }; + } + ) + ); default = { }; description = "LVS for the volume group"; }; @@ -68,12 +97,15 @@ in internal = true; readOnly = true; type = diskoLib.jsonType; - default = - diskoLib.deepMergeMap - (lv: - lib.optionalAttrs (lv.content != null) (lv.content._meta [ "lvm_vg" config.name ]) - ) - (lib.attrValues config.lvs); + default = diskoLib.deepMergeMap ( + lv: + lib.optionalAttrs (lv.content != null) ( + lv.content._meta [ + "lvm_vg" + config.name + ] + ) + ) (lib.attrValues config.lvs); description = "Metadata"; }; _create = diskoLib.mkCreateOption { @@ -93,8 +125,14 @@ in if ! lvdisplay "${config.name}/${lv.name}"; then lvcreate \ --yes \ - ${if (lv.lvm_type == "thinlv") then "-V" - else if lib.hasInfix "%" lv.size then "-l" else "-L"} \ + ${ + if (lv.lvm_type == "thinlv") then + "-V" + else if lib.hasInfix "%" lv.size then + "-l" + else + "-L" + } \ ${if lib.hasSuffix "%" lv.size then "${lv.size}FREE" else lv.size} \ -n "${lv.name}" \ ${lib.optionalString (lv.lvm_type == "thinlv") "--thinpool=${lv.pool}"} \ @@ -113,11 +151,9 @@ in inherit config options; default = let - lvMounts = diskoLib.deepMergeMap - (lv: - lib.optionalAttrs (lv.content != null) lv.content._mount - ) - (lib.attrValues config.lvs); + lvMounts = diskoLib.deepMergeMap (lv: lib.optionalAttrs (lv.content != null) lv.content._mount) ( + lib.attrValues config.lvs + ); in { dev = '' @@ -131,12 +167,11 @@ in inherit config options; default = let - lvMounts = diskoLib.deepMergeMap - (lv: - lib.optionalAttrs (lv.content != null) lv.content._unmount - ) - (lib.attrValues config.lvs); - in { + lvMounts = diskoLib.deepMergeMap (lv: lib.optionalAttrs (lv.content != null) lv.content._unmount) ( + lib.attrValues config.lvs + ); + in + { dev = '' ${lib.concatMapStrings (x: x.dev or "") (lib.attrValues lvMounts)} vgchange -a n @@ -147,36 +182,35 @@ in _config = lib.mkOption { internal = true; readOnly = true; - default = [{ boot.initrd.kernelModules = kernelModules; }] ++ - map - (lv: [ - (lib.optional (lv.content != null) lv.content._config) - (lib.optional (lv.lvm_type != null) { - boot.initrd.kernelModules = [ + default = + [ { boot.initrd.kernelModules = kernelModules; } ] + ++ map (lv: [ + (lib.optional (lv.content != null) lv.content._config) + (lib.optional (lv.lvm_type != null) { + boot.initrd.kernelModules = + [ (if lv.lvm_type == "mirror" then "dm-mirror" else "dm-raid") ] ++ lib.optional (lv.lvm_type == "raid0") "raid0" ++ lib.optional (lv.lvm_type == "raid1") "raid1" # ++ lib.optional (lv.lvm_type == "raid10") "raid10" - ++ lib.optional - (lv.lvm_type == "raid4" || - lv.lvm_type == "raid5" || - lv.lvm_type == "raid6") "raid456"; + ++ lib.optional ( + lv.lvm_type == "raid4" || lv.lvm_type == "raid5" || lv.lvm_type == "raid6" + ) "raid456"; - }) - ]) - (lib.attrValues config.lvs); + }) + ]) (lib.attrValues config.lvs); description = "NixOS configuration"; }; _pkgs = lib.mkOption { internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: lib.flatten (map - (lv: - lib.optional (lv.content != null) (lv.content._pkgs pkgs) - ) - (lib.attrValues config.lvs)); + default = + pkgs: + lib.flatten ( + map (lv: lib.optional (lv.content != null) (lv.content._pkgs pkgs)) (lib.attrValues config.lvs) + ); description = "Packages"; }; }; diff --git a/lib/types/mdadm.nix b/lib/types/mdadm.nix index f29d6a1..8077c0a 100644 --- a/lib/types/mdadm.nix +++ b/lib/types/mdadm.nix @@ -1,4 +1,10 @@ -{ config, options, lib, diskoLib, ... }: +{ + config, + options, + lib, + diskoLib, + ... +}: { options = { name = lib.mkOption { @@ -18,17 +24,32 @@ description = "mdadm level"; }; metadata = lib.mkOption { - type = lib.types.enum [ "1" "1.0" "1.1" "1.2" "default" "ddf" "imsm" ]; + type = lib.types.enum [ + "1" + "1.0" + "1.1" + "1.2" + "default" + "ddf" + "imsm" + ]; default = "default"; description = "Metadata"; }; - content = diskoLib.deviceType { parent = config; device = "/dev/md/${config.name}"; }; + content = diskoLib.deviceType { + parent = config; + device = "/dev/md/${config.name}"; + }; _meta = lib.mkOption { internal = true; readOnly = true; type = diskoLib.jsonType; - default = - lib.optionalAttrs (config.content != null) (config.content._meta [ "mdadm" config.name ]); + default = lib.optionalAttrs (config.content != null) ( + config.content._meta [ + "mdadm" + config.name + ] + ); description = "Metadata"; }; _create = diskoLib.mkCreateOption { @@ -54,45 +75,52 @@ }; _mount = diskoLib.mkMountOption { inherit config options; - default = - lib.optionalAttrs (config.content != null) config.content._mount; + default = lib.optionalAttrs (config.content != null) config.content._mount; # TODO we probably need to assemble the mdadm somehow }; _unmount = diskoLib.mkUnmountOption { inherit config options; - default = let - content = lib.optionalAttrs (config.content != null) config.content._unmount; - in { - fs = content.fs; - dev = '' - ${content.dev or ""} - if [ -e "/dev/md/${config.name}" ]; then - mdadm --stop "/dev/md/${config.name}" - fi - ''; - }; + default = + let + content = lib.optionalAttrs (config.content != null) config.content._unmount; + in + { + fs = content.fs; + dev = '' + ${content.dev or ""} + if [ -e "/dev/md/${config.name}" ]; then + mdadm --stop "/dev/md/${config.name}" + fi + ''; + }; }; _config = lib.mkOption { internal = true; readOnly = true; - default = - [ - (if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then { - boot.swraid.enable = true; - } else { - boot.initrd.services.swraid.enable = true; - }) - ] ++ - lib.optional (config.content != null) config.content._config; + default = [ + ( + if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then + { + boot.swraid.enable = true; + } + else + { + boot.initrd.services.swraid.enable = true; + } + ) + ] ++ lib.optional (config.content != null) config.content._config; description = "NixOS configuration"; }; _pkgs = lib.mkOption { internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: [ - pkgs.parted # for partprobe - ] ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs)); + default = + pkgs: + [ + pkgs.parted # for partprobe + ] + ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs)); description = "Packages"; }; }; diff --git a/lib/types/mdraid.nix b/lib/types/mdraid.nix index b00626a..9686ac8 100644 --- a/lib/types/mdraid.nix +++ b/lib/types/mdraid.nix @@ -1,4 +1,12 @@ -{ config, options, lib, diskoLib, parent, device, ... }: +{ + config, + options, + lib, + diskoLib, + parent, + device, + ... +}: { options = { type = lib.mkOption { diff --git a/lib/types/nodev.nix b/lib/types/nodev.nix index 6a45865..f0d3c50 100644 --- a/lib/types/nodev.nix +++ b/lib/types/nodev.nix @@ -1,4 +1,11 @@ -{ lib, config, options, diskoLib, rootMountPoint, ... }: +{ + lib, + config, + options, + diskoLib, + rootMountPoint, + ... +}: { options = { type = lib.mkOption { diff --git a/lib/types/swap.nix b/lib/types/swap.nix index 83a6a74..3bed885 100644 --- a/lib/types/swap.nix +++ b/lib/types/swap.nix @@ -1,4 +1,12 @@ -{ diskoLib, config, options, lib, parent, device, ... }: +{ + diskoLib, + config, + options, + lib, + parent, + device, + ... +}: { options = { type = lib.mkOption { @@ -14,7 +22,13 @@ discardPolicy = lib.mkOption { default = null; example = "once"; - type = lib.types.nullOr (lib.types.enum [ "once" "pages" "both" ]); + type = lib.types.nullOr ( + lib.types.enum [ + "once" + "pages" + "both" + ] + ); description = '' Specify the discard policy for the swap device. If "once", then the whole swap space is discarded at swapon invocation. If "pages", @@ -83,12 +97,8 @@ if test "''${DISKO_SKIP_SWAP:-}" != 1 && ! swapon --show | grep -q "^$(readlink -f "${config.device}") "; then swapon ${ lib.optionalString (config.discardPolicy != null) - "--discard${lib.optionalString (config.discardPolicy != "both") - "=${config.discardPolicy}" - }"} ${ - lib.optionalString (config.priority != null) - "--priority=${toString config.priority}" - } \ + "--discard${lib.optionalString (config.discardPolicy != "both") "=${config.discardPolicy}"}" + } ${lib.optionalString (config.priority != null) "--priority=${toString config.priority}"} \ --options=${lib.concatStringsSep "," config.mountOptions} \ "${config.device}" fi @@ -108,26 +118,33 @@ _config = lib.mkOption { internal = true; readOnly = true; - default = [{ - swapDevices = [{ - device = config.device; - inherit (config) discardPolicy priority; - randomEncryption = { - enable = config.randomEncryption; - # forward discard/TRIM attempts through dm-crypt - allowDiscards = config.discardPolicy != null; - }; - options = config.mountOptions; - }]; - boot.resumeDevice = lib.mkIf config.resumeDevice config.device; - }]; + default = [ + { + swapDevices = [ + { + device = config.device; + inherit (config) discardPolicy priority; + randomEncryption = { + enable = config.randomEncryption; + # forward discard/TRIM attempts through dm-crypt + allowDiscards = config.discardPolicy != null; + }; + options = config.mountOptions; + } + ]; + boot.resumeDevice = lib.mkIf config.resumeDevice config.device; + } + ]; description = "NixOS configuration"; }; _pkgs = lib.mkOption { internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: [ pkgs.gnugrep pkgs.util-linux ]; + default = pkgs: [ + pkgs.gnugrep + pkgs.util-linux + ]; description = "Packages"; }; }; diff --git a/lib/types/table.nix b/lib/types/table.nix index 6640da5..d9ce7a3 100644 --- a/lib/types/table.nix +++ b/lib/types/table.nix @@ -1,179 +1,227 @@ -{ config, options, lib, diskoLib, parent, device, ... }: { - options = lib.warn '' - The legacy table is outdated and should not be used. We recommend using the gpt type instead. - Please note that certain features, such as the test framework, may not function properly with the legacy table type. - If you encounter errors similar to: - "error: The option `disko.devices.disk.disk1.content.partitions."[definition 1-entry 1]".content._config` is read-only, but it's set multiple times," - this is likely due to the use of the legacy table type. - for a migration you can follow the guide at https://github.com/nix-community/disko/blob/master/docs/table-to-gpt.md - '' - { - type = lib.mkOption { - type = lib.types.enum [ "table" ]; - internal = true; - description = "Partition table"; - }; - device = lib.mkOption { - type = lib.types.str; - default = device; - description = "Device to partition"; - }; - format = lib.mkOption { - type = lib.types.enum [ "gpt" "msdos" ]; - default = "gpt"; - description = "The kind of partition table"; - }; - partitions = lib.mkOption { - type = lib.types.listOf (lib.types.submodule ({ name, ... }@partition: { - options = { - part-type = lib.mkOption { - type = lib.types.enum [ "primary" "logical" "extended" ]; - default = "primary"; - description = "Partition type"; - }; - fs-type = lib.mkOption { - type = lib.types.nullOr (lib.types.enum [ "btrfs" "ext2" "ext3" "ext4" "fat16" "fat32" "hfs" "hfs+" "linux-swap" "ntfs" "reiserfs" "udf" "xfs" ]); - default = null; - description = "Filesystem type to use"; - }; - name = lib.mkOption { - type = lib.types.nullOr lib.types.str; - description = "Name of the partition"; - }; - start = lib.mkOption { - type = lib.types.str; - default = "0%"; - description = "Start of the partition"; - }; - end = lib.mkOption { - type = lib.types.str; - default = "100%"; - description = "End of the partition"; - }; - flags = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - description = "Partition flags"; - }; - bootable = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether to make the partition bootable"; - }; - content = diskoLib.partitionType { parent = config; device = diskoLib.deviceNumbering config.device partition.config._index; }; - _index = lib.mkOption { - type = lib.types.int; - internal = true; - default = lib.toInt (lib.head (builtins.match ".*entry ([[:digit:]]+)]" name)); - defaultText = null; - }; - }; - })); - default = [ ]; - description = "List of partitions to add to the partition table"; - }; - _parent = lib.mkOption { - internal = true; - default = parent; - }; - _meta = lib.mkOption { - internal = true; - readOnly = true; - type = lib.types.functionTo diskoLib.jsonType; - default = dev: - lib.foldr lib.recursiveUpdate { } (lib.imap - (_index: partition: - lib.optionalAttrs (partition.content != null) (partition.content._meta dev) + config, + options, + lib, + diskoLib, + parent, + device, + ... +}: +{ + options = + lib.warn + '' + The legacy table is outdated and should not be used. We recommend using the gpt type instead. + Please note that certain features, such as the test framework, may not function properly with the legacy table type. + If you encounter errors similar to: + "error: The option `disko.devices.disk.disk1.content.partitions."[definition 1-entry 1]".content._config` is read-only, but it's set multiple times," + this is likely due to the use of the legacy table type. + for a migration you can follow the guide at https://github.com/nix-community/disko/blob/master/docs/table-to-gpt.md + '' + { + type = lib.mkOption { + type = lib.types.enum [ "table" ]; + internal = true; + description = "Partition table"; + }; + device = lib.mkOption { + type = lib.types.str; + default = device; + description = "Device to partition"; + }; + format = lib.mkOption { + type = lib.types.enum [ + "gpt" + "msdos" + ]; + default = "gpt"; + description = "The kind of partition table"; + }; + partitions = lib.mkOption { + type = lib.types.listOf ( + lib.types.submodule ( + { name, ... }@partition: + { + options = { + part-type = lib.mkOption { + type = lib.types.enum [ + "primary" + "logical" + "extended" + ]; + default = "primary"; + description = "Partition type"; + }; + fs-type = lib.mkOption { + type = lib.types.nullOr ( + lib.types.enum [ + "btrfs" + "ext2" + "ext3" + "ext4" + "fat16" + "fat32" + "hfs" + "hfs+" + "linux-swap" + "ntfs" + "reiserfs" + "udf" + "xfs" + ] + ); + default = null; + description = "Filesystem type to use"; + }; + name = lib.mkOption { + type = lib.types.nullOr lib.types.str; + description = "Name of the partition"; + }; + start = lib.mkOption { + type = lib.types.str; + default = "0%"; + description = "Start of the partition"; + }; + end = lib.mkOption { + type = lib.types.str; + default = "100%"; + description = "End of the partition"; + }; + flags = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Partition flags"; + }; + bootable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Whether to make the partition bootable"; + }; + content = diskoLib.partitionType { + parent = config; + device = diskoLib.deviceNumbering config.device partition.config._index; + }; + _index = lib.mkOption { + type = lib.types.int; + internal = true; + default = lib.toInt (lib.head (builtins.match ".*entry ([[:digit:]]+)]" name)); + defaultText = null; + }; + }; + } ) - config.partitions); - description = "Metadata"; + ); + default = [ ]; + description = "List of partitions to add to the partition table"; + }; + _parent = lib.mkOption { + internal = true; + default = parent; + }; + _meta = lib.mkOption { + internal = true; + readOnly = true; + type = lib.types.functionTo diskoLib.jsonType; + default = + dev: + lib.foldr lib.recursiveUpdate { } ( + lib.imap ( + _index: partition: lib.optionalAttrs (partition.content != null) (partition.content._meta dev) + ) config.partitions + ); + description = "Metadata"; + }; + _create = diskoLib.mkCreateOption { + inherit config options; + default = '' + if ! blkid "${config.device}" >/dev/null; then + parted -s "${config.device}" -- mklabel ${config.format} + ${lib.concatStrings ( + map (partition: '' + ${lib.optionalString (config.format == "gpt") '' + parted -s "${config.device}" -- mkpart "${diskoLib.hexEscapeUdevSymlink partition.name}" ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end} + ''} + ${lib.optionalString (config.format == "msdos") '' + parted -s "${config.device}" -- mkpart ${partition.part-type} ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end} + ''} + # ensure /dev/disk/by-path/..-partN exists before continuing + partprobe "${config.device}" + udevadm trigger --subsystem-match=block + udevadm settle + ${lib.optionalString partition.bootable '' + parted -s "${config.device}" -- set ${toString partition._index} boot on + ''} + ${lib.concatMapStringsSep "" (flag: '' + parted -s "${config.device}" -- set ${toString partition._index} ${flag} on + '') partition.flags} + # ensure further operations can detect new partitions + partprobe "${config.device}" + udevadm trigger --subsystem-match=block + udevadm settle + '') config.partitions + )} + fi + ${lib.concatStrings ( + map (partition: '' + ${lib.optionalString (partition.content != null) partition.content._create} + '') config.partitions + )} + ''; + }; + _mount = diskoLib.mkMountOption { + inherit config options; + default = + let + partMounts = lib.foldr lib.recursiveUpdate { } ( + map ( + partition: lib.optionalAttrs (partition.content != null) partition.content._mount + ) config.partitions + ); + in + { + dev = partMounts.dev or ""; + fs = partMounts.fs or { }; + }; + }; + _unmount = diskoLib.mkUnmountOption { + inherit config options; + default = + let + partMounts = lib.foldr lib.recursiveUpdate { } ( + map ( + partition: lib.optionalAttrs (partition.content != null) partition.content._unmount + ) config.partitions + ); + in + { + dev = partMounts.dev or ""; + fs = partMounts.fs or { }; + }; + }; + _config = lib.mkOption { + internal = true; + readOnly = true; + default = map ( + partition: lib.optional (partition.content != null) partition.content._config + ) config.partitions; + description = "NixOS configuration"; + }; + _pkgs = lib.mkOption { + internal = true; + readOnly = true; + type = lib.types.functionTo (lib.types.listOf lib.types.package); + default = + pkgs: + [ + pkgs.parted + pkgs.systemdMinimal + ] + ++ lib.flatten ( + map ( + partition: lib.optional (partition.content != null) (partition.content._pkgs pkgs) + ) config.partitions + ); + description = "Packages"; + }; }; - _create = diskoLib.mkCreateOption { - inherit config options; - default = '' - if ! blkid "${config.device}" >/dev/null; then - parted -s "${config.device}" -- mklabel ${config.format} - ${lib.concatStrings (map (partition: '' - ${lib.optionalString (config.format == "gpt") '' - parted -s "${config.device}" -- mkpart "${diskoLib.hexEscapeUdevSymlink partition.name}" ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end} - ''} - ${lib.optionalString (config.format == "msdos") '' - parted -s "${config.device}" -- mkpart ${partition.part-type} ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end} - ''} - # ensure /dev/disk/by-path/..-partN exists before continuing - partprobe "${config.device}" - udevadm trigger --subsystem-match=block - udevadm settle - ${lib.optionalString partition.bootable '' - parted -s "${config.device}" -- set ${toString partition._index} boot on - ''} - ${lib.concatMapStringsSep "" (flag: '' - parted -s "${config.device}" -- set ${toString partition._index} ${flag} on - '') partition.flags} - # ensure further operations can detect new partitions - partprobe "${config.device}" - udevadm trigger --subsystem-match=block - udevadm settle - '') config.partitions)} - fi - ${lib.concatStrings (map (partition: '' - ${lib.optionalString (partition.content != null) partition.content._create} - '') config.partitions)} - ''; - }; - _mount = diskoLib.mkMountOption { - inherit config options; - default = - let - partMounts = lib.foldr lib.recursiveUpdate { } (map - (partition: - lib.optionalAttrs (partition.content != null) partition.content._mount - ) - config.partitions); - in - { - dev = partMounts.dev or ""; - fs = partMounts.fs or { }; - }; - }; - _unmount = diskoLib.mkUnmountOption { - inherit config options; - default = - let - partMounts = lib.foldr lib.recursiveUpdate { } (map - (partition: - lib.optionalAttrs (partition.content != null) partition.content._unmount - ) - config.partitions); - in - { - dev = partMounts.dev or ""; - fs = partMounts.fs or { }; - }; - }; - _config = lib.mkOption { - internal = true; - readOnly = true; - default = - map - (partition: - lib.optional (partition.content != null) partition.content._config - ) - config.partitions; - description = "NixOS configuration"; - }; - _pkgs = lib.mkOption { - internal = true; - readOnly = true; - type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: - [ pkgs.parted pkgs.systemdMinimal ] ++ lib.flatten (map - (partition: - lib.optional (partition.content != null) (partition.content._pkgs pkgs) - ) - config.partitions); - description = "Packages"; - }; - }; } diff --git a/lib/types/zfs.nix b/lib/types/zfs.nix index f9e9778..fc987f1 100644 --- a/lib/types/zfs.nix +++ b/lib/types/zfs.nix @@ -1,4 +1,12 @@ -{ config, options, lib, diskoLib, parent, device, ... }: +{ + config, + options, + lib, + diskoLib, + parent, + device, + ... +}: { options = { type = lib.mkOption { diff --git a/lib/types/zfs_fs.nix b/lib/types/zfs_fs.nix index 1399ce9..129ddf5 100644 --- a/lib/types/zfs_fs.nix +++ b/lib/types/zfs_fs.nix @@ -1,4 +1,12 @@ -{ config, options, lib, diskoLib, rootMountPoint, parent, ... }: +{ + config, + options, + lib, + diskoLib, + rootMountPoint, + parent, + ... +}: { options = { name = lib.mkOption { @@ -58,45 +66,53 @@ default = true; }; - _create = diskoLib.mkCreateOption - { - inherit config options; - # -u prevents mounting newly created datasets, which is - # important to prevent accidental shadowing of mount points - # since (create order != mount order) - # -p creates parents automatically - default = - let - createOptions = (lib.optionalAttrs (config.mountpoint != null) { mountpoint = config.mountpoint; }) // config.options; - # All options defined as PROP_ONETIME or PROP_ONETIME_DEFAULT in https://github.com/openzfs/zfs/blob/master/module/zcommon/zfs_prop.c - onetimeProperties = [ - "encryption" - "casesensitivity" - "utf8only" - "normalization" - "volblocksize" - "pbkdf2iters" - "pbkdf2salt" - "keyformat" - ]; - updateOptions = builtins.removeAttrs createOptions onetimeProperties; - in - '' - if ! zfs get type ${config._name} >/dev/null 2>&1; then - ${if config._createFilesystem then '' - zfs create -up ${config._name} \ - ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-o ${n}=${v}") (createOptions))} - '' else '' - # don't create anything for root dataset of zpools - true - ''} - ${lib.optionalString (updateOptions != {}) '' + _create = diskoLib.mkCreateOption { + inherit config options; + # -u prevents mounting newly created datasets, which is + # important to prevent accidental shadowing of mount points + # since (create order != mount order) + # -p creates parents automatically + default = + let + createOptions = + (lib.optionalAttrs (config.mountpoint != null) { mountpoint = config.mountpoint; }) + // config.options; + # All options defined as PROP_ONETIME or PROP_ONETIME_DEFAULT in https://github.com/openzfs/zfs/blob/master/module/zcommon/zfs_prop.c + onetimeProperties = [ + "encryption" + "casesensitivity" + "utf8only" + "normalization" + "volblocksize" + "pbkdf2iters" + "pbkdf2salt" + "keyformat" + ]; + updateOptions = builtins.removeAttrs createOptions onetimeProperties; + in + '' + if ! zfs get type ${config._name} >/dev/null 2>&1; then + ${ + if config._createFilesystem then + '' + zfs create -up ${config._name} \ + ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-o ${n}=${v}") (createOptions))} + '' + else + '' + # don't create anything for root dataset of zpools + true + '' + } + ${lib.optionalString (updateOptions != { }) '' else - zfs set -u ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${v}") updateOptions)} ${config._name} - ''} - fi - ''; - }; + zfs set -u ${ + lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${v}") updateOptions) + } ${config._name} + ''} + fi + ''; + }; _mount = diskoLib.mkMountOption { inherit config options; @@ -107,17 +123,20 @@ zfs load-key ${config._name} fi ''; - }) // lib.optionalAttrs (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") { - fs.${config.mountpoint} = '' - if ! findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then - mount ${config._name} "${rootMountPoint}${config.mountpoint}" \ - -o X-mount.mkdir \ - ${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \ - ${lib.optionalString ((config.options.mountpoint or "") != "legacy") "-o zfsutil"} \ - -t zfs - fi - ''; - }; + }) + // lib.optionalAttrs + (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") + { + fs.${config.mountpoint} = '' + if ! findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then + mount ${config._name} "${rootMountPoint}${config.mountpoint}" \ + -o X-mount.mkdir \ + ${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \ + ${lib.optionalString ((config.options.mountpoint or "") != "legacy") "-o zfsutil"} \ + -t zfs + fi + ''; + }; }; _unmount = diskoLib.mkUnmountOption { @@ -125,26 +144,32 @@ default = (lib.optionalAttrs (config.options.keylocation or "none" != "none") { dev = "zfs unload-key ${config.name}"; - }) // lib.optionalAttrs (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") { - fs.${config.mountpoint} = '' - if findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then - umount "${rootMountPoint}${config.mountpoint}" - fi - ''; - }; + }) + // lib.optionalAttrs + (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") + { + fs.${config.mountpoint} = '' + if findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then + umount "${rootMountPoint}${config.mountpoint}" + fi + ''; + }; }; _config = lib.mkOption { internal = true; readOnly = true; default = - lib.optional (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") { - fileSystems.${config.mountpoint} = { - device = "${config._name}"; - fsType = "zfs"; - options = config.mountOptions ++ lib.optional ((config.options.mountpoint or "") != "legacy") "zfsutil"; + lib.optional (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") + { + fileSystems.${config.mountpoint} = { + device = "${config._name}"; + fsType = "zfs"; + options = + config.mountOptions + ++ lib.optional ((config.options.mountpoint or "") != "legacy") "zfsutil"; + }; }; - }; description = "NixOS configuration"; }; @@ -157,4 +182,3 @@ }; }; } - diff --git a/lib/types/zfs_volume.nix b/lib/types/zfs_volume.nix index cc76066..c2aa03f 100644 --- a/lib/types/zfs_volume.nix +++ b/lib/types/zfs_volume.nix @@ -1,4 +1,11 @@ -{ config, options, lib, diskoLib, parent, ... }: +{ + config, + options, + lib, + diskoLib, + parent, + ... +}: { options = { name = lib.mkOption { @@ -35,7 +42,10 @@ description = "Size of the dataset"; }; - content = diskoLib.partitionType { parent = config; device = "/dev/zvol/${config._parent.name}/${config.name}"; }; + content = diskoLib.partitionType { + parent = config; + device = "/dev/zvol/${config._parent.name}/${config.name}"; + }; _parent = lib.mkOption { internal = true; @@ -45,8 +55,7 @@ internal = true; readOnly = true; type = lib.types.functionTo diskoLib.jsonType; - default = dev: - lib.optionalAttrs (config.content != null) (config.content._meta dev); + default = dev: lib.optionalAttrs (config.content != null) (config.content._meta dev); description = "Metadata"; }; _create = diskoLib.mkCreateOption { @@ -83,31 +92,34 @@ inherit config options; default = { dev = '' - ${lib.optionalString (config.options.keylocation or "none" != "none") "zfs unload-key ${config.name}"} + ${lib.optionalString ( + config.options.keylocation or "none" != "none" + ) "zfs unload-key ${config.name}"} ${config.content._unmount.dev or ""} ''; - fs = config.content._unmount.fs or {}; + fs = config.content._unmount.fs or { }; }; }; _config = lib.mkOption { internal = true; readOnly = true; - default = - lib.optional (config.content != null) config.content._config; + default = lib.optional (config.content != null) config.content._config; description = "NixOS configuration"; }; _pkgs = lib.mkOption { internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: [ - pkgs.util-linux - pkgs.parted # for partprobe - ] ++ lib.optionals (config.content != null) (config.content._pkgs pkgs); + default = + pkgs: + [ + pkgs.util-linux + pkgs.parted # for partprobe + ] + ++ lib.optionals (config.content != null) (config.content._pkgs pkgs); description = "Packages"; }; }; } - diff --git a/lib/types/zpool.nix b/lib/types/zpool.nix index 8034048..2f4530d 100644 --- a/lib/types/zpool.nix +++ b/lib/types/zpool.nix @@ -1,4 +1,11 @@ -{ config, options, lib, diskoLib, rootMountPoint, ... }: +{ + config, + options, + lib, + diskoLib, + rootMountPoint, + ... +}: let # TODO: Consider expanding to handle `file` and `draid` mode options. modeOptions = [ @@ -63,134 +70,161 @@ in }; }; }; - type = (lib.types.oneOf [ - (lib.types.enum modeOptions) - (lib.types.attrsOf (diskoLib.subType { - types = { - topology = - let - vdev = lib.types.submodule ({ ... }: { - options = { - mode = lib.mkOption { - type = lib.types.enum modeOptions; - default = ""; - description = "Mode of the zfs vdev"; - }; - members = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "Members of the vdev"; - }; - }; - }); - in - lib.types.submodule - ({ ... }: { - options = { - type = lib.mkOption { - type = lib.types.enum [ "topology" ]; - default = "topology"; - internal = true; - description = "Type"; - }; - # zfs device types - vdev = lib.mkOption { - type = lib.types.listOf vdev; - default = [ ]; - description = '' - A list of storage vdevs. See - https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Virtual_Devices_(vdevs) - for details. - ''; - example = [ - { - mode = "mirror"; - members = [ "x" "y" ]; - } - { - members = [ "z" ]; - } - ]; - }; - spare = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - description = '' - A list of devices to use as hot spares. See - https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Hot_Spares - for details. - ''; - example = [ "x" "y" ]; - }; - log = lib.mkOption { - type = lib.types.listOf vdev; - default = [ ]; - description = '' - A list of vdevs used for the zfs intent log (ZIL). See - https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Intent_Log - for details. - ''; - example = [ - { - mode = "mirror"; - members = [ "x" "y" ]; - } - { - members = [ "z" ]; - } - ]; - }; - dedup = lib.mkOption { - type = lib.types.listOf vdev; - default = [ ]; - description = '' - A list of vdevs used for the deduplication table. See - https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#dedup - for details. - ''; - example = [ - { - mode = "mirror"; - members = [ "x" "y" ]; - } - { - members = [ "z" ]; - } - ]; - }; - special = lib.mkOption { - type = lib.types.either (lib.types.listOf vdev) (lib.types.nullOr vdev); - default = [ ]; - description = '' - A list of vdevs used as special devices. See - https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#special - for details. - ''; - example = [ - { - mode = "mirror"; - members = [ "x" "y" ]; - } - { - members = [ "z" ]; - } - ]; - }; - cache = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = [ ]; - description = '' - A dedicated zfs cache device (L2ARC). See - https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Cache_Devices - for details. - ''; - example = [ "x" "y" ]; - }; - }; - }); - }; - extraArgs.parent = config; - })) - ]); + type = ( + lib.types.oneOf [ + (lib.types.enum modeOptions) + (lib.types.attrsOf ( + diskoLib.subType { + types = { + topology = + let + vdev = lib.types.submodule ( + { ... }: + { + options = { + mode = lib.mkOption { + type = lib.types.enum modeOptions; + default = ""; + description = "Mode of the zfs vdev"; + }; + members = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "Members of the vdev"; + }; + }; + } + ); + in + lib.types.submodule ( + { ... }: + { + options = { + type = lib.mkOption { + type = lib.types.enum [ "topology" ]; + default = "topology"; + internal = true; + description = "Type"; + }; + # zfs device types + vdev = lib.mkOption { + type = lib.types.listOf vdev; + default = [ ]; + description = '' + A list of storage vdevs. See + https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Virtual_Devices_(vdevs) + for details. + ''; + example = [ + { + mode = "mirror"; + members = [ + "x" + "y" + ]; + } + { + members = [ "z" ]; + } + ]; + }; + spare = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = '' + A list of devices to use as hot spares. See + https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Hot_Spares + for details. + ''; + example = [ + "x" + "y" + ]; + }; + log = lib.mkOption { + type = lib.types.listOf vdev; + default = [ ]; + description = '' + A list of vdevs used for the zfs intent log (ZIL). See + https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Intent_Log + for details. + ''; + example = [ + { + mode = "mirror"; + members = [ + "x" + "y" + ]; + } + { + members = [ "z" ]; + } + ]; + }; + dedup = lib.mkOption { + type = lib.types.listOf vdev; + default = [ ]; + description = '' + A list of vdevs used for the deduplication table. See + https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#dedup + for details. + ''; + example = [ + { + mode = "mirror"; + members = [ + "x" + "y" + ]; + } + { + members = [ "z" ]; + } + ]; + }; + special = lib.mkOption { + type = lib.types.either (lib.types.listOf vdev) (lib.types.nullOr vdev); + default = [ ]; + description = '' + A list of vdevs used as special devices. See + https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#special + for details. + ''; + example = [ + { + mode = "mirror"; + members = [ + "x" + "y" + ]; + } + { + members = [ "z" ]; + } + ]; + }; + cache = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = '' + A dedicated zfs cache device (L2ARC). See + https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Cache_Devices + for details. + ''; + example = [ + "x" + "y" + ]; + }; + }; + } + ); + }; + extraArgs.parent = config; + } + )) + ] + ); description = "Mode of the ZFS pool"; }; options = lib.mkOption { @@ -214,18 +248,25 @@ in description = "Options to pass to mount"; }; datasets = lib.mkOption { - type = lib.types.attrsOf (diskoLib.subType { - types = { inherit (diskoLib.types) zfs_fs zfs_volume; }; - extraArgs.parent = config; - }); + type = lib.types.attrsOf ( + diskoLib.subType { + types = { inherit (diskoLib.types) zfs_fs zfs_volume; }; + extraArgs.parent = config; + } + ); description = "List of datasets to define"; }; _meta = lib.mkOption { internal = true; readOnly = true; type = diskoLib.jsonType; - default = - diskoLib.deepMergeMap (dataset: dataset._meta [ "zpool" config.name ]) (lib.attrValues config.datasets); + default = diskoLib.deepMergeMap ( + dataset: + dataset._meta [ + "zpool" + config.name + ] + ) (lib.attrValues config.datasets); description = "Metadata"; }; _create = diskoLib.mkCreateOption { @@ -234,14 +275,14 @@ in let formatOutput = type: mode: members: '' entries+=("${type} ${mode}=${ - lib.concatMapStringsSep " " - (d: if lib.strings.hasPrefix "/" d then d else "/dev/disk/by-partlabel/disk-${d}-zfs") members + lib.concatMapStringsSep " " ( + d: if lib.strings.hasPrefix "/" d then d else "/dev/disk/by-partlabel/disk-${d}-zfs" + ) members }") ''; formatVdev = type: vdev: formatOutput type vdev.mode vdev.members; - formatVdevList = type: vdevs: lib.concatMapStrings - (formatVdev type) - (builtins.sort (a: _: a.mode == "") vdevs); + formatVdevList = + type: vdevs: lib.concatMapStrings (formatVdev type) (builtins.sort (a: _: a.mode == "") vdevs); hasTopology = !(builtins.isString config.mode); mode = if hasTopology then "prescribed" else config.mode; topology = lib.optionalAttrs hasTopology config.mode.topology; @@ -281,18 +322,20 @@ in topology="${mode} ''${zfs_devices[*]}" else entries=() - ${lib.optionalString (hasTopology && topology.vdev != null) - (formatVdevList "" topology.vdev)} - ${lib.optionalString (hasTopology && topology.spare != []) - (formatOutput "spare" "" topology.spare)} - ${lib.optionalString (hasTopology && topology.log != []) - (formatVdevList "log" topology.log)} - ${lib.optionalString (hasTopology && topology.dedup != []) - (formatVdevList "dedup" topology.dedup)} - ${lib.optionalString (hasTopology && topology.special != null && topology.special != []) - (formatVdevList "special" (lib.lists.toList topology.special))} - ${lib.optionalString (hasTopology && topology.cache != []) - (formatOutput "cache" "" topology.cache)} + ${lib.optionalString (hasTopology && topology.vdev != null) (formatVdevList "" topology.vdev)} + ${lib.optionalString (hasTopology && topology.spare != [ ]) ( + formatOutput "spare" "" topology.spare + )} + ${lib.optionalString (hasTopology && topology.log != [ ]) (formatVdevList "log" topology.log)} + ${lib.optionalString (hasTopology && topology.dedup != [ ]) ( + formatVdevList "dedup" topology.dedup + )} + ${lib.optionalString (hasTopology && topology.special != null && topology.special != [ ]) ( + formatVdevList "special" (lib.lists.toList topology.special) + )} + ${lib.optionalString (hasTopology && topology.cache != [ ]) ( + formatOutput "cache" "" topology.cache + )} all_devices=() last_type= for line in "''${entries[@]}"; do @@ -337,7 +380,9 @@ in inherit config options; default = let - datasetFilesystemsMounts = diskoLib.deepMergeMap (dataset: dataset._mount.fs or {}) (lib.attrValues config.datasets); + datasetFilesystemsMounts = diskoLib.deepMergeMap (dataset: dataset._mount.fs or { }) ( + lib.attrValues config.datasets + ); in { dev = '' @@ -359,7 +404,7 @@ in zpool export "${config.name}" fi ''; - fs = diskoLib.deepMergeMap (dataset: dataset._unmount.fs or {}) (lib.attrValues config.datasets); + fs = diskoLib.deepMergeMap (dataset: dataset._unmount.fs or { }) (lib.attrValues config.datasets); }; }; _config = lib.mkOption { @@ -372,7 +417,13 @@ in internal = true; readOnly = true; type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = pkgs: [ pkgs.gnugrep pkgs.util-linux ] ++ lib.flatten (map (dataset: dataset._pkgs pkgs) (lib.attrValues config.datasets)); + default = + pkgs: + [ + pkgs.gnugrep + pkgs.util-linux + ] + ++ lib.flatten (map (dataset: dataset._pkgs pkgs) (lib.attrValues config.datasets)); description = "Packages"; }; }; diff --git a/module.nix b/module.nix index d146da3..24d2305 100644 --- a/module.nix +++ b/module.nix @@ -1,4 +1,11 @@ -{ config, lib, pkgs, extendModules, diskoLib, ... }: +{ + config, + lib, + pkgs, + extendModules, + diskoLib, + ... +}: let cfg = config.disko; @@ -107,7 +114,10 @@ in }; imageFormat = lib.mkOption { - type = lib.types.enum [ "raw" "qcow2" ]; + type = lib.types.enum [ + "raw" + "qcow2" + ]; description = "QEMU image format to use for the disk images"; default = "raw"; }; @@ -239,38 +249,49 @@ in eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix"); }; - system.build = (cfg.devices._scripts { inherit pkgs; checked = cfg.checkScripts; }) // ( - let - throwIfNoDisksDetected = _: v: if cfg.devices.disk == { } then throw "No disks defined, did you forget to import your disko config?" else v; - in - lib.mapAttrs throwIfNoDisksDetected { - # we keep these old outputs for compatibility - disko = builtins.trace "the .disko output is deprecated, please use .diskoScript instead" (cfg.devices._scripts { inherit pkgs; }).diskoScript; - diskoNoDeps = builtins.trace "the .diskoNoDeps output is deprecated, please use .diskoScriptNoDeps instead" (cfg.devices._scripts { inherit pkgs; }).diskoScriptNoDeps; + system.build = + (cfg.devices._scripts { + inherit pkgs; + checked = cfg.checkScripts; + }) + // ( + let + throwIfNoDisksDetected = + _: v: + if cfg.devices.disk == { } then + throw "No disks defined, did you forget to import your disko config?" + else + v; + in + lib.mapAttrs throwIfNoDisksDetected { + # we keep these old outputs for compatibility + disko = + builtins.trace "the .disko output is deprecated, please use .diskoScript instead" + (cfg.devices._scripts { inherit pkgs; }).diskoScript; + diskoNoDeps = + builtins.trace "the .diskoNoDeps output is deprecated, please use .diskoScriptNoDeps instead" + (cfg.devices._scripts { inherit pkgs; }).diskoScriptNoDeps; - installTest = diskoLib.testLib.makeDiskoTest { - inherit extendModules pkgs; - name = "${config.networking.hostName}-disko"; - disko-config = builtins.removeAttrs config [ "_module" ]; - testMode = "direct"; - bootCommands = cfg.tests.bootCommands; - efi = cfg.tests.efi; - enableOCR = cfg.tests.enableOCR; - extraSystemConfig = cfg.tests.extraConfig; - extraTestScript = cfg.tests.extraChecks; - }; + installTest = diskoLib.testLib.makeDiskoTest { + inherit extendModules pkgs; + name = "${config.networking.hostName}-disko"; + disko-config = builtins.removeAttrs config [ "_module" ]; + testMode = "direct"; + bootCommands = cfg.tests.bootCommands; + efi = cfg.tests.efi; + enableOCR = cfg.tests.enableOCR; + extraSystemConfig = cfg.tests.extraConfig; + extraTestScript = cfg.tests.extraChecks; + }; - vmWithDisko = lib.mkDefault config.virtualisation.vmVariantWithDisko.system.build.vmWithDisko; - } - ); + vmWithDisko = lib.mkDefault config.virtualisation.vmVariantWithDisko.system.build.vmWithDisko; + } + ); # we need to specify the keys here, so we don't get an infinite recursion error # Remember to add config keys here if they are added to types - fileSystems = lib.mkIf - cfg.enableConfig cfg.devices._config.fileSystems or { }; - boot = lib.mkIf - cfg.enableConfig cfg.devices._config.boot or { }; - swapDevices = lib.mkIf - cfg.enableConfig cfg.devices._config.swapDevices or [ ]; + fileSystems = lib.mkIf cfg.enableConfig cfg.devices._config.fileSystems or { }; + boot = lib.mkIf cfg.enableConfig cfg.devices._config.boot or { }; + swapDevices = lib.mkIf cfg.enableConfig cfg.devices._config.swapDevices or [ ]; }; } diff --git a/package.nix b/package.nix index 3464854..764d655 100644 --- a/package.nix +++ b/package.nix @@ -1,4 +1,14 @@ -{ stdenvNoCC, makeWrapper, lib, path, nix, coreutils, nixos-install-tools, binlore, diskoVersion }: +{ + stdenvNoCC, + makeWrapper, + lib, + path, + nix, + coreutils, + nixos-install-tools, + binlore, + diskoVersion, +}: let self = stdenvNoCC.mkDerivation (finalAttrs: { @@ -16,7 +26,13 @@ let chmod 755 "$out/bin/$i" wrapProgram "$out/bin/$i" \ --set DISKO_VERSION "${diskoVersion}" \ - --prefix PATH : ${lib.makeBinPath [ nix coreutils nixos-install-tools ]} \ + --prefix PATH : ${ + lib.makeBinPath [ + nix + coreutils + nixos-install-tools + ] + } \ --prefix NIX_PATH : "nixpkgs=${path}" done ''; diff --git a/scripts/create-release.sh b/scripts/create-release.sh index 9ea37dc..c5fcd2f 100755 --- a/scripts/create-release.sh +++ b/scripts/create-release.sh @@ -1,3 +1,5 @@ +#! /usr/bin/env bash + # Don't run directly! Instead, use # nix run .#create-release diff --git a/tests/bcachefs.nix b/tests/bcachefs.nix index f8806d5..f8e9e16 100644 --- a/tests/bcachefs.nix +++ b/tests/bcachefs.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/boot-raid1.nix b/tests/boot-raid1.nix index e020fdd..e05b3db 100644 --- a/tests/boot-raid1.nix +++ b/tests/boot-raid1.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/btrfs-only-root-subvolume.nix b/tests/btrfs-only-root-subvolume.nix index 818aec7..ef2d2ec 100644 --- a/tests/btrfs-only-root-subvolume.nix +++ b/tests/btrfs-only-root-subvolume.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/btrfs-subvolumes.nix b/tests/btrfs-subvolumes.nix index 7059c1a..b9cc096 100644 --- a/tests/btrfs-subvolumes.nix +++ b/tests/btrfs-subvolumes.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; @@ -17,4 +18,3 @@ diskoLib.testLib.makeDiskoTest { machine.succeed("test -e /partition-root/swapfile1"); ''; } - diff --git a/tests/cli.nix b/tests/cli.nix index 76cc2b1..3fe0f7c 100644 --- a/tests/cli.nix +++ b/tests/cli.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; @@ -26,7 +27,10 @@ diskoLib.testLib.makeDiskoTest { ]; }; extraInstallerConfig = { - boot.kernelModules = [ "dm-raid" "dm-mirror" ]; + boot.kernelModules = [ + "dm-raid" + "dm-mirror" + ]; imports = [ ../module.nix ]; diff --git a/tests/complex.nix b/tests/complex.nix index 8ea7adc..2f821c6 100644 --- a/tests/complex.nix +++ b/tests/complex.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; @@ -24,6 +25,9 @@ diskoLib.testLib.makeDiskoTest { machine.succeed("test -e /ext4_on_lvm/file-from-postMountHook"); ''; extraInstallerConfig = { - boot.kernelModules = [ "dm-raid" "dm-mirror" ]; + boot.kernelModules = [ + "dm-raid" + "dm-mirror" + ]; }; } diff --git a/tests/default.nix b/tests/default.nix index 1ea3143..0bb5e46 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -1,20 +1,28 @@ -{ makeTest ? import -, eval-config ? import -, pkgs ? import { } +{ + makeTest ? import , + eval-config ? import , + pkgs ? import { }, }: let lib = pkgs.lib; diskoLib = import ../lib { inherit lib makeTest eval-config; }; - allTestFilenames = - builtins.map (lib.removeSuffix ".nix") ( - builtins.filter - (x: lib.hasSuffix ".nix" x && x != "default.nix") - (lib.attrNames (builtins.readDir ./.)) - ); - incompatibleTests = lib.optionals pkgs.stdenv.buildPlatform.isRiscV64 [ "zfs" "zfs-over-legacy" "cli" "module" "complex" ]; + allTestFilenames = builtins.map (lib.removeSuffix ".nix") ( + builtins.filter (x: lib.hasSuffix ".nix" x && x != "default.nix") ( + lib.attrNames (builtins.readDir ./.) + ) + ); + incompatibleTests = lib.optionals pkgs.stdenv.buildPlatform.isRiscV64 [ + "zfs" + "zfs-over-legacy" + "cli" + "module" + "complex" + ]; allCompatibleFilenames = lib.subtractLists incompatibleTests allTestFilenames; - allTests = lib.genAttrs allCompatibleFilenames (test: import (./. + "/${test}.nix") { inherit diskoLib pkgs; }); + allTests = lib.genAttrs allCompatibleFilenames ( + test: import (./. + "/${test}.nix") { inherit diskoLib pkgs; } + ); in allTests diff --git a/tests/disko-install/configuration.nix b/tests/disko-install/configuration.nix index 41e33e0..319d724 100644 --- a/tests/disko-install/configuration.nix +++ b/tests/disko-install/configuration.nix @@ -1,4 +1,10 @@ -{ lib, pkgs, modulesPath, ... }: { +{ + lib, + pkgs, + modulesPath, + ... +}: +{ imports = [ (modulesPath + "/testing/test-instrumentation.nix") (modulesPath + "/profiles/qemu-guest.nix") @@ -13,11 +19,15 @@ hashed-mirrors = null; connect-timeout = 3; flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}''; - experimental-features = [ "nix-command" "flakes" ]; + experimental-features = [ + "nix-command" + "flakes" + ]; }; services.openssh.enable = true; - boot.kernelParams = [ "console=tty0" ] ++ - (lib.optional (pkgs.stdenv.hostPlatform.isAarch) "ttyAMA0,115200") ++ - (lib.optional (pkgs.stdenv.hostPlatform.isRiscV64) "ttySIF0,115200") ++ - [ "console=ttyS0,115200" ]; + boot.kernelParams = + [ "console=tty0" ] + ++ (lib.optional (pkgs.stdenv.hostPlatform.isAarch) "ttyAMA0,115200") + ++ (lib.optional (pkgs.stdenv.hostPlatform.isRiscV64) "ttySIF0,115200") + ++ [ "console=ttyS0,115200" ]; } diff --git a/tests/disko-install/default.nix b/tests/disko-install/default.nix index af3a660..340616d 100644 --- a/tests/disko-install/default.nix +++ b/tests/disko-install/default.nix @@ -1,4 +1,8 @@ -{ pkgs ? import { }, self, diskoVersion }: +{ + pkgs ? import { }, + self, + diskoVersion, +}: let disko = pkgs.callPackage ../../package.nix { inherit diskoVersion; }; diff --git a/tests/f2fs.nix b/tests/f2fs.nix index ebcf8d8..cbae7f8 100644 --- a/tests/f2fs.nix +++ b/tests/f2fs.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/gpt-bios-compat.nix b/tests/gpt-bios-compat.nix index de45d3b..c6ac331 100644 --- a/tests/gpt-bios-compat.nix +++ b/tests/gpt-bios-compat.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/gpt-name-with-special-chars.nix b/tests/gpt-name-with-special-chars.nix index 48b4304..aac12e3 100644 --- a/tests/gpt-name-with-special-chars.nix +++ b/tests/gpt-name-with-special-chars.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/gpt-unformatted.nix b/tests/gpt-unformatted.nix index 9c75f46..6ff25b4 100644 --- a/tests/gpt-unformatted.nix +++ b/tests/gpt-unformatted.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/hybrid-mbr.nix b/tests/hybrid-mbr.nix index de68b26..105abfb 100644 --- a/tests/hybrid-mbr.nix +++ b/tests/hybrid-mbr.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/hybrid-tmpfs-on-root.nix b/tests/hybrid-tmpfs-on-root.nix index 09d15d6..8fecf9b 100644 --- a/tests/hybrid-tmpfs-on-root.nix +++ b/tests/hybrid-tmpfs-on-root.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/hybrid.nix b/tests/hybrid.nix index adf7ccd..7feb2a3 100644 --- a/tests/hybrid.nix +++ b/tests/hybrid.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/legacy-table-with-whitespace.nix b/tests/legacy-table-with-whitespace.nix index 300c641..5a6fef7 100644 --- a/tests/legacy-table-with-whitespace.nix +++ b/tests/legacy-table-with-whitespace.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/legacy-table.nix b/tests/legacy-table.nix index 2c7b646..5c58bf4 100644 --- a/tests/legacy-table.nix +++ b/tests/legacy-table.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/long-device-name.nix b/tests/long-device-name.nix index e328a9f..273fa62 100644 --- a/tests/long-device-name.nix +++ b/tests/long-device-name.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/luks-btrfs-subvolumes.nix b/tests/luks-btrfs-subvolumes.nix index 6a4e64b..eb1264a 100644 --- a/tests/luks-btrfs-subvolumes.nix +++ b/tests/luks-btrfs-subvolumes.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/luks-lvm.nix b/tests/luks-lvm.nix index 848a5b7..fec9c3b 100644 --- a/tests/luks-lvm.nix +++ b/tests/luks-lvm.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/luks-on-mdadm.nix b/tests/luks-on-mdadm.nix index bd49762..34f8317 100644 --- a/tests/luks-on-mdadm.nix +++ b/tests/luks-on-mdadm.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/lvm-raid.nix b/tests/lvm-raid.nix index b30332a..88d6c74 100644 --- a/tests/lvm-raid.nix +++ b/tests/lvm-raid.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; @@ -9,7 +10,11 @@ diskoLib.testLib.makeDiskoTest { machine.succeed("mountpoint /home"); ''; extraInstallerConfig = { - boot.kernelModules = [ "dm-raid" "raid0" "dm-mirror" ]; + boot.kernelModules = [ + "dm-raid" + "raid0" + "dm-mirror" + ]; }; extraSystemConfig = { # sadly systemd-boot fails to install to a raid /boot device diff --git a/tests/lvm-sizes-sort.nix b/tests/lvm-sizes-sort.nix index 83ed472..976d58c 100644 --- a/tests/lvm-sizes-sort.nix +++ b/tests/lvm-sizes-sort.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/lvm-thin.nix b/tests/lvm-thin.nix index bfbcfc1..6a848a0 100644 --- a/tests/lvm-thin.nix +++ b/tests/lvm-thin.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/make-disk-image-impure.nix b/tests/make-disk-image-impure.nix index 1f96a3e..8d56aee 100644 --- a/tests/make-disk-image-impure.nix +++ b/tests/make-disk-image-impure.nix @@ -1,13 +1,17 @@ -{ pkgs ? import { } -, ... +{ + pkgs ? import { }, + ... }: (pkgs.nixos [ ../module.nix ../example/simple-efi.nix - ({ config, ... }: { - documentation.enable = false; - system.stateVersion = config.system.nixos.version; - disko.checkScripts = true; - }) + ( + { config, ... }: + { + documentation.enable = false; + system.stateVersion = config.system.nixos.version; + disko.checkScripts = true; + } + ) ]).config.system.build.diskoImagesScript diff --git a/tests/make-disk-image.nix b/tests/make-disk-image.nix index 75647d1..54e70d1 100644 --- a/tests/make-disk-image.nix +++ b/tests/make-disk-image.nix @@ -1,14 +1,18 @@ -{ pkgs ? import { } -, ... +{ + pkgs ? import { }, + ... }: (pkgs.nixos [ ../module.nix ../example/simple-efi.nix - ({ config, ... }: { - documentation.enable = false; - system.stateVersion = config.system.nixos.version; - disko.memSize = 2048; - disko.checkScripts = true; - }) + ( + { config, ... }: + { + documentation.enable = false; + system.stateVersion = config.system.nixos.version; + disko.memSize = 2048; + disko.checkScripts = true; + } + ) ]).config.system.build.diskoImages diff --git a/tests/mdadm-raid0.nix b/tests/mdadm-raid0.nix index 7d40109..e8db3cc 100644 --- a/tests/mdadm-raid0.nix +++ b/tests/mdadm-raid0.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/mdadm.nix b/tests/mdadm.nix index 3bd9037..e569f65 100644 --- a/tests/mdadm.nix +++ b/tests/mdadm.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/module.nix b/tests/module.nix index c6eb092..a9c0da9 100644 --- a/tests/module.nix +++ b/tests/module.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; @@ -21,6 +22,9 @@ diskoLib.testLib.makeDiskoTest { machine.succeed("mountpoint /ext4_on_lvm"); ''; extraInstallerConfig = { - boot.kernelModules = [ "dm-raid" "dm-mirror" ]; + boot.kernelModules = [ + "dm-raid" + "dm-mirror" + ]; }; } diff --git a/tests/multi-device-no-deps.nix b/tests/multi-device-no-deps.nix index 77e3477..f063fa8 100644 --- a/tests/multi-device-no-deps.nix +++ b/tests/multi-device-no-deps.nix @@ -1,6 +1,7 @@ # this is a regression test for https://github.com/nix-community/disko/issues/52 -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/negative-size.nix b/tests/negative-size.nix index b891b08..2d4329b 100644 --- a/tests/negative-size.nix +++ b/tests/negative-size.nix @@ -1,6 +1,7 @@ # this is a regression test for https://github.com/nix-community/disko/issues/52 -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/non-root-zfs.nix b/tests/non-root-zfs.nix index 2338483..ada8f20 100644 --- a/tests/non-root-zfs.nix +++ b/tests/non-root-zfs.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/simple-efi.nix b/tests/simple-efi.nix index f3b9071..fa47173 100644 --- a/tests/simple-efi.nix +++ b/tests/simple-efi.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/standalone.nix b/tests/standalone.nix index 5da5cc0..b597d58 100644 --- a/tests/standalone.nix +++ b/tests/standalone.nix @@ -1,4 +1,7 @@ -{ pkgs ? import { }, ... }: +{ + pkgs ? import { }, + ... +}: (pkgs.nixos [ ../example/stand-alone/configuration.nix { documentation.enable = false; } diff --git a/tests/swap.nix b/tests/swap.nix index 7d1678b..f7075ea 100644 --- a/tests/swap.nix +++ b/tests/swap.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/tmpfs.nix b/tests/tmpfs.nix index 21cb217..af9b3c3 100644 --- a/tests/tmpfs.nix +++ b/tests/tmpfs.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/with-lib.nix b/tests/with-lib.nix index d8274b7..1ad4829 100644 --- a/tests/with-lib.nix +++ b/tests/with-lib.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/xfs.nix b/tests/xfs.nix index 3c7a123..081755a 100644 --- a/tests/xfs.nix +++ b/tests/xfs.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/zfs-encrypted-root.nix b/tests/zfs-encrypted-root.nix index d92b85e..113625b 100644 --- a/tests/zfs-encrypted-root.nix +++ b/tests/zfs-encrypted-root.nix @@ -1,18 +1,17 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; name = "zfs-encrypted-root"; extraInstallerConfig.networking.hostId = "8425e349"; extraSystemConfig.networking.hostId = "8425e349"; - disko-config = - pkgs.lib.recursiveUpdate (import ../example/zfs-encrypted-root.nix) { - disko.devices.zpool.zroot.datasets.root.options.keylocation = "file:///tmp/secret.key"; - }; + disko-config = pkgs.lib.recursiveUpdate (import ../example/zfs-encrypted-root.nix) { + disko.devices.zpool.zroot.datasets.root.options.keylocation = "file:///tmp/secret.key"; + }; extraTestScript = '' machine.succeed("mountpoint /"); machine.succeed("mountpoint /nix"); ''; } - diff --git a/tests/zfs-over-legacy.nix b/tests/zfs-over-legacy.nix index af78060..1d60a85 100644 --- a/tests/zfs-over-legacy.nix +++ b/tests/zfs-over-legacy.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; @@ -12,4 +13,3 @@ diskoLib.testLib.makeDiskoTest { machine.succeed("mountpoint /zfs_fs"); ''; } - diff --git a/tests/zfs-with-vdevs.nix b/tests/zfs-with-vdevs.nix index 6b9e2d5..4ac5e98 100644 --- a/tests/zfs-with-vdevs.nix +++ b/tests/zfs-with-vdevs.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/tests/zfs.nix b/tests/zfs.nix index 806d623..c3d2af8 100644 --- a/tests/zfs.nix +++ b/tests/zfs.nix @@ -1,5 +1,6 @@ -{ pkgs ? import { } -, diskoLib ? pkgs.callPackage ../lib { } +{ + pkgs ? import { }, + diskoLib ? pkgs.callPackage ../lib { }, }: diskoLib.testLib.makeDiskoTest { inherit pkgs; diff --git a/version.nix b/version.nix index fc21dc8..74617d4 100644 --- a/version.nix +++ b/version.nix @@ -1 +1,4 @@ -{ version = "1.10.0"; released = false; } +{ + version = "1.10.0"; + released = false; +}