disko: support multiple disks

This commit is contained in:
Sandro - 2023-05-19 01:57:15 +02:00
parent 31d255b388
commit 7e3a98d68f
Signed by: sandro
GPG Key ID: 3AF5A43A3EECC2E5
2 changed files with 166 additions and 145 deletions

View File

@ -1,4 +1,4 @@
{ config, pkgs, ... }: { pkgs, ... }:
{ {
imports = [ ./hardware-configuration.nix ]; imports = [ ./hardware-configuration.nix ];
@ -9,12 +9,12 @@
autoUpdate = true; autoUpdate = true;
}; };
disko = { disko.disks = [ {
enableCeph = false; device = "/dev/sda";
enableLuks = false; name = "";
name = config.networking.hostName; withCeph = false;
rootDisk = "/dev/sda"; withLuks = false;
}; } ];
nix.settings = { nix.settings = {
cores = 4; cores = 4;

View File

@ -4,72 +4,91 @@ let
cfg = config.disko; cfg = config.disko;
in in
{ {
options.disko = { options.disko.disks = lib.mkOption {
name = lib.mkOption { description = lib.mdDoc "Disk names to format.";
type = lib.types.str; type = with lib.types; listOf (submodule (_: {
example = "chaos"; options = {
description = "Machine name used in eg zpool name."; device = lib.mkOption {
}; type = lib.types.str;
default = null;
example = "/dev/sda";
description = "Path of the disk.";
};
rootDisk = lib.mkOption { name = lib.mkOption {
type = with lib.types; nullOr str; type = lib.types.str;
default = null; default = null;
example = "/dev/sda"; example = "ssd0";
description = "Path of the root disk."; description = "Name of the disk.";
}; };
enableCeph = lib.mkOption { withBoot = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = true; default = true;
description = "Wether to include a ceph on the root disk."; description = "Wether to include a boot partition.";
}; };
enableLuks = lib.mkOption { withCeph = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = true; default = true;
description = "Wether to encrypt the root disk."; description = "Wether to include a ceph partition.";
}; };
enableZfs = lib.mkOption { withLuks = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = true; default = true;
description = "Wether to include a zfs on the root disk."; description = "Wether to encrypt the paritions.";
}; };
withZfs = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Wether to include a zfs parition.";
};
};
}));
default = [ ];
}; };
config = { config = {
assertions = [ assertions = map
{ (disk: [
assertion = cfg.enableCeph || cfg.enableZfs; {
message = "Must enable ceph or zfs!"; assertion = disk.withCeph || disk.withZfs;
} message = "Must enable ceph or zfs!";
{ }
assertion = cfg.enableCeph -> cfg.enableLuks; {
message = "Ceph requires Luks!"; assertion = disk.withCeph -> disk.withLuks;
} message = "Ceph requires Luks!";
]; }
])
(lib.attrNames cfg.disks);
disko = { disko = {
devices = devices = lib.mkIf (cfg.disks != [ ]) (lib.head (map
let (disk:
rootSize = 200; let
zfs = { diskName = if disk.name != "" then "-${disk.name}" else "";
size = if (!cfg.enableCeph) then "100%FREE" else "${toString rootSize}GiB"; luksName = "crypt-${config.networking.hostName}${diskName}";
content = { rootSize = 200;
pool = cfg.name; vgName = "lvm-${config.networking.hostName}${diskName}";
type = "zfs"; zfs = {
size = if (!disk.withCeph) then "100%FREE" else "${toString rootSize}GiB";
content = {
pool = disk.name;
type = "zfs";
};
}; };
}; zfsName = "${config.networking.hostName}${diskName}";
in in
lib.mkIf (cfg.rootDisk != "") ({
{ disk.${disk.device} = {
disk.${cfg.rootDisk} = { inherit (disk) device;
device = cfg.rootDisk;
type = "disk"; type = "disk";
content = { content = {
type = "table"; type = "table";
format = "gpt"; format = "gpt";
partitions = lib.optional cfg.enableZfs partitions = lib.optional disk.withZfs
{ {
name = "ESP"; name = "ESP";
start = "1MiB"; start = "1MiB";
@ -83,107 +102,109 @@ in
} ++ [ } ++ [
{ {
name = "root"; name = "root";
start = if cfg.enableZfs then "512MiB" else "1MiB"; start = if disk.withZfs then "512MiB" else "1MiB";
end = "100%"; end = "100%";
part-type = "primary"; part-type = "primary";
content = lib.optionalAttrs cfg.enableLuks content = lib.optionalAttrs disk.withLuks
{ {
type = "luks"; type = "luks";
name = "crypt-${cfg.name}"; name = luksName;
# TODO: add password, otherwise prompt opens # TODO: add password, otherwise prompt opens
keyFile = "/$PWD/keyFile"; keyFile = "/$PWD/keyFile";
content = { content = {
type = "lvm_pv"; type = "lvm_pv";
vg = "lvm-${cfg.name}"; vg = vgName;
}; };
} // lib.optionalAttrs (!cfg.enableLuks) zfs.content; } // lib.optionalAttrs (!disk.withLuks) zfs.content;
} }
]; ];
}; };
}; };
} // lib.optionalAttrs cfg.enableLuks { } // lib.optionalAttrs disk.withLuks {
lvm_vg."lvm-${cfg.name}" = { lvm_vg.${vgName} = {
type = "lvm_vg"; type = "lvm_vg";
lvs = lib.optionalAttrs cfg.enableCeph lvs = lib.optionalAttrs disk.withCeph
{ {
# the header is 3650 byte long and substract an additional 446 byte for aligment # TODO: delete old code if this works
# error messages: ceph.size = "100%FREE";
# Volume group "lvm-chaos" has insufficient free space (51195 extents): 51200 required. # the header is 3650 byte long and substract an additional 446 byte for aligment
# Size is not a multiple of 512. Try using 40057405440 or 40057405952. # error messages:
ceph.size = # Volume group "lvm-chaos" has insufficient free space (51195 extents): 51200 required.
let # Size is not a multiple of 512. Try using 40057405440 or 40057405952.
# convert GiB to bytes # ceph.size =
rootSizeMiB = rootSize * 1024 * 1024 * 1024; # let
# convert back to MiB and allign to 4 MiB in the process # # convert GiB to bytes
roundToMiB = "/1024/1024/4*4"; # rootSizeMiB = rootSize * 1024 * 1024 * 1024;
# substract 512 MiB for /boot and 20 MiB for luks+header+other # # convert back to MiB and allign to 4 MiB in the process
bootOther = "-512-20"; # roundToMiB = "/1024/1024/4*4";
in # # substract 512 MiB for /boot and 20 MiB for luks+header+other
"$((($(lsblk /dev/sda --noheadings --nodeps --output SIZE --bytes)-${toString rootSizeMiB})${roundToMiB}${bootOther}))MiB"; # bootOther = "-512-20";
} // lib.optionalAttrs cfg.enableZfs { inherit zfs; }; # in
}; # "$((($(lsblk ${disk.device} --noheadings --nodeps --output SIZE --bytes)-${toString rootSizeMiB})${roundToMiB}${bootOther}))MiB";
} // { } // lib.optionalAttrs disk.withZfs { inherit zfs; };
zpool."${cfg.name}" = {
type = "zpool";
mountpoint = null;
mountRoot = "/mnt";
rootFsOptions.acltype = "posixacl";
options = {
ashift = "12";
autotrim = "on";
}; };
datasets = } // {
let zpool.${zfsName} = {
dataset = mountpoint: { type = "zpool";
options = { mountpoint = null;
canmount = "on"; rootFsOptions.acltype = "posixacl";
compression = "zstd"; options = {
dnodesize = "auto"; ashift = "12";
normalization = "formD"; autotrim = "on";
xattr = "sa";
inherit mountpoint;
};
type = "zfs_fs";
};
in
{
"data" = dataset "/";
"data/etc" = dataset "/etc";
"data/home" = dataset "/home";
"data/var" = dataset "/var";
# used by services.postgresqlBackup and later by restic
"data/var/backup" = dataset "/var/backup";
"data/var/lib" = dataset "/var/lib";
"data/var/log" = dataset "/var/log";
"nixos" = {
options = {
canmount = "off";
mountpoint = "none";
};
type = "zfs_fs";
};
"nixos/nix" = dataset "/nix";
"nixos/nix/store" = {
options = {
atime = "off";
canmount = "on";
mountpoint = "/nix/store";
};
type = "zfs_fs";
};
"nixos/nix/var" = dataset "/nix/var";
"reserved" = {
# zfs uses copy on write and requires some free space to delete files when the disk is completely filled
options = {
canmount = "off";
mountpoint = "none";
reservation = "5GiB";
};
type = "zfs_fs";
};
}; };
}; datasets =
}; let
dataset = mountpoint: {
options = {
canmount = "on";
compression = "zstd";
dnodesize = "auto";
normalization = "formD";
xattr = "sa";
inherit mountpoint;
};
type = "zfs_fs";
};
in
{
"data" = dataset "/";
"data/etc" = dataset "/etc";
"data/home" = dataset "/home";
"data/var" = dataset "/var";
# used by services.postgresqlBackup and later by restic
"data/var/backup" = dataset "/var/backup";
"data/var/lib" = dataset "/var/lib";
"data/var/log" = dataset "/var/log";
"nixos" = {
options = {
canmount = "off";
mountpoint = "none";
};
type = "zfs_fs";
};
"nixos/nix" = dataset "/nix";
"nixos/nix/store" = {
options = {
atime = "off";
canmount = "on";
mountpoint = "/nix/store";
};
type = "zfs_fs";
};
"nixos/nix/var" = dataset "/nix/var";
"reserved" = {
# zfs uses copy on write and requires some free space to delete files when the disk is completely filled
options = {
canmount = "off";
mountpoint = "none";
reservation = "5GiB";
};
type = "zfs_fs";
};
};
};
}))
cfg.disks));
# we use our own hardware-configuration.nix # we use our own hardware-configuration.nix
enableConfig = false; enableConfig = false;
}; };