diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 3bc0dedec00..fbfc61177d3 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -642,41 +642,14 @@ in }; scriptArgs = "%i"; - path = [ pkgs.gawk cfgZfs.package ]; + path = [ cfgZfs.package ]; - # ZFS has no way of enumerating just devices in a pool in a way - # that 'zpool online -e' supports. Thus, we've implemented a - # bit of a strange approach of highlighting just devices. - # See: https://github.com/openzfs/zfs/issues/12505 - script = let - # This UUID has been chosen at random and is to provide a - # collision-proof, predictable token to search for - magicIdentifier = "NIXOS-ZFS-ZPOOL-DEVICE-IDENTIFIER-37108bec-aff6-4b58-9e5e-53c7c9766f05"; - zpoolScripts = pkgs.writeShellScriptBin "device-highlighter" '' - echo "${magicIdentifier}" - ''; - in '' + script = '' pool=$1 echo "Expanding all devices for $pool." - # Put our device-highlighter script it to the PATH - export ZPOOL_SCRIPTS_PATH=${zpoolScripts}/bin - - # Enable running our precisely specified zpool script as root - export ZPOOL_SCRIPTS_AS_ROOT=1 - - devices() ( - zpool status -c device-highlighter "$pool" \ - | awk '($2 == "ONLINE" && $6 == "${magicIdentifier}") { print $1; }' - ) - - for device in $(devices); do - echo "Attempting to expand $device of $pool..." - if ! zpool online -e "$pool" "$device"; then - echo "Failed to expand '$device' of '$pool'." - fi - done + ${pkgs.zpool-auto-expand-partitions}/bin/zpool_part_disks --automatically-grow "$pool" ''; }; @@ -701,8 +674,6 @@ in RemainAfterExit = true; }; - path = [ pkgs.gawk cfgZfs.package ]; - script = '' for pool in ${poolListProvider}; do systemctl start --no-block "zpool-expand@$pool" diff --git a/nixos/tests/zfs.nix b/nixos/tests/zfs.nix index bf0165b8816..0b44961a3de 100644 --- a/nixos/tests/zfs.nix +++ b/nixos/tests/zfs.nix @@ -127,4 +127,54 @@ in { }; installer = (import ./installer.nix { }).zfsroot; + + expand-partitions = makeTest { + name = "multi-disk-zfs"; + nodes = { + machine = { pkgs, ... }: { + environment.systemPackages = [ pkgs.parted ]; + boot.supportedFilesystems = [ "zfs" ]; + networking.hostId = "00000000"; + + virtualisation = { + emptyDiskImages = [ 20480 20480 20480 20480 20480 20480 ]; + }; + + specialisation.resize.configuration = { + services.zfs.expandOnBoot = [ "tank" ]; + }; + }; + }; + + testScript = { nodes, ... }: + '' + start_all() + machine.wait_for_unit("default.target") + print(machine.succeed('mount')) + + print(machine.succeed('parted --script /dev/vdb -- mklabel gpt')) + print(machine.succeed('parted --script /dev/vdb -- mkpart primary 1M 70M')) + + print(machine.succeed('parted --script /dev/vdc -- mklabel gpt')) + print(machine.succeed('parted --script /dev/vdc -- mkpart primary 1M 70M')) + + print(machine.succeed('zpool create tank mirror /dev/vdb1 /dev/vdc1 mirror /dev/vdd /dev/vde mirror /dev/vdf /dev/vdg')) + print(machine.succeed('zpool list -v')) + print(machine.succeed('mount')) + start_size = int(machine.succeed('df -k --output=size /tank | tail -n1').strip()) + + print(machine.succeed("/run/current-system/specialisation/resize/bin/switch-to-configuration test >&2")) + machine.wait_for_unit("zpool-expand-pools.service") + machine.wait_for_unit("zpool-expand@tank.service") + + print(machine.succeed('zpool list -v')) + new_size = int(machine.succeed('df -k --output=size /tank | tail -n1').strip()) + + if (new_size - start_size) > 20000000: + print("Disk grew appropriately.") + else: + print(f"Disk went from {start_size} to {new_size}, which doesn't seem right.") + exit(1) + ''; + }; } diff --git a/pkgs/tools/filesystems/zpool-auto-expand-partitions/default.nix b/pkgs/tools/filesystems/zpool-auto-expand-partitions/default.nix new file mode 100644 index 00000000000..afafbca58ba --- /dev/null +++ b/pkgs/tools/filesystems/zpool-auto-expand-partitions/default.nix @@ -0,0 +1,46 @@ +{ rustPlatform +, cloud-utils +, fetchFromGitHub +, lib +, llvmPackages +, pkg-config +, util-linux +, zfs +}: +rustPlatform.buildRustPackage rec { + pname = "zpool-auto-expand-partitions"; + version = "0.1.0"; + + src = fetchFromGitHub { + owner = "DeterminateSystems"; + repo = "zpool-auto-expand-partitions"; + rev = "v${version}"; + hash = "sha256-LA6YO6vv7VCXwFfayQVxVR80niSCo89sG0hqh0wDEh8="; + }; + + cargoHash = "sha256-5v0fqp8aro+QD/f5VudMREc8RvKQapNAoArcCKMN1Sw="; + + preBuild = '' + substituteInPlace src/grow.rs \ + --replace '"growpart"' '"${cloud-utils}/bin/growpart"' + substituteInPlace src/lsblk.rs \ + --replace '"lsblk"' '"${util-linux}/bin/lsblk"' + ''; + + nativeBuildInputs = [ + pkg-config + rustPlatform.bindgenHook + ]; + + buildInputs = [ + util-linux + zfs + ]; + + meta = with lib; { + description = "A tool that aims to expand all partitions in a specified zpool to fill the available space"; + homepage = "https://github.com/DeterminateSystems/zpool-auto-expand-partitions"; + license = licenses.asl20; + maintainers = teams.determinatesystems.members; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 2d640c6b1ac..92ecf969169 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -11619,6 +11619,8 @@ with pkgs; zfsnap = callPackage ../tools/backup/zfsnap { }; + zpool-auto-expand-partitions = callPackage ../tools/filesystems/zpool-auto-expand-partitions { }; + zile = callPackage ../applications/editors/zile { }; zinnia = callPackage ../tools/inputmethods/zinnia { };