treewide: format all files

This commit is contained in:
DavHau
2025-02-15 16:12:27 +07:00
committed by lassulus
parent c23ac2891c
commit ff2d853a84
82 changed files with 2929 additions and 1993 deletions

143
cli.nix
View File

@@ -1,12 +1,13 @@
{ pkgs ? import <nixpkgs> { } {
, lib ? pkgs.lib pkgs ? import <nixpkgs> { },
, mode ? "mount" lib ? pkgs.lib,
, flake ? null mode ? "mount",
, flakeAttr ? null flake ? null,
, diskoFile ? null flakeAttr ? null,
, rootMountPoint ? "/mnt" diskoFile ? null,
, noDeps ? false rootMountPoint ? "/mnt",
, ... noDeps ? false,
...
}@args: }@args:
let let
disko = import ./. { disko = import ./. {
@@ -17,66 +18,77 @@ let
hasDiskoFile = diskoFile != null; hasDiskoFile = diskoFile != null;
diskoAttr = diskoAttr =
(if noDeps then (
(if hasDiskoFile then if noDeps then
{ (
destroy = "_cliDestroyNoDeps"; if hasDiskoFile then
format = "_cliFormatNoDeps"; {
mount = "_cliMountNoDeps"; destroy = "_cliDestroyNoDeps";
unmount = "_cliUnmountNoDeps"; format = "_cliFormatNoDeps";
mount = "_cliMountNoDeps";
unmount = "_cliUnmountNoDeps";
"format,mount" = "_cliFormatMountNoDeps"; "format,mount" = "_cliFormatMountNoDeps";
"destroy,format,mount" = "_cliDestroyFormatMountNoDeps"; "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 else
{ (
destroy = "destroyNoDeps"; if hasDiskoFile then
format = "formatNoDeps"; {
mount = "mountNoDeps"; destroy = "_cliDestroy";
unmount = "unmountNoDeps"; format = "_cliFormat";
mount = "_cliMount";
unmount = "_cliUnmount";
"format,mount" = "formatMountNoDeps"; "format,mount" = "_cliFormatMount";
"destroy,format,mount" = "destroyFormatMountNoDeps"; "destroy,format,mount" = "_cliDestroyFormatMount";
}) // { }
# legacy aliases else
disko = "diskoScriptNoDeps"; {
create = "createScriptNoDeps"; destroy = "destroy";
zap_create_mount = "diskoScriptNoDeps"; format = "format";
} mount = "mount";
else unmount = "unmount";
(if hasDiskoFile then
{
destroy = "_cliDestroy";
format = "_cliFormat";
mount = "_cliMount";
unmount = "_cliUnmount";
"format,mount" = "_cliFormatMount"; "format,mount" = "formatMount";
"destroy,format,mount" = "_cliDestroyFormatMount"; "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}; ).${mode};
hasDiskoConfigFlake = hasDiskoConfigFlake =
hasDiskoFile || lib.hasAttrByPath [ "diskoConfigurations" flakeAttr ] (builtins.getFlake flake); hasDiskoFile || lib.hasAttrByPath [ "diskoConfigurations" flakeAttr ] (builtins.getFlake flake);
hasDiskoModuleFlake = hasDiskoModuleFlake = lib.hasAttrByPath [
lib.hasAttrByPath [ "nixosConfigurations" flakeAttr "config" "disko" "devices" ] (builtins.getFlake flake); "nixosConfigurations"
flakeAttr
"config"
"disko"
"devices"
] (builtins.getFlake flake);
diskFormat = diskFormat =
let let
@@ -86,20 +98,16 @@ let
else else
(builtins.getFlake flake).diskoConfigurations.${flakeAttr}; (builtins.getFlake flake).diskoConfigurations.${flakeAttr};
in in
if builtins.isFunction diskoConfig then if builtins.isFunction diskoConfig then diskoConfig ({ inherit lib; } // args) else diskoConfig;
diskoConfig ({ inherit lib; } // args)
else
diskoConfig;
diskoEval = diskoEval = disko.${diskoAttr} diskFormat pkgs;
disko.${diskoAttr} diskFormat pkgs;
diskoScript = diskoScript =
if hasDiskoConfigFlake then if hasDiskoConfigFlake then
diskoEval diskoEval
else if hasDiskoModuleFlake then else if hasDiskoModuleFlake then
(builtins.getFlake flake).nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr} or ( (builtins.getFlake flake).nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr}
pkgs.writeShellScriptBin "disko-compat-error" '' or (pkgs.writeShellScriptBin "disko-compat-error" ''
echo 'Error: Attribute `nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr}` >&2 echo 'Error: Attribute `nixosConfigurations.${flakeAttr}.config.system.build.${diskoAttr}` >&2
echo ' not found in flake `${flake}`!' >&2 echo ' not found in flake `${flake}`!' >&2
echo ' This is probably caused by the locked version of disko in the 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 '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 ' 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 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 else
(builtins.abort "couldn't find `diskoConfigurations.${flakeAttr}` or `nixosConfigurations.${flakeAttr}.config.disko.devices`"); (builtins.abort "couldn't find `diskoConfigurations.${flakeAttr}` or `nixosConfigurations.${flakeAttr}.config.disko.devices`");

View File

@@ -1,64 +1,107 @@
{ lib ? import <nixpkgs/lib> {
, rootMountPoint ? "/mnt" lib ? import <nixpkgs/lib>,
, checked ? false rootMountPoint ? "/mnt",
, diskoLib ? import ./lib { inherit lib rootMountPoint; } checked ? false,
diskoLib ? import ./lib { inherit lib rootMountPoint; },
}: }:
let let
eval = cfg: lib.evalModules { eval =
modules = lib.singleton { cfg:
# _file = toString input; lib.evalModules {
imports = lib.singleton { disko.devices = cfg.disko.devices; }; modules = lib.singleton {
options = { # _file = toString input;
disko.devices = lib.mkOption { imports = lib.singleton { disko.devices = cfg.disko.devices; };
type = diskoLib.toplevel; 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, # 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. # 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 in
{ {
lib = warnDeprecated ".lib.lib" diskoLib; lib = warnDeprecated ".lib.lib" diskoLib;
_cliDestroy = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroy; _cliDestroy =
_cliDestroyNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyNoDeps; 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; _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; _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; _cliUnmount =
_cliUnmountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmountNoDeps; 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; _cliFormatMount =
_cliFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMountNoDeps; 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; _cliDestroyFormatMount =
_cliDestroyFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMountNoDeps; 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 # legacy aliases
create = cfg: warnDeprecated "create" (eval cfg).config.disko.devices._create; 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; createScript =
createScriptNoDeps = cfg: pkgs: warnDeprecated "createScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps; 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; 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; formatScript =
formatScriptNoDeps = cfg: pkgs: warnDeprecated "formatScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps; 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; 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; mountScript =
mountScriptNoDeps = cfg: pkgs: warnDeprecated "mountScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScriptNoDeps; 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; 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; diskoScript =
diskoScriptNoDeps = cfg: pkgs: warnDeprecated "diskoScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps; 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 # 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; config = cfg: (eval cfg).config.disko.devices._config;
packages = cfg: (eval cfg).config.disko.devices._packages; packages = cfg: (eval cfg).config.disko.devices._packages;

28
doc.nix
View File

@@ -1,4 +1,10 @@
{ lib, nixosOptionsDoc, runCommand, fetchurl, pandoc }: {
lib,
nixosOptionsDoc,
runCommand,
fetchurl,
pandoc,
}:
let let
diskoLib = import ./lib { diskoLib = import ./lib {
@@ -21,16 +27,18 @@ let
options = nixosOptionsDoc { options = nixosOptionsDoc {
options = eval.options; options = eval.options;
}; };
md = (runCommand "disko-options.md" { } '' md =
cat >$out <<EOF (runCommand "disko-options.md" { } ''
# Disko options cat >$out <<EOF
# Disko options
EOF EOF
cat ${options.optionsCommonMark} >>$out cat ${options.optionsCommonMark} >>$out
'').overrideAttrs (_o: { '').overrideAttrs
# Work around https://github.com/hercules-ci/hercules-ci-agent/issues/168 (_o: {
allowSubstitutes = true; # Work around https://github.com/hercules-ci/hercules-ci-agent/issues/168
}); allowSubstitutes = true;
});
css = fetchurl { css = fetchurl {
url = "https://gist.githubusercontent.com/killercup/5917178/raw/40840de5352083adb2693dc742e9f75dbb18650f/pandoc.css"; url = "https://gist.githubusercontent.com/killercup/5917178/raw/40840de5352083adb2693dc742e9f75dbb18650f/pandoc.css";
sha256 = "sha256-SzSvxBIrylxBF6B/mOImLlZ+GvCfpWNLzGFViLyOeTk="; sha256 = "sha256-SzSvxBIrylxBF6B/mOImLlZ+GvCfpWNLzGFViLyOeTk=";

View File

@@ -26,7 +26,10 @@
type = "btrfs"; type = "btrfs";
extraArgs = [ "-f" ]; # Override existing partition extraArgs = [ "-f" ]; # Override existing partition
mountpoint = "/"; mountpoint = "/";
mountOptions = [ "compress=zstd" "noatime" ]; mountOptions = [
"compress=zstd"
"noatime"
];
}; };
}; };
}; };
@@ -35,4 +38,3 @@
}; };
}; };
} }

View File

@@ -41,7 +41,10 @@
"/home/user" = { }; "/home/user" = { };
# Parent is not mounted so the mountpoint must be set # Parent is not mounted so the mountpoint must be set
"/nix" = { "/nix" = {
mountOptions = [ "compress=zstd" "noatime" ]; mountOptions = [
"compress=zstd"
"noatime"
];
mountpoint = "/nix"; mountpoint = "/nix";
}; };
# This subvolume will be created but not mounted # This subvolume will be created but not mounted
@@ -74,4 +77,3 @@
}; };
}; };
} }

View File

@@ -38,4 +38,3 @@
}; };
}; };
} }

View File

@@ -35,15 +35,24 @@
subvolumes = { subvolumes = {
"/root" = { "/root" = {
mountpoint = "/"; mountpoint = "/";
mountOptions = [ "compress=zstd" "noatime" ]; mountOptions = [
"compress=zstd"
"noatime"
];
}; };
"/home" = { "/home" = {
mountpoint = "/home"; mountpoint = "/home";
mountOptions = [ "compress=zstd" "noatime" ]; mountOptions = [
"compress=zstd"
"noatime"
];
}; };
"/nix" = { "/nix" = {
mountpoint = "/nix"; mountpoint = "/nix";
mountOptions = [ "compress=zstd" "noatime" ]; mountOptions = [
"compress=zstd"
"noatime"
];
}; };
"/swap" = { "/swap" = {
mountpoint = "/.swapvol"; mountpoint = "/.swapvol";

View File

@@ -56,4 +56,3 @@
}; };
}; };
} }

View File

@@ -1,6 +1,7 @@
{ pkgs {
, lib pkgs,
, ... lib,
...
}: }:
let let
# We just import from the repository for testing here: # We just import from the repository for testing here:

View File

@@ -1,5 +1,10 @@
# Example to create a bios compatible gpt partition # Example to create a bios compatible gpt partition
{ disks ? [ "/dev/vdb" ], lib, ... }: { {
disks ? [ "/dev/vdb" ],
lib,
...
}:
{
disko.devices = { disko.devices = {
disk = lib.genAttrs disks (device: { disk = lib.genAttrs disks (device: {
name = lib.replaceStrings [ "/" ] [ "_" ] device; name = lib.replaceStrings [ "/" ] [ "_" ] device;

View File

@@ -23,7 +23,10 @@
type = "filesystem"; type = "filesystem";
format = "xfs"; format = "xfs";
mountpoint = "/"; mountpoint = "/";
mountOptions = [ "defaults" "pquota" ]; mountOptions = [
"defaults"
"pquota"
];
}; };
}; };
}; };

View File

@@ -251,14 +251,20 @@
} }
{ {
mode = "mirror"; mode = "mirror";
members = [ "data2" "data3" ]; members = [
"data2"
"data3"
];
} }
]; ];
spare = [ "spare" ]; spare = [ "spare" ];
log = [ log = [
{ {
mode = "mirror"; mode = "mirror";
members = [ "log1" "log2" ]; members = [
"log1"
"log2"
];
} }
{ {
members = [ "log3" ]; members = [ "log3" ];
@@ -267,7 +273,10 @@
dedup = [ dedup = [
{ {
mode = "mirror"; mode = "mirror";
members = [ "dedup1" "dedup2" ]; members = [
"dedup1"
"dedup2"
];
} }
{ {
members = [ "dedup3" ]; members = [ "dedup3" ];
@@ -276,7 +285,10 @@
special = [ special = [
{ {
mode = "mirror"; mode = "mirror";
members = [ "special1" "special2" ]; members = [
"special1"
"special2"
];
} }
{ {
members = [ "special3" ]; members = [ "special3" ];

View File

@@ -6,7 +6,8 @@
#inputs.nixpkgs.url = "nixpkgs"; #inputs.nixpkgs.url = "nixpkgs";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
outputs = { self, nixpkgs, ... }: outputs =
{ self, nixpkgs, ... }:
let let
lib = nixpkgs.lib; lib = nixpkgs.lib;
supportedSystems = [ supportedSystems = [
@@ -28,7 +29,8 @@
nixosModules.default = self.nixosModules.disko; # convention nixosModules.default = self.nixosModules.disko; # convention
nixosModules.disko = ./module.nix; nixosModules.disko = ./module.nix;
lib = diskoLib; lib = diskoLib;
packages = forAllSystems (system: packages = forAllSystems (
system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
in in
@@ -41,27 +43,35 @@
default = self.packages.${system}.disko; default = self.packages.${system}.disko;
create-release = pkgs.callPackage ./scripts/create-release.nix { }; 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 { }; disko-doc = pkgs.callPackage ./doc.nix { };
}); }
);
# TODO: disable bios-related tests on aarch64... # TODO: disable bios-related tests on aarch64...
# Run checks: nix flake check -L # Run checks: nix flake check -L
checks = forAllSystems (system: checks = forAllSystems (
system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
# FIXME: aarch64-linux seems to hang on boot # FIXME: aarch64-linux seems to hang on boot
nixosTests = lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (import ./tests { nixosTests = lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (
inherit pkgs; import ./tests {
makeTest = import (pkgs.path + "/nixos/tests/make-test-python.nix"); inherit pkgs;
eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix"); 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 { disko-install = pkgs.callPackage ./tests/disko-install {
inherit self; inherit self;
diskoVersion = version; 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" { } '' treefmt = pkgs.runCommand "treefmt" { } ''
${self.formatter.${system}}/bin/treefmt --ci --working-dir ${self} ${self.formatter.${system}}/bin/treefmt --ci --working-dir ${self}
@@ -69,11 +79,14 @@
''; '';
in in
# FIXME: aarch64-linux seems to hang on boot # FIXME: aarch64-linux seems to hang on boot
lib.optionalAttrs pkgs.stdenv.hostPlatform.isx86_64 (nixosTests // { inherit disko-install; }) // 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; pkgs.lib.optionalAttrs (!pkgs.stdenv.buildPlatform.isRiscV64 && !pkgs.stdenv.hostPlatform.isx86_32)
inherit (self.packages.${system}) disko-doc; {
}); inherit jsonTypes treefmt;
inherit (self.packages.${system}) disko-doc;
}
);
nixosConfigurations.testmachine = lib.nixosSystem { nixosConfigurations.testmachine = lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
@@ -83,7 +96,8 @@
./module.nix ./module.nix
]; ];
}; };
formatter = forAllSystems (system: formatter = forAllSystems (
system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
in in
@@ -104,6 +118,6 @@
self.formatter.${system} self.formatter.${system}
]; ];
}; };
}); });
}; };
} }

View File

@@ -1,10 +1,10 @@
{ flake {
, flakeAttr flake,
, diskMappings flakeAttr,
, extraSystemConfig ? "{}" diskMappings,
, writeEfiBootEntries ? false extraSystemConfig ? "{}",
, rootMountPoint ? "/mnt" writeEfiBootEntries ? false,
, rootMountPoint ? "/mnt",
}: }:
let let
originalSystem = (builtins.getFlake "${flake}").nixosConfigurations."${flakeAttr}"; originalSystem = (builtins.getFlake "${flake}").nixosConfigurations."${flakeAttr}";
@@ -17,21 +17,19 @@ let
else else
throw "No device passed for disk '${name}'. Pass `--disk ${name} /dev/name` via commandline"; throw "No device passed for disk '${name}'. Pass `--disk ${name} /dev/name` via commandline";
modifiedDisks = builtins.mapAttrs modifiedDisks = builtins.mapAttrs (
( name: value:
name: value: let
let dev = deviceName name;
dev = deviceName name; in
in value
value // {
// { device = dev;
device = dev; content = value.content // {
content = value.content // { device = dev;
device = dev; };
}; }
} ) originalSystem.config.disko.devices.disk;
)
originalSystem.config.disko.devices.disk;
# filter all nixos module internal attributes # filter all nixos module internal attributes
cleanedDisks = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) modifiedDisks; cleanedDisks = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) modifiedDisks;

View File

@@ -1,25 +1,33 @@
{ lib, diskoLib, pkgs, imagePkgs, ... }: {
lib,
diskoLib,
pkgs,
imagePkgs,
...
}:
let let
# from https://github.com/NixOS/nixpkgs/blob/851f7fc119e9597c26cc43e10938ce7272d0af9d/nixos/modules/system/boot/binfmt.nix # from https://github.com/NixOS/nixpkgs/blob/851f7fc119e9597c26cc43e10938ce7272d0af9d/nixos/modules/system/boot/binfmt.nix
makeBinfmtLine = makeBinfmtLine =
{ name {
, recognitionType name,
, offset recognitionType,
, magicOrExtension offset,
, mask magicOrExtension,
, preserveArgvZero mask,
, openBinary preserveArgvZero,
, matchCredentials openBinary,
, fixBinary matchCredentials,
, interpreter fixBinary,
, ... interpreter,
...
}: }:
let let
type = if recognitionType == "magic" then "M" else "E"; type = if recognitionType == "magic" then "M" else "E";
offset' = toString offset; offset' = toString offset;
mask' = toString mask; mask' = toString mask;
flags = with lib; flags =
with lib;
if !(matchCredentials -> openBinary) then if !(matchCredentials -> openBinary) then
throw "boot.binfmt.registrations.${name}: you can't specify openBinary = false when matchCredentials = true." throw "boot.binfmt.registrations.${name}: you can't specify openBinary = false when matchCredentials = true."
else else
@@ -144,29 +152,30 @@ let
in in
{ {
binfmtRegistration = binfmtRegistration =
let let
system = imagePkgs.stdenv.hostPlatform.system; system = imagePkgs.stdenv.hostPlatform.system;
enabled = system != pkgs.stdenv.hostPlatform.system; enabled = system != pkgs.stdenv.hostPlatform.system;
elaborated = lib.systems.elaborate { inherit system; }; elaborated = lib.systems.elaborate { inherit system; };
useStaticEmulator = true; # needed for chroot useStaticEmulator = true; # needed for chroot
interpreter = elaborated.emulator (if useStaticEmulator then pkgs.pkgsStatic else pkgs); interpreter = elaborated.emulator (if useStaticEmulator then pkgs.pkgsStatic else pkgs);
inherit (elaborated) qemuArch; inherit (elaborated) qemuArch;
isQemu = "qemu-${qemuArch}" == baseNameOf interpreter; isQemu = "qemu-${qemuArch}" == baseNameOf interpreter;
in makeBinfmtLine ( in
{ makeBinfmtLine (
name = system; {
inherit interpreter; name = system;
recognitionType = "magic"; inherit interpreter;
offset = null; recognitionType = "magic";
openBinary = false; offset = null;
matchCredentials = false; openBinary = false;
matchCredentials = false;
preserveArgvZero = isQemu; preserveArgvZero = isQemu;
fixBinary = useStaticEmulator; fixBinary = useStaticEmulator;
} }
// (magics.${system} or (throw "Cannot create binfmt registration for system ${system}")) // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}"))
); );
systemsAreDifferent = imagePkgs.stdenv.hostPlatform.system != pkgs.stdenv.hostPlatform.system; systemsAreDifferent = imagePkgs.stdenv.hostPlatform.system != pkgs.stdenv.hostPlatform.system;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +1,30 @@
{ diskoLib, modulesPath, config, pkgs, lib, ... }: {
diskoLib,
modulesPath,
config,
pkgs,
lib,
...
}:
let let
vm_disko = (diskoLib.testLib.prepareDiskoConfig config diskoLib.testLib.devices).disko; vm_disko = (diskoLib.testLib.prepareDiskoConfig config diskoLib.testLib.devices).disko;
cfg_ = (lib.evalModules { cfg_ =
modules = lib.singleton { (lib.evalModules {
# _file = toString input; modules = lib.singleton {
imports = lib.singleton { disko.devices = vm_disko.devices; }; # _file = toString input;
options = { imports = lib.singleton { disko.devices = vm_disko.devices; };
disko.devices = lib.mkOption { options = {
type = diskoLib.toplevel; disko.devices = lib.mkOption {
}; type = diskoLib.toplevel;
disko.testMode = lib.mkOption { };
type = lib.types.bool; disko.testMode = lib.mkOption {
default = true; type = lib.types.bool;
default = true;
};
}; };
}; };
}; }).config;
}).config;
disks = lib.attrValues cfg_.disko.devices.disk; disks = lib.attrValues cfg_.disko.devices.disk;
rootDisk = { rootDisk = {
name = "root"; name = "root";
@@ -26,13 +34,11 @@ let
deviceExtraOpts.bootindex = "1"; deviceExtraOpts.bootindex = "1";
deviceExtraOpts.serial = "root"; deviceExtraOpts.serial = "root";
}; };
otherDisks = map otherDisks = map (disk: {
(disk: { name = disk.name;
name = disk.name; file = ''"$tmp"/${lib.escapeShellArg disk.name}.qcow2'';
file = ''"$tmp"/${lib.escapeShellArg disk.name}.qcow2''; driveExtraOpts.werror = "report";
driveExtraOpts.werror = "report"; }) (builtins.tail disks);
})
(builtins.tail disks);
diskoBasedConfiguration = { diskoBasedConfiguration = {
# generated from disko config # generated from disko config

View File

@@ -1,10 +1,11 @@
{ config {
, diskoLib config,
, lib diskoLib,
, extendModules lib,
, options extendModules,
, imagePkgs options,
, ... imagePkgs,
...
}: }:
let let
diskoCfg = config.disko; diskoCfg = config.disko;
@@ -13,33 +14,45 @@ let
checked = diskoCfg.checkScripts; checked = diskoCfg.checkScripts;
configSupportsZfs = config.boot.supportedFilesystems.zfs or false; 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) '' binfmtSetup = lib.optionalString (cfg.enableBinfmt && binfmt.systemsAreDifferent) ''
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
${pkgs.systemdMinimal}/lib/systemd/systemd-binfmt <(echo ${lib.strings.escapeShellArg binfmt.binfmtRegistration}) ${pkgs.systemdMinimal}/lib/systemd/systemd-binfmt <(echo ${lib.strings.escapeShellArg binfmt.binfmtRegistration})
''; '';
vmTools = pkgs.vmTools.override vmTools = pkgs.vmTools.override (
({ {
rootModules = [ rootModules =
"9p" "9pnet_virtio" # we can drop those in future if we stop supporting 24.11 [
"9p"
"9pnet_virtio" # we can drop those in future if we stop supporting 24.11
"virtiofs" "virtiofs"
"virtio_pci" "virtio_pci"
"virtio_blk" "virtio_blk"
"virtio_balloon" "virtio_balloon"
"virtio_rng" "virtio_rng"
] ]
++ (lib.optional configSupportsZfs "zfs") ++ (lib.optional configSupportsZfs "zfs")
++ cfg.extraRootModules; ++ cfg.extraRootModules;
kernel = pkgs.aggregateModules kernel = pkgs.aggregateModules (
([ cfg.kernelPackages.kernel ] [ cfg.kernelPackages.kernel ]
++ lib.optional (lib.elem "zfs" cfg.extraRootModules || configSupportsZfs) cfg.kernelPackages.${config.boot.zfs.package.kernelModuleAttribute}); ++ 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; customQemu = cfg.qemu;
}); }
);
cleanedConfig = diskoLib.testLib.prepareDiskoConfig config diskoLib.testLib.devices; cleanedConfig = diskoLib.testLib.prepareDiskoConfig config diskoLib.testLib.devices;
systemToInstall = extendModules { systemToInstall = extendModules {
modules = [ modules = [
@@ -51,34 +64,41 @@ let
} }
]; ];
}; };
systemToInstallNative = if binfmt.systemsAreDifferent then extendModules { systemToInstallNative =
modules = [ if binfmt.systemsAreDifferent then
cfg.extraConfig extendModules {
{ modules = [
disko.testMode = true; cfg.extraConfig
disko.devices = lib.mkForce cleanedConfig.disko.devices; {
boot.loader.grub.devices = lib.mkForce cleanedConfig.boot.loader.grub.devices; disko.testMode = true;
nixpkgs.hostPlatform = lib.mkForce pkgs.stdenv.hostPlatform; 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;
else systemToInstall; dependencies =
dependencies = with pkgs; [ with pkgs;
bash [
coreutils bash
gnused coreutils
parted # for partprobe gnused
systemdMinimal parted # for partprobe
nix systemdMinimal
util-linux nix
findutils util-linux
kmod findutils
] ++ cfg.extraDependencies; kmod
]
++ cfg.extraDependencies;
preVM = '' preVM = ''
# shellcheck disable=SC2154 # shellcheck disable=SC2154
mkdir -p "$out" mkdir -p "$out"
${lib.concatMapStringsSep "\n" (disk: ${lib.concatMapStringsSep "\n" (
# shellcheck disable=SC2154 disk:
# shellcheck disable=SC2154
"${pkgs.qemu}/bin/qemu-img create -f ${imageFormat} \"$out/${disk.imageName}.${imageFormat}\" ${disk.imageSize}" "${pkgs.qemu}/bin/qemu-img create -f ${imageFormat} \"$out/${disk.imageName}.${imageFormat}\" ${disk.imageSize}"
) (lib.attrValues diskoCfg.devices.disk)} ) (lib.attrValues diskoCfg.devices.disk)}
# This makes disko work, when canTouchEfiVariables is set to true. # This makes disko work, when canTouchEfiVariables is set to true.
@@ -127,24 +147,26 @@ let
umount -Rv ${systemToInstall.config.disko.rootMountPoint} umount -Rv ${systemToInstall.config.disko.rootMountPoint}
''; '';
QEMU_OPTS = lib.concatStringsSep " " ([ 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" "-drive if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}"
] ++ builtins.map "-drive if=pflash,format=raw,unit=1,file=efivars.fd"
(disk: ]
++ builtins.map (
disk:
"-drive file=\"$out\"/${disk.imageName}.${imageFormat},if=virtio,cache=unsafe,werror=report,format=${imageFormat}" "-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 in
{ {
system.build.diskoImages = vmTools.runInLinuxVM (pkgs.runCommand cfg.name system.build.diskoImages = vmTools.runInLinuxVM (
{ pkgs.runCommand cfg.name {
buildInputs = dependencies; buildInputs = dependencies;
inherit preVM QEMU_OPTS; inherit preVM QEMU_OPTS;
postVM = cfg.extraPostVM; postVM = cfg.extraPostVM;
inherit (diskoCfg) memSize; inherit (diskoCfg) memSize;
} } (binfmtSetup + partitioner + installer)
(binfmtSetup + partitioner + installer)); );
system.build.diskoImagesScript = diskoLib.writeCheckedBash { inherit checked pkgs; } cfg.name '' system.build.diskoImagesScript = diskoLib.writeCheckedBash { inherit checked pkgs; } cfg.name ''
set -efu set -efu
@@ -209,32 +231,34 @@ in
shift shift
done done
export preVM=${diskoLib.writeCheckedBash { inherit pkgs checked; } "preVM.sh" '' export preVM=${
set -efu diskoLib.writeCheckedBash { inherit pkgs checked; } "preVM.sh" ''
mv copy_before_disko copy_after_disko xchg/ set -efu
origBuilder=${pkgs.writeScript "disko-builder" '' mv copy_before_disko copy_after_disko xchg/
set -eu origBuilder=${pkgs.writeScript "disko-builder" ''
export PATH=${lib.makeBinPath dependencies} set -eu
for src in /tmp/xchg/copy_before_disko/*; do export PATH=${lib.makeBinPath dependencies}
[ -e "$src" ] || continue for src in /tmp/xchg/copy_before_disko/*; do
dst=$(basename "$src" | base64 -d) [ -e "$src" ] || continue
mkdir -p "$(dirname "$dst")" dst=$(basename "$src" | base64 -d)
cp -r "$src" "$dst" mkdir -p "$(dirname "$dst")"
done cp -r "$src" "$dst"
set -f done
${partitioner} set -f
set +f ${partitioner}
for src in /tmp/xchg/copy_after_disko/*; do set +f
[ -e "$src" ] || continue for src in /tmp/xchg/copy_after_disko/*; do
dst=/mnt/$(basename "$src" | base64 -d) [ -e "$src" ] || continue
mkdir -p "$(dirname "$dst")" dst=/mnt/$(basename "$src" | base64 -d)
cp -r "$src" "$dst" mkdir -p "$(dirname "$dst")"
done cp -r "$src" "$dst"
${installer} done
''} ${installer}
echo "export origBuilder=$origBuilder" >> xchg/saved-env ''}
${preVM} echo "export origBuilder=$origBuilder" >> xchg/saved-env
''} ${preVM}
''
}
export postVM=${diskoLib.writeCheckedBash { inherit pkgs checked; } "postVM.sh" cfg.extraPostVM} export postVM=${diskoLib.writeCheckedBash { inherit pkgs checked; } "postVM.sh" cfg.extraPostVM}
build_memory=''${build_memory:-${builtins.toString diskoCfg.memSize}} build_memory=''${build_memory:-${builtins.toString diskoCfg.memSize}}

View File

@@ -1,37 +1,48 @@
{ lib {
, makeTest lib,
, eval-config makeTest,
, ... eval-config,
...
}: }:
let let
testLib = { testLib = {
# this takes a nixos config and changes the disk devices so we can run them inside the qemu test runner # 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. # basically changes all the disk.*.devices to something like /dev/vda or /dev/vdb etc.
prepareDiskoConfig = cfg: devices: prepareDiskoConfig =
cfg: devices:
let let
cleanedTopLevel = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) cfg; cleanedTopLevel = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) cfg;
preparedDisks = lib.foldlAttrs preparedDisks =
(acc: n: v: { lib.foldlAttrs
devices = lib.tail acc.devices; (acc: n: v: {
grub-devices = acc.grub-devices ++ (lib.optional (lib.any (part: (part.type or "") == "EF02") (lib.attrValues (v.content.partitions or { }))) (lib.head acc.devices)); devices = lib.tail acc.devices;
disks = acc.disks // { grub-devices =
"${n}" = v // { acc.grub-devices
device = lib.head acc.devices; ++ (lib.optional (lib.any (part: (part.type or "") == "EF02") (
content = v.content // { device = lib.head acc.devices; }; 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;
inherit devices; grub-devices = [ ];
grub-devices = [ ]; disks = { };
disks = { }; }
} cleanedTopLevel.disko.devices.disk;
cleanedTopLevel.disko.devices.disk;
in in
cleanedTopLevel // { cleanedTopLevel
boot.loader.grub.devices = if (preparedDisks.grub-devices != [ ]) then preparedDisks.grub-devices else [ "nodev" ]; // {
boot.loader.grub.devices =
if (preparedDisks.grub-devices != [ ]) then preparedDisks.grub-devices else [ "nodev" ];
disko.devices = cleanedTopLevel.disko.devices // { disko.devices = cleanedTopLevel.disko.devices // {
disk = preparedDisks.disks; disk = preparedDisks.disks;
}; };
@@ -58,33 +69,31 @@ let
# This is the test generator for a disko test # This is the test generator for a disko test
makeDiskoTest = makeDiskoTest =
{ name {
, disko-config name,
, extendModules ? null disko-config,
, pkgs ? import <nixpkgs> { } extendModules ? null,
, extraTestScript ? "" pkgs ? import <nixpkgs> { },
, bootCommands ? "" extraTestScript ? "",
, extraInstallerConfig ? { } bootCommands ? "",
, extraSystemConfig ? { } extraInstallerConfig ? { },
, efi ? !pkgs.stdenv.hostPlatform.isRiscV64 extraSystemConfig ? { },
, postDisko ? "" efi ? !pkgs.stdenv.hostPlatform.isRiscV64,
, testMode ? "module" # can be one of direct module cli postDisko ? "",
, testBoot ? true # if we actually want to test booting or just create/mount testMode ? "module", # can be one of direct module cli
, enableOCR ? false testBoot ? true, # if we actually want to test booting or just create/mount
enableOCR ? false,
}: }:
let let
makeTest' = args: makeTest' =
args:
makeTest args { makeTest args {
inherit pkgs; inherit pkgs;
inherit (pkgs) system; inherit (pkgs) system;
}; };
# for installation we skip /dev/vda because it is the test runner disk # for installation we skip /dev/vda because it is the test runner disk
importedDiskoConfig = importedDiskoConfig = if builtins.isPath disko-config then import disko-config else disko-config;
if builtins.isPath disko-config then
import disko-config
else
disko-config;
diskoConfigWithArgs = diskoConfigWithArgs =
if builtins.isFunction importedDiskoConfig then if builtins.isFunction importedDiskoConfig then
@@ -104,79 +113,93 @@ let
tsp-config = tsp-generator.config testConfigBooted; tsp-config = tsp-generator.config testConfigBooted;
num-disks = builtins.length (lib.attrNames testConfigBooted.disko.devices.disk); num-disks = builtins.length (lib.attrNames testConfigBooted.disko.devices.disk);
installed-system = { config, ... }: { installed-system =
imports = [ { config, ... }:
(lib.optionalAttrs (testMode == "direct") tsp-config) {
(lib.optionalAttrs (testMode == "module") { imports = [
disko.enableConfig = true; (lib.optionalAttrs (testMode == "direct") tsp-config)
imports = [ (lib.optionalAttrs (testMode == "module") {
../module.nix disko.enableConfig = true;
testConfigBooted imports = [
]; ../module.nix
}) testConfigBooted
]; ];
})
];
# config for tests to make them run faster or work at all # config for tests to make them run faster or work at all
documentation.enable = false; documentation.enable = false;
hardware.enableAllFirmware = lib.mkForce false; hardware.enableAllFirmware = lib.mkForce false;
# FIXME: we don't have an systemd in stage-1 equialvent for this # FIXME: we don't have an systemd in stage-1 equialvent for this
boot.initrd.preDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) '' boot.initrd.preDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
echo -n 'secretsecret' > /tmp/secret.key echo -n 'secretsecret' > /tmp/secret.key
''; '';
boot.consoleLogLevel = lib.mkForce 100; boot.consoleLogLevel = lib.mkForce 100;
boot.loader.systemd-boot.enable = lib.mkDefault efi; boot.loader.systemd-boot.enable = lib.mkDefault efi;
}; };
installed-system-eval = eval-config { installed-system-eval = eval-config {
modules = [ installed-system ]; modules = [ installed-system ];
inherit (pkgs) system; inherit (pkgs) system;
}; };
installedTopLevel = ((if extendModules != null then extendModules else installed-system-eval.extendModules) { installedTopLevel =
modules = [ ((if extendModules != null then extendModules else installed-system-eval.extendModules) {
({ config, ... }: { modules = [
imports = [ (
extraSystemConfig { config, ... }:
({ 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 == [ ]; imports = [
message = '' extraSystemConfig
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 [];`. { modulesPath, ... }:
This adjustment is crucial because the `--vm-test` mechanism automatically overrides the grub boot devices as part of the virtual machine test. {
''; 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 in
makeTest' { makeTest' {
@@ -184,153 +207,177 @@ let
meta.timeout = 600; # 10 minutes meta.timeout = 600; # 10 minutes
inherit enableOCR; inherit enableOCR;
nodes.machine = { pkgs, ... }: { nodes.machine =
imports = [ { pkgs, ... }:
(lib.optionalAttrs (testMode == "module") { {
imports = [ imports = [
../module.nix (lib.optionalAttrs (testMode == "module") {
]; imports = [
disko = { ../module.nix
enableConfig = false; ];
checkScripts = true; disko = {
devices = testConfigInstall.disko.devices; enableConfig = false;
}; checkScripts = true;
}) devices = testConfigInstall.disko.devices;
extraInstallerConfig };
})
extraInstallerConfig
# from base.nix # from base.nix
({ config, ... }: { (
boot.supportedFilesystems = { config, ... }:
[ "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"; 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; if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then
} else { {
boot.initrd.services.swraid.enable = true; 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 = [ environment.systemPackages = [
pkgs.jq pkgs.jq
]; ];
# speed-up eval # speed-up eval
documentation.enable = false; documentation.enable = false;
nix.settings = { nix.settings = {
substituters = lib.mkForce [ ]; substituters = lib.mkForce [ ];
hashed-mirrors = null; hashed-mirrors = null;
connect-timeout = 1; 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 testScript =
( { nodes, ... }:
(testConfigInstall ? networking.hostId) && (testConfigInstall.networking.hostId != null) ''
) def disks(oldmachine, num_disks):
testConfigInstall.networking.hostId; 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; def create_test_machine(
oldmachine=None, **kwargs
# useful for debugging via repl ): # taken from <nixpkgs/nixos/tests/installer.nix>
system.build.systemToInstall = installed-system-eval; start_command = [
}; "${pkgs.qemu_test}/bin/qemu-kvm",
"-cpu",
testScript = { nodes, ... }: '' "max",
def disks(oldmachine, num_disks): "-m",
disk_flags = [] "1024",
for i in range(num_disks): "-virtfs",
disk_flags += [ "local,path=/nix/store,security_model=none,mount_tag=nix-store",
'-drive', *disks(oldmachine, ${toString num-disks})
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 <nixpkgs/nixos/tests/installer.nix>
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}"
] ]
''} ${lib.optionalString efi ''
machine = create_machine(start_command=" ".join(start_command), **kwargs) start_command += ["-drive",
driver.machines.append(machine) "if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}",
return machine "-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() machine.start()
${bootCommands} machine.succeed("echo -n 'additionalSecret' > /tmp/additionalSecret.key")
machine.wait_for_unit("local-fs.target") 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 in

View File

@@ -1,60 +1,71 @@
{ config, options, diskoLib, lib, rootMountPoint, parent, device, ... }: {
config,
options,
diskoLib,
lib,
rootMountPoint,
parent,
device,
...
}:
let let
swapType = lib.mkOption { swapType = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { type = lib.types.attrsOf (
options = { lib.types.submodule (
size = lib.mkOption { { name, ... }:
type = lib.types.strMatching "^([0-9]+[KMGTP])?$"; {
description = "Size of the swap file (e.g. 2G)"; options = {
}; size = lib.mkOption {
type = lib.types.strMatching "^([0-9]+[KMGTP])?$";
description = "Size of the swap file (e.g. 2G)";
};
path = lib.mkOption { path = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = name; default = name;
description = "Path to the swap file (relative to the mountpoint)"; description = "Path to the swap file (relative to the mountpoint)";
}; };
priority = lib.mkOption { priority = lib.mkOption {
type = lib.types.nullOr lib.types.int; type = lib.types.nullOr lib.types.int;
default = null; default = null;
description = '' description = ''
Specify the priority of the swap file. Priority is a value between 0 and 32767. Specify the priority of the swap file. Priority is a value between 0 and 32767.
Higher numbers indicate higher priority. Higher numbers indicate higher priority.
null lets the kernel choose a priority, which will show up as a negative value. null lets the kernel choose a priority, which will show up as a negative value.
''; '';
}; };
options = lib.mkOption { options = lib.mkOption {
type = lib.types.listOf lib.types.nonEmptyStr; type = lib.types.listOf lib.types.nonEmptyStr;
default = [ "defaults" ]; default = [ "defaults" ];
example = [ "nofail" ]; example = [ "nofail" ];
description = "Options used to mount the swap."; description = "Options used to mount the swap.";
}; };
}; };
})); }
)
);
default = { }; default = { };
description = "Swap files"; description = "Swap files";
}; };
swapConfig = { mountpoint, swap }: swapConfig =
{ mountpoint, swap }:
{ {
swapDevices = builtins.map swapDevices = builtins.map (file: {
(file: { device = "${mountpoint}/${file.path}";
device = "${mountpoint}/${file.path}"; inherit (file) priority options;
inherit (file) priority options; }) (lib.attrValues swap);
})
(lib.attrValues swap);
}; };
swapCreate = mountpoint: swap: swapCreate =
lib.concatMapStringsSep mountpoint: swap:
"\n" lib.concatMapStringsSep "\n" (file: ''
(file: '' if ! test -e "${mountpoint}/${file.path}"; then
if ! test -e "${mountpoint}/${file.path}"; then btrfs filesystem mkswapfile --size ${file.size} "${mountpoint}/${file.path}"
btrfs filesystem mkswapfile --size ${file.size} "${mountpoint}/${file.path}" fi
fi '') (lib.attrValues swap);
'')
(lib.attrValues swap);
in in
{ {
@@ -80,37 +91,42 @@ in
description = "A list of options to pass to mount."; description = "A list of options to pass to mount.";
}; };
subvolumes = lib.mkOption { subvolumes = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: { type = lib.types.attrsOf (
options = { lib.types.submodule (
name = lib.mkOption { { config, ... }:
type = lib.types.str; {
default = config._module.args.name; options = {
description = "Name of the BTRFS subvolume."; name = lib.mkOption {
}; type = lib.types.str;
type = lib.mkOption { default = config._module.args.name;
type = lib.types.enum [ "btrfs_subvol" ]; description = "Name of the BTRFS subvolume.";
default = "btrfs_subvol"; };
internal = true; type = lib.mkOption {
description = "Type"; type = lib.types.enum [ "btrfs_subvol" ];
}; default = "btrfs_subvol";
extraArgs = lib.mkOption { internal = true;
type = lib.types.listOf lib.types.str; description = "Type";
default = [ ]; };
description = "Extra arguments"; extraArgs = lib.mkOption {
}; type = lib.types.listOf lib.types.str;
mountOptions = lib.mkOption { default = [ ];
type = lib.types.listOf lib.types.str; description = "Extra arguments";
default = [ "defaults" ]; };
description = "Options to pass to mount"; mountOptions = lib.mkOption {
}; type = lib.types.listOf lib.types.str;
mountpoint = lib.mkOption { default = [ "defaults" ];
type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname; description = "Options to pass to mount";
default = null; };
description = "Location to mount the subvolume to."; mountpoint = lib.mkOption {
}; type = lib.types.nullOr diskoLib.optionTypes.absolute-pathname;
swap = swapType; default = null;
}; description = "Location to mount the subvolume to.";
})); };
swap = swapType;
};
}
)
);
default = { }; default = { };
description = "Subvolumes to define for BTRFS."; description = "Subvolumes to define for BTRFS.";
}; };
@@ -138,9 +154,9 @@ in
if ! (blkid "${config.device}" -o export | grep -q '^TYPE='); then if ! (blkid "${config.device}" -o export | grep -q '^TYPE='); then
mkfs.btrfs "${config.device}" ${toString config.extraArgs} mkfs.btrfs "${config.device}" ${toString config.extraArgs}
fi fi
${lib.optionalString (config.swap != {} || config.subvolumes != {}) '' ${lib.optionalString (config.swap != { } || config.subvolumes != { }) ''
if (blkid "${config.device}" -o export | grep -q '^TYPE=btrfs$'); then if (blkid "${config.device}" -o export | grep -q '^TYPE=btrfs$'); then
${lib.optionalString (config.swap != {}) '' ${lib.optionalString (config.swap != { }) ''
( (
MNTPOINT=$(mktemp -d) MNTPOINT=$(mktemp -d)
mount ${device} "$MNTPOINT" -o subvol=/ mount ${device} "$MNTPOINT" -o subvol=/
@@ -169,79 +185,84 @@ in
inherit config options; inherit config options;
default = default =
let let
subvolMounts = lib.concatMapAttrs subvolMounts = lib.concatMapAttrs (
(_: subvol: _: subvol:
lib.warnIf (subvol.mountOptions != (options.subvolumes.type.getSubOptions [ ]).mountOptions.default && subvol.mountpoint == null) lib.warnIf
"Subvolume ${subvol.name} has mountOptions but no mountpoint. See upgrade guide (2023-07-09 121df48)." (
lib.optionalAttrs subvol.mountOptions != (options.subvolumes.type.getSubOptions [ ]).mountOptions.default
(subvol.mountpoint != null) && subvol.mountpoint == null
{ )
${subvol.mountpoint} = '' "Subvolume ${subvol.name} has mountOptions but no mountpoint. See upgrade guide (2023-07-09 121df48)."
if ! findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then lib.optionalAttrs
mount "${config.device}" "${rootMountPoint}${subvol.mountpoint}" \ (subvol.mountpoint != null)
${lib.concatMapStringsSep " " (opt: "-o ${opt}") (subvol.mountOptions ++ [ "subvol=${subvol.name}" ])} \ {
-o X-mount.mkdir ${subvol.mountpoint} = ''
fi 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}" ])
config.subvolumes; } \
-o X-mount.mkdir
fi
'';
}
) config.subvolumes;
in in
{ {
fs = subvolMounts // lib.optionalAttrs (config.mountpoint != null) { fs =
${config.mountpoint} = '' subvolMounts
if ! findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then // lib.optionalAttrs (config.mountpoint != null) {
mount "${config.device}" "${rootMountPoint}${config.mountpoint}" \ ${config.mountpoint} = ''
${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \ if ! findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then
-o X-mount.mkdir mount "${config.device}" "${rootMountPoint}${config.mountpoint}" \
fi ${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \
''; -o X-mount.mkdir
}; fi
'';
};
}; };
}; };
_unmount = diskoLib.mkUnmountOption { _unmount = diskoLib.mkUnmountOption {
inherit config options; inherit config options;
default = default =
let let
subvolMounts = lib.concatMapAttrs subvolMounts = lib.concatMapAttrs (
(_: subvol: _: subvol:
lib.optionalAttrs lib.optionalAttrs (subvol.mountpoint != null) {
(subvol.mountpoint != null) ${subvol.mountpoint} = ''
{ if findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then
${subvol.mountpoint} = '' umount "${rootMountPoint}${subvol.mountpoint}"
if findmnt "${config.device}" "${rootMountPoint}${subvol.mountpoint}" > /dev/null 2>&1; then fi
umount "${rootMountPoint}${subvol.mountpoint}" '';
fi }
''; ) config.subvolumes;
}
)
config.subvolumes;
in in
{ {
fs = subvolMounts // lib.optionalAttrs (config.mountpoint != null) { fs =
${config.mountpoint} = '' subvolMounts
if findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then // lib.optionalAttrs (config.mountpoint != null) {
umount "${rootMountPoint}${config.mountpoint}" ${config.mountpoint} = ''
fi if findmnt "${config.device}" "${rootMountPoint}${config.mountpoint}" > /dev/null 2>&1; then
''; umount "${rootMountPoint}${config.mountpoint}"
}; fi
'';
};
}; };
}; };
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = [ default = [
(map (map (
(subvol: subvol:
lib.optional (subvol.mountpoint != null) { lib.optional (subvol.mountpoint != null) {
fileSystems.${subvol.mountpoint} = { fileSystems.${subvol.mountpoint} = {
device = config.device; device = config.device;
fsType = "btrfs"; fsType = "btrfs";
options = subvol.mountOptions ++ [ "subvol=${subvol.name}" ]; options = subvol.mountOptions ++ [ "subvol=${subvol.name}" ];
}; };
} }
) ) (lib.attrValues config.subvolumes))
(lib.attrValues config.subvolumes))
(lib.optional (config.mountpoint != null) { (lib.optional (config.mountpoint != null) {
fileSystems.${config.mountpoint} = { fileSystems.${config.mountpoint} = {
device = config.device; device = config.device;
@@ -249,11 +270,12 @@ in
options = config.mountOptions; options = config.mountOptions;
}; };
}) })
(map (map (
(subvol: swapConfig { subvol:
swapConfig {
inherit (subvol) mountpoint swap; inherit (subvol) mountpoint swap;
}) }
(lib.attrValues config.subvolumes)) ) (lib.attrValues config.subvolumes))
(swapConfig { (swapConfig {
inherit (config) mountpoint swap; inherit (config) mountpoint swap;
}) })
@@ -264,8 +286,10 @@ in
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: default = pkgs: [
[ pkgs.btrfs-progs pkgs.gnugrep ]; pkgs.btrfs-progs
pkgs.gnugrep
];
description = "Packages"; description = "Packages";
}; };
}; };

View File

@@ -1,4 +1,10 @@
{ config, options, lib, diskoLib, ... }: {
config,
options,
lib,
diskoLib,
...
}:
{ {
options = { options = {
name = lib.mkOption { name = lib.mkOption {
@@ -32,13 +38,20 @@
''; '';
default = "2G"; default = "2G";
}; };
content = diskoLib.deviceType { parent = config; device = config.device; }; content = diskoLib.deviceType {
parent = config;
device = config.device;
};
_meta = lib.mkOption { _meta = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = diskoLib.jsonType; type = diskoLib.jsonType;
default = default = lib.optionalAttrs (config.content != null) (
lib.optionalAttrs (config.content != null) (config.content._meta [ "disk" config.device ]); config.content._meta [
"disk"
config.device
]
);
description = "Metadata"; description = "Metadata";
}; };
_create = diskoLib.mkCreateOption { _create = diskoLib.mkCreateOption {
@@ -56,8 +69,7 @@
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = default = lib.optional (config.content != null) config.content._config;
lib.optional (config.content != null) config.content._config;
description = "NixOS configuration"; description = "NixOS configuration";
}; };
_pkgs = lib.mkOption { _pkgs = lib.mkOption {

View File

@@ -1,4 +1,13 @@
{ config, options, lib, diskoLib, rootMountPoint, parent, device, ... }: {
config,
options,
lib,
diskoLib,
rootMountPoint,
parent,
device,
...
}:
{ {
options = { options = {
type = lib.mkOption { type = lib.mkOption {
@@ -90,18 +99,32 @@
internal = true; internal = true;
readOnly = true; readOnly = true;
# type = lib.types.functionTo (lib.types.listOf lib.types.package); # type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: default =
[ pkgs.util-linux pkgs.gnugrep ] ++ ( pkgs:
[
pkgs.util-linux
pkgs.gnugrep
]
++ (
# TODO add many more # TODO add many more
if (config.format == "xfs") then [ pkgs.xfsprogs ] if (config.format == "xfs") then
else if (config.format == "btrfs") then [ pkgs.btrfs-progs ] [ pkgs.xfsprogs ]
else if (config.format == "vfat") then [ pkgs.dosfstools ] else if (config.format == "btrfs") then
else if (config.format == "ext2") then [ pkgs.e2fsprogs ] [ pkgs.btrfs-progs ]
else if (config.format == "ext3") then [ pkgs.e2fsprogs ] else if (config.format == "vfat") then
else if (config.format == "ext4") then [ pkgs.e2fsprogs ] [ pkgs.dosfstools ]
else if (config.format == "bcachefs") then [ pkgs.bcachefs-tools ] else if (config.format == "ext2") then
else if (config.format == "f2fs") then [ pkgs.f2fs-tools ] [ pkgs.e2fsprogs ]
else [ ] 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"; description = "Packages";
}; };

View File

@@ -1,4 +1,12 @@
{ config, options, lib, diskoLib, parent, device, ... }: {
config,
options,
lib,
diskoLib,
parent,
device,
...
}:
let let
sortedPartitions = lib.sort (x: y: x.priority < y.priority) (lib.attrValues config.partitions); sortedPartitions = lib.sort (x: y: x.priority < y.priority) (lib.attrValues config.partitions);
sortedHybridPartitions = lib.filter (p: p.hybrid != null) sortedPartitions; sortedHybridPartitions = lib.filter (p: p.hybrid != null) sortedPartitions;
@@ -16,171 +24,210 @@ in
description = "Device to use for the partition table"; description = "Device to use for the partition table";
}; };
partitions = lib.mkOption { partitions = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }@partition: { type = lib.types.attrsOf (
options = { lib.types.submodule (
type = lib.mkOption { { name, ... }@partition:
type = {
let options = {
hexPattern = len: "[A-Fa-f0-9]{${toString len}}"; type = lib.mkOption {
in type =
lib.types.either let
(lib.types.strMatching (hexPattern 4)) hexPattern = len: "[A-Fa-f0-9]{${toString len}}";
(lib.types.strMatching (lib.concatMapStringsSep "-" hexPattern [ 8 4 4 4 12 ])); in
default = if partition.config.content != null && partition.config.content.type == "swap" then "8200" else "8300"; lib.types.either (lib.types.strMatching (hexPattern 4)) (
defaultText = ''8300 (Linux filesystem) normally, 8200 (Linux swap) if content.type is "swap"''; lib.types.strMatching (
description = '' lib.concatMapStringsSep "-" hexPattern [
Filesystem type to use. 8
This can either be an sgdisk-specific short code (run sgdisk -L to see what is available), 4
or a fully specified GUID (see https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs). 4
''; 4
}; 12
device = lib.mkOption { ]
type = lib.types.str; )
default = );
if partition.config.uuid != null then default =
"/dev/disk/by-partuuid/${partition.config.uuid}" if partition.config.content != null && partition.config.content.type == "swap" then
else if config._parent.type == "mdadm" then "8200"
# workaround because mdadm partlabel do not appear in /dev/disk/by-partlabel else
"/dev/disk/by-id/md-name-any:${config._parent.name}-part${toString partition.config._index}" "8300";
else defaultText = ''8300 (Linux filesystem) normally, 8200 (Linux swap) if content.type is "swap"'';
"/dev/disk/by-partlabel/${diskoLib.hexEscapeUdevSymlink partition.config.label}"; description = ''
defaultText = '' Filesystem type to use.
if `uuid` is provided: This can either be an sgdisk-specific short code (run sgdisk -L to see what is available),
/dev/disk/by-partuuid/''${partition.config.uuid} or a fully specified GUID (see https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs).
'';
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)}
''}
'';
};
}; };
})); device = lib.mkOption {
default = null; type = lib.types.str;
description = "Entry to add to the Hybrid MBR table"; default =
}; if partition.config.uuid != null then
_index = lib.mkOption { "/dev/disk/by-partuuid/${partition.config.uuid}"
type = lib.types.int; else if config._parent.type == "mdadm" then
internal = true; # workaround because mdadm partlabel do not appear in /dev/disk/by-partlabel
default = diskoLib.indexOf (x: x.name == partition.config.name) sortedPartitions 0; "/dev/disk/by-id/md-name-any:${config._parent.name}-part${toString partition.config._index}"
defaultText = null; 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 = { }; default = { };
description = "Attrs of partitions to add to the partition table"; description = "Attrs of partitions to add to the partition table";
}; };
@@ -197,12 +244,13 @@ in
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo diskoLib.jsonType; type = lib.types.functionTo diskoLib.jsonType;
default = dev: default =
lib.foldr lib.recursiveUpdate { } (map dev:
(partition: lib.foldr lib.recursiveUpdate { } (
lib.optionalAttrs (partition.content != null) (partition.content._meta dev) map (partition: lib.optionalAttrs (partition.content != null) (partition.content._meta dev)) (
lib.attrValues config.partitions
) )
(lib.attrValues config.partitions)); );
description = "Metadata"; description = "Metadata";
}; };
_create = diskoLib.mkCreateOption { _create = diskoLib.mkCreateOption {
@@ -211,61 +259,63 @@ in
if ! blkid "${config.device}" >&2; then if ! blkid "${config.device}" >&2; then
sgdisk --clear "${config.device}" sgdisk --clear "${config.device}"
fi fi
${lib.concatMapStrings (partition: ${lib.concatMapStrings (
partition:
let let
args = '' 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}" \ --change-name="${toString partition._index}:${partition.label}" \
--typecode=${toString partition._index}:${partition.type} \ --typecode=${toString partition._index}:${partition.type} \
"${config.device}" \ "${config.device}" \
''; '';
createArgs = '' 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} \ --new=${toString partition._index}:${partition.start}:${partition.end} \
''; '';
in in
'' ''
# try to create the partition, if it fails, try to change the type and name # try to create the partition, if it fails, try to change the type and name
if ! sgdisk ${createArgs} ${args} if ! sgdisk ${createArgs} ${args}
then then
sgdisk ${args} sgdisk ${args}
fi fi
# ensure /dev/disk/by-path/..-partN exists before continuing # ensure /dev/disk/by-path/..-partN exists before continuing
partprobe "${config.device}" || : # sometimes partprobe fails, but the partitions are still up2date partprobe "${config.device}" || : # sometimes partprobe fails, but the partitions are still up2date
udevadm trigger --subsystem-match=block udevadm trigger --subsystem-match=block
udevadm settle udevadm settle
'' ''
) sortedPartitions} ) sortedPartitions}
${ ${lib.optionalString (sortedHybridPartitions != [ ]) (
lib.optionalString (sortedHybridPartitions != []) "sgdisk -h "
("sgdisk -h " + (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions))
+ (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions)) + (lib.optionalString (!config.efiGptPartitionFirst) ":EE ")
+ ( + ''"${parent.device}"''
lib.optionalString (!config.efiGptPartitionFirst) ":EE " )}
) ${lib.concatMapStrings (p: p.hybrid._create) sortedHybridPartitions}
+ ''"${parent.device}"'')
}
${lib.concatMapStrings (p:
p.hybrid._create
)
sortedHybridPartitions
}
${lib.concatStrings (map (partition: '' ${lib.concatStrings (
${lib.optionalString (partition.content != null) partition.content._create} map (partition: ''
'') sortedPartitions)} ${lib.optionalString (partition.content != null) partition.content._create}
'') sortedPartitions
)}
''; '';
}; };
_mount = diskoLib.mkMountOption { _mount = diskoLib.mkMountOption {
inherit config options; inherit config options;
default = default =
let let
partMounts = lib.foldr lib.recursiveUpdate { } (map partMounts = lib.foldr lib.recursiveUpdate { } (
(partition: map (partition: lib.optionalAttrs (partition.content != null) partition.content._mount) (
lib.optionalAttrs (partition.content != null) partition.content._mount lib.attrValues config.partitions
) )
(lib.attrValues config.partitions)); );
in in
{ {
dev = partMounts.dev or ""; dev = partMounts.dev or "";
@@ -276,11 +326,11 @@ in
inherit config options; inherit config options;
default = default =
let let
partMounts = lib.foldr lib.recursiveUpdate { } (map partMounts = lib.foldr lib.recursiveUpdate { } (
(partition: map (partition: lib.optionalAttrs (partition.content != null) partition.content._unmount) (
lib.optionalAttrs (partition.content != null) partition.content._unmount lib.attrValues config.partitions
) )
(lib.attrValues config.partitions)); );
in in
{ {
dev = partMounts.dev or ""; dev = partMounts.dev or "";
@@ -290,30 +340,31 @@ in
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = (map default =
(partition: (map (partition: lib.optional (partition.content != null) partition.content._config) (
lib.optional (partition.content != null) partition.content._config lib.attrValues config.partitions
) ))
(lib.attrValues config.partitions)) ++ (lib.optional (lib.any (part: part.type == "EF02") (lib.attrValues config.partitions)) {
++ (lib.optional (lib.any (part: part.type == "EF02") (lib.attrValues config.partitions)) { boot.loader.grub.devices = [ config.device ];
boot.loader.grub.devices = [ config.device ]; });
});
description = "NixOS configuration"; description = "NixOS configuration";
}; };
_pkgs = lib.mkOption { _pkgs = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: default =
pkgs:
[ [
pkgs.gptfdisk pkgs.gptfdisk
pkgs.systemdMinimal pkgs.systemdMinimal
pkgs.parted # for partprobe pkgs.parted # for partprobe
] ++ lib.flatten (map ]
(partition: ++ lib.flatten (
lib.optional (partition.content != null) (partition.content._pkgs pkgs) map (partition: lib.optional (partition.content != null) (partition.content._pkgs pkgs)) (
lib.attrValues config.partitions
) )
(lib.attrValues config.partitions)); );
description = "Packages"; description = "Packages";
}; };
}; };

View File

@@ -1,20 +1,30 @@
{ config, options, lib, diskoLib, parent, device, ... }: {
config,
options,
lib,
diskoLib,
parent,
device,
...
}:
let let
keyFile = keyFile =
if config.settings ? "keyFile" if config.settings ? "keyFile" then
then config.settings.keyFile config.settings.keyFile
else if config.askPassword else if config.askPassword then
then ''<(set +x; echo -n "$password"; set -x)'' ''<(set +x; echo -n "$password"; set -x)''
else if config.passwordFile != null else if
config.passwordFile != null
# do not print the password to the console # do not print the password to the console
then ''<(set +x; echo -n "$(cat ${config.passwordFile})"; set -x)''
else if config.keyFile != null
then then
lib.warn ''<(set +x; echo -n "$(cat ${config.passwordFile})"; set -x)''
("The option `keyFile` is deprecated." else if config.keyFile != null then
+ "Use passwordFile instead if you want to use interactive login or settings.keyFile if you want to use key file login") lib.warn (
config.keyFile "The option `keyFile` is deprecated."
else null; + "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 = '' keyFileArgs = ''
${lib.optionalString (keyFile != null) "--key-file ${keyFile}"} \ ${lib.optionalString (keyFile != null) "--key-file ${keyFile}"} \
${lib.optionalString (lib.hasAttr "keyFileSize" config.settings) "--keyfile-size ${builtins.toString config.settings.keyFileSize}"} \ ${lib.optionalString (lib.hasAttr "keyFileSize" config.settings) "--keyfile-size ${builtins.toString config.settings.keyFileSize}"} \
@@ -23,7 +33,10 @@ let
cryptsetupOpen = '' cryptsetupOpen = ''
cryptsetup open "${config.device}" "${config.name}" \ cryptsetup open "${config.device}" "${config.name}" \
${lib.optionalString (config.settings.allowDiscards or false) "--allow-discards"} \ ${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} \ ${toString config.extraOpenArgs} \
${keyFileArgs} \ ${keyFileArgs} \
''; '';
@@ -58,7 +71,7 @@ in
}; };
askPassword = lib.mkOption { askPassword = lib.mkOption {
type = lib.types.bool; 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"; defaultText = "true if neither keyFile nor passwordFile are set";
description = "Whether to ask for a password for initial encryption"; description = "Whether to ask for a password for initial encryption";
}; };
@@ -66,13 +79,14 @@ in
type = lib.types.attrsOf lib.types.anything; type = lib.types.attrsOf lib.types.anything;
default = { }; default = { };
description = "LUKS settings (as defined in configuration.nix in boot.initrd.luks.devices.<name>)"; description = "LUKS settings (as defined in configuration.nix in boot.initrd.luks.devices.<name>)";
example = ''{ example = ''
keyFile = "/tmp/disk.key"; {
keyFileSize = 2048; keyFile = "/tmp/disk.key";
keyFileOffset = 1024; keyFileSize = 2048;
fallbackToPassword = true; keyFileOffset = 1024;
allowDiscards = true; fallbackToPassword = true;
}; allowDiscards = true;
};
''; '';
}; };
additionalKeyFiles = lib.mkOption { additionalKeyFiles = lib.mkOption {
@@ -98,7 +112,10 @@ in
description = "Extra arguments to pass to `cryptsetup luksOpen` when opening"; description = "Extra arguments to pass to `cryptsetup luksOpen` when opening";
example = [ "--timeout 10" ]; 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 { _parent = lib.mkOption {
internal = true; internal = true;
default = parent; default = parent;
@@ -107,8 +124,7 @@ in
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo diskoLib.jsonType; type = lib.types.functionTo diskoLib.jsonType;
default = dev: default = dev: lib.optionalAttrs (config.content != null) (config.content._meta dev);
lib.optionalAttrs (config.content != null) (config.content._meta dev);
description = "Metadata"; description = "Metadata";
}; };
_create = diskoLib.mkCreateOption { _create = diskoLib.mkCreateOption {
@@ -136,9 +152,11 @@ in
''} ''}
cryptsetup -q luksFormat "${config.device}" ${toString config.extraFormatArgs} ${keyFileArgs} cryptsetup -q luksFormat "${config.device}" ${toString config.extraFormatArgs} ${keyFileArgs}
${cryptsetupOpen} --persistent ${cryptsetupOpen} --persistent
${toString (lib.forEach config.additionalKeyFiles (keyFile: '' ${toString (
cryptsetup luksAddKey "${config.device}" ${keyFile} ${keyFileArgs} lib.forEach config.additionalKeyFiles (keyFile: ''
''))} cryptsetup luksAddKey "${config.device}" ${keyFile} ${keyFileArgs}
'')
)}
fi fi
${lib.optionalString (config.content != null) config.content._create} ${lib.optionalString (config.content != null) config.content._create}
''; '';
@@ -176,34 +194,42 @@ in
let let
contentUnmount = config.content._unmount; contentUnmount = config.content._unmount;
in in
{ {
dev = '' dev = ''
${lib.optionalString (config.content != null) contentUnmount.dev or ""} ${lib.optionalString (config.content != null) contentUnmount.dev or ""}
if cryptsetup status "${config.name}" >/dev/null 2>/dev/null; then if cryptsetup status "${config.name}" >/dev/null 2>/dev/null; then
cryptsetup close "${config.name}" cryptsetup close "${config.name}"
fi fi
''; '';
}; };
}; };
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = [ ] default =
[ ]
# If initrdUnlock is true, then add a device entry to the initrd.luks.devices config. # If initrdUnlock is true, then add a device entry to the initrd.luks.devices config.
++ (lib.optional config.initrdUnlock [ ++ (lib.optional config.initrdUnlock [
{ {
boot.initrd.luks.devices.${config.name} = { boot.initrd.luks.devices.${config.name} = {
inherit (config) device; inherit (config) device;
} // config.settings; } // config.settings;
} }
]) ++ (lib.optional (config.content != null) config.content._config); ])
++ (lib.optional (config.content != null) config.content._config);
description = "NixOS configuration"; description = "NixOS configuration";
}; };
_pkgs = lib.mkOption { _pkgs = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); 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"; description = "Packages";
}; };
}; };

View File

@@ -1,4 +1,12 @@
{ config, options, lib, diskoLib, parent, device, ... }: {
config,
options,
lib,
diskoLib,
parent,
device,
...
}:
{ {
options = { options = {
type = lib.mkOption { type = lib.mkOption {
@@ -55,7 +63,10 @@
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: [ pkgs.gnugrep pkgs.lvm2 ]; default = pkgs: [
pkgs.gnugrep
pkgs.lvm2
];
description = "Packages"; description = "Packages";
}; };
}; };

View File

@@ -1,14 +1,22 @@
{ config, options, lib, diskoLib, ... }: {
config,
options,
lib,
diskoLib,
...
}:
let let
# Load kernel modules to ensure device mapper types are available # Load kernel modules to ensure device mapper types are available
kernelModules = kernelModules =
[ [
# Prevent unbootable systems if LVM snapshots are present at boot time. # Prevent unbootable systems if LVM snapshots are present at boot time.
"dm-snapshot" "dm-snapshot"
] ++ ]
lib.filter (x: x != "") (map ++ lib.filter (x: x != "") (
(lv: lib.optionalString (lv.lvm_type != null && lv.lvm_type != "thinlv") "dm-${lv.lvm_type}") map (lv: lib.optionalString (lv.lvm_type != null && lv.lvm_type != "thinlv") "dm-${lv.lvm_type}") (
(lib.attrValues config.lvs)); lib.attrValues config.lvs
)
);
in in
{ {
options = { options = {
@@ -23,44 +31,65 @@ in
description = "Type"; description = "Type";
}; };
lvs = lib.mkOption { lvs = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }@lv: { type = lib.types.attrsOf (
options = { lib.types.submodule (
name = lib.mkOption { { name, ... }@lv:
type = lib.types.str; {
default = name; options = {
description = "Name of the logical volume"; name = lib.mkOption {
}; type = lib.types.str;
priority = lib.mkOption { default = name;
type = lib.types.int; description = "Name of the logical volume";
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 '' priority = lib.mkOption {
if (lib.hasInfix "100%" lv.config.size) then 9001 else 1000 type = lib.types.int;
''; default =
description = "Priority of the logical volume, smaller values are created first"; (if lv.config.lvm_type == "thin-pool" then 501 else 1000)
}; + (if lib.hasInfix "100%" lv.config.size then 251 else 0);
size = lib.mkOption { defaultText = lib.literalExpression ''
type = lib.types.str; # TODO lvm size type if (lib.hasInfix "100%" lv.config.size) then 9001 else 1000
description = "Size of the logical volume"; '';
}; description = "Priority of the logical volume, smaller values are created first";
lvm_type = lib.mkOption { };
# TODO: add raid10 size = lib.mkOption {
type = lib.types.nullOr (lib.types.enum [ "mirror" "raid0" "raid1" "raid4" "raid5" "raid6" "thin-pool" "thinlv" ]); # TODO add all lib.types type = lib.types.str; # TODO lvm size type
default = null; # maybe there is always a default type? description = "Size of the logical volume";
description = "LVM type"; };
}; lvm_type = lib.mkOption {
extraArgs = lib.mkOption { # TODO: add raid10
type = lib.types.listOf lib.types.str; type = lib.types.nullOr (
default = [ ]; lib.types.enum [
description = "Extra arguments"; "mirror"
}; "raid0"
pool = lib.mkOption { "raid1"
type = lib.types.nullOr lib.types.str; "raid4"
default = null; "raid5"
description = "Name of pool LV that this LV belongs to"; "raid6"
}; "thin-pool"
content = diskoLib.partitionType { parent = config; device = "/dev/${config.name}/${lv.config.name}"; }; "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 = { }; default = { };
description = "LVS for the volume group"; description = "LVS for the volume group";
}; };
@@ -68,12 +97,15 @@ in
internal = true; internal = true;
readOnly = true; readOnly = true;
type = diskoLib.jsonType; type = diskoLib.jsonType;
default = default = diskoLib.deepMergeMap (
diskoLib.deepMergeMap lv:
(lv: lib.optionalAttrs (lv.content != null) (
lib.optionalAttrs (lv.content != null) (lv.content._meta [ "lvm_vg" config.name ]) lv.content._meta [
) "lvm_vg"
(lib.attrValues config.lvs); config.name
]
)
) (lib.attrValues config.lvs);
description = "Metadata"; description = "Metadata";
}; };
_create = diskoLib.mkCreateOption { _create = diskoLib.mkCreateOption {
@@ -93,8 +125,14 @@ in
if ! lvdisplay "${config.name}/${lv.name}"; then if ! lvdisplay "${config.name}/${lv.name}"; then
lvcreate \ lvcreate \
--yes \ --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} \ ${if lib.hasSuffix "%" lv.size then "${lv.size}FREE" else lv.size} \
-n "${lv.name}" \ -n "${lv.name}" \
${lib.optionalString (lv.lvm_type == "thinlv") "--thinpool=${lv.pool}"} \ ${lib.optionalString (lv.lvm_type == "thinlv") "--thinpool=${lv.pool}"} \
@@ -113,11 +151,9 @@ in
inherit config options; inherit config options;
default = default =
let let
lvMounts = diskoLib.deepMergeMap lvMounts = diskoLib.deepMergeMap (lv: lib.optionalAttrs (lv.content != null) lv.content._mount) (
(lv: lib.attrValues config.lvs
lib.optionalAttrs (lv.content != null) lv.content._mount );
)
(lib.attrValues config.lvs);
in in
{ {
dev = '' dev = ''
@@ -131,12 +167,11 @@ in
inherit config options; inherit config options;
default = default =
let let
lvMounts = diskoLib.deepMergeMap lvMounts = diskoLib.deepMergeMap (lv: lib.optionalAttrs (lv.content != null) lv.content._unmount) (
(lv: lib.attrValues config.lvs
lib.optionalAttrs (lv.content != null) lv.content._unmount );
) in
(lib.attrValues config.lvs); {
in {
dev = '' dev = ''
${lib.concatMapStrings (x: x.dev or "") (lib.attrValues lvMounts)} ${lib.concatMapStrings (x: x.dev or "") (lib.attrValues lvMounts)}
vgchange -a n vgchange -a n
@@ -147,36 +182,35 @@ in
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = [{ boot.initrd.kernelModules = kernelModules; }] ++ default =
map [ { boot.initrd.kernelModules = kernelModules; } ]
(lv: [ ++ map (lv: [
(lib.optional (lv.content != null) lv.content._config) (lib.optional (lv.content != null) lv.content._config)
(lib.optional (lv.lvm_type != null) { (lib.optional (lv.lvm_type != null) {
boot.initrd.kernelModules = [ boot.initrd.kernelModules =
[
(if lv.lvm_type == "mirror" then "dm-mirror" else "dm-raid") (if lv.lvm_type == "mirror" then "dm-mirror" else "dm-raid")
] ]
++ lib.optional (lv.lvm_type == "raid0") "raid0" ++ lib.optional (lv.lvm_type == "raid0") "raid0"
++ lib.optional (lv.lvm_type == "raid1") "raid1" ++ lib.optional (lv.lvm_type == "raid1") "raid1"
# ++ lib.optional (lv.lvm_type == "raid10") "raid10" # ++ lib.optional (lv.lvm_type == "raid10") "raid10"
++ lib.optional ++ lib.optional (
(lv.lvm_type == "raid4" || lv.lvm_type == "raid4" || lv.lvm_type == "raid5" || lv.lvm_type == "raid6"
lv.lvm_type == "raid5" || ) "raid456";
lv.lvm_type == "raid6") "raid456";
}) })
]) ]) (lib.attrValues config.lvs);
(lib.attrValues config.lvs);
description = "NixOS configuration"; description = "NixOS configuration";
}; };
_pkgs = lib.mkOption { _pkgs = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: lib.flatten (map default =
(lv: pkgs:
lib.optional (lv.content != null) (lv.content._pkgs pkgs) lib.flatten (
) map (lv: lib.optional (lv.content != null) (lv.content._pkgs pkgs)) (lib.attrValues config.lvs)
(lib.attrValues config.lvs)); );
description = "Packages"; description = "Packages";
}; };
}; };

View File

@@ -1,4 +1,10 @@
{ config, options, lib, diskoLib, ... }: {
config,
options,
lib,
diskoLib,
...
}:
{ {
options = { options = {
name = lib.mkOption { name = lib.mkOption {
@@ -18,17 +24,32 @@
description = "mdadm level"; description = "mdadm level";
}; };
metadata = lib.mkOption { 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"; default = "default";
description = "Metadata"; 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 { _meta = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = diskoLib.jsonType; type = diskoLib.jsonType;
default = default = lib.optionalAttrs (config.content != null) (
lib.optionalAttrs (config.content != null) (config.content._meta [ "mdadm" config.name ]); config.content._meta [
"mdadm"
config.name
]
);
description = "Metadata"; description = "Metadata";
}; };
_create = diskoLib.mkCreateOption { _create = diskoLib.mkCreateOption {
@@ -54,45 +75,52 @@
}; };
_mount = diskoLib.mkMountOption { _mount = diskoLib.mkMountOption {
inherit config options; inherit config options;
default = default = lib.optionalAttrs (config.content != null) config.content._mount;
lib.optionalAttrs (config.content != null) config.content._mount;
# TODO we probably need to assemble the mdadm somehow # TODO we probably need to assemble the mdadm somehow
}; };
_unmount = diskoLib.mkUnmountOption { _unmount = diskoLib.mkUnmountOption {
inherit config options; inherit config options;
default = let default =
content = lib.optionalAttrs (config.content != null) config.content._unmount; let
in { content = lib.optionalAttrs (config.content != null) config.content._unmount;
fs = content.fs; in
dev = '' {
${content.dev or ""} fs = content.fs;
if [ -e "/dev/md/${config.name}" ]; then dev = ''
mdadm --stop "/dev/md/${config.name}" ${content.dev or ""}
fi if [ -e "/dev/md/${config.name}" ]; then
''; mdadm --stop "/dev/md/${config.name}"
}; fi
'';
};
}; };
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = default = [
[ (
(if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then { if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then
boot.swraid.enable = true; {
} else { boot.swraid.enable = true;
boot.initrd.services.swraid.enable = true; }
}) else
] ++ {
lib.optional (config.content != null) config.content._config; boot.initrd.services.swraid.enable = true;
}
)
] ++ lib.optional (config.content != null) config.content._config;
description = "NixOS configuration"; description = "NixOS configuration";
}; };
_pkgs = lib.mkOption { _pkgs = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: [ default =
pkgs.parted # for partprobe pkgs:
] ++ (lib.optionals (config.content != null) (config.content._pkgs pkgs)); [
pkgs.parted # for partprobe
]
++ (lib.optionals (config.content != null) (config.content._pkgs pkgs));
description = "Packages"; description = "Packages";
}; };
}; };

View File

@@ -1,4 +1,12 @@
{ config, options, lib, diskoLib, parent, device, ... }: {
config,
options,
lib,
diskoLib,
parent,
device,
...
}:
{ {
options = { options = {
type = lib.mkOption { type = lib.mkOption {

View File

@@ -1,4 +1,11 @@
{ lib, config, options, diskoLib, rootMountPoint, ... }: {
lib,
config,
options,
diskoLib,
rootMountPoint,
...
}:
{ {
options = { options = {
type = lib.mkOption { type = lib.mkOption {

View File

@@ -1,4 +1,12 @@
{ diskoLib, config, options, lib, parent, device, ... }: {
diskoLib,
config,
options,
lib,
parent,
device,
...
}:
{ {
options = { options = {
type = lib.mkOption { type = lib.mkOption {
@@ -14,7 +22,13 @@
discardPolicy = lib.mkOption { discardPolicy = lib.mkOption {
default = null; default = null;
example = "once"; example = "once";
type = lib.types.nullOr (lib.types.enum [ "once" "pages" "both" ]); type = lib.types.nullOr (
lib.types.enum [
"once"
"pages"
"both"
]
);
description = '' description = ''
Specify the discard policy for the swap device. If "once", then the Specify the discard policy for the swap device. If "once", then the
whole swap space is discarded at swapon invocation. If "pages", 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 if test "''${DISKO_SKIP_SWAP:-}" != 1 && ! swapon --show | grep -q "^$(readlink -f "${config.device}") "; then
swapon ${ swapon ${
lib.optionalString (config.discardPolicy != null) lib.optionalString (config.discardPolicy != null)
"--discard${lib.optionalString (config.discardPolicy != "both") "--discard${lib.optionalString (config.discardPolicy != "both") "=${config.discardPolicy}"}"
"=${config.discardPolicy}" } ${lib.optionalString (config.priority != null) "--priority=${toString config.priority}"} \
}"} ${
lib.optionalString (config.priority != null)
"--priority=${toString config.priority}"
} \
--options=${lib.concatStringsSep "," config.mountOptions} \ --options=${lib.concatStringsSep "," config.mountOptions} \
"${config.device}" "${config.device}"
fi fi
@@ -108,26 +118,33 @@
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = [{ default = [
swapDevices = [{ {
device = config.device; swapDevices = [
inherit (config) discardPolicy priority; {
randomEncryption = { device = config.device;
enable = config.randomEncryption; inherit (config) discardPolicy priority;
# forward discard/TRIM attempts through dm-crypt randomEncryption = {
allowDiscards = config.discardPolicy != null; enable = config.randomEncryption;
}; # forward discard/TRIM attempts through dm-crypt
options = config.mountOptions; allowDiscards = config.discardPolicy != null;
}]; };
boot.resumeDevice = lib.mkIf config.resumeDevice config.device; options = config.mountOptions;
}]; }
];
boot.resumeDevice = lib.mkIf config.resumeDevice config.device;
}
];
description = "NixOS configuration"; description = "NixOS configuration";
}; };
_pkgs = lib.mkOption { _pkgs = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); 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"; description = "Packages";
}; };
}; };

View File

@@ -1,179 +1,227 @@
{ config, options, lib, diskoLib, parent, device, ... }:
{ {
options = lib.warn '' config,
The legacy table is outdated and should not be used. We recommend using the gpt type instead. options,
Please note that certain features, such as the test framework, may not function properly with the legacy table type. lib,
If you encounter errors similar to: diskoLib,
"error: The option `disko.devices.disk.disk1.content.partitions."[definition 1-entry 1]".content._config` is read-only, but it's set multiple times," parent,
this is likely due to the use of the legacy table type. device,
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 { options =
type = lib.types.enum [ "table" ]; lib.warn
internal = true; ''
description = "Partition table"; 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.
device = lib.mkOption { If you encounter errors similar to:
type = lib.types.str; "error: The option `disko.devices.disk.disk1.content.partitions."[definition 1-entry 1]".content._config` is read-only, but it's set multiple times,"
default = device; this is likely due to the use of the legacy table type.
description = "Device to partition"; for a migration you can follow the guide at https://github.com/nix-community/disko/blob/master/docs/table-to-gpt.md
}; ''
format = lib.mkOption { {
type = lib.types.enum [ "gpt" "msdos" ]; type = lib.mkOption {
default = "gpt"; type = lib.types.enum [ "table" ];
description = "The kind of partition table"; internal = true;
}; description = "Partition table";
partitions = lib.mkOption { };
type = lib.types.listOf (lib.types.submodule ({ name, ... }@partition: { device = lib.mkOption {
options = { type = lib.types.str;
part-type = lib.mkOption { default = device;
type = lib.types.enum [ "primary" "logical" "extended" ]; description = "Device to partition";
default = "primary"; };
description = "Partition type"; format = lib.mkOption {
}; type = lib.types.enum [
fs-type = lib.mkOption { "gpt"
type = lib.types.nullOr (lib.types.enum [ "btrfs" "ext2" "ext3" "ext4" "fat16" "fat32" "hfs" "hfs+" "linux-swap" "ntfs" "reiserfs" "udf" "xfs" ]); "msdos"
default = null; ];
description = "Filesystem type to use"; default = "gpt";
}; description = "The kind of partition table";
name = lib.mkOption { };
type = lib.types.nullOr lib.types.str; partitions = lib.mkOption {
description = "Name of the partition"; type = lib.types.listOf (
}; lib.types.submodule (
start = lib.mkOption { { name, ... }@partition:
type = lib.types.str; {
default = "0%"; options = {
description = "Start of the partition"; part-type = lib.mkOption {
}; type = lib.types.enum [
end = lib.mkOption { "primary"
type = lib.types.str; "logical"
default = "100%"; "extended"
description = "End of the partition"; ];
}; default = "primary";
flags = lib.mkOption { description = "Partition type";
type = lib.types.listOf lib.types.str; };
default = [ ]; fs-type = lib.mkOption {
description = "Partition flags"; type = lib.types.nullOr (
}; lib.types.enum [
bootable = lib.mkOption { "btrfs"
type = lib.types.bool; "ext2"
default = false; "ext3"
description = "Whether to make the partition bootable"; "ext4"
}; "fat16"
content = diskoLib.partitionType { parent = config; device = diskoLib.deviceNumbering config.device partition.config._index; }; "fat32"
_index = lib.mkOption { "hfs"
type = lib.types.int; "hfs+"
internal = true; "linux-swap"
default = lib.toInt (lib.head (builtins.match ".*entry ([[:digit:]]+)]" name)); "ntfs"
defaultText = null; "reiserfs"
}; "udf"
}; "xfs"
})); ]
default = [ ]; );
description = "List of partitions to add to the partition table"; default = null;
}; description = "Filesystem type to use";
_parent = lib.mkOption { };
internal = true; name = lib.mkOption {
default = parent; type = lib.types.nullOr lib.types.str;
}; description = "Name of the partition";
_meta = lib.mkOption { };
internal = true; start = lib.mkOption {
readOnly = true; type = lib.types.str;
type = lib.types.functionTo diskoLib.jsonType; default = "0%";
default = dev: description = "Start of the partition";
lib.foldr lib.recursiveUpdate { } (lib.imap };
(_index: partition: end = lib.mkOption {
lib.optionalAttrs (partition.content != null) (partition.content._meta dev) 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";
};
};
} }

View File

@@ -1,4 +1,12 @@
{ config, options, lib, diskoLib, parent, device, ... }: {
config,
options,
lib,
diskoLib,
parent,
device,
...
}:
{ {
options = { options = {
type = lib.mkOption { type = lib.mkOption {

View File

@@ -1,4 +1,12 @@
{ config, options, lib, diskoLib, rootMountPoint, parent, ... }: {
config,
options,
lib,
diskoLib,
rootMountPoint,
parent,
...
}:
{ {
options = { options = {
name = lib.mkOption { name = lib.mkOption {
@@ -58,45 +66,53 @@
default = true; default = true;
}; };
_create = diskoLib.mkCreateOption _create = diskoLib.mkCreateOption {
{ inherit config options;
inherit config options; # -u prevents mounting newly created datasets, which is
# -u prevents mounting newly created datasets, which is # important to prevent accidental shadowing of mount points
# important to prevent accidental shadowing of mount points # since (create order != mount order)
# since (create order != mount order) # -p creates parents automatically
# -p creates parents automatically default =
default = let
let createOptions =
createOptions = (lib.optionalAttrs (config.mountpoint != null) { mountpoint = config.mountpoint; }) // config.options; (lib.optionalAttrs (config.mountpoint != null) { mountpoint = config.mountpoint; })
# All options defined as PROP_ONETIME or PROP_ONETIME_DEFAULT in https://github.com/openzfs/zfs/blob/master/module/zcommon/zfs_prop.c // config.options;
onetimeProperties = [ # All options defined as PROP_ONETIME or PROP_ONETIME_DEFAULT in https://github.com/openzfs/zfs/blob/master/module/zcommon/zfs_prop.c
"encryption" onetimeProperties = [
"casesensitivity" "encryption"
"utf8only" "casesensitivity"
"normalization" "utf8only"
"volblocksize" "normalization"
"pbkdf2iters" "volblocksize"
"pbkdf2salt" "pbkdf2iters"
"keyformat" "pbkdf2salt"
]; "keyformat"
updateOptions = builtins.removeAttrs createOptions onetimeProperties; ];
in updateOptions = builtins.removeAttrs createOptions onetimeProperties;
'' in
if ! zfs get type ${config._name} >/dev/null 2>&1; then ''
${if config._createFilesystem then '' if ! zfs get type ${config._name} >/dev/null 2>&1; then
zfs create -up ${config._name} \ ${
${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-o ${n}=${v}") (createOptions))} if config._createFilesystem then
'' else '' ''
# don't create anything for root dataset of zpools zfs create -up ${config._name} \
true ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "-o ${n}=${v}") (createOptions))}
''} ''
${lib.optionalString (updateOptions != {}) '' else
''
# don't create anything for root dataset of zpools
true
''
}
${lib.optionalString (updateOptions != { }) ''
else else
zfs set -u ${lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${v}") updateOptions)} ${config._name} zfs set -u ${
''} lib.concatStringsSep " " (lib.mapAttrsToList (n: v: "${n}=${v}") updateOptions)
fi } ${config._name}
''; ''}
}; fi
'';
};
_mount = diskoLib.mkMountOption { _mount = diskoLib.mkMountOption {
inherit config options; inherit config options;
@@ -107,17 +123,20 @@
zfs load-key ${config._name} zfs load-key ${config._name}
fi fi
''; '';
}) // lib.optionalAttrs (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") { })
fs.${config.mountpoint} = '' // lib.optionalAttrs
if ! findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off")
mount ${config._name} "${rootMountPoint}${config.mountpoint}" \ {
-o X-mount.mkdir \ fs.${config.mountpoint} = ''
${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \ if ! findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then
${lib.optionalString ((config.options.mountpoint or "") != "legacy") "-o zfsutil"} \ mount ${config._name} "${rootMountPoint}${config.mountpoint}" \
-t zfs -o X-mount.mkdir \
fi ${lib.concatMapStringsSep " " (opt: "-o ${opt}") config.mountOptions} \
''; ${lib.optionalString ((config.options.mountpoint or "") != "legacy") "-o zfsutil"} \
}; -t zfs
fi
'';
};
}; };
_unmount = diskoLib.mkUnmountOption { _unmount = diskoLib.mkUnmountOption {
@@ -125,26 +144,32 @@
default = default =
(lib.optionalAttrs (config.options.keylocation or "none" != "none") { (lib.optionalAttrs (config.options.keylocation or "none" != "none") {
dev = "zfs unload-key ${config.name}"; dev = "zfs unload-key ${config.name}";
}) // lib.optionalAttrs (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") { })
fs.${config.mountpoint} = '' // lib.optionalAttrs
if findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off")
umount "${rootMountPoint}${config.mountpoint}" {
fi fs.${config.mountpoint} = ''
''; if findmnt ${config._name} "${rootMountPoint}${config.mountpoint}" >/dev/null 2>&1; then
}; umount "${rootMountPoint}${config.mountpoint}"
fi
'';
};
}; };
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = default =
lib.optional (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off") { lib.optional (config.options.mountpoint or "" != "none" && config.options.canmount or "" != "off")
fileSystems.${config.mountpoint} = { {
device = "${config._name}"; fileSystems.${config.mountpoint} = {
fsType = "zfs"; device = "${config._name}";
options = config.mountOptions ++ lib.optional ((config.options.mountpoint or "") != "legacy") "zfsutil"; fsType = "zfs";
options =
config.mountOptions
++ lib.optional ((config.options.mountpoint or "") != "legacy") "zfsutil";
};
}; };
};
description = "NixOS configuration"; description = "NixOS configuration";
}; };
@@ -157,4 +182,3 @@
}; };
}; };
} }

View File

@@ -1,4 +1,11 @@
{ config, options, lib, diskoLib, parent, ... }: {
config,
options,
lib,
diskoLib,
parent,
...
}:
{ {
options = { options = {
name = lib.mkOption { name = lib.mkOption {
@@ -35,7 +42,10 @@
description = "Size of the dataset"; 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 { _parent = lib.mkOption {
internal = true; internal = true;
@@ -45,8 +55,7 @@
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo diskoLib.jsonType; type = lib.types.functionTo diskoLib.jsonType;
default = dev: default = dev: lib.optionalAttrs (config.content != null) (config.content._meta dev);
lib.optionalAttrs (config.content != null) (config.content._meta dev);
description = "Metadata"; description = "Metadata";
}; };
_create = diskoLib.mkCreateOption { _create = diskoLib.mkCreateOption {
@@ -83,31 +92,34 @@
inherit config options; inherit config options;
default = { default = {
dev = '' 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 ""} ${config.content._unmount.dev or ""}
''; '';
fs = config.content._unmount.fs or {}; fs = config.content._unmount.fs or { };
}; };
}; };
_config = lib.mkOption { _config = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = default = lib.optional (config.content != null) config.content._config;
lib.optional (config.content != null) config.content._config;
description = "NixOS configuration"; description = "NixOS configuration";
}; };
_pkgs = lib.mkOption { _pkgs = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs: [ default =
pkgs.util-linux pkgs:
pkgs.parted # for partprobe [
] ++ lib.optionals (config.content != null) (config.content._pkgs pkgs); pkgs.util-linux
pkgs.parted # for partprobe
]
++ lib.optionals (config.content != null) (config.content._pkgs pkgs);
description = "Packages"; description = "Packages";
}; };
}; };
} }

View File

@@ -1,4 +1,11 @@
{ config, options, lib, diskoLib, rootMountPoint, ... }: {
config,
options,
lib,
diskoLib,
rootMountPoint,
...
}:
let let
# TODO: Consider expanding to handle `file` and `draid` mode options. # TODO: Consider expanding to handle `file` and `draid` mode options.
modeOptions = [ modeOptions = [
@@ -63,134 +70,161 @@ in
}; };
}; };
}; };
type = (lib.types.oneOf [ type = (
(lib.types.enum modeOptions) lib.types.oneOf [
(lib.types.attrsOf (diskoLib.subType { (lib.types.enum modeOptions)
types = { (lib.types.attrsOf (
topology = diskoLib.subType {
let types = {
vdev = lib.types.submodule ({ ... }: { topology =
options = { let
mode = lib.mkOption { vdev = lib.types.submodule (
type = lib.types.enum modeOptions; { ... }:
default = ""; {
description = "Mode of the zfs vdev"; options = {
}; mode = lib.mkOption {
members = lib.mkOption { type = lib.types.enum modeOptions;
type = lib.types.listOf lib.types.str; default = "";
description = "Members of the vdev"; description = "Mode of the zfs vdev";
}; };
}; members = lib.mkOption {
}); type = lib.types.listOf lib.types.str;
in description = "Members of the vdev";
lib.types.submodule };
({ ... }: { };
options = { }
type = lib.mkOption { );
type = lib.types.enum [ "topology" ]; in
default = "topology"; lib.types.submodule (
internal = true; { ... }:
description = "Type"; {
}; options = {
# zfs device types type = lib.mkOption {
vdev = lib.mkOption { type = lib.types.enum [ "topology" ];
type = lib.types.listOf vdev; default = "topology";
default = [ ]; internal = true;
description = '' description = "Type";
A list of storage vdevs. See };
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Virtual_Devices_(vdevs) # zfs device types
for details. vdev = lib.mkOption {
''; type = lib.types.listOf vdev;
example = [ default = [ ];
{ description = ''
mode = "mirror"; A list of storage vdevs. See
members = [ "x" "y" ]; https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Virtual_Devices_(vdevs)
} for details.
{ '';
members = [ "z" ]; example = [
} {
]; mode = "mirror";
}; members = [
spare = lib.mkOption { "x"
type = lib.types.listOf lib.types.str; "y"
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 members = [ "z" ];
for details. }
''; ];
example = [ "x" "y" ]; };
}; spare = lib.mkOption {
log = lib.mkOption { type = lib.types.listOf lib.types.str;
type = lib.types.listOf vdev; default = [ ];
default = [ ]; description = ''
description = '' A list of devices to use as hot spares. See
A list of vdevs used for the zfs intent log (ZIL). See https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Hot_Spares
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Intent_Log for details.
for details. '';
''; example = [
example = [ "x"
{ "y"
mode = "mirror"; ];
members = [ "x" "y" ]; };
} log = lib.mkOption {
{ type = lib.types.listOf vdev;
members = [ "z" ]; 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
dedup = lib.mkOption { for details.
type = lib.types.listOf vdev; '';
default = [ ]; example = [
description = '' {
A list of vdevs used for the deduplication table. See mode = "mirror";
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#dedup members = [
for details. "x"
''; "y"
example = [ ];
{ }
mode = "mirror"; {
members = [ "x" "y" ]; members = [ "z" ];
} }
{ ];
members = [ "z" ]; };
} dedup = lib.mkOption {
]; type = lib.types.listOf vdev;
}; default = [ ];
special = lib.mkOption { description = ''
type = lib.types.either (lib.types.listOf vdev) (lib.types.nullOr vdev); A list of vdevs used for the deduplication table. See
default = [ ]; https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#dedup
description = '' for details.
A list of vdevs used as special devices. See '';
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#special example = [
for details. {
''; mode = "mirror";
example = [ members = [
{ "x"
mode = "mirror"; "y"
members = [ "x" "y" ]; ];
} }
{ {
members = [ "z" ]; members = [ "z" ];
} }
]; ];
}; };
cache = lib.mkOption { special = lib.mkOption {
type = lib.types.listOf lib.types.str; type = lib.types.either (lib.types.listOf vdev) (lib.types.nullOr vdev);
default = [ ]; default = [ ];
description = '' description = ''
A dedicated zfs cache device (L2ARC). See A list of vdevs used as special devices. See
https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#Cache_Devices https://openzfs.github.io/openzfs-docs/man/master/7/zpoolconcepts.7.html#special
for details. for details.
''; '';
example = [ "x" "y" ]; example = [
}; {
}; mode = "mirror";
}); members = [
}; "x"
extraArgs.parent = config; "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"; description = "Mode of the ZFS pool";
}; };
options = lib.mkOption { options = lib.mkOption {
@@ -214,18 +248,25 @@ in
description = "Options to pass to mount"; description = "Options to pass to mount";
}; };
datasets = lib.mkOption { datasets = lib.mkOption {
type = lib.types.attrsOf (diskoLib.subType { type = lib.types.attrsOf (
types = { inherit (diskoLib.types) zfs_fs zfs_volume; }; diskoLib.subType {
extraArgs.parent = config; types = { inherit (diskoLib.types) zfs_fs zfs_volume; };
}); extraArgs.parent = config;
}
);
description = "List of datasets to define"; description = "List of datasets to define";
}; };
_meta = lib.mkOption { _meta = lib.mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
type = diskoLib.jsonType; type = diskoLib.jsonType;
default = default = diskoLib.deepMergeMap (
diskoLib.deepMergeMap (dataset: dataset._meta [ "zpool" config.name ]) (lib.attrValues config.datasets); dataset:
dataset._meta [
"zpool"
config.name
]
) (lib.attrValues config.datasets);
description = "Metadata"; description = "Metadata";
}; };
_create = diskoLib.mkCreateOption { _create = diskoLib.mkCreateOption {
@@ -234,14 +275,14 @@ in
let let
formatOutput = type: mode: members: '' formatOutput = type: mode: members: ''
entries+=("${type} ${mode}=${ entries+=("${type} ${mode}=${
lib.concatMapStringsSep " " lib.concatMapStringsSep " " (
(d: if lib.strings.hasPrefix "/" d then d else "/dev/disk/by-partlabel/disk-${d}-zfs") members 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; formatVdev = type: vdev: formatOutput type vdev.mode vdev.members;
formatVdevList = type: vdevs: lib.concatMapStrings formatVdevList =
(formatVdev type) type: vdevs: lib.concatMapStrings (formatVdev type) (builtins.sort (a: _: a.mode == "") vdevs);
(builtins.sort (a: _: a.mode == "") vdevs);
hasTopology = !(builtins.isString config.mode); hasTopology = !(builtins.isString config.mode);
mode = if hasTopology then "prescribed" else config.mode; mode = if hasTopology then "prescribed" else config.mode;
topology = lib.optionalAttrs hasTopology config.mode.topology; topology = lib.optionalAttrs hasTopology config.mode.topology;
@@ -281,18 +322,20 @@ in
topology="${mode} ''${zfs_devices[*]}" topology="${mode} ''${zfs_devices[*]}"
else else
entries=() entries=()
${lib.optionalString (hasTopology && topology.vdev != null) ${lib.optionalString (hasTopology && topology.vdev != null) (formatVdevList "" topology.vdev)}
(formatVdevList "" topology.vdev)} ${lib.optionalString (hasTopology && topology.spare != [ ]) (
${lib.optionalString (hasTopology && topology.spare != []) formatOutput "spare" "" topology.spare
(formatOutput "spare" "" topology.spare)} )}
${lib.optionalString (hasTopology && topology.log != []) ${lib.optionalString (hasTopology && topology.log != [ ]) (formatVdevList "log" topology.log)}
(formatVdevList "log" topology.log)} ${lib.optionalString (hasTopology && topology.dedup != [ ]) (
${lib.optionalString (hasTopology && topology.dedup != []) formatVdevList "dedup" topology.dedup
(formatVdevList "dedup" topology.dedup)} )}
${lib.optionalString (hasTopology && topology.special != null && topology.special != []) ${lib.optionalString (hasTopology && topology.special != null && topology.special != [ ]) (
(formatVdevList "special" (lib.lists.toList topology.special))} formatVdevList "special" (lib.lists.toList topology.special)
${lib.optionalString (hasTopology && topology.cache != []) )}
(formatOutput "cache" "" topology.cache)} ${lib.optionalString (hasTopology && topology.cache != [ ]) (
formatOutput "cache" "" topology.cache
)}
all_devices=() all_devices=()
last_type= last_type=
for line in "''${entries[@]}"; do for line in "''${entries[@]}"; do
@@ -337,7 +380,9 @@ in
inherit config options; inherit config options;
default = default =
let 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 in
{ {
dev = '' dev = ''
@@ -359,7 +404,7 @@ in
zpool export "${config.name}" zpool export "${config.name}"
fi 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 { _config = lib.mkOption {
@@ -372,7 +417,13 @@ in
internal = true; internal = true;
readOnly = true; readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package); 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"; description = "Packages";
}; };
}; };

View File

@@ -1,4 +1,11 @@
{ config, lib, pkgs, extendModules, diskoLib, ... }: {
config,
lib,
pkgs,
extendModules,
diskoLib,
...
}:
let let
cfg = config.disko; cfg = config.disko;
@@ -107,7 +114,10 @@ in
}; };
imageFormat = lib.mkOption { 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"; description = "QEMU image format to use for the disk images";
default = "raw"; default = "raw";
}; };
@@ -239,38 +249,49 @@ in
eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix"); eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix");
}; };
system.build = (cfg.devices._scripts { inherit pkgs; checked = cfg.checkScripts; }) // ( system.build =
let (cfg.devices._scripts {
throwIfNoDisksDetected = _: v: if cfg.devices.disk == { } then throw "No disks defined, did you forget to import your disko config?" else v; inherit pkgs;
in checked = cfg.checkScripts;
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; let
diskoNoDeps = builtins.trace "the .diskoNoDeps output is deprecated, please use .diskoScriptNoDeps instead" (cfg.devices._scripts { inherit pkgs; }).diskoScriptNoDeps; 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 { installTest = diskoLib.testLib.makeDiskoTest {
inherit extendModules pkgs; inherit extendModules pkgs;
name = "${config.networking.hostName}-disko"; name = "${config.networking.hostName}-disko";
disko-config = builtins.removeAttrs config [ "_module" ]; disko-config = builtins.removeAttrs config [ "_module" ];
testMode = "direct"; testMode = "direct";
bootCommands = cfg.tests.bootCommands; bootCommands = cfg.tests.bootCommands;
efi = cfg.tests.efi; efi = cfg.tests.efi;
enableOCR = cfg.tests.enableOCR; enableOCR = cfg.tests.enableOCR;
extraSystemConfig = cfg.tests.extraConfig; extraSystemConfig = cfg.tests.extraConfig;
extraTestScript = cfg.tests.extraChecks; 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 # 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 # Remember to add config keys here if they are added to types
fileSystems = lib.mkIf fileSystems = lib.mkIf cfg.enableConfig cfg.devices._config.fileSystems or { };
cfg.enableConfig cfg.devices._config.fileSystems or { }; boot = lib.mkIf cfg.enableConfig cfg.devices._config.boot or { };
boot = lib.mkIf swapDevices = lib.mkIf cfg.enableConfig cfg.devices._config.swapDevices or [ ];
cfg.enableConfig cfg.devices._config.boot or { };
swapDevices = lib.mkIf
cfg.enableConfig cfg.devices._config.swapDevices or [ ];
}; };
} }

View File

@@ -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 let
self = stdenvNoCC.mkDerivation (finalAttrs: { self = stdenvNoCC.mkDerivation (finalAttrs: {
@@ -16,7 +26,13 @@ let
chmod 755 "$out/bin/$i" chmod 755 "$out/bin/$i"
wrapProgram "$out/bin/$i" \ wrapProgram "$out/bin/$i" \
--set DISKO_VERSION "${diskoVersion}" \ --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}" --prefix NIX_PATH : "nixpkgs=${path}"
done done
''; '';

View File

@@ -1,3 +1,5 @@
#! /usr/bin/env bash
# Don't run directly! Instead, use # Don't run directly! Instead, use
# nix run .#create-release # nix run .#create-release

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;
@@ -17,4 +18,3 @@ diskoLib.testLib.makeDiskoTest {
machine.succeed("test -e /partition-root/swapfile1"); machine.succeed("test -e /partition-root/swapfile1");
''; '';
} }

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;
@@ -26,7 +27,10 @@ diskoLib.testLib.makeDiskoTest {
]; ];
}; };
extraInstallerConfig = { extraInstallerConfig = {
boot.kernelModules = [ "dm-raid" "dm-mirror" ]; boot.kernelModules = [
"dm-raid"
"dm-mirror"
];
imports = [ imports = [
../module.nix ../module.nix
]; ];

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;
@@ -24,6 +25,9 @@ diskoLib.testLib.makeDiskoTest {
machine.succeed("test -e /ext4_on_lvm/file-from-postMountHook"); machine.succeed("test -e /ext4_on_lvm/file-from-postMountHook");
''; '';
extraInstallerConfig = { extraInstallerConfig = {
boot.kernelModules = [ "dm-raid" "dm-mirror" ]; boot.kernelModules = [
"dm-raid"
"dm-mirror"
];
}; };
} }

View File

@@ -1,20 +1,28 @@
{ makeTest ? import <nixpkgs/nixos/tests/make-test-python.nix> {
, eval-config ? import <nixpkgs/nixos/lib/eval-config.nix> makeTest ? import <nixpkgs/nixos/tests/make-test-python.nix>,
, pkgs ? import <nixpkgs> { } eval-config ? import <nixpkgs/nixos/lib/eval-config.nix>,
pkgs ? import <nixpkgs> { },
}: }:
let let
lib = pkgs.lib; lib = pkgs.lib;
diskoLib = import ../lib { inherit lib makeTest eval-config; }; diskoLib = import ../lib { inherit lib makeTest eval-config; };
allTestFilenames = allTestFilenames = builtins.map (lib.removeSuffix ".nix") (
builtins.map (lib.removeSuffix ".nix") ( builtins.filter (x: lib.hasSuffix ".nix" x && x != "default.nix") (
builtins.filter lib.attrNames (builtins.readDir ./.)
(x: lib.hasSuffix ".nix" x && x != "default.nix") )
(lib.attrNames (builtins.readDir ./.)) );
); incompatibleTests = lib.optionals pkgs.stdenv.buildPlatform.isRiscV64 [
incompatibleTests = lib.optionals pkgs.stdenv.buildPlatform.isRiscV64 [ "zfs" "zfs-over-legacy" "cli" "module" "complex" ]; "zfs"
"zfs-over-legacy"
"cli"
"module"
"complex"
];
allCompatibleFilenames = lib.subtractLists incompatibleTests allTestFilenames; 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 in
allTests allTests

View File

@@ -1,4 +1,10 @@
{ lib, pkgs, modulesPath, ... }: { {
lib,
pkgs,
modulesPath,
...
}:
{
imports = [ imports = [
(modulesPath + "/testing/test-instrumentation.nix") (modulesPath + "/testing/test-instrumentation.nix")
(modulesPath + "/profiles/qemu-guest.nix") (modulesPath + "/profiles/qemu-guest.nix")
@@ -13,11 +19,15 @@
hashed-mirrors = null; hashed-mirrors = null;
connect-timeout = 3; connect-timeout = 3;
flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}''; flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}'';
experimental-features = [ "nix-command" "flakes" ]; experimental-features = [
"nix-command"
"flakes"
];
}; };
services.openssh.enable = true; services.openssh.enable = true;
boot.kernelParams = [ "console=tty0" ] ++ boot.kernelParams =
(lib.optional (pkgs.stdenv.hostPlatform.isAarch) "ttyAMA0,115200") ++ [ "console=tty0" ]
(lib.optional (pkgs.stdenv.hostPlatform.isRiscV64) "ttySIF0,115200") ++ ++ (lib.optional (pkgs.stdenv.hostPlatform.isAarch) "ttyAMA0,115200")
[ "console=ttyS0,115200" ]; ++ (lib.optional (pkgs.stdenv.hostPlatform.isRiscV64) "ttySIF0,115200")
++ [ "console=ttyS0,115200" ];
} }

View File

@@ -1,4 +1,8 @@
{ pkgs ? import <nixpkgs> { }, self, diskoVersion }: {
pkgs ? import <nixpkgs> { },
self,
diskoVersion,
}:
let let
disko = pkgs.callPackage ../../package.nix { inherit diskoVersion; }; disko = pkgs.callPackage ../../package.nix { inherit diskoVersion; };

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;
@@ -9,7 +10,11 @@ diskoLib.testLib.makeDiskoTest {
machine.succeed("mountpoint /home"); machine.succeed("mountpoint /home");
''; '';
extraInstallerConfig = { extraInstallerConfig = {
boot.kernelModules = [ "dm-raid" "raid0" "dm-mirror" ]; boot.kernelModules = [
"dm-raid"
"raid0"
"dm-mirror"
];
}; };
extraSystemConfig = { extraSystemConfig = {
# sadly systemd-boot fails to install to a raid /boot device # sadly systemd-boot fails to install to a raid /boot device

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,13 +1,17 @@
{ pkgs ? import <nixpkgs> { } {
, ... pkgs ? import <nixpkgs> { },
...
}: }:
(pkgs.nixos [ (pkgs.nixos [
../module.nix ../module.nix
../example/simple-efi.nix ../example/simple-efi.nix
({ config, ... }: { (
documentation.enable = false; { config, ... }:
system.stateVersion = config.system.nixos.version; {
disko.checkScripts = true; documentation.enable = false;
}) system.stateVersion = config.system.nixos.version;
disko.checkScripts = true;
}
)
]).config.system.build.diskoImagesScript ]).config.system.build.diskoImagesScript

View File

@@ -1,14 +1,18 @@
{ pkgs ? import <nixpkgs> { } {
, ... pkgs ? import <nixpkgs> { },
...
}: }:
(pkgs.nixos [ (pkgs.nixos [
../module.nix ../module.nix
../example/simple-efi.nix ../example/simple-efi.nix
({ config, ... }: { (
documentation.enable = false; { config, ... }:
system.stateVersion = config.system.nixos.version; {
disko.memSize = 2048; documentation.enable = false;
disko.checkScripts = true; system.stateVersion = config.system.nixos.version;
}) disko.memSize = 2048;
disko.checkScripts = true;
}
)
]).config.system.build.diskoImages ]).config.system.build.diskoImages

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;
@@ -21,6 +22,9 @@ diskoLib.testLib.makeDiskoTest {
machine.succeed("mountpoint /ext4_on_lvm"); machine.succeed("mountpoint /ext4_on_lvm");
''; '';
extraInstallerConfig = { extraInstallerConfig = {
boot.kernelModules = [ "dm-raid" "dm-mirror" ]; boot.kernelModules = [
"dm-raid"
"dm-mirror"
];
}; };
} }

View File

@@ -1,6 +1,7 @@
# this is a regression test for https://github.com/nix-community/disko/issues/52 # this is a regression test for https://github.com/nix-community/disko/issues/52
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,6 +1,7 @@
# this is a regression test for https://github.com/nix-community/disko/issues/52 # this is a regression test for https://github.com/nix-community/disko/issues/52
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,4 +1,7 @@
{ pkgs ? import <nixpkgs> { }, ... }: {
pkgs ? import <nixpkgs> { },
...
}:
(pkgs.nixos [ (pkgs.nixos [
../example/stand-alone/configuration.nix ../example/stand-alone/configuration.nix
{ documentation.enable = false; } { documentation.enable = false; }

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,18 +1,17 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;
name = "zfs-encrypted-root"; name = "zfs-encrypted-root";
extraInstallerConfig.networking.hostId = "8425e349"; extraInstallerConfig.networking.hostId = "8425e349";
extraSystemConfig.networking.hostId = "8425e349"; extraSystemConfig.networking.hostId = "8425e349";
disko-config = disko-config = pkgs.lib.recursiveUpdate (import ../example/zfs-encrypted-root.nix) {
pkgs.lib.recursiveUpdate (import ../example/zfs-encrypted-root.nix) { disko.devices.zpool.zroot.datasets.root.options.keylocation = "file:///tmp/secret.key";
disko.devices.zpool.zroot.datasets.root.options.keylocation = "file:///tmp/secret.key"; };
};
extraTestScript = '' extraTestScript = ''
machine.succeed("mountpoint /"); machine.succeed("mountpoint /");
machine.succeed("mountpoint /nix"); machine.succeed("mountpoint /nix");
''; '';
} }

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;
@@ -12,4 +13,3 @@ diskoLib.testLib.makeDiskoTest {
machine.succeed("mountpoint /zfs_fs"); machine.succeed("mountpoint /zfs_fs");
''; '';
} }

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { } {
, diskoLib ? pkgs.callPackage ../lib { } pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}: }:
diskoLib.testLib.makeDiskoTest { diskoLib.testLib.makeDiskoTest {
inherit pkgs; inherit pkgs;

View File

@@ -1 +1,4 @@
{ version = "1.10.0"; released = false; } {
version = "1.10.0";
released = false;
}