remove most of zfs stuff
This commit is contained in:
parent
2a1e055aff
commit
117d65010b
@ -58,8 +58,6 @@ in
|
|||||||
hardware.cpu.intel.updateMicrocode = true;
|
hardware.cpu.intel.updateMicrocode = true;
|
||||||
nixpkgs.hostPlatform = "x86_64-linux";
|
nixpkgs.hostPlatform = "x86_64-linux";
|
||||||
|
|
||||||
systemd.services.zfs-mount.enable = false;
|
|
||||||
|
|
||||||
mj = {
|
mj = {
|
||||||
stateVersion = "23.11";
|
stateVersion = "23.11";
|
||||||
timeZone = "Europe/Vilnius";
|
timeZone = "Europe/Vilnius";
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
## From https://github.com/ne9z/dotfiles-flake, branch openzfs-guide
|
|
||||||
|
|
||||||
857dea48debb4d45021b4005784919e96e63cc4a
|
|
||||||
|
|
||||||
boot/
|
|
||||||
fileSystems/
|
|
@ -1,186 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
cfg = config.zfs-root.boot;
|
|
||||||
inherit (lib)
|
|
||||||
mkIf
|
|
||||||
types
|
|
||||||
mkDefault
|
|
||||||
mkOption
|
|
||||||
mkMerge
|
|
||||||
strings
|
|
||||||
;
|
|
||||||
inherit (builtins)
|
|
||||||
head
|
|
||||||
toString
|
|
||||||
map
|
|
||||||
tail
|
|
||||||
;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.zfs-root.boot = {
|
|
||||||
enable = mkOption {
|
|
||||||
description = "Enable root on ZFS support";
|
|
||||||
type = types.bool;
|
|
||||||
default = false; # TODO: change by @motiejus
|
|
||||||
};
|
|
||||||
devNodes = mkOption {
|
|
||||||
description = "Specify where to discover ZFS pools";
|
|
||||||
type = types.str;
|
|
||||||
apply =
|
|
||||||
x:
|
|
||||||
assert (strings.hasSuffix "/" x || abort "devNodes '${x}' must have trailing slash!");
|
|
||||||
x;
|
|
||||||
default = "/dev/disk/by-id/";
|
|
||||||
};
|
|
||||||
bootDevices = mkOption {
|
|
||||||
description = "Specify boot devices";
|
|
||||||
type = types.nonEmptyListOf types.str;
|
|
||||||
};
|
|
||||||
availableKernelModules = mkOption {
|
|
||||||
type = types.nonEmptyListOf types.str;
|
|
||||||
default = [
|
|
||||||
"uas"
|
|
||||||
"nvme"
|
|
||||||
"ahci"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
kernelParams = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
immutable = mkOption {
|
|
||||||
description = "Enable root on ZFS immutable root support";
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
};
|
|
||||||
removableEfi = mkOption {
|
|
||||||
description = "install bootloader to fallback location";
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
};
|
|
||||||
partitionScheme = mkOption {
|
|
||||||
default = {
|
|
||||||
biosBoot = "-part5";
|
|
||||||
efiBoot = "-part1";
|
|
||||||
swap = "-part4";
|
|
||||||
bootPool = "-part2";
|
|
||||||
rootPool = "-part3";
|
|
||||||
};
|
|
||||||
description = "Describe on disk partitions";
|
|
||||||
type = types.attrsOf types.str;
|
|
||||||
};
|
|
||||||
sshUnlock = {
|
|
||||||
enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
};
|
|
||||||
authorizedKeys = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = mkIf (cfg.enable) (mkMerge [
|
|
||||||
{
|
|
||||||
zfs-root.fileSystems.datasets = {
|
|
||||||
"rpool/nixos/home" = mkDefault "/home";
|
|
||||||
"rpool/nixos/var/lib" = mkDefault "/var/lib";
|
|
||||||
"rpool/nixos/var/log" = mkDefault "/var/log";
|
|
||||||
"rpool/nixos/nix" = mkDefault "/nix";
|
|
||||||
"bpool/nixos/root" = "/boot";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(mkIf (!cfg.immutable) {
|
|
||||||
zfs-root.fileSystems.datasets = {
|
|
||||||
"rpool/nixos/root" = "/";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(mkIf cfg.immutable {
|
|
||||||
zfs-root.fileSystems = {
|
|
||||||
datasets = {
|
|
||||||
"rpool/nixos/empty" = "/";
|
|
||||||
"rpool/nixos/root" = "/oldroot";
|
|
||||||
};
|
|
||||||
bindmounts = {
|
|
||||||
"/oldroot/nix" = "/nix";
|
|
||||||
"/oldroot/etc/nixos" = "/etc/nixos";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
boot.initrd.postDeviceCommands = ''
|
|
||||||
if ! grep -q zfs_no_rollback /proc/cmdline; then
|
|
||||||
zpool import -N rpool
|
|
||||||
zfs rollback -r rpool/nixos/empty@start
|
|
||||||
zpool export -a
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
})
|
|
||||||
{
|
|
||||||
zfs-root.fileSystems = {
|
|
||||||
efiSystemPartitions = map (diskName: diskName + cfg.partitionScheme.efiBoot) cfg.bootDevices;
|
|
||||||
swapPartitions =
|
|
||||||
if cfg.partitionScheme ? swap then
|
|
||||||
map (diskName: diskName + cfg.partitionScheme.swap) cfg.bootDevices
|
|
||||||
else
|
|
||||||
[ ];
|
|
||||||
};
|
|
||||||
boot = {
|
|
||||||
initrd.availableKernelModules = cfg.availableKernelModules;
|
|
||||||
kernelParams = cfg.kernelParams;
|
|
||||||
supportedFilesystems = [ "zfs" ];
|
|
||||||
zfs = {
|
|
||||||
devNodes = cfg.devNodes;
|
|
||||||
forceImportRoot = mkDefault false;
|
|
||||||
};
|
|
||||||
loader = {
|
|
||||||
efi = {
|
|
||||||
canTouchEfiVariables = if cfg.removableEfi then false else true;
|
|
||||||
efiSysMountPoint = "/boot/efis/" + (head cfg.bootDevices) + cfg.partitionScheme.efiBoot;
|
|
||||||
};
|
|
||||||
generationsDir.copyKernels = true;
|
|
||||||
grub = {
|
|
||||||
enable = true;
|
|
||||||
devices = map (diskName: cfg.devNodes + diskName) cfg.bootDevices;
|
|
||||||
efiInstallAsRemovable = cfg.removableEfi;
|
|
||||||
copyKernels = true;
|
|
||||||
efiSupport = true;
|
|
||||||
zfsSupport = true;
|
|
||||||
extraInstallCommands = toString (
|
|
||||||
map (diskName: ''
|
|
||||||
set -x
|
|
||||||
${pkgs.coreutils-full}/bin/cp -r ${config.boot.loader.efi.efiSysMountPoint}/EFI /boot/efis/${diskName}${cfg.partitionScheme.efiBoot}
|
|
||||||
set +x
|
|
||||||
'') (tail cfg.bootDevices)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(mkIf cfg.sshUnlock.enable {
|
|
||||||
boot.initrd = {
|
|
||||||
network = {
|
|
||||||
enable = true;
|
|
||||||
ssh = {
|
|
||||||
enable = true;
|
|
||||||
hostKeys = [
|
|
||||||
"/var/lib/ssh_unlock_zfs_ed25519_key"
|
|
||||||
"/var/lib/ssh_unlock_zfs_rsa_key"
|
|
||||||
];
|
|
||||||
authorizedKeys = cfg.sshUnlock.authorizedKeys;
|
|
||||||
};
|
|
||||||
postCommands = ''
|
|
||||||
tee -a /root/.profile >/dev/null <<EOF
|
|
||||||
if zfs load-key rpool/nixos; then
|
|
||||||
pkill zfs
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
EOF'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
}
|
|
@ -10,14 +10,11 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./boot
|
|
||||||
./fileSystems
|
|
||||||
./snapshot
|
./snapshot
|
||||||
./sshd
|
./sshd
|
||||||
./unitstatus
|
./unitstatus
|
||||||
./users
|
./users
|
||||||
./zfs
|
./zfs
|
||||||
./zfsborg
|
|
||||||
];
|
];
|
||||||
|
|
||||||
options.mj = with lib.types; {
|
options.mj = with lib.types; {
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
{ config, lib, ... }:
|
|
||||||
let
|
|
||||||
cfg = config.zfs-root.fileSystems;
|
|
||||||
inherit (lib)
|
|
||||||
types
|
|
||||||
mkDefault
|
|
||||||
mkOption
|
|
||||||
mkMerge
|
|
||||||
mapAttrsToList
|
|
||||||
;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.zfs-root.fileSystems = {
|
|
||||||
datasets = mkOption {
|
|
||||||
description = "Set mountpoint for datasets";
|
|
||||||
type = types.attrsOf types.str;
|
|
||||||
default = { };
|
|
||||||
};
|
|
||||||
bindmounts = mkOption {
|
|
||||||
description = "Set mountpoint for bindmounts";
|
|
||||||
type = types.attrsOf types.str;
|
|
||||||
default = { };
|
|
||||||
};
|
|
||||||
efiSystemPartitions = mkOption {
|
|
||||||
description = "Set mountpoint for efi system partitions";
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
swapPartitions = mkOption {
|
|
||||||
description = "Set swap partitions";
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config.fileSystems = mkMerge (
|
|
||||||
mapAttrsToList (dataset: mountpoint: {
|
|
||||||
"${mountpoint}" = {
|
|
||||||
device = "${dataset}";
|
|
||||||
fsType = "zfs";
|
|
||||||
options = [
|
|
||||||
"X-mount.mkdir"
|
|
||||||
"noatime"
|
|
||||||
];
|
|
||||||
neededForBoot = true;
|
|
||||||
};
|
|
||||||
}) cfg.datasets
|
|
||||||
++ mapAttrsToList (bindsrc: mountpoint: {
|
|
||||||
"${mountpoint}" = {
|
|
||||||
device = "${bindsrc}";
|
|
||||||
fsType = "none";
|
|
||||||
options = [
|
|
||||||
"bind"
|
|
||||||
"X-mount.mkdir"
|
|
||||||
"noatime"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}) cfg.bindmounts
|
|
||||||
++ map (esp: {
|
|
||||||
"/boot/efis/${esp}" = {
|
|
||||||
device = "${config.zfs-root.boot.devNodes}${esp}";
|
|
||||||
fsType = "vfat";
|
|
||||||
options = [
|
|
||||||
"x-systemd.idle-timeout=1min"
|
|
||||||
"x-systemd.automount"
|
|
||||||
"noauto"
|
|
||||||
"nofail"
|
|
||||||
"noatime"
|
|
||||||
"X-mount.mkdir"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}) cfg.efiSystemPartitions
|
|
||||||
);
|
|
||||||
config.swapDevices = mkDefault (
|
|
||||||
map (swap: {
|
|
||||||
device = "${config.zfs-root.boot.devNodes}${swap}";
|
|
||||||
discardPolicy = mkDefault "both";
|
|
||||||
randomEncryption = {
|
|
||||||
enable = true;
|
|
||||||
allowDiscards = mkDefault true;
|
|
||||||
};
|
|
||||||
}) cfg.swapPartitions
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,118 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
mkPreHook = zfs_name: i: ''
|
|
||||||
set -x
|
|
||||||
sleep ${toString i}
|
|
||||||
mkdir "$RUNTIME_DIRECTORY/snapshot"
|
|
||||||
${pkgs.util-linux}/bin/mount \
|
|
||||||
-t zfs \
|
|
||||||
-o ro \
|
|
||||||
$(${pkgs.zfs}/bin/zfs list -H -t snapshot -o name ${zfs_name} | sort | tail -1) \
|
|
||||||
"$RUNTIME_DIRECTORY/snapshot"
|
|
||||||
cd "$RUNTIME_DIRECTORY/snapshot"
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.mj.base.zfsborg = with lib.types; {
|
|
||||||
enable = lib.mkEnableOption "backup zfs snapshots with borg";
|
|
||||||
|
|
||||||
passwordPath = lib.mkOption { type = str; };
|
|
||||||
sshKeyPath = lib.mkOption {
|
|
||||||
type = nullOr path;
|
|
||||||
default = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
dirs = lib.mkOption {
|
|
||||||
default = { };
|
|
||||||
type = listOf (submodule {
|
|
||||||
options = {
|
|
||||||
mountpoint = lib.mkOption { type = path; };
|
|
||||||
repo = lib.mkOption { type = str; };
|
|
||||||
paths = lib.mkOption { type = listOf str; };
|
|
||||||
patterns = lib.mkOption {
|
|
||||||
type = listOf str;
|
|
||||||
default = [ ];
|
|
||||||
};
|
|
||||||
prune = lib.mkOption {
|
|
||||||
type = anything;
|
|
||||||
default = { };
|
|
||||||
};
|
|
||||||
backup_at = lib.mkOption { type = str; };
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config =
|
|
||||||
with config.mj.base.zfsborg;
|
|
||||||
lib.mkIf enable {
|
|
||||||
systemd.services = lib.listToAttrs (
|
|
||||||
lib.imap0 (
|
|
||||||
i: attr:
|
|
||||||
let
|
|
||||||
svcName = "borgbackup-job-${lib.strings.sanitizeDerivationName attr.mountpoint}-${toString i}";
|
|
||||||
in
|
|
||||||
lib.nameValuePair svcName { serviceConfig.RuntimeDirectory = svcName; }
|
|
||||||
) dirs
|
|
||||||
);
|
|
||||||
|
|
||||||
services.borgbackup.jobs = builtins.listToAttrs (
|
|
||||||
lib.imap0 (
|
|
||||||
i: attrs:
|
|
||||||
let
|
|
||||||
mountpoint = builtins.getAttr "mountpoint" attrs;
|
|
||||||
fs = builtins.getAttr mountpoint config.fileSystems;
|
|
||||||
in
|
|
||||||
assert fs.fsType == "zfs";
|
|
||||||
assert lib.assertMsg config.mj.base.unitstatus.enable
|
|
||||||
"config.mj.base.unitstatus.enable must be true";
|
|
||||||
lib.nameValuePair "${lib.strings.sanitizeDerivationName mountpoint}-${toString i}" (
|
|
||||||
{
|
|
||||||
inherit (attrs) repo paths;
|
|
||||||
|
|
||||||
doInit = true;
|
|
||||||
encryption = {
|
|
||||||
mode = "repokey-blake2";
|
|
||||||
passCommand = "cat ${config.mj.base.zfsborg.passwordPath}";
|
|
||||||
};
|
|
||||||
extraArgs = "--remote-path=borg1";
|
|
||||||
compression = "auto,zstd,10";
|
|
||||||
extraCreateArgs = "--chunker-params buzhash,10,23,16,4095";
|
|
||||||
startAt = attrs.backup_at;
|
|
||||||
preHook = mkPreHook fs.device i;
|
|
||||||
prune.keep = {
|
|
||||||
within = "1d";
|
|
||||||
daily = 7;
|
|
||||||
weekly = 4;
|
|
||||||
monthly = 3;
|
|
||||||
};
|
|
||||||
environment =
|
|
||||||
{
|
|
||||||
BORG_HOST_ID =
|
|
||||||
let
|
|
||||||
h = config.networking;
|
|
||||||
in
|
|
||||||
"${h.hostName}.${h.domain}@${h.hostId}";
|
|
||||||
}
|
|
||||||
// lib.optionalAttrs (sshKeyPath != null) {
|
|
||||||
BORG_RSH = ''ssh -i "${config.mj.base.zfsborg.sshKeyPath}"'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// lib.optionalAttrs (attrs ? patterns) { inherit (attrs) patterns; }
|
|
||||||
// lib.optionalAttrs (attrs ? prune) { inherit (attrs) prune; }
|
|
||||||
)
|
|
||||||
) dirs
|
|
||||||
);
|
|
||||||
|
|
||||||
mj.base.unitstatus.units =
|
|
||||||
let
|
|
||||||
sanitized = map lib.strings.sanitizeDerivationName (lib.catAttrs "mountpoint" dirs);
|
|
||||||
in
|
|
||||||
lib.imap0 (i: name: "borgbackup-job-${name}-${toString i}") sanitized;
|
|
||||||
};
|
|
||||||
}
|
|
@ -9,7 +9,7 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.mj.services.btrfsborg = with lib.types; {
|
options.mj.services.btrfsborg = with lib.types; {
|
||||||
enable = lib.mkEnableOption "backup zfs snapshots with borg";
|
enable = lib.mkEnableOption "backup btrfs snapshots with borg";
|
||||||
|
|
||||||
passwordPath = lib.mkOption { type = str; };
|
passwordPath = lib.mkOption { type = str; };
|
||||||
sshKeyPath = lib.mkOption {
|
sshKeyPath = lib.mkOption {
|
||||||
|
@ -22,6 +22,5 @@
|
|||||||
./tailscale
|
./tailscale
|
||||||
./vaultwarden
|
./vaultwarden
|
||||||
./wifibackup
|
./wifibackup
|
||||||
./zfsunlock
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
mkUnlock =
|
|
||||||
{
|
|
||||||
sshEndpoint,
|
|
||||||
pingEndpoint,
|
|
||||||
remotePubkey,
|
|
||||||
pwFile,
|
|
||||||
pingTimeoutSec,
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
timeoutStr = builtins.toString pingTimeoutSec;
|
|
||||||
in
|
|
||||||
''
|
|
||||||
set -x
|
|
||||||
# if host is reachable via "pingEndpoint", which, we presume is
|
|
||||||
# VPN (which implies the rootfs has been unlocked for VPN to work),
|
|
||||||
# exit successfully.
|
|
||||||
${pkgs.iputils}/bin/ping -q -W ${timeoutStr} -c 1 ${pingEndpoint} && exit 0
|
|
||||||
|
|
||||||
exec ${pkgs.openssh}/bin/ssh \
|
|
||||||
-i /etc/ssh/ssh_host_ed25519_key \
|
|
||||||
-o UserKnownHostsFile=none \
|
|
||||||
-o GlobalKnownHostsFile=/dev/null \
|
|
||||||
-o KnownHostsCommand="${pkgs.coreutils}/bin/echo ${sshEndpoint} ${remotePubkey}" \
|
|
||||||
root@${sshEndpoint} < "${pwFile}"
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.mj.services.zfsunlock = with lib.types; {
|
|
||||||
enable = lib.mkEnableOption "remotely unlock zfs-encrypted root volumes";
|
|
||||||
|
|
||||||
targets = lib.mkOption {
|
|
||||||
default = { };
|
|
||||||
type = attrsOf (submodule {
|
|
||||||
options = {
|
|
||||||
sshEndpoint = lib.mkOption { type = str; };
|
|
||||||
pingEndpoint = lib.mkOption { type = str; };
|
|
||||||
pingTimeoutSec = lib.mkOption {
|
|
||||||
type = int;
|
|
||||||
default = 20;
|
|
||||||
};
|
|
||||||
remotePubkey = lib.mkOption { type = str; };
|
|
||||||
pwFile = lib.mkOption { type = path; };
|
|
||||||
startAt = lib.mkOption { type = either str (listOf str); };
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf config.mj.services.zfsunlock.enable {
|
|
||||||
systemd.services = lib.mapAttrs' (
|
|
||||||
name: cfg:
|
|
||||||
lib.nameValuePair "zfsunlock-${name}" {
|
|
||||||
description = "zfsunlock service for ${name}";
|
|
||||||
script = mkUnlock (builtins.removeAttrs cfg [ "startAt" ]);
|
|
||||||
serviceConfig = {
|
|
||||||
User = "root";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
) config.mj.services.zfsunlock.targets;
|
|
||||||
|
|
||||||
systemd.timers = lib.mapAttrs' (
|
|
||||||
name: cfg:
|
|
||||||
lib.nameValuePair "zfsunlock-${name}" {
|
|
||||||
description = "zfsunlock timer for ${name}";
|
|
||||||
wantedBy = [ "timers.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnCalendar = cfg.startAt;
|
|
||||||
};
|
|
||||||
after = [ "network-online.target" ];
|
|
||||||
wants = [ "network-online.target" ];
|
|
||||||
}
|
|
||||||
) config.mj.services.zfsunlock.targets;
|
|
||||||
|
|
||||||
mj.base.unitstatus.units = map (name: "zfsunlock-${name}") (
|
|
||||||
builtins.attrNames config.mj.services.zfsunlock.targets
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user