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

View File

@@ -1,64 +1,107 @@
{ lib ? import <nixpkgs/lib>
, rootMountPoint ? "/mnt"
, checked ? false
, diskoLib ? import ./lib { inherit lib rootMountPoint; }
{
lib ? import <nixpkgs/lib>,
rootMountPoint ? "/mnt",
checked ? false,
diskoLib ? import ./lib { inherit lib rootMountPoint; },
}:
let
eval = cfg: lib.evalModules {
modules = lib.singleton {
# _file = toString input;
imports = lib.singleton { disko.devices = cfg.disko.devices; };
options = {
disko.devices = lib.mkOption {
type = diskoLib.toplevel;
eval =
cfg:
lib.evalModules {
modules = lib.singleton {
# _file = toString input;
imports = lib.singleton { disko.devices = cfg.disko.devices; };
options = {
disko.devices = lib.mkOption {
type = diskoLib.toplevel;
};
};
};
};
};
# We might instead reuse some of the deprecated output names to refer to the values the _cli* outputs currently do,
# but this warning allows us to get feedback from users early in case they have a use case we haven't considered.
warnDeprecated = name: lib.warn "the ${name} output is deprecated and will be removed, please open an issue if you're using it!";
warnDeprecated =
name:
lib.warn "the ${name} output is deprecated and will be removed, please open an issue if you're using it!";
in
{
lib = warnDeprecated ".lib.lib" diskoLib;
_cliDestroy = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroy;
_cliDestroyNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyNoDeps;
_cliDestroy =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroy;
_cliDestroyNoDeps =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyNoDeps;
_cliFormat = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).format;
_cliFormatNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatNoDeps;
_cliFormatNoDeps =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatNoDeps;
_cliMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mount;
_cliMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountNoDeps;
_cliMountNoDeps =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountNoDeps;
_cliUnmount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmount;
_cliUnmountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmountNoDeps;
_cliUnmount =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmount;
_cliUnmountNoDeps =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).unmountNoDeps;
_cliFormatMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMount;
_cliFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMountNoDeps;
_cliFormatMount =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMount;
_cliFormatMountNoDeps =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatMountNoDeps;
_cliDestroyFormatMount = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMount;
_cliDestroyFormatMountNoDeps = cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMountNoDeps;
_cliDestroyFormatMount =
cfg: pkgs: ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMount;
_cliDestroyFormatMountNoDeps =
cfg: pkgs:
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).destroyFormatMountNoDeps;
# legacy aliases
create = cfg: warnDeprecated "create" (eval cfg).config.disko.devices._create;
createScript = cfg: pkgs: warnDeprecated "createScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
createScriptNoDeps = cfg: pkgs: warnDeprecated "createScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;
createScript =
cfg: pkgs:
warnDeprecated "createScript"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
createScriptNoDeps =
cfg: pkgs:
warnDeprecated "createScriptNoDeps"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;
format = cfg: warnDeprecated "format" (eval cfg).config.disko.devices._create;
formatScript = cfg: pkgs: warnDeprecated "formatScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
formatScriptNoDeps = cfg: pkgs: warnDeprecated "formatScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;
formatScript =
cfg: pkgs:
warnDeprecated "formatScript"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScript;
formatScriptNoDeps =
cfg: pkgs:
warnDeprecated "formatScriptNoDeps"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).formatScriptNoDeps;
mount = cfg: warnDeprecated "mount" (eval cfg).config.disko.devices._mount;
mountScript = cfg: pkgs: warnDeprecated "mountScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScript;
mountScriptNoDeps = cfg: pkgs: warnDeprecated "mountScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScriptNoDeps;
mountScript =
cfg: pkgs:
warnDeprecated "mountScript"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScript;
mountScriptNoDeps =
cfg: pkgs:
warnDeprecated "mountScriptNoDeps"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).mountScriptNoDeps;
disko = cfg: warnDeprecated "disko" (eval cfg).config.disko.devices._disko;
diskoScript = cfg: pkgs: warnDeprecated "diskoScript" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScript;
diskoScriptNoDeps = cfg: pkgs: warnDeprecated "diskoScriptNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps;
diskoScript =
cfg: pkgs:
warnDeprecated "diskoScript"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScript;
diskoScriptNoDeps =
cfg: pkgs:
warnDeprecated "diskoScriptNoDeps"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps;
# we keep this old output for backwards compatibility
diskoNoDeps = cfg: pkgs: warnDeprecated "diskoNoDeps" ((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps;
diskoNoDeps =
cfg: pkgs:
warnDeprecated "diskoNoDeps"
((eval cfg).config.disko.devices._scripts { inherit pkgs checked; }).diskoScriptNoDeps;
config = cfg: (eval cfg).config.disko.devices._config;
packages = cfg: (eval cfg).config.disko.devices._packages;

28
doc.nix
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@@ -1,37 +1,48 @@
{ lib
, makeTest
, eval-config
, ...
{
lib,
makeTest,
eval-config,
...
}:
let
testLib = {
# this takes a nixos config and changes the disk devices so we can run them inside the qemu test runner
# basically changes all the disk.*.devices to something like /dev/vda or /dev/vdb etc.
prepareDiskoConfig = cfg: devices:
prepareDiskoConfig =
cfg: devices:
let
cleanedTopLevel = lib.filterAttrsRecursive (n: _: !lib.hasPrefix "_" n) cfg;
preparedDisks = lib.foldlAttrs
(acc: n: v: {
devices = lib.tail acc.devices;
grub-devices = acc.grub-devices ++ (lib.optional (lib.any (part: (part.type or "") == "EF02") (lib.attrValues (v.content.partitions or { }))) (lib.head acc.devices));
disks = acc.disks // {
"${n}" = v // {
device = lib.head acc.devices;
content = v.content // { device = lib.head acc.devices; };
preparedDisks =
lib.foldlAttrs
(acc: n: v: {
devices = lib.tail acc.devices;
grub-devices =
acc.grub-devices
++ (lib.optional (lib.any (part: (part.type or "") == "EF02") (
lib.attrValues (v.content.partitions or { })
)) (lib.head acc.devices));
disks = acc.disks // {
"${n}" = v // {
device = lib.head acc.devices;
content = v.content // {
device = lib.head acc.devices;
};
};
};
};
})
{
inherit devices;
grub-devices = [ ];
disks = { };
}
cleanedTopLevel.disko.devices.disk;
})
{
inherit devices;
grub-devices = [ ];
disks = { };
}
cleanedTopLevel.disko.devices.disk;
in
cleanedTopLevel // {
boot.loader.grub.devices = if (preparedDisks.grub-devices != [ ]) then preparedDisks.grub-devices else [ "nodev" ];
cleanedTopLevel
// {
boot.loader.grub.devices =
if (preparedDisks.grub-devices != [ ]) then preparedDisks.grub-devices else [ "nodev" ];
disko.devices = cleanedTopLevel.disko.devices // {
disk = preparedDisks.disks;
};
@@ -58,33 +69,31 @@ let
# This is the test generator for a disko test
makeDiskoTest =
{ name
, disko-config
, extendModules ? null
, pkgs ? import <nixpkgs> { }
, extraTestScript ? ""
, bootCommands ? ""
, extraInstallerConfig ? { }
, extraSystemConfig ? { }
, efi ? !pkgs.stdenv.hostPlatform.isRiscV64
, postDisko ? ""
, testMode ? "module" # can be one of direct module cli
, testBoot ? true # if we actually want to test booting or just create/mount
, enableOCR ? false
{
name,
disko-config,
extendModules ? null,
pkgs ? import <nixpkgs> { },
extraTestScript ? "",
bootCommands ? "",
extraInstallerConfig ? { },
extraSystemConfig ? { },
efi ? !pkgs.stdenv.hostPlatform.isRiscV64,
postDisko ? "",
testMode ? "module", # can be one of direct module cli
testBoot ? true, # if we actually want to test booting or just create/mount
enableOCR ? false,
}:
let
makeTest' = args:
makeTest' =
args:
makeTest args {
inherit pkgs;
inherit (pkgs) system;
};
# for installation we skip /dev/vda because it is the test runner disk
importedDiskoConfig =
if builtins.isPath disko-config then
import disko-config
else
disko-config;
importedDiskoConfig = if builtins.isPath disko-config then import disko-config else disko-config;
diskoConfigWithArgs =
if builtins.isFunction importedDiskoConfig then
@@ -104,79 +113,93 @@ let
tsp-config = tsp-generator.config testConfigBooted;
num-disks = builtins.length (lib.attrNames testConfigBooted.disko.devices.disk);
installed-system = { config, ... }: {
imports = [
(lib.optionalAttrs (testMode == "direct") tsp-config)
(lib.optionalAttrs (testMode == "module") {
disko.enableConfig = true;
imports = [
../module.nix
testConfigBooted
];
})
];
installed-system =
{ config, ... }:
{
imports = [
(lib.optionalAttrs (testMode == "direct") tsp-config)
(lib.optionalAttrs (testMode == "module") {
disko.enableConfig = true;
imports = [
../module.nix
testConfigBooted
];
})
];
# config for tests to make them run faster or work at all
documentation.enable = false;
hardware.enableAllFirmware = lib.mkForce false;
# FIXME: we don't have an systemd in stage-1 equialvent for this
boot.initrd.preDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
echo -n 'secretsecret' > /tmp/secret.key
'';
boot.consoleLogLevel = lib.mkForce 100;
boot.loader.systemd-boot.enable = lib.mkDefault efi;
};
# config for tests to make them run faster or work at all
documentation.enable = false;
hardware.enableAllFirmware = lib.mkForce false;
# FIXME: we don't have an systemd in stage-1 equialvent for this
boot.initrd.preDeviceCommands = lib.mkIf (!config.boot.initrd.systemd.enable) ''
echo -n 'secretsecret' > /tmp/secret.key
'';
boot.consoleLogLevel = lib.mkForce 100;
boot.loader.systemd-boot.enable = lib.mkDefault efi;
};
installed-system-eval = eval-config {
modules = [ installed-system ];
inherit (pkgs) system;
};
installedTopLevel = ((if extendModules != null then extendModules else installed-system-eval.extendModules) {
modules = [
({ config, ... }: {
imports = [
extraSystemConfig
({ modulesPath, ... }: {
imports = [
(modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests
(modulesPath + "/profiles/qemu-guest.nix")
];
disko.devices = lib.mkForce testConfigBooted.disko.devices;
})
];
# since we boot on a different machine, the efi payload needs to be portable
boot.loader.grub.efiInstallAsRemovable = efi;
boot.loader.grub.efiSupport = efi;
boot.loader.systemd-boot.graceful = true;
# we always want the bind-mounted nix store. otherwise tests take forever
fileSystems."/nix/store" = lib.mkForce {
device = "nix-store";
fsType = "9p";
neededForBoot = true;
options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ];
};
boot.zfs.devNodes = "/dev/disk/by-uuid"; # needed because /dev/disk/by-id is empty in qemu-vms
# grub will install to these devices, we need to force those or we are offset by 1
# we use mkOveride 70, so that users can override this with mkForce in case they are testing grub mirrored boots
boot.loader.grub.devices = lib.mkOverride 70 testConfigInstall.boot.loader.grub.devices;
assertions = [
installedTopLevel =
((if extendModules != null then extendModules else installed-system-eval.extendModules) {
modules = [
(
{ config, ... }:
{
assertion = builtins.length config.boot.loader.grub.mirroredBoots > 1 -> config.boot.loader.grub.devices == [ ];
message = ''
When using `--vm-test` in combination with `mirroredBoots`,
it is necessary to configure `boot.loader.grub.devices` as an empty list by setting `boot.loader.grub.devices = lib.mkForce [];`.
This adjustment is crucial because the `--vm-test` mechanism automatically overrides the grub boot devices as part of the virtual machine test.
'';
imports = [
extraSystemConfig
(
{ modulesPath, ... }:
{
imports = [
(modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests
(modulesPath + "/profiles/qemu-guest.nix")
];
disko.devices = lib.mkForce testConfigBooted.disko.devices;
}
)
];
# since we boot on a different machine, the efi payload needs to be portable
boot.loader.grub.efiInstallAsRemovable = efi;
boot.loader.grub.efiSupport = efi;
boot.loader.systemd-boot.graceful = true;
# we always want the bind-mounted nix store. otherwise tests take forever
fileSystems."/nix/store" = lib.mkForce {
device = "nix-store";
fsType = "9p";
neededForBoot = true;
options = [
"trans=virtio"
"version=9p2000.L"
"cache=loose"
];
};
boot.zfs.devNodes = "/dev/disk/by-uuid"; # needed because /dev/disk/by-id is empty in qemu-vms
# grub will install to these devices, we need to force those or we are offset by 1
# we use mkOveride 70, so that users can override this with mkForce in case they are testing grub mirrored boots
boot.loader.grub.devices = lib.mkOverride 70 testConfigInstall.boot.loader.grub.devices;
assertions = [
{
assertion =
builtins.length config.boot.loader.grub.mirroredBoots > 1 -> config.boot.loader.grub.devices == [ ];
message = ''
When using `--vm-test` in combination with `mirroredBoots`,
it is necessary to configure `boot.loader.grub.devices` as an empty list by setting `boot.loader.grub.devices = lib.mkForce [];`.
This adjustment is crucial because the `--vm-test` mechanism automatically overrides the grub boot devices as part of the virtual machine test.
'';
}
];
}
];
})
];
}).config.system.build.toplevel;
)
];
}).config.system.build.toplevel;
in
makeTest' {
@@ -184,153 +207,177 @@ let
meta.timeout = 600; # 10 minutes
inherit enableOCR;
nodes.machine = { pkgs, ... }: {
imports = [
(lib.optionalAttrs (testMode == "module") {
imports = [
../module.nix
];
disko = {
enableConfig = false;
checkScripts = true;
devices = testConfigInstall.disko.devices;
};
})
extraInstallerConfig
nodes.machine =
{ pkgs, ... }:
{
imports = [
(lib.optionalAttrs (testMode == "module") {
imports = [
../module.nix
];
disko = {
enableConfig = false;
checkScripts = true;
devices = testConfigInstall.disko.devices;
};
})
extraInstallerConfig
# from base.nix
({ config, ... }: {
boot.supportedFilesystems =
[ "btrfs" "cifs" "f2fs" "jfs" "ntfs" "reiserfs" "vfat" "xfs" ] ++
lib.optional (config.networking.hostId != null && lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package) "zfs";
})
# from base.nix
(
{ config, ... }:
{
boot.supportedFilesystems =
[
"btrfs"
"cifs"
"f2fs"
"jfs"
"ntfs"
"reiserfs"
"vfat"
"xfs"
]
++ lib.optional (
config.networking.hostId != null
&& lib.meta.availableOn pkgs.stdenv.hostPlatform config.boot.zfs.package
) "zfs";
}
)
(if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then {
boot.swraid.enable = true;
} else {
boot.initrd.services.swraid.enable = true;
})
];
(
if lib.versionAtLeast (lib.versions.majorMinor lib.version) "23.11" then
{
boot.swraid.enable = true;
}
else
{
boot.initrd.services.swraid.enable = true;
}
)
];
systemd.services.mdmonitor.enable = false; # silence some weird warnings
systemd.services.mdmonitor.enable = false; # silence some weird warnings
environment.systemPackages = [
pkgs.jq
];
environment.systemPackages = [
pkgs.jq
];
# speed-up eval
documentation.enable = false;
# speed-up eval
documentation.enable = false;
nix.settings = {
substituters = lib.mkForce [ ];
hashed-mirrors = null;
connect-timeout = 1;
nix.settings = {
substituters = lib.mkForce [ ];
hashed-mirrors = null;
connect-timeout = 1;
};
networking.hostId = lib.mkIf (
(testConfigInstall ? networking.hostId) && (testConfigInstall.networking.hostId != null)
) testConfigInstall.networking.hostId;
virtualisation.emptyDiskImages = builtins.genList (_: 4096) num-disks;
# useful for debugging via repl
system.build.systemToInstall = installed-system-eval;
};
networking.hostId = lib.mkIf
(
(testConfigInstall ? networking.hostId) && (testConfigInstall.networking.hostId != null)
)
testConfigInstall.networking.hostId;
testScript =
{ nodes, ... }:
''
def disks(oldmachine, num_disks):
disk_flags = []
for i in range(num_disks):
disk_flags += [
'-drive',
f"file={oldmachine.state_dir}/empty{i}.qcow2,id=drive{i + 1},if=none,index={i + 1},werror=report",
'-device',
f"virtio-blk-pci,drive=drive{i + 1}"
]
return disk_flags
virtualisation.emptyDiskImages = builtins.genList (_: 4096) num-disks;
# useful for debugging via repl
system.build.systemToInstall = installed-system-eval;
};
testScript = { nodes, ... }: ''
def disks(oldmachine, num_disks):
disk_flags = []
for i in range(num_disks):
disk_flags += [
'-drive',
f"file={oldmachine.state_dir}/empty{i}.qcow2,id=drive{i + 1},if=none,index={i + 1},werror=report",
'-device',
f"virtio-blk-pci,drive=drive{i + 1}"
]
return disk_flags
def create_test_machine(
oldmachine=None, **kwargs
): # taken from <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}"
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})
]
''}
machine = create_machine(start_command=" ".join(start_command), **kwargs)
driver.machines.append(machine)
return machine
${lib.optionalString efi ''
start_command += ["-drive",
"if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}",
"-drive",
"if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}"
]
''}
machine = create_machine(start_command=" ".join(start_command), **kwargs)
driver.machines.append(machine)
return machine
machine.start()
machine.succeed("echo -n 'additionalSecret' > /tmp/additionalSecret.key")
machine.succeed("echo -n 'secretsecret' > /tmp/secret.key")
${lib.optionalString (testMode == "direct") ''
# running direct mode
machine.succeed("${lib.getExe tsp-format}")
machine.succeed("${lib.getExe tsp-mount}")
machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent
machine.succeed("${lib.getExe tsp-unmount}")
machine.succeed("${lib.getExe tsp-unmount}") # verify that umount is idempotent
machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent
machine.succeed("${lib.getExe tsp-disko} --yes-wipe-all-disks") # verify that we can destroy and recreate
machine.succeed("mkdir -p /mnt/home")
machine.succeed("touch /mnt/home/testfile")
machine.succeed("${lib.getExe tsp-format}") # verify that format is idempotent
machine.succeed("test -e /mnt/home/testfile")
''}
${lib.optionalString (testMode == "module") ''
# running module mode
machine.succeed("${lib.getExe nodes.machine.system.build.format}")
machine.succeed("${lib.getExe nodes.machine.system.build.mount}")
machine.succeed("${lib.getExe nodes.machine.system.build.mount}") # verify that mount is idempotent
machine.succeed("${lib.getExe nodes.machine.system.build.destroyFormatMount} --yes-wipe-all-disks") # verify that we can destroy and recreate again
machine.succeed("mkdir -p /mnt/home")
machine.succeed("touch /mnt/home/testfile")
machine.succeed("${lib.getExe nodes.machine.system.build.format}") # verify that format is idempotent
machine.succeed("test -e /mnt/home/testfile")
''}
${postDisko}
${lib.optionalString testBoot ''
# mount nix-store in /mnt
machine.succeed("mkdir -p /mnt/nix/store")
machine.succeed("mount --bind /nix/store /mnt/nix/store")
machine.succeed("nix-store --load-db < ${pkgs.closureInfo {rootPaths = [installedTopLevel];}}/registration")
# fix "this is not a NixOS installation"
machine.succeed("mkdir -p /mnt/etc")
machine.succeed("touch /mnt/etc/NIXOS")
machine.succeed("mkdir -p /mnt/nix/var/nix/profiles")
machine.succeed("nix-env -p /mnt/nix/var/nix/profiles/system --set ${installedTopLevel}")
machine.succeed("NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root /mnt -- ${installedTopLevel}/bin/switch-to-configuration boot")
machine.succeed("sync")
machine.shutdown()
machine = create_test_machine(oldmachine=machine, name="booted_machine")
machine.start()
${bootCommands}
machine.wait_for_unit("local-fs.target")
''}
machine.succeed("echo -n 'additionalSecret' > /tmp/additionalSecret.key")
machine.succeed("echo -n 'secretsecret' > /tmp/secret.key")
${lib.optionalString (testMode == "direct") ''
# running direct mode
machine.succeed("${lib.getExe tsp-format}")
machine.succeed("${lib.getExe tsp-mount}")
machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent
machine.succeed("${lib.getExe tsp-unmount}")
machine.succeed("${lib.getExe tsp-unmount}") # verify that umount is idempotent
machine.succeed("${lib.getExe tsp-mount}") # verify that mount is idempotent
machine.succeed("${lib.getExe tsp-disko} --yes-wipe-all-disks") # verify that we can destroy and recreate
machine.succeed("mkdir -p /mnt/home")
machine.succeed("touch /mnt/home/testfile")
machine.succeed("${lib.getExe tsp-format}") # verify that format is idempotent
machine.succeed("test -e /mnt/home/testfile")
''}
${lib.optionalString (testMode == "module") ''
# running module mode
machine.succeed("${lib.getExe nodes.machine.system.build.format}")
machine.succeed("${lib.getExe nodes.machine.system.build.mount}")
machine.succeed("${lib.getExe nodes.machine.system.build.mount}") # verify that mount is idempotent
machine.succeed("${lib.getExe nodes.machine.system.build.destroyFormatMount} --yes-wipe-all-disks") # verify that we can destroy and recreate again
machine.succeed("mkdir -p /mnt/home")
machine.succeed("touch /mnt/home/testfile")
machine.succeed("${lib.getExe nodes.machine.system.build.format}") # verify that format is idempotent
machine.succeed("test -e /mnt/home/testfile")
''}
${extraTestScript}
'';
${postDisko}
${lib.optionalString testBoot ''
# mount nix-store in /mnt
machine.succeed("mkdir -p /mnt/nix/store")
machine.succeed("mount --bind /nix/store /mnt/nix/store")
machine.succeed("nix-store --load-db < ${
pkgs.closureInfo { rootPaths = [ installedTopLevel ]; }
}/registration")
# fix "this is not a NixOS installation"
machine.succeed("mkdir -p /mnt/etc")
machine.succeed("touch /mnt/etc/NIXOS")
machine.succeed("mkdir -p /mnt/nix/var/nix/profiles")
machine.succeed("nix-env -p /mnt/nix/var/nix/profiles/system --set ${installedTopLevel}")
machine.succeed("NIXOS_INSTALL_BOOTLOADER=1 nixos-enter --root /mnt -- ${installedTopLevel}/bin/switch-to-configuration boot")
machine.succeed("sync")
machine.shutdown()
machine = create_test_machine(oldmachine=machine, name="booted_machine")
machine.start()
${bootCommands}
machine.wait_for_unit("local-fs.target")
''}
${extraTestScript}
'';
};
};
in

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,12 @@
{ config, options, lib, diskoLib, parent, device, ... }:
{
config,
options,
lib,
diskoLib,
parent,
device,
...
}:
let
sortedPartitions = lib.sort (x: y: x.priority < y.priority) (lib.attrValues config.partitions);
sortedHybridPartitions = lib.filter (p: p.hybrid != null) sortedPartitions;
@@ -16,171 +24,210 @@ in
description = "Device to use for the partition table";
};
partitions = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }@partition: {
options = {
type = lib.mkOption {
type =
let
hexPattern = len: "[A-Fa-f0-9]{${toString len}}";
in
lib.types.either
(lib.types.strMatching (hexPattern 4))
(lib.types.strMatching (lib.concatMapStringsSep "-" hexPattern [ 8 4 4 4 12 ]));
default = if partition.config.content != null && partition.config.content.type == "swap" then "8200" else "8300";
defaultText = ''8300 (Linux filesystem) normally, 8200 (Linux swap) if content.type is "swap"'';
description = ''
Filesystem type to use.
This can either be an sgdisk-specific short code (run sgdisk -L to see what is available),
or a fully specified GUID (see https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs).
'';
};
device = lib.mkOption {
type = lib.types.str;
default =
if partition.config.uuid != null then
"/dev/disk/by-partuuid/${partition.config.uuid}"
else if config._parent.type == "mdadm" then
# workaround because mdadm partlabel do not appear in /dev/disk/by-partlabel
"/dev/disk/by-id/md-name-any:${config._parent.name}-part${toString partition.config._index}"
else
"/dev/disk/by-partlabel/${diskoLib.hexEscapeUdevSymlink partition.config.label}";
defaultText = ''
if `uuid` is provided:
/dev/disk/by-partuuid/''${partition.config.uuid}
otherwise, if the parent is an mdadm device:
/dev/disk/by-id/md-name-any:''${config._parent.name}-part''${toString partition.config._index}
otherwise:
/dev/disk/by-partlabel/''${diskoLib.hexEscapeUdevSymlink partition.config.label}
'';
description = "Device to use for the partition";
};
priority = lib.mkOption {
type = lib.types.int;
default =
if partition.config.size or "" == "100%" then
9001
else if partition.config.type == "EF02" then
# Boot partition should be created first, because some BIOS implementations require it.
# Priority defaults to 100 here to support any potential use-case for placing partitions prior to EF02
100
else
1000;
defaultText = ''
1000: normal partitions
9001: partitions with 100% size
100: boot partitions (EF02)
'';
description = "Priority of the partition, smaller values are created first";
};
name = lib.mkOption {
type = lib.types.str;
description = "Name of the partition";
default = name;
};
uuid = lib.mkOption {
type = lib.types.nullOr (lib.types.strMatching "[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}");
default = null;
defaultText = "`null` - generate a UUID when creating the partition";
example = "809b3a2b-828a-4730-95e1-75b6343e415a";
description = ''
The UUID (also known as GUID) of the partition. Note that this is distinct from the UUID of the filesystem.
You can generate a UUID with the command `uuidgen -r`.
'';
};
label = lib.mkOption {
type = lib.types.str;
default =
let
# 72 bytes is the maximum length of a GPT partition name
# the labels seem to be in UTF-16, so 2 bytes per character
limit = 36;
label = "${config._parent.type}-${config._parent.name}-${partition.config.name}";
in
if (lib.stringLength label) > limit then
builtins.substring 0 limit (builtins.hashString "sha256" label)
else
label;
defaultText = ''
''${config._parent.type}-''${config._parent.name}-''${partition.config.name}
or a truncated hash of the above if it is longer than 36 characters
'';
};
size = lib.mkOption {
type = lib.types.either (lib.types.enum [ "100%" ]) (lib.types.strMatching "[0-9]+[KMGTP]?");
default = "0";
description = ''
Size of the partition, in sgdisk format.
sets end automatically with the + prefix
can be 100% for the whole remaining disk, will be done last in that case.
'';
};
alignment = lib.mkOption {
type = lib.types.int;
default = if (builtins.substring (builtins.stringLength partition.config.start - 1) 1 partition.config.start == "s" || (builtins.substring (builtins.stringLength partition.config.end - 1) 1 partition.config.end == "s")) then 1 else 0;
defaultText = "1 if the unit of start or end is sectors, 0 otherwise";
description = "Alignment of the partition, if sectors are used as start or end it can be aligned to 1";
};
start = lib.mkOption {
type = lib.types.str;
default = "0";
description = "Start of the partition, in sgdisk format, use 0 for next available range";
};
end = lib.mkOption {
type = lib.types.str;
default = if partition.config.size == "100%" then "-0" else "+${partition.config.size}";
defaultText = ''
if partition.config.size == "100%" then "-0" else "+''${partition.config.size}";
'';
description = ''
End of the partition, in sgdisk format.
Use + for relative sizes from the partitions start
or - for relative sizes from the disks end
'';
};
content = diskoLib.partitionType { parent = config; device = partition.config.device; };
hybrid = lib.mkOption {
type = lib.types.nullOr (lib.types.submodule ({ ... } @ hp: {
options = {
mbrPartitionType = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "MBR type code";
};
mbrBootableFlag = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Set the bootable flag (aka the active flag) on any or all of your hybridized partitions";
};
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
${lib.optionalString (hp.config.mbrPartitionType != null) ''
sfdisk --label-nested dos --part-type "${parent.device}" ${(toString partition.config._index)} ${hp.config.mbrPartitionType}
udevadm trigger --subsystem-match=block
udevadm settle
''}
${lib.optionalString hp.config.mbrBootableFlag ''
sfdisk --label-nested dos --activate "${parent.device}" ${(toString partition.config._index)}
''}
'';
};
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }@partition:
{
options = {
type = lib.mkOption {
type =
let
hexPattern = len: "[A-Fa-f0-9]{${toString len}}";
in
lib.types.either (lib.types.strMatching (hexPattern 4)) (
lib.types.strMatching (
lib.concatMapStringsSep "-" hexPattern [
8
4
4
4
12
]
)
);
default =
if partition.config.content != null && partition.config.content.type == "swap" then
"8200"
else
"8300";
defaultText = ''8300 (Linux filesystem) normally, 8200 (Linux swap) if content.type is "swap"'';
description = ''
Filesystem type to use.
This can either be an sgdisk-specific short code (run sgdisk -L to see what is available),
or a fully specified GUID (see https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs).
'';
};
}));
default = null;
description = "Entry to add to the Hybrid MBR table";
};
_index = lib.mkOption {
type = lib.types.int;
internal = true;
default = diskoLib.indexOf (x: x.name == partition.config.name) sortedPartitions 0;
defaultText = null;
};
};
}));
device = lib.mkOption {
type = lib.types.str;
default =
if partition.config.uuid != null then
"/dev/disk/by-partuuid/${partition.config.uuid}"
else if config._parent.type == "mdadm" then
# workaround because mdadm partlabel do not appear in /dev/disk/by-partlabel
"/dev/disk/by-id/md-name-any:${config._parent.name}-part${toString partition.config._index}"
else
"/dev/disk/by-partlabel/${diskoLib.hexEscapeUdevSymlink partition.config.label}";
defaultText = ''
if `uuid` is provided:
/dev/disk/by-partuuid/''${partition.config.uuid}
otherwise, if the parent is an mdadm device:
/dev/disk/by-id/md-name-any:''${config._parent.name}-part''${toString partition.config._index}
otherwise:
/dev/disk/by-partlabel/''${diskoLib.hexEscapeUdevSymlink partition.config.label}
'';
description = "Device to use for the partition";
};
priority = lib.mkOption {
type = lib.types.int;
default =
if partition.config.size or "" == "100%" then
9001
else if partition.config.type == "EF02" then
# Boot partition should be created first, because some BIOS implementations require it.
# Priority defaults to 100 here to support any potential use-case for placing partitions prior to EF02
100
else
1000;
defaultText = ''
1000: normal partitions
9001: partitions with 100% size
100: boot partitions (EF02)
'';
description = "Priority of the partition, smaller values are created first";
};
name = lib.mkOption {
type = lib.types.str;
description = "Name of the partition";
default = name;
};
uuid = lib.mkOption {
type = lib.types.nullOr (
lib.types.strMatching "[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}"
);
default = null;
defaultText = "`null` - generate a UUID when creating the partition";
example = "809b3a2b-828a-4730-95e1-75b6343e415a";
description = ''
The UUID (also known as GUID) of the partition. Note that this is distinct from the UUID of the filesystem.
You can generate a UUID with the command `uuidgen -r`.
'';
};
label = lib.mkOption {
type = lib.types.str;
default =
let
# 72 bytes is the maximum length of a GPT partition name
# the labels seem to be in UTF-16, so 2 bytes per character
limit = 36;
label = "${config._parent.type}-${config._parent.name}-${partition.config.name}";
in
if (lib.stringLength label) > limit then
builtins.substring 0 limit (builtins.hashString "sha256" label)
else
label;
defaultText = ''
''${config._parent.type}-''${config._parent.name}-''${partition.config.name}
or a truncated hash of the above if it is longer than 36 characters
'';
};
size = lib.mkOption {
type = lib.types.either (lib.types.enum [ "100%" ]) (lib.types.strMatching "[0-9]+[KMGTP]?");
default = "0";
description = ''
Size of the partition, in sgdisk format.
sets end automatically with the + prefix
can be 100% for the whole remaining disk, will be done last in that case.
'';
};
alignment = lib.mkOption {
type = lib.types.int;
default =
if
(
builtins.substring (builtins.stringLength partition.config.start - 1) 1 partition.config.start
== "s"
|| (
builtins.substring (builtins.stringLength partition.config.end - 1) 1 partition.config.end == "s"
)
)
then
1
else
0;
defaultText = "1 if the unit of start or end is sectors, 0 otherwise";
description = "Alignment of the partition, if sectors are used as start or end it can be aligned to 1";
};
start = lib.mkOption {
type = lib.types.str;
default = "0";
description = "Start of the partition, in sgdisk format, use 0 for next available range";
};
end = lib.mkOption {
type = lib.types.str;
default = if partition.config.size == "100%" then "-0" else "+${partition.config.size}";
defaultText = ''
if partition.config.size == "100%" then "-0" else "+''${partition.config.size}";
'';
description = ''
End of the partition, in sgdisk format.
Use + for relative sizes from the partitions start
or - for relative sizes from the disks end
'';
};
content = diskoLib.partitionType {
parent = config;
device = partition.config.device;
};
hybrid = lib.mkOption {
type = lib.types.nullOr (
lib.types.submodule (
{ ... }@hp:
{
options = {
mbrPartitionType = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "MBR type code";
};
mbrBootableFlag = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Set the bootable flag (aka the active flag) on any or all of your hybridized partitions";
};
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
${lib.optionalString (hp.config.mbrPartitionType != null) ''
sfdisk --label-nested dos --part-type "${parent.device}" ${(toString partition.config._index)} ${hp.config.mbrPartitionType}
udevadm trigger --subsystem-match=block
udevadm settle
''}
${lib.optionalString hp.config.mbrBootableFlag ''
sfdisk --label-nested dos --activate "${parent.device}" ${(toString partition.config._index)}
''}
'';
};
};
}
)
);
default = null;
description = "Entry to add to the Hybrid MBR table";
};
_index = lib.mkOption {
type = lib.types.int;
internal = true;
default = diskoLib.indexOf (x: x.name == partition.config.name) sortedPartitions 0;
defaultText = null;
};
};
}
)
);
default = { };
description = "Attrs of partitions to add to the partition table";
};
@@ -197,12 +244,13 @@ in
internal = true;
readOnly = true;
type = lib.types.functionTo diskoLib.jsonType;
default = dev:
lib.foldr lib.recursiveUpdate { } (map
(partition:
lib.optionalAttrs (partition.content != null) (partition.content._meta dev)
default =
dev:
lib.foldr lib.recursiveUpdate { } (
map (partition: lib.optionalAttrs (partition.content != null) (partition.content._meta dev)) (
lib.attrValues config.partitions
)
(lib.attrValues config.partitions));
);
description = "Metadata";
};
_create = diskoLib.mkCreateOption {
@@ -211,61 +259,63 @@ in
if ! blkid "${config.device}" >&2; then
sgdisk --clear "${config.device}"
fi
${lib.concatMapStrings (partition:
${lib.concatMapStrings (
partition:
let
args = ''
--partition-guid="${toString partition._index}:${if partition.uuid == null then "R" else partition.uuid}" \
--partition-guid="${toString partition._index}:${
if partition.uuid == null then "R" else partition.uuid
}" \
--change-name="${toString partition._index}:${partition.label}" \
--typecode=${toString partition._index}:${partition.type} \
"${config.device}" \
'';
createArgs = ''
--align-end ${lib.optionalString (partition.alignment != 0) ''--set-alignment=${builtins.toString partition.alignment}''} \
--align-end ${
lib.optionalString (
partition.alignment != 0
) ''--set-alignment=${builtins.toString partition.alignment}''
} \
--new=${toString partition._index}:${partition.start}:${partition.end} \
'';
in
''
# try to create the partition, if it fails, try to change the type and name
if ! sgdisk ${createArgs} ${args}
then
sgdisk ${args}
fi
# ensure /dev/disk/by-path/..-partN exists before continuing
partprobe "${config.device}" || : # sometimes partprobe fails, but the partitions are still up2date
udevadm trigger --subsystem-match=block
udevadm settle
''
''
# try to create the partition, if it fails, try to change the type and name
if ! sgdisk ${createArgs} ${args}
then
sgdisk ${args}
fi
# ensure /dev/disk/by-path/..-partN exists before continuing
partprobe "${config.device}" || : # sometimes partprobe fails, but the partitions are still up2date
udevadm trigger --subsystem-match=block
udevadm settle
''
) sortedPartitions}
${
lib.optionalString (sortedHybridPartitions != [])
("sgdisk -h "
+ (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions))
+ (
lib.optionalString (!config.efiGptPartitionFirst) ":EE "
)
+ ''"${parent.device}"'')
}
${lib.concatMapStrings (p:
p.hybrid._create
)
sortedHybridPartitions
}
${lib.optionalString (sortedHybridPartitions != [ ]) (
"sgdisk -h "
+ (lib.concatStringsSep ":" (map (p: (toString p._index)) sortedHybridPartitions))
+ (lib.optionalString (!config.efiGptPartitionFirst) ":EE ")
+ ''"${parent.device}"''
)}
${lib.concatMapStrings (p: p.hybrid._create) sortedHybridPartitions}
${lib.concatStrings (map (partition: ''
${lib.optionalString (partition.content != null) partition.content._create}
'') sortedPartitions)}
${lib.concatStrings (
map (partition: ''
${lib.optionalString (partition.content != null) partition.content._create}
'') sortedPartitions
)}
'';
};
_mount = diskoLib.mkMountOption {
inherit config options;
default =
let
partMounts = lib.foldr lib.recursiveUpdate { } (map
(partition:
lib.optionalAttrs (partition.content != null) partition.content._mount
partMounts = lib.foldr lib.recursiveUpdate { } (
map (partition: lib.optionalAttrs (partition.content != null) partition.content._mount) (
lib.attrValues config.partitions
)
(lib.attrValues config.partitions));
);
in
{
dev = partMounts.dev or "";
@@ -276,11 +326,11 @@ in
inherit config options;
default =
let
partMounts = lib.foldr lib.recursiveUpdate { } (map
(partition:
lib.optionalAttrs (partition.content != null) partition.content._unmount
partMounts = lib.foldr lib.recursiveUpdate { } (
map (partition: lib.optionalAttrs (partition.content != null) partition.content._unmount) (
lib.attrValues config.partitions
)
(lib.attrValues config.partitions));
);
in
{
dev = partMounts.dev or "";
@@ -290,30 +340,31 @@ in
_config = lib.mkOption {
internal = true;
readOnly = true;
default = (map
(partition:
lib.optional (partition.content != null) partition.content._config
)
(lib.attrValues config.partitions))
++ (lib.optional (lib.any (part: part.type == "EF02") (lib.attrValues config.partitions)) {
boot.loader.grub.devices = [ config.device ];
});
default =
(map (partition: lib.optional (partition.content != null) partition.content._config) (
lib.attrValues config.partitions
))
++ (lib.optional (lib.any (part: part.type == "EF02") (lib.attrValues config.partitions)) {
boot.loader.grub.devices = [ config.device ];
});
description = "NixOS configuration";
};
_pkgs = lib.mkOption {
internal = true;
readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs:
default =
pkgs:
[
pkgs.gptfdisk
pkgs.systemdMinimal
pkgs.parted # for partprobe
] ++ lib.flatten (map
(partition:
lib.optional (partition.content != null) (partition.content._pkgs pkgs)
]
++ lib.flatten (
map (partition: lib.optional (partition.content != null) (partition.content._pkgs pkgs)) (
lib.attrValues config.partitions
)
(lib.attrValues config.partitions));
);
description = "Packages";
};
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,179 +1,227 @@
{ config, options, lib, diskoLib, parent, device, ... }:
{
options = lib.warn ''
The legacy table is outdated and should not be used. We recommend using the gpt type instead.
Please note that certain features, such as the test framework, may not function properly with the legacy table type.
If you encounter errors similar to:
"error: The option `disko.devices.disk.disk1.content.partitions."[definition 1-entry 1]".content._config` is read-only, but it's set multiple times,"
this is likely due to the use of the legacy table type.
for a migration you can follow the guide at https://github.com/nix-community/disko/blob/master/docs/table-to-gpt.md
''
{
type = lib.mkOption {
type = lib.types.enum [ "table" ];
internal = true;
description = "Partition table";
};
device = lib.mkOption {
type = lib.types.str;
default = device;
description = "Device to partition";
};
format = lib.mkOption {
type = lib.types.enum [ "gpt" "msdos" ];
default = "gpt";
description = "The kind of partition table";
};
partitions = lib.mkOption {
type = lib.types.listOf (lib.types.submodule ({ name, ... }@partition: {
options = {
part-type = lib.mkOption {
type = lib.types.enum [ "primary" "logical" "extended" ];
default = "primary";
description = "Partition type";
};
fs-type = lib.mkOption {
type = lib.types.nullOr (lib.types.enum [ "btrfs" "ext2" "ext3" "ext4" "fat16" "fat32" "hfs" "hfs+" "linux-swap" "ntfs" "reiserfs" "udf" "xfs" ]);
default = null;
description = "Filesystem type to use";
};
name = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "Name of the partition";
};
start = lib.mkOption {
type = lib.types.str;
default = "0%";
description = "Start of the partition";
};
end = lib.mkOption {
type = lib.types.str;
default = "100%";
description = "End of the partition";
};
flags = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Partition flags";
};
bootable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to make the partition bootable";
};
content = diskoLib.partitionType { parent = config; device = diskoLib.deviceNumbering config.device partition.config._index; };
_index = lib.mkOption {
type = lib.types.int;
internal = true;
default = lib.toInt (lib.head (builtins.match ".*entry ([[:digit:]]+)]" name));
defaultText = null;
};
};
}));
default = [ ];
description = "List of partitions to add to the partition table";
};
_parent = lib.mkOption {
internal = true;
default = parent;
};
_meta = lib.mkOption {
internal = true;
readOnly = true;
type = lib.types.functionTo diskoLib.jsonType;
default = dev:
lib.foldr lib.recursiveUpdate { } (lib.imap
(_index: partition:
lib.optionalAttrs (partition.content != null) (partition.content._meta dev)
config,
options,
lib,
diskoLib,
parent,
device,
...
}:
{
options =
lib.warn
''
The legacy table is outdated and should not be used. We recommend using the gpt type instead.
Please note that certain features, such as the test framework, may not function properly with the legacy table type.
If you encounter errors similar to:
"error: The option `disko.devices.disk.disk1.content.partitions."[definition 1-entry 1]".content._config` is read-only, but it's set multiple times,"
this is likely due to the use of the legacy table type.
for a migration you can follow the guide at https://github.com/nix-community/disko/blob/master/docs/table-to-gpt.md
''
{
type = lib.mkOption {
type = lib.types.enum [ "table" ];
internal = true;
description = "Partition table";
};
device = lib.mkOption {
type = lib.types.str;
default = device;
description = "Device to partition";
};
format = lib.mkOption {
type = lib.types.enum [
"gpt"
"msdos"
];
default = "gpt";
description = "The kind of partition table";
};
partitions = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule (
{ name, ... }@partition:
{
options = {
part-type = lib.mkOption {
type = lib.types.enum [
"primary"
"logical"
"extended"
];
default = "primary";
description = "Partition type";
};
fs-type = lib.mkOption {
type = lib.types.nullOr (
lib.types.enum [
"btrfs"
"ext2"
"ext3"
"ext4"
"fat16"
"fat32"
"hfs"
"hfs+"
"linux-swap"
"ntfs"
"reiserfs"
"udf"
"xfs"
]
);
default = null;
description = "Filesystem type to use";
};
name = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "Name of the partition";
};
start = lib.mkOption {
type = lib.types.str;
default = "0%";
description = "Start of the partition";
};
end = lib.mkOption {
type = lib.types.str;
default = "100%";
description = "End of the partition";
};
flags = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Partition flags";
};
bootable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to make the partition bootable";
};
content = diskoLib.partitionType {
parent = config;
device = diskoLib.deviceNumbering config.device partition.config._index;
};
_index = lib.mkOption {
type = lib.types.int;
internal = true;
default = lib.toInt (lib.head (builtins.match ".*entry ([[:digit:]]+)]" name));
defaultText = null;
};
};
}
)
config.partitions);
description = "Metadata";
);
default = [ ];
description = "List of partitions to add to the partition table";
};
_parent = lib.mkOption {
internal = true;
default = parent;
};
_meta = lib.mkOption {
internal = true;
readOnly = true;
type = lib.types.functionTo diskoLib.jsonType;
default =
dev:
lib.foldr lib.recursiveUpdate { } (
lib.imap (
_index: partition: lib.optionalAttrs (partition.content != null) (partition.content._meta dev)
) config.partitions
);
description = "Metadata";
};
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
if ! blkid "${config.device}" >/dev/null; then
parted -s "${config.device}" -- mklabel ${config.format}
${lib.concatStrings (
map (partition: ''
${lib.optionalString (config.format == "gpt") ''
parted -s "${config.device}" -- mkpart "${diskoLib.hexEscapeUdevSymlink partition.name}" ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end}
''}
${lib.optionalString (config.format == "msdos") ''
parted -s "${config.device}" -- mkpart ${partition.part-type} ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end}
''}
# ensure /dev/disk/by-path/..-partN exists before continuing
partprobe "${config.device}"
udevadm trigger --subsystem-match=block
udevadm settle
${lib.optionalString partition.bootable ''
parted -s "${config.device}" -- set ${toString partition._index} boot on
''}
${lib.concatMapStringsSep "" (flag: ''
parted -s "${config.device}" -- set ${toString partition._index} ${flag} on
'') partition.flags}
# ensure further operations can detect new partitions
partprobe "${config.device}"
udevadm trigger --subsystem-match=block
udevadm settle
'') config.partitions
)}
fi
${lib.concatStrings (
map (partition: ''
${lib.optionalString (partition.content != null) partition.content._create}
'') config.partitions
)}
'';
};
_mount = diskoLib.mkMountOption {
inherit config options;
default =
let
partMounts = lib.foldr lib.recursiveUpdate { } (
map (
partition: lib.optionalAttrs (partition.content != null) partition.content._mount
) config.partitions
);
in
{
dev = partMounts.dev or "";
fs = partMounts.fs or { };
};
};
_unmount = diskoLib.mkUnmountOption {
inherit config options;
default =
let
partMounts = lib.foldr lib.recursiveUpdate { } (
map (
partition: lib.optionalAttrs (partition.content != null) partition.content._unmount
) config.partitions
);
in
{
dev = partMounts.dev or "";
fs = partMounts.fs or { };
};
};
_config = lib.mkOption {
internal = true;
readOnly = true;
default = map (
partition: lib.optional (partition.content != null) partition.content._config
) config.partitions;
description = "NixOS configuration";
};
_pkgs = lib.mkOption {
internal = true;
readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default =
pkgs:
[
pkgs.parted
pkgs.systemdMinimal
]
++ lib.flatten (
map (
partition: lib.optional (partition.content != null) (partition.content._pkgs pkgs)
) config.partitions
);
description = "Packages";
};
};
_create = diskoLib.mkCreateOption {
inherit config options;
default = ''
if ! blkid "${config.device}" >/dev/null; then
parted -s "${config.device}" -- mklabel ${config.format}
${lib.concatStrings (map (partition: ''
${lib.optionalString (config.format == "gpt") ''
parted -s "${config.device}" -- mkpart "${diskoLib.hexEscapeUdevSymlink partition.name}" ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end}
''}
${lib.optionalString (config.format == "msdos") ''
parted -s "${config.device}" -- mkpart ${partition.part-type} ${diskoLib.maybeStr partition.fs-type} ${partition.start} ${partition.end}
''}
# ensure /dev/disk/by-path/..-partN exists before continuing
partprobe "${config.device}"
udevadm trigger --subsystem-match=block
udevadm settle
${lib.optionalString partition.bootable ''
parted -s "${config.device}" -- set ${toString partition._index} boot on
''}
${lib.concatMapStringsSep "" (flag: ''
parted -s "${config.device}" -- set ${toString partition._index} ${flag} on
'') partition.flags}
# ensure further operations can detect new partitions
partprobe "${config.device}"
udevadm trigger --subsystem-match=block
udevadm settle
'') config.partitions)}
fi
${lib.concatStrings (map (partition: ''
${lib.optionalString (partition.content != null) partition.content._create}
'') config.partitions)}
'';
};
_mount = diskoLib.mkMountOption {
inherit config options;
default =
let
partMounts = lib.foldr lib.recursiveUpdate { } (map
(partition:
lib.optionalAttrs (partition.content != null) partition.content._mount
)
config.partitions);
in
{
dev = partMounts.dev or "";
fs = partMounts.fs or { };
};
};
_unmount = diskoLib.mkUnmountOption {
inherit config options;
default =
let
partMounts = lib.foldr lib.recursiveUpdate { } (map
(partition:
lib.optionalAttrs (partition.content != null) partition.content._unmount
)
config.partitions);
in
{
dev = partMounts.dev or "";
fs = partMounts.fs or { };
};
};
_config = lib.mkOption {
internal = true;
readOnly = true;
default =
map
(partition:
lib.optional (partition.content != null) partition.content._config
)
config.partitions;
description = "NixOS configuration";
};
_pkgs = lib.mkOption {
internal = true;
readOnly = true;
type = lib.types.functionTo (lib.types.listOf lib.types.package);
default = pkgs:
[ pkgs.parted pkgs.systemdMinimal ] ++ lib.flatten (map
(partition:
lib.optional (partition.content != null) (partition.content._pkgs pkgs)
)
config.partitions);
description = "Packages";
};
};
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,11 @@
{ config, lib, pkgs, extendModules, diskoLib, ... }:
{
config,
lib,
pkgs,
extendModules,
diskoLib,
...
}:
let
cfg = config.disko;
@@ -107,7 +114,10 @@ in
};
imageFormat = lib.mkOption {
type = lib.types.enum [ "raw" "qcow2" ];
type = lib.types.enum [
"raw"
"qcow2"
];
description = "QEMU image format to use for the disk images";
default = "raw";
};
@@ -239,38 +249,49 @@ in
eval-config = import (pkgs.path + "/nixos/lib/eval-config.nix");
};
system.build = (cfg.devices._scripts { inherit pkgs; checked = cfg.checkScripts; }) // (
let
throwIfNoDisksDetected = _: v: if cfg.devices.disk == { } then throw "No disks defined, did you forget to import your disko config?" else v;
in
lib.mapAttrs throwIfNoDisksDetected {
# we keep these old outputs for compatibility
disko = builtins.trace "the .disko output is deprecated, please use .diskoScript instead" (cfg.devices._scripts { inherit pkgs; }).diskoScript;
diskoNoDeps = builtins.trace "the .diskoNoDeps output is deprecated, please use .diskoScriptNoDeps instead" (cfg.devices._scripts { inherit pkgs; }).diskoScriptNoDeps;
system.build =
(cfg.devices._scripts {
inherit pkgs;
checked = cfg.checkScripts;
})
// (
let
throwIfNoDisksDetected =
_: v:
if cfg.devices.disk == { } then
throw "No disks defined, did you forget to import your disko config?"
else
v;
in
lib.mapAttrs throwIfNoDisksDetected {
# we keep these old outputs for compatibility
disko =
builtins.trace "the .disko output is deprecated, please use .diskoScript instead"
(cfg.devices._scripts { inherit pkgs; }).diskoScript;
diskoNoDeps =
builtins.trace "the .diskoNoDeps output is deprecated, please use .diskoScriptNoDeps instead"
(cfg.devices._scripts { inherit pkgs; }).diskoScriptNoDeps;
installTest = diskoLib.testLib.makeDiskoTest {
inherit extendModules pkgs;
name = "${config.networking.hostName}-disko";
disko-config = builtins.removeAttrs config [ "_module" ];
testMode = "direct";
bootCommands = cfg.tests.bootCommands;
efi = cfg.tests.efi;
enableOCR = cfg.tests.enableOCR;
extraSystemConfig = cfg.tests.extraConfig;
extraTestScript = cfg.tests.extraChecks;
};
installTest = diskoLib.testLib.makeDiskoTest {
inherit extendModules pkgs;
name = "${config.networking.hostName}-disko";
disko-config = builtins.removeAttrs config [ "_module" ];
testMode = "direct";
bootCommands = cfg.tests.bootCommands;
efi = cfg.tests.efi;
enableOCR = cfg.tests.enableOCR;
extraSystemConfig = cfg.tests.extraConfig;
extraTestScript = cfg.tests.extraChecks;
};
vmWithDisko = lib.mkDefault config.virtualisation.vmVariantWithDisko.system.build.vmWithDisko;
}
);
vmWithDisko = lib.mkDefault config.virtualisation.vmVariantWithDisko.system.build.vmWithDisko;
}
);
# we need to specify the keys here, so we don't get an infinite recursion error
# Remember to add config keys here if they are added to types
fileSystems = lib.mkIf
cfg.enableConfig cfg.devices._config.fileSystems or { };
boot = lib.mkIf
cfg.enableConfig cfg.devices._config.boot or { };
swapDevices = lib.mkIf
cfg.enableConfig cfg.devices._config.swapDevices or [ ];
fileSystems = lib.mkIf cfg.enableConfig cfg.devices._config.fileSystems or { };
boot = lib.mkIf cfg.enableConfig cfg.devices._config.boot or { };
swapDevices = lib.mkIf cfg.enableConfig cfg.devices._config.swapDevices or [ ];
};
}

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

View File

@@ -1,3 +1,5 @@
#! /usr/bin/env bash
# Don't run directly! Instead, use
# 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 {
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 {
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 {
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 {
inherit pkgs;
@@ -17,4 +18,3 @@ diskoLib.testLib.makeDiskoTest {
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 {
inherit pkgs;
@@ -26,7 +27,10 @@ diskoLib.testLib.makeDiskoTest {
];
};
extraInstallerConfig = {
boot.kernelModules = [ "dm-raid" "dm-mirror" ];
boot.kernelModules = [
"dm-raid"
"dm-mirror"
];
imports = [
../module.nix
];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
# 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 {
inherit pkgs;

View File

@@ -1,6 +1,7 @@
# 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 {
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 {
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 {
inherit pkgs;

View File

@@ -1,4 +1,7 @@
{ pkgs ? import <nixpkgs> { }, ... }:
{
pkgs ? import <nixpkgs> { },
...
}:
(pkgs.nixos [
../example/stand-alone/configuration.nix
{ 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 {
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 {
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 {
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 {
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 {
inherit pkgs;
name = "zfs-encrypted-root";
extraInstallerConfig.networking.hostId = "8425e349";
extraSystemConfig.networking.hostId = "8425e349";
disko-config =
pkgs.lib.recursiveUpdate (import ../example/zfs-encrypted-root.nix) {
disko.devices.zpool.zroot.datasets.root.options.keylocation = "file:///tmp/secret.key";
};
disko-config = pkgs.lib.recursiveUpdate (import ../example/zfs-encrypted-root.nix) {
disko.devices.zpool.zroot.datasets.root.options.keylocation = "file:///tmp/secret.key";
};
extraTestScript = ''
machine.succeed("mountpoint /");
machine.succeed("mountpoint /nix");
'';
}

View File

@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { }
, diskoLib ? pkgs.callPackage ../lib { }
{
pkgs ? import <nixpkgs> { },
diskoLib ? pkgs.callPackage ../lib { },
}:
diskoLib.testLib.makeDiskoTest {
inherit pkgs;
@@ -12,4 +13,3 @@ diskoLib.testLib.makeDiskoTest {
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 {
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 {
inherit pkgs;

View File

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