Skip to content

Instantly share code, notes, and snippets.

@pruiz
Last active November 21, 2020 13:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pruiz/5d7fbd75efb413ac15d2d0e3ef54f32a to your computer and use it in GitHub Desktop.
Save pruiz/5d7fbd75efb413ac15d2d0e3ef54f32a to your computer and use it in GitHub Desktop.
##
## Proxmox's ZFSPoolPlugin patch allowing dynamic guessing of pool name.
##
## Description:
## Needed on clusters composed of nodes with mixed ZFS layouts,
## where pool names do not match across all cluster' nodes.
##
## This extends/overrides default ZFSPoolPlugin allowing declaration
## of 'pool' property at storage.cfg like:
## 1) Using a coma separated list, so each item will be tried in order.
## 2) Using '$auto' in order to lookup a pool with pve:id=$storeid.
##
## Version: 1.0
## Author: Pablo Ruiz García <pablo.ruiz@gmail.com>
##
package PVE::Storage::Custom::ZFSPoolPluginEx;
use strict;
use warnings;
use IO::File;
use POSIX;
use PVE::Tools qw(run_command);
use PVE::Storage::Plugin;
use PVE::Storage::ZFSPoolPlugin;
use PVE::RPCEnvironment;
use Data::Dumper;
use base qw(PVE::Storage::ZFSPoolPlugin);
# Configuration
sub type {
return 'zfspool';
}
sub api {
return 5;
}
sub register {
my ($class) = @_;
my $type = $class->type();
my $pdata = 'PVE::Storage::Plugin'->private();
# Remove default ZFSPoolPlugin, so we can override it
delete $pdata->{plugins}->{$type};
delete $pdata->{plugindata}->{$type};
$class->SUPER::register();
}
sub zfs_pool_is_valid {
my ($class, $pool) = @_;
my $name = undef;
eval {
$name = $class->zfs_get_properties(undef, 'name', $pool);
};
return defined($name) && $name eq $pool;
}
sub zfs_find_by_id {
my ($class, $id) = @_;
my $result = undef;
my @params = ('-t', 'filesystem', '-o', 'name,pve:id');
my $output = $class->zfs_request(undef, undef, 'list', @params);
if ($output)
{
my @lines = sort(split /\n/, $output);
foreach my $line (@lines) {
my ($name, $pveid) = split(/\s+/, $line);
next if ($pveid ne $id);
# XXX: Skip nested datasets/volumes..
next if (defined($result) && rindex($result, $name));
die "multiple zfs datasets with pve:id=$id found?!\n" if defined($result);
$result = $name;
}
}
return $result;
}
sub check_value {
my ($class, $type, $key, $value, $storeid, $skipSchemaCheck) = @_;
# if pool is a list, let's try each pool
# in order, first one found/existing, wins.
if ($key eq "pool" && index($value, ",")) {
foreach my $pool (split /,/, $value) {
$pool = PVE::Tools::trim($pool);
if ($class->zfs_pool_is_valid($pool)) {
$value = $pool;
last;
}
}
}
# if pool is magic keyword '$auto', we need to
# search for a dataset with pve:id=$storeid.
if ($key eq "pool" && $value eq "\$auto") {
$value = $class->zfs_find_by_id($storeid) // $value;
}
return $class->SUPER::check_value($type, $key, $value, $storeid, $skipSchemaCheck);
}
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment