pve-installer/Proxmox/Sys/ZFS.pm
Christoph Heiss 4359104918 low-level: install: check for already-existing rpool on install
.. much in the same manner as the detection for LVM works.

zpools can only be renamed by importing them with a new name, so
unfortunately the import-export dance is needed.

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
Reviewed-by: Aaron Lauterer <a.lauterer@proxmox.com>
Tested-by: Aaron Lauterer <a.lauterer@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2024-07-16 17:51:41 +02:00

110 lines
3.1 KiB
Perl

package Proxmox::Sys::ZFS;
use strict;
use warnings;
use Proxmox::Sys::Command qw(run_command syscmd);
use base qw(Exporter);
our @EXPORT_OK = qw(get_exported_pools rename_pool);
# Parses the output of running `zpool import`, which shows all importable
# ZFS pools.
# Unfortunately, `zpool` does not support JSON or any other machine-readable
# format for output, so we have to do it the hard way.
#
# Example output of `zpool import` looks like this:
#
# root@proxmox:/# zpool import
# pool: testpool
# id: 4958685680270539150
# state: ONLINE
# action: The pool can be imported using its name or numeric identifier.
# config:
#
# testpool ONLINE
# vdc ONLINE
# vdd ONLINE
#
# pool: rpool
# id: 9412322616744093413
# state: ONLINE
# status: The pool was last accessed by another system.
# action: The pool can be imported using its name or numeric identifier and
# the '-f' flag.
# see: https://openzfs.github.io/openzfs-docs/msg/ZFS-8000-EY
# config:
#
# rpool ONLINE
# mirror-0 ONLINE
# vda3 ONLINE
# vdb3 ONLINE
#
sub zpool_import_parse_output {
my ($fh) = @_;
my $pools = []; # all found pools
my $pool = {}; # last found pool in output
while (my $line = <$fh>) {
# first, if we find the start of a new pool, add it to the list with
# its name
if ($line =~ /^\s+pool: (.+)$/) {
# push the previous parsed pool to the result list
push @$pools, $pool if %$pool;
$pool = { name => $1 };
next;
}
# ignore any (garbage) output before the actual list, just in case
next if !%$pool;
# add any possibly-useful attribute to the last (aka. current) pool
if ($line =~ /^\s*(id|state|status|action): (.+)$/) {
chomp($pool->{$1} = $2);
next;
}
}
# add the final parsed pool to the list
push @$pools, $pool if %$pool;
return $pools;
}
# Returns an array of all importable ZFS pools on the system.
# Each entry is a hash of the format:
#
# {
# name => '<pool name>',
# id => <numeric pool-id>,
# /* see also zpool_state_to_name() in lib/libzfs/libzfs_pool.c /*
# state => 'OFFLINE' | 'REMOVED' | 'FAULTED' | 'SPLIT' | 'UNAVAIL' \
# | 'FAULTED' | 'DEGRADED' | 'ONLINE',
# status => '<human-readable status string>', optional
# action => '<human-readable action string>', optional
# }
sub get_exported_pools {
my $raw = run_command(['zpool', 'import']);
open (my $fh, '<', \$raw) or die 'failed to open in-memory stream';
return zpool_import_parse_output($fh);
}
# Renames a importable ZFS pool by importing it with a new name and then
# exporting again.
#
# Arguments:
#
# $poolid - Unique, numeric identifier of the pool to rename
# $new_name - New name for the pool
sub rename_pool {
my ($poolid, $new_name) = @_;
syscmd("zpool import -f $poolid $new_name") == 0 ||
die "failed to import zfs pool with id '$poolid' with new name '$new_name'\n";
syscmd("zpool export $new_name") == 0 ||
warn "failed to export renamed zfs pool '$new_name'\n";
}
1;