Use ssh key stored in pmxcfg. Use ssh -i /etc/pve/priv/zfs/portal_id_rsa for remote commands

Signed-off-by: Michael Rasmussen <mir@datanom.net>
This commit is contained in:
Michael Rasmussen
2013-10-23 02:53:08 +02:00
committed by Dietmar Maurer
parent 86f00da603
commit 3b219e8037
4 changed files with 634 additions and 630 deletions

View File

@ -8,94 +8,95 @@ use Data::Dumper;
my @ssh_opts = ('-o', 'BatchMode=yes');
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
my $id_rsa_path = '/etc/pve/priv/zfs';
my $get_lun_cmd_map = sub {
my ($method) = @_;
my $stmfadmcmd = "/usr/sbin/stmfadm";
my $sbdadmcmd = "/usr/sbin/sbdadm";
my ($method) = @_;
my $cmdmap = {
create_lu => { cmd => $stmfadmcmd, method => 'create-lu' },
delete_lu => { cmd => $stmfadmcmd, method => 'delete-lu' },
import_lu => { cmd => $stmfadmcmd, method => 'import-lu' },
modify_lu => { cmd => $stmfadmcmd, method => 'modify-lu' },
add_view => { cmd => $stmfadmcmd, method => 'add-view' },
list_view => { cmd => $stmfadmcmd, method => 'list-view' },
list_lu => { cmd => $sbdadmcmd, method => 'list-lu' },
};
die "unknown command '$method'" unless exists $cmdmap->{$method};
return $cmdmap->{$method};
my $stmfadmcmd = "/usr/sbin/stmfadm";
my $sbdadmcmd = "/usr/sbin/sbdadm";
my $cmdmap = {
create_lu => { cmd => $stmfadmcmd, method => 'create-lu' },
delete_lu => { cmd => $stmfadmcmd, method => 'delete-lu' },
import_lu => { cmd => $stmfadmcmd, method => 'import-lu' },
modify_lu => { cmd => $stmfadmcmd, method => 'modify-lu' },
add_view => { cmd => $stmfadmcmd, method => 'add-view' },
list_view => { cmd => $stmfadmcmd, method => 'list-view' },
list_lu => { cmd => $sbdadmcmd, method => 'list-lu' },
};
die "unknown command '$method'" unless exists $cmdmap->{$method};
return $cmdmap->{$method};
};
sub get_base {
return '/dev/zvol/rdsk';
return '/dev/zvol/rdsk';
}
sub run_lun_command {
my ($scfg, $timeout, $method, @params) = @_;
my ($scfg, $timeout, $method, @params) = @_;
my $msg = '';
my $luncmd;
my $target;
my $guid;
$timeout = 10 if !$timeout;
my $output = sub {
my $line = shift;
$msg .= "$line\n";
$msg .= "$line\n";
};
if ($method eq 'create_lu') {
my $prefix = '600144f';
my $digest = md5_hex($params[0]);
$digest =~ /(\w{7}(.*))/;
$guid = "$prefix$2";
@params = ('-p', 'wcd=false', '-p', "guid=$guid", @params);
} elsif ($method eq 'modify_lu') {
@params = ('-s', @params);
} elsif ($method eq 'list_view') {
@params = ('-l', @params);
} elsif ($method eq 'list_lu') {
$guid = $params[0];
@params = undef;
}
my $cmdmap = $get_lun_cmd_map->($method);
$luncmd = $cmdmap->{cmd};
my $lunmethod = $cmdmap->{method};
$target = 'root@' . $scfg->{portal};
my $cmd = [@ssh_cmd, $target, $luncmd, $lunmethod, @params];
run_command($cmd, outfunc => $output, timeout => $timeout);
if ($method eq 'list_view') {
my @lines = split /\n/, $msg;
$msg = undef;
foreach my $line (@lines) {
if ($line =~ /^\s*LUN\s*:\s*(\d+)$/) {
$msg = $1;
last;
}
}
if ($method eq 'create_lu') {
my $prefix = '600144f';
my $digest = md5_hex($params[0]);
$digest =~ /(\w{7}(.*))/;
$guid = "$prefix$2";
@params = ('-p', 'wcd=false', '-p', "guid=$guid", @params);
} elsif ($method eq 'modify_lu') {
@params = ('-s', @params);
} elsif ($method eq 'list_view') {
@params = ('-l', @params);
} elsif ($method eq 'list_lu') {
my $object = $guid;
my @lines = split /\n/, $msg;
$msg = undef;
foreach my $line (@lines) {
if ($line =~ /(\w+)\s+\d+\s+$object$/) {
$msg = $1;
last;
}
}
} elsif ($method eq 'create_lu') {
$msg = $guid;
}
return $msg;
$guid = $params[0];
@params = undef;
}
my $cmdmap = $get_lun_cmd_map->($method);
$luncmd = $cmdmap->{cmd};
my $lunmethod = $cmdmap->{method};
$target = 'root@' . $scfg->{portal};
my $cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $luncmd, $lunmethod, @params];
run_command($cmd, outfunc => $output, timeout => $timeout);
if ($method eq 'list_view') {
my @lines = split /\n/, $msg;
$msg = undef;
foreach my $line (@lines) {
if ($line =~ /^\s*LUN\s*:\s*(\d+)$/) {
$msg = $1;
last;
}
}
} elsif ($method eq 'list_lu') {
my $object = $guid;
my @lines = split /\n/, $msg;
$msg = undef;
foreach my $line (@lines) {
if ($line =~ /(\w+)\s+\d+\s+$object$/) {
$msg = $1;
last;
}
}
} elsif ($method eq 'create_lu') {
$msg = $guid;
}
return $msg;
}

View File

@ -33,6 +33,7 @@ my $OLD_CONFIG = undef;
my @ssh_opts = ('-o', 'BatchMode=yes');
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
my @scp_cmd = ('/usr/bin/scp', @ssh_opts);
my $id_rsa_path = '/etc/pve/priv/zfs';
my $ietadm = '/usr/sbin/ietadm';
my $execute_command = sub {
@ -59,9 +60,9 @@ my $execute_command = sub {
$target = 'root@' . $scfg->{portal};
if ($exec eq 'scp') {
$cmd = [@scp_cmd, $method, "$target:$params[0]"];
$cmd = [@scp_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $method, "$target:$params[0]"];
} else {
$cmd = [@ssh_cmd, $target, $method, @params];
$cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $method, @params];
}
eval {
@ -103,7 +104,7 @@ my $read_config = sub {
$target = 'root@' . $scfg->{portal};
my $cmd = [@ssh_cmd, $target, $luncmd, $CONFIG_FILE];
my $cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $luncmd, $CONFIG_FILE];
eval {
run_command($cmd, outfunc => $output, errfunc => $errfunc, timeout => $timeout);
};

View File

@ -10,12 +10,12 @@ use PVE::Tools qw(run_command file_read_firstline trim dir_glob_regex dir_glob_f
use Data::Dumper;
my @CONFIG_FILES = (
'/usr/local/etc/istgt/istgt.conf', # FreeBSD, FreeNAS
'/var/etc/iscsi/istgt.conf' # NAS4Free
'/usr/local/etc/istgt/istgt.conf', # FreeBSD, FreeNAS
'/var/etc/iscsi/istgt.conf' # NAS4Free
);
my @DAEMONS = (
'/usr/local/etc/rc.d/istgt', # FreeBSD, FreeNAS
'/var/etc/rc.d/istgt' # NAS4Free
'/usr/local/etc/rc.d/istgt', # FreeBSD, FreeNAS
'/var/etc/rc.d/istgt' # NAS4Free
);
# A logical unit can max have 63 LUNs
@ -31,6 +31,7 @@ my $OLD_CONFIG = undef;
my @ssh_opts = ('-o', 'BatchMode=yes');
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
my @scp_cmd = ('/usr/bin/scp', @ssh_opts);
my $id_rsa_path = '/etc/pve/priv/zfs';
#Current SIGHUP reload limitations (http://www.peach.ne.jp/archives/istgt/):
#
@ -38,7 +39,7 @@ my @scp_cmd = ('/usr/bin/scp', @ssh_opts);
# LU connected by the initiator can't be reloaded by SIGHUP.
# PG and IG mapped to LU can't be deleted by SIGHUP.
# If you delete an active LU, all connections of the LU are closed by SIGHUP.
# Updating IG is not affected until the next login.
# Updating IG is not affected until the next login.
#
# FreeBSD
# 1. Alt-F2 to change to native shell (zfsguru)
@ -59,57 +60,57 @@ sub get_base;
sub run_lun_command;
my $read_config = sub {
my ($scfg, $timeout, $method) = @_;
my ($scfg, $timeout, $method) = @_;
my $msg = '';
my $err = undef;
my $err = undef;
my $luncmd = 'cat';
my $target;
$timeout = 10 if !$timeout;
my $output = sub {
my $line = shift;
$msg .= "$line\n";
$msg .= "$line\n";
};
my $errfunc = sub {
my $errfunc = sub {
my $line = shift;
$err .= "$line";
};
$err .= "$line";
};
$target = 'root@' . $scfg->{portal};
$target = 'root@' . $scfg->{portal};
my $daemon = 0;
foreach my $config (@CONFIG_FILES) {
$err = undef;
my $cmd = [@ssh_cmd, $target, $luncmd, $config];
eval {
run_command($cmd, outfunc => $output, errfunc => $errfunc, timeout => $timeout);
};
do {
$err = undef;
$DAEMON = $DAEMONS[$daemon];
$CONFIG_FILE = $config;
last;
} unless $@;
$daemon++;
}
die $err if ($err && $err !~ /No such file or directory/);
die "No configuration found. Install istgt on $scfg->{portal}" if $msg eq '';
my $daemon = 0;
foreach my $config (@CONFIG_FILES) {
$err = undef;
my $cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $luncmd, $config];
eval {
run_command($cmd, outfunc => $output, errfunc => $errfunc, timeout => $timeout);
};
do {
$err = undef;
$DAEMON = $DAEMONS[$daemon];
$CONFIG_FILE = $config;
last;
} unless $@;
$daemon++;
}
die $err if ($err && $err !~ /No such file or directory/);
die "No configuration found. Install istgt on $scfg->{portal}" if $msg eq '';
return $msg;
return $msg;
};
my $get_config = sub {
my ($scfg) = @_;
my @conf = undef;
my $config = $read_config->($scfg, undef, 'get_config');
die "Missing config file" unless $config;
my ($scfg) = @_;
my @conf = undef;
$OLD_CONFIG = $config;
my $config = $read_config->($scfg, undef, 'get_config');
die "Missing config file" unless $config;
return $config;
$OLD_CONFIG = $config;
return $config;
};
my $parse_size = sub {
@ -118,25 +119,25 @@ my $parse_size = sub {
return 0 if !$text;
if ($text =~ m/^(\d+(\.\d+)?)([TGMK]B)?$/) {
my ($size, $reminder, $unit) = ($1, $2, $3);
return $size if !$unit;
if ($unit eq 'KB') {
$size *= 1024;
} elsif ($unit eq 'MB') {
$size *= 1024*1024;
} elsif ($unit eq 'GB') {
$size *= 1024*1024*1024;
} elsif ($unit eq 'TB') {
$size *= 1024*1024*1024*1024;
}
if ($reminder) {
$size = ceil($size);
}
return $size;
my ($size, $reminder, $unit) = ($1, $2, $3);
return $size if !$unit;
if ($unit eq 'KB') {
$size *= 1024;
} elsif ($unit eq 'MB') {
$size *= 1024*1024;
} elsif ($unit eq 'GB') {
$size *= 1024*1024*1024;
} elsif ($unit eq 'TB') {
$size *= 1024*1024*1024*1024;
}
if ($reminder) {
$size = ceil($size);
}
return $size;
} elsif ($text =~ /^auto$/i) {
return 'AUTO';
} else {
return 0;
return 'AUTO';
} else {
return 0;
}
};
@ -145,435 +146,435 @@ my $size_with_unit = sub {
return '0KB' if !$size;
return $size if $size eq 'AUTO';
return $size if $size eq 'AUTO';
if ($size =~ m/^\d+$/) {
++$n and $size /= 1024 until $size < 1024;
if ($size =~ /\./) {
return sprintf "%.2f%s", $size, ( qw[bytes KB MB GB TB] )[ $n ];
} else {
return sprintf "%d%s", $size, ( qw[bytes KB MB GB TB] )[ $n ];
}
}
die "$size: Not a number";
++$n and $size /= 1024 until $size < 1024;
if ($size =~ /\./) {
return sprintf "%.2f%s", $size, ( qw[bytes KB MB GB TB] )[ $n ];
} else {
return sprintf "%d%s", $size, ( qw[bytes KB MB GB TB] )[ $n ];
}
}
die "$size: Not a number";
};
my $lun_dumper = sub {
my ($lun) = @_;
my $config = '';
my ($lun) = @_;
my $config = '';
$config .= "\n[$lun]\n";
$config .= 'TargetName ' . $SETTINGS->{$lun}->{TargetName} . "\n";
$config .= 'Mapping ' . $SETTINGS->{$lun}->{Mapping} . "\n";
$config .= 'AuthGroup ' . $SETTINGS->{$lun}->{AuthGroup} . "\n";
$config .= 'UnitType ' . $SETTINGS->{$lun}->{UnitType} . "\n";
$config .= 'QueueDepth ' . $SETTINGS->{$lun}->{QueueDepth} . "\n";
$config .= "\n[$lun]\n";
$config .= 'TargetName ' . $SETTINGS->{$lun}->{TargetName} . "\n";
$config .= 'Mapping ' . $SETTINGS->{$lun}->{Mapping} . "\n";
$config .= 'AuthGroup ' . $SETTINGS->{$lun}->{AuthGroup} . "\n";
$config .= 'UnitType ' . $SETTINGS->{$lun}->{UnitType} . "\n";
$config .= 'QueueDepth ' . $SETTINGS->{$lun}->{QueueDepth} . "\n";
foreach my $conf (@{$SETTINGS->{$lun}->{luns}}) {
$config .= "$conf->{lun} Storage " . $conf->{Storage};
$config .= ' ' . $size_with_unit->($conf->{Size}) . "\n";
}
$config .= "\n";
foreach my $conf (@{$SETTINGS->{$lun}->{luns}}) {
$config .= "$conf->{lun} Storage " . $conf->{Storage};
$config .= ' ' . $size_with_unit->($conf->{Size}) . "\n";
}
$config .= "\n";
return $config;
return $config;
};
my $get_lu_name = sub {
my ($target) = @_;
my $used = ();
my $i;
if (! exists $SETTINGS->{$target}->{used}) {
for ($i = 0; $i < $MAX_LUNS; $i++) {
$used->{$i} = 0;
}
foreach my $lun (@{$SETTINGS->{$target}->{luns}}) {
$lun->{lun} =~ /^LUN(\d+)$/;
$used->{$1} = 1;
}
$SETTINGS->{$target}->{used} = $used;
}
$used = $SETTINGS->{$target}->{used};
for ($i = 0; $i < $MAX_LUNS; $i++) {
last unless $used->{$i};
}
$SETTINGS->{$target}->{used}->{$i} = 1;
my ($target) = @_;
my $used = ();
my $i;
return "LUN$i";
if (! exists $SETTINGS->{$target}->{used}) {
for ($i = 0; $i < $MAX_LUNS; $i++) {
$used->{$i} = 0;
}
foreach my $lun (@{$SETTINGS->{$target}->{luns}}) {
$lun->{lun} =~ /^LUN(\d+)$/;
$used->{$1} = 1;
}
$SETTINGS->{$target}->{used} = $used;
}
$used = $SETTINGS->{$target}->{used};
for ($i = 0; $i < $MAX_LUNS; $i++) {
last unless $used->{$i};
}
$SETTINGS->{$target}->{used}->{$i} = 1;
return "LUN$i";
};
my $init_lu_name = sub {
my ($target) = @_;
my $used = ();
my ($target) = @_;
my $used = ();
if (! exists($SETTINGS->{$target}->{used})) {
for (my $i = 0; $i < $MAX_LUNS; $i++) {
$used->{$i} = 0;
}
$SETTINGS->{$target}->{used} = $used;
}
foreach my $lun (@{$SETTINGS->{$target}->{luns}}) {
$lun->{lun} =~ /^LUN(\d+)$/;
$SETTINGS->{$target}->{used}->{$1} = 1;
}
if (! exists($SETTINGS->{$target}->{used})) {
for (my $i = 0; $i < $MAX_LUNS; $i++) {
$used->{$i} = 0;
}
$SETTINGS->{$target}->{used} = $used;
}
foreach my $lun (@{$SETTINGS->{$target}->{luns}}) {
$lun->{lun} =~ /^LUN(\d+)$/;
$SETTINGS->{$target}->{used}->{$1} = 1;
}
};
my $free_lu_name = sub {
my ($target, $lu_name) = @_;
my ($target, $lu_name) = @_;
$lu_name =~ /^LUN(\d+)$/;
$SETTINGS->{$target}->{used}->{$1} = 0;
$lu_name =~ /^LUN(\d+)$/;
$SETTINGS->{$target}->{used}->{$1} = 0;
};
my $make_lun = sub {
my ($path) = @_;
my $target = $SETTINGS->{current};
die 'Maximum number of LUNs per target is 63' if scalar @{$SETTINGS->{$target}->{luns}} >= $MAX_LUNS;
my $lun = $get_lu_name->($target);
my $conf = {
lun => $lun,
Storage => $path,
Size => 'AUTO',
};
push @{$SETTINGS->{$target}->{luns}}, $conf;
my ($path) = @_;
return $conf->{lun};
my $target = $SETTINGS->{current};
die 'Maximum number of LUNs per target is 63' if scalar @{$SETTINGS->{$target}->{luns}} >= $MAX_LUNS;
my $lun = $get_lu_name->($target);
my $conf = {
lun => $lun,
Storage => $path,
Size => 'AUTO',
};
push @{$SETTINGS->{$target}->{luns}}, $conf;
return $conf->{lun};
};
my $parser = sub {
my ($scfg) = @_;
my $lun = undef;
my $line = 0;
my $config = $get_config->($scfg);
my @cfgfile = split "\n", $config;
my ($scfg) = @_;
foreach (@cfgfile) {
$line++;
if ($_ =~ /^\s*\[(PortalGroup\d+)\]\s*/) {
$lun = undef;
$SETTINGS->{$1} = ();
} elsif ($_ =~ /^\s*\[(InitiatorGroup\d+)\]\s*/) {
$lun = undef;
$SETTINGS->{$1} = ();
} elsif ($_ =~ /^\s*PidFile\s+"?([\w\/\.]+)"?\s*/) {
$lun = undef;
$SETTINGS->{pidfile} = $1;
} elsif ($_ =~ /^\s*NodeBase\s+"?([\w\-\.]+)"?\s*/) {
$lun = undef;
$SETTINGS->{nodebase} = $1;
} elsif ($_ =~ /^\s*\[(LogicalUnit\d+)\]\s*/) {
$lun = $1;
$SETTINGS->{$lun} = ();
$SETTINGS->{targets}++;
} elsif ($lun) {
next if (($_ =~ /^\s*#/) || ($_ =~ /^\s*$/));
if ($_ =~ /^\s*(\w+)\s+(.+)\s*/) {
#next if $2 =~ /^Option.*/;
$SETTINGS->{$lun}->{$1} = $2;
$SETTINGS->{$lun}->{$1} =~ s/^\s+|\s+$|"\s*//g;
} else {
die "$line: parse error [$_]";
}
}
$CONFIG .= "$_\n" unless $lun;
}
my $lun = undef;
my $line = 0;
$CONFIG =~ s/\n$//;
die "$scfg->{target}: Target not found" unless $SETTINGS->{targets};
my $max = $SETTINGS->{targets};
my $base = get_base;
my $config = $get_config->($scfg);
my @cfgfile = split "\n", $config;
for (my $i = 1; $i <= $max; $i++) {
my $target = $SETTINGS->{nodebase}.':'.$SETTINGS->{"LogicalUnit$i"}->{TargetName};
if ($target eq $scfg->{target}) {
my $lu = ();
while ((my $key, my $val) = each(%{$SETTINGS->{"LogicalUnit$i"}})) {
if ($key =~ /^LUN\d+/) {
if ($val =~ /^Storage\s+([\w\/\-]+)\s+(\w+)/) {
my $storage = $1;
my $size = $parse_size->($2);
my $conf = undef;
if ($storage =~ /^$base\/$scfg->{pool}\/([\w\-]+)$/) {
$conf = {
lun => $key,
Storage => $storage,
Size => $size,
};
}
push @$lu, $conf if $conf;
}
delete $SETTINGS->{"LogicalUnit$i"}->{$key};
}
}
$SETTINGS->{"LogicalUnit$i"}->{luns} = $lu;
$SETTINGS->{current} = "LogicalUnit$i";
$init_lu_name->("LogicalUnit$i");
} else {
$CONFIG .= $lun_dumper->("LogicalUnit$i");
delete $SETTINGS->{"LogicalUnit$i"};
$SETTINGS->{targets}--;
}
}
die "$scfg->{target}: Target not found" unless $SETTINGS->{targets} > 0;
foreach (@cfgfile) {
$line++;
if ($_ =~ /^\s*\[(PortalGroup\d+)\]\s*/) {
$lun = undef;
$SETTINGS->{$1} = ();
} elsif ($_ =~ /^\s*\[(InitiatorGroup\d+)\]\s*/) {
$lun = undef;
$SETTINGS->{$1} = ();
} elsif ($_ =~ /^\s*PidFile\s+"?([\w\/\.]+)"?\s*/) {
$lun = undef;
$SETTINGS->{pidfile} = $1;
} elsif ($_ =~ /^\s*NodeBase\s+"?([\w\-\.]+)"?\s*/) {
$lun = undef;
$SETTINGS->{nodebase} = $1;
} elsif ($_ =~ /^\s*\[(LogicalUnit\d+)\]\s*/) {
$lun = $1;
$SETTINGS->{$lun} = ();
$SETTINGS->{targets}++;
} elsif ($lun) {
next if (($_ =~ /^\s*#/) || ($_ =~ /^\s*$/));
if ($_ =~ /^\s*(\w+)\s+(.+)\s*/) {
#next if $2 =~ /^Option.*/;
$SETTINGS->{$lun}->{$1} = $2;
$SETTINGS->{$lun}->{$1} =~ s/^\s+|\s+$|"\s*//g;
} else {
die "$line: parse error [$_]";
}
}
$CONFIG .= "$_\n" unless $lun;
}
$CONFIG =~ s/\n$//;
die "$scfg->{target}: Target not found" unless $SETTINGS->{targets};
my $max = $SETTINGS->{targets};
my $base = get_base;
for (my $i = 1; $i <= $max; $i++) {
my $target = $SETTINGS->{nodebase}.':'.$SETTINGS->{"LogicalUnit$i"}->{TargetName};
if ($target eq $scfg->{target}) {
my $lu = ();
while ((my $key, my $val) = each(%{$SETTINGS->{"LogicalUnit$i"}})) {
if ($key =~ /^LUN\d+/) {
if ($val =~ /^Storage\s+([\w\/\-]+)\s+(\w+)/) {
my $storage = $1;
my $size = $parse_size->($2);
my $conf = undef;
if ($storage =~ /^$base\/$scfg->{pool}\/([\w\-]+)$/) {
$conf = {
lun => $key,
Storage => $storage,
Size => $size,
};
}
push @$lu, $conf if $conf;
}
delete $SETTINGS->{"LogicalUnit$i"}->{$key};
}
}
$SETTINGS->{"LogicalUnit$i"}->{luns} = $lu;
$SETTINGS->{current} = "LogicalUnit$i";
$init_lu_name->("LogicalUnit$i");
} else {
$CONFIG .= $lun_dumper->("LogicalUnit$i");
delete $SETTINGS->{"LogicalUnit$i"};
$SETTINGS->{targets}--;
}
}
die "$scfg->{target}: Target not found" unless $SETTINGS->{targets} > 0;
};
my $list_lun = sub {
my ($scfg, $timeout, $method, @params) = @_;
my $name = undef;
my ($scfg, $timeout, $method, @params) = @_;
my $name = undef;
my $object = $params[0];
for my $key (keys %$SETTINGS) {
next unless $key =~ /^LogicalUnit\d+$/;
foreach my $lun (@{$SETTINGS->{$key}->{luns}}) {
if ($lun->{Storage} =~ /^$object$/) {
return $lun->{Storage};
}
}
}
return $name;
my $object = $params[0];
for my $key (keys %$SETTINGS) {
next unless $key =~ /^LogicalUnit\d+$/;
foreach my $lun (@{$SETTINGS->{$key}->{luns}}) {
if ($lun->{Storage} =~ /^$object$/) {
return $lun->{Storage};
}
}
}
return $name;
};
my $create_lun = sub {
my ($scfg, $timeout, $method, @params) = @_;
my $res = ();
my $file = "/tmp/config$$";
my ($scfg, $timeout, $method, @params) = @_;
my $res = ();
my $file = "/tmp/config$$";
if ($list_lun->($scfg, $timeout, $method, @params)) {
die "$params[0]: LUN exists";
}
my $lun = $params[0];
$lun = $make_lun->($lun);
my $config = $lun_dumper->($SETTINGS->{current});
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
if ($list_lun->($scfg, $timeout, $method, @params)) {
die "$params[0]: LUN exists";
}
my $lun = $params[0];
$lun = $make_lun->($lun);
my $config = $lun_dumper->($SETTINGS->{current});
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
print $fh $CONFIG;
print $fh $config;
close $fh;
@params = ($CONFIG_FILE);
$res = {
cmd => 'scp',
method => $file,
params => \@params,
msg => $lun,
post_exe => sub {
unlink $file;
},
};
print $fh $CONFIG;
print $fh $config;
close $fh;
@params = ($CONFIG_FILE);
$res = {
cmd => 'scp',
method => $file,
params => \@params,
msg => $lun,
post_exe => sub {
unlink $file;
},
};
return $res;
return $res;
};
my $delete_lun = sub {
my ($scfg, $timeout, $method, @params) = @_;
my $res = ();
my $file = "/tmp/config$$";
my $target = $SETTINGS->{current};
my $luns = ();
my ($scfg, $timeout, $method, @params) = @_;
my $res = ();
my $file = "/tmp/config$$";
foreach my $conf (@{$SETTINGS->{$target}->{luns}}) {
if ($conf->{Storage} =~ /^$params[0]$/) {
$free_lu_name->($target, $conf->{lun});
} else {
push @$luns, $conf;
}
}
$SETTINGS->{$target}->{luns} = $luns;
my $config = $lun_dumper->($SETTINGS->{current});
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
my $target = $SETTINGS->{current};
my $luns = ();
print $fh $CONFIG;
print $fh $config;
close $fh;
@params = ($CONFIG_FILE);
$res = {
cmd => 'scp',
method => $file,
params => \@params,
post_exe => sub {
unlink $file;
run_lun_command($scfg, undef, 'add_view', 'restart');
},
};
foreach my $conf (@{$SETTINGS->{$target}->{luns}}) {
if ($conf->{Storage} =~ /^$params[0]$/) {
$free_lu_name->($target, $conf->{lun});
} else {
push @$luns, $conf;
}
}
$SETTINGS->{$target}->{luns} = $luns;
return $res;
my $config = $lun_dumper->($SETTINGS->{current});
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
print $fh $CONFIG;
print $fh $config;
close $fh;
@params = ($CONFIG_FILE);
$res = {
cmd => 'scp',
method => $file,
params => \@params,
post_exe => sub {
unlink $file;
run_lun_command($scfg, undef, 'add_view', 'restart');
},
};
return $res;
};
my $import_lun = sub {
my ($scfg, $timeout, $method, @params) = @_;
my ($scfg, $timeout, $method, @params) = @_;
my $res = $create_lun->($scfg, $timeout, $method, @params);
my $res = $create_lun->($scfg, $timeout, $method, @params);
return $res;
return $res;
};
my $add_view = sub {
my ($scfg, $timeout, $method, @params) = @_;
my $cmdmap;
if (@params && $params[0] eq 'restart') {
@params = ('restart', '1>&2', '>', '/dev/null');
$cmdmap = {
cmd => 'ssh',
method => $DAEMON,
params => \@params,
};
} else {
@params = ('-HUP', '$(cat '. "$SETTINGS->{pidfile})");
$cmdmap = {
cmd => 'ssh',
method => 'kill',
params => \@params,
};
}
my ($scfg, $timeout, $method, @params) = @_;
my $cmdmap;
return $cmdmap;
if (@params && $params[0] eq 'restart') {
@params = ('restart', '1>&2', '>', '/dev/null');
$cmdmap = {
cmd => 'ssh',
method => $DAEMON,
params => \@params,
};
} else {
@params = ('-HUP', '$(cat '. "$SETTINGS->{pidfile})");
$cmdmap = {
cmd => 'ssh',
method => 'kill',
params => \@params,
};
}
return $cmdmap;
};
my $modify_lun = sub {
my ($scfg, $timeout, $method, @params) = @_;
my ($scfg, $timeout, $method, @params) = @_;
# Current SIGHUP reload limitations
# LU connected by the initiator can't be reloaded by SIGHUP.
# Until above limitation persists modifying a LUN will require
# a restart of the daemon breaking all current connections
#die 'Modify a connected LUN is not currently supported by istgt';
@params = ('restart', @params);
return $add_view->($scfg, $timeout, $method, @params);
# Current SIGHUP reload limitations
# LU connected by the initiator can't be reloaded by SIGHUP.
# Until above limitation persists modifying a LUN will require
# a restart of the daemon breaking all current connections
#die 'Modify a connected LUN is not currently supported by istgt';
@params = ('restart', @params);
return $add_view->($scfg, $timeout, $method, @params);
};
my $list_view = sub {
my ($scfg, $timeout, $method, @params) = @_;
my $lun = undef;
my $object = $params[0];
for my $key (keys %$SETTINGS) {
next unless $key =~ /^LogicalUnit\d+$/;
foreach my $lun (@{$SETTINGS->{$key}->{luns}}) {
if ($lun->{Storage} =~ /^$object$/) {
if ($lun->{lun} =~ /^LUN(\d+)/) {
return $1;
}
die "$lun->{Storage}: Missing LUN";
}
}
}
return $lun;
my ($scfg, $timeout, $method, @params) = @_;
my $lun = undef;
my $object = $params[0];
for my $key (keys %$SETTINGS) {
next unless $key =~ /^LogicalUnit\d+$/;
foreach my $lun (@{$SETTINGS->{$key}->{luns}}) {
if ($lun->{Storage} =~ /^$object$/) {
if ($lun->{lun} =~ /^LUN(\d+)/) {
return $1;
}
die "$lun->{Storage}: Missing LUN";
}
}
}
return $lun;
};
my $get_lun_cmd_map = sub {
my ($method) = @_;
my $cmdmap = {
create_lu => { cmd => $create_lun },
delete_lu => { cmd => $delete_lun },
import_lu => { cmd => $import_lun },
modify_lu => { cmd => $modify_lun },
add_view => { cmd => $add_view },
list_view => { cmd => $list_view },
list_lu => { cmd => $list_lun },
};
die "unknown command '$method'" unless exists $cmdmap->{$method};
return $cmdmap->{$method};
my ($method) = @_;
my $cmdmap = {
create_lu => { cmd => $create_lun },
delete_lu => { cmd => $delete_lun },
import_lu => { cmd => $import_lun },
modify_lu => { cmd => $modify_lun },
add_view => { cmd => $add_view },
list_view => { cmd => $list_view },
list_lu => { cmd => $list_lun },
};
die "unknown command '$method'" unless exists $cmdmap->{$method};
return $cmdmap->{$method};
};
sub run_lun_command {
my ($scfg, $timeout, $method, @params) = @_;
my ($scfg, $timeout, $method, @params) = @_;
my $msg = '';
my $luncmd;
my $target;
my $cmd;
my $res;
my $cmd;
my $res;
$timeout = 10 if !$timeout;
my $is_add_view = 0;
my $is_add_view = 0;
my $output = sub {
my $line = shift;
$msg .= "$line\n";
$msg .= "$line\n";
};
$target = 'root@' . $scfg->{portal};
$target = 'root@' . $scfg->{portal};
$parser->($scfg) unless $SETTINGS;
my $cmdmap = $get_lun_cmd_map->($method);
if ($method eq 'add_view') {
$is_add_view = 1 ;
$timeout = 15;
}
if (ref $cmdmap->{cmd} eq 'CODE') {
$res = $cmdmap->{cmd}->($scfg, $timeout, $method, @params);
if (ref $res) {
$method = $res->{method};
@params = @{$res->{params}};
if ($res->{cmd} eq 'scp') {
$cmd = [@scp_cmd, $method, "$target:$params[0]"];
} else {
$cmd = [@ssh_cmd, $target, $method, @params];
}
} else {
return $res;
}
} else {
$luncmd = $cmdmap->{cmd};
$method = $cmdmap->{method};
$cmd = [@ssh_cmd, $target, $luncmd, $method, @params];
}
$parser->($scfg) unless $SETTINGS;
my $cmdmap = $get_lun_cmd_map->($method);
if ($method eq 'add_view') {
$is_add_view = 1 ;
$timeout = 15;
}
if (ref $cmdmap->{cmd} eq 'CODE') {
$res = $cmdmap->{cmd}->($scfg, $timeout, $method, @params);
if (ref $res) {
$method = $res->{method};
@params = @{$res->{params}};
if ($res->{cmd} eq 'scp') {
$cmd = [@scp_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $method, "$target:$params[0]"];
} else {
$cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $method, @params];
}
} else {
return $res;
}
} else {
$luncmd = $cmdmap->{cmd};
$method = $cmdmap->{method};
$cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $luncmd, $method, @params];
}
eval {
run_command($cmd, outfunc => $output, timeout => $timeout);
};
if ($@ && $is_add_view) {
my $err = $@;
if ($OLD_CONFIG) {
my $err1 = undef;
my $file = "/tmp/config$$";
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
print $fh $OLD_CONFIG;
close $fh;
$cmd = [@scp_cmd, $file, $CONFIG_FILE];
eval {
run_command($cmd, outfunc => $output, timeout => $timeout);
};
$err1 = $@ if $@;
unlink $file;
die "$err\n$err1" if $err1;
eval {
run_lun_command($scfg, undef, 'add_view', 'restart');
};
die "$err\n$@" if ($@);
}
die $err;
} elsif ($@) {
die $@;
} elsif ($is_add_view) {
$OLD_CONFIG = undef;
}
if ($res->{post_exe} && ref $res->{post_exe} eq 'CODE') {
$res->{post_exe}->();
}
eval {
run_command($cmd, outfunc => $output, timeout => $timeout);
};
if ($@ && $is_add_view) {
my $err = $@;
if ($OLD_CONFIG) {
my $err1 = undef;
my $file = "/tmp/config$$";
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
print $fh $OLD_CONFIG;
close $fh;
$cmd = [@scp_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $file, $CONFIG_FILE];
eval {
run_command($cmd, outfunc => $output, timeout => $timeout);
};
$err1 = $@ if $@;
unlink $file;
die "$err\n$err1" if $err1;
eval {
run_lun_command($scfg, undef, 'add_view', 'restart');
};
die "$err\n$@" if ($@);
}
die $err;
} elsif ($@) {
die $@;
} elsif ($is_add_view) {
$OLD_CONFIG = undef;
}
if ($res->{msg}) {
$msg = $res->{msg};
}
return $msg;
if ($res->{post_exe} && ref $res->{post_exe} eq 'CODE') {
$res->{post_exe}->();
}
if ($res->{msg}) {
$msg = $res->{msg};
}
return $msg;
}
sub get_base {
return '/dev/zvol';
return '/dev/zvol';
}
1;
1;

View File

@ -14,35 +14,36 @@ use PVE::Storage::LunCmd::Iet;
my @ssh_opts = ('-o', 'BatchMode=yes');
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
my $id_rsa_path = '/etc/pve/priv/zfs';
my $lun_cmds = {
create_lu => 1,
delete_lu => 1,
import_lu => 1,
modify_lu => 1,
add_view => 1,
list_view => 1,
list_lu => 1,
create_lu => 1,
delete_lu => 1,
import_lu => 1,
modify_lu => 1,
add_view => 1,
list_view => 1,
list_lu => 1,
};
my $zfs_unknown_scsi_provider = sub {
my ($provider) = @_;
my ($provider) = @_;
die "$provider: unknown iscsi provider. Available [comstar, istgt, iet]";
die "$provider: unknown iscsi provider. Available [comstar, istgt, iet]";
};
my $zfs_get_base = sub {
my ($scfg) = @_;
my ($scfg) = @_;
if ($scfg->{iscsiprovider} eq 'comstar') {
return PVE::Storage::LunCmd::Comstar::get_base;
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
return PVE::Storage::LunCmd::Istgt::get_base;
} elsif ($scfg->{iscsiprovider} eq 'iet') {
return PVE::Storage::LunCmd::Iet::get_base;
} else {
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
}
if ($scfg->{iscsiprovider} eq 'comstar') {
return PVE::Storage::LunCmd::Comstar::get_base;
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
return PVE::Storage::LunCmd::Istgt::get_base;
} elsif ($scfg->{iscsiprovider} eq 'iet') {
return PVE::Storage::LunCmd::Iet::get_base;
} else {
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
}
};
sub zfs_request {
@ -51,41 +52,41 @@ sub zfs_request {
my $cmdmap;
my $zfscmd;
my $target;
my $msg;
my $msg;
$timeout = 5 if !$timeout;
if ($lun_cmds->{$method}) {
if ($scfg->{iscsiprovider} eq 'comstar') {
$msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'iet') {
$msg = PVE::Storage::LunCmd::Iet::run_lun_command($scfg, $timeout, $method, @params);
} else {
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
}
} else {
if ($method eq 'zpool_list') {
$zfscmd = 'zpool';
$method = 'list',
} else {
$zfscmd = 'zfs';
}
if ($lun_cmds->{$method}) {
if ($scfg->{iscsiprovider} eq 'comstar') {
$msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'iet') {
$msg = PVE::Storage::LunCmd::Iet::run_lun_command($scfg, $timeout, $method, @params);
} else {
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
}
} else {
if ($method eq 'zpool_list') {
$zfscmd = 'zpool';
$method = 'list',
} else {
$zfscmd = 'zfs';
}
$target = 'root@' . $scfg->{portal};
$target = 'root@' . $scfg->{portal};
my $cmd = [@ssh_cmd, $target, $zfscmd, $method, @params];
my $cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $zfscmd, $method, @params];
$msg = '';
$msg = '';
my $output = sub {
my $line = shift;
$msg .= "$line\n";
};
my $output = sub {
my $line = shift;
$msg .= "$line\n";
};
run_command($cmd, outfunc => $output, timeout => $timeout);
}
run_command($cmd, outfunc => $output, timeout => $timeout);
}
return $msg;
}
@ -96,24 +97,24 @@ sub zfs_parse_size {
return 0 if !$text;
if ($text =~ m/^(\d+(\.\d+)?)([TGMK])?$/) {
my ($size, $reminder, $unit) = ($1, $2, $3);
return $size if !$unit;
if ($unit eq 'K') {
$size *= 1024;
} elsif ($unit eq 'M') {
$size *= 1024*1024;
} elsif ($unit eq 'G') {
$size *= 1024*1024*1024;
} elsif ($unit eq 'T') {
$size *= 1024*1024*1024*1024;
}
my ($size, $reminder, $unit) = ($1, $2, $3);
return $size if !$unit;
if ($unit eq 'K') {
$size *= 1024;
} elsif ($unit eq 'M') {
$size *= 1024*1024;
} elsif ($unit eq 'G') {
$size *= 1024*1024*1024;
} elsif ($unit eq 'T') {
$size *= 1024*1024*1024*1024;
}
if ($reminder) {
$size = ceil($size);
}
return $size;
if ($reminder) {
$size = ceil($size);
}
return $size;
} else {
return 0;
return 0;
}
}
@ -124,16 +125,16 @@ sub zfs_get_pool_stats {
my $used = 0;
my $text = zfs_request($scfg, undef, 'get', '-o', 'value', '-Hp',
'available,used', $scfg->{pool});
'available,used', $scfg->{pool});
my @lines = split /\n/, $text;
if($lines[0] =~ /^(\d+)$/) {
$available = $1;
$available = $1;
}
if($lines[1] =~ /^(\d+)$/) {
$used = $1;
$used = $1;
}
return ($available, $used);
@ -148,28 +149,28 @@ sub zfs_parse_zvol_list {
my @lines = split /\n/, $text;
foreach my $line (@lines) {
if ($line =~ /^(.+)\s+([a-zA-Z0-9\.]+|\-)\s+(.+)$/) {
my $zvol = {};
my $name;
my $disk;
my @zvols = split /\//, $1;
my $pool = $zvols[0];
if ($line =~ /^(.+)\s+([a-zA-Z0-9\.]+|\-)\s+(.+)$/) {
my $zvol = {};
my $name;
my $disk;
my @zvols = split /\//, $1;
my $pool = $zvols[0];
if (scalar(@zvols) == 2 && $zvols[0] !~ /^rpool$/) {
$disk = $zvols[1];
next unless $disk =~ m!^(\w+)-(\d+)-(\w+)-(\d+)$!;
$name = $pool . '/' . $disk;
} else {
next;
}
if (scalar(@zvols) == 2 && $zvols[0] !~ /^rpool$/) {
$disk = $zvols[1];
next unless $disk =~ m!^(\w+)-(\d+)-(\w+)-(\d+)$!;
$name = $pool . '/' . $disk;
} else {
next;
}
$zvol->{name} = $name;
$zvol->{size} = zfs_parse_size($2);
if ($3 !~ /^-$/) {
$zvol->{origin} = $3;
}
push @$list, $zvol;
}
$zvol->{name} = $name;
$zvol->{size} = zfs_parse_size($2);
if ($3 !~ /^-$/) {
$zvol->{origin} = $3;
}
push @$list, $zvol;
}
}
return $list;
@ -179,7 +180,7 @@ sub zfs_get_lu_name {
my ($scfg, $zvol) = @_;
my $object;
my $base = $zfs_get_base->($scfg);
my $base = $zfs_get_base->($scfg);
if ($zvol =~ /^.+\/.+/) {
$object = "$base/$zvol";
} else {
@ -188,8 +189,8 @@ sub zfs_get_lu_name {
my $lu_name = zfs_request($scfg, undef, 'list_lu', $object);
return $lu_name if $lu_name;
return $lu_name if $lu_name;
die "Could not find lu_name for zvol $zvol";
}
@ -199,7 +200,7 @@ sub zfs_get_zvol_size {
my $text = zfs_request($scfg, undef, 'get', '-Hp', 'volsize', "$scfg->{pool}/$zvol");
if($text =~ /volsize\s(\d+)/){
return $1;
return $1;
}
die "Could not get zvol size";
@ -209,9 +210,9 @@ sub zfs_add_lun_mapping_entry {
my ($scfg, $zvol, $guid) = @_;
if (! defined($guid)) {
$guid = zfs_get_lu_name($scfg, $zvol);
$guid = zfs_get_lu_name($scfg, $zvol);
}
zfs_request($scfg, undef, 'add_view', $guid);
}
@ -226,7 +227,7 @@ sub zfs_delete_lu {
sub zfs_create_lu {
my ($scfg, $zvol) = @_;
my $base = $zfs_get_base->($scfg);
my $base = $zfs_get_base->($scfg);
my $guid = zfs_request($scfg, undef, 'create_lu', "$base/$scfg->{pool}/$zvol");
return $guid;
@ -235,7 +236,7 @@ sub zfs_create_lu {
sub zfs_import_lu {
my ($scfg, $zvol) = @_;
my $base = $zfs_get_base->($scfg);
my $base = $zfs_get_base->($scfg);
zfs_request($scfg, undef, 'import_lu', "$base/$scfg->{pool}/$zvol");
}
@ -276,26 +277,26 @@ sub zfs_list_zvol {
my $list = ();
foreach my $zvol (@$zvols) {
my @values = split('/', $zvol->{name});
my @values = split('/', $zvol->{name});
my $pool = $values[0];
my $image = $values[1];
my $pool = $values[0];
my $image = $values[1];
next if $image !~ m/^((vm|base)-(\d+)-\S+)$/;
my $owner = $3;
next if $image !~ m/^((vm|base)-(\d+)-\S+)$/;
my $owner = $3;
my $parent = $zvol->{origin};
if($zvol->{origin} && $zvol->{origin} =~ m/^$scfg->{pool}\/(\S+)$/){
$parent = $1;
}
my $parent = $zvol->{origin};
if($zvol->{origin} && $zvol->{origin} =~ m/^$scfg->{pool}\/(\S+)$/){
$parent = $1;
}
$list->{$pool}->{$image} = {
name => $image,
size => $zvol->{size},
parent => $parent,
format => 'raw',
vmid => $owner
};
$list->{$pool}->{$image} = {
name => $image,
size => $zvol->{size},
parent => $parent,
format => 'raw',
vmid => $owner
};
}
return $list;
@ -309,16 +310,16 @@ sub type {
sub plugindata {
return {
content => [ {images => 1}, { images => 1 }],
content => [ {images => 1}, { images => 1 }],
};
}
sub properties {
return {
iscsiprovider => {
description => "iscsi provider",
type => 'string',
},
iscsiprovider => {
description => "iscsi provider",
type => 'string',
},
blocksize => {
description => "block size",
type => 'string',
@ -331,11 +332,11 @@ sub options {
nodes => { optional => 1 },
disable => { optional => 1 },
portal => { fixed => 1 },
target => { fixed => 1 },
target => { fixed => 1 },
pool => { fixed => 1 },
blocksize => { fixed => 1 },
iscsiprovider => { fixed => 1 },
content => { optional => 1 },
blocksize => { fixed => 1 },
iscsiprovider => { fixed => 1 },
content => { optional => 1 },
};
}
@ -345,7 +346,7 @@ sub parse_volname {
my ($class, $volname) = @_;
if ($volname =~ m/^(((base|vm)-(\d+)-\S+)\/)?((base)?(vm)?-(\d+)-\S+)$/) {
return ('images', $5, $8, $2, $4, $6);
return ('images', $5, $8, $2, $4, $6);
}
die "unable to parse zfs volume name '$volname'\n";
@ -361,9 +362,9 @@ sub path {
my $guid = zfs_get_lu_name($scfg, $name);
my $lun = zfs_get_lun_number($scfg, $guid);
my $path = "iscsi://$portal/$target/$lun";
return ($path, $vmid, $vtype);
}
@ -448,7 +449,7 @@ sub alloc_image {
die "unsupported format '$fmt'" if $fmt ne 'raw';
die "illegal name '$name' - sould be 'vm-$vmid-*'\n"
if $name && $name !~ m/^vm-$vmid-/;
if $name && $name !~ m/^vm-$vmid-/;
$name = &$find_free_diskname($storeid, $scfg, $vmid);
@ -487,31 +488,31 @@ sub list_images {
if (my $dat = $cache->{zfs}->{$zfspool}) {
foreach my $image (keys %$dat) {
foreach my $image (keys %$dat) {
my $volname = $dat->{$image}->{name};
my $parent = $dat->{$image}->{parent};
my $volname = $dat->{$image}->{name};
my $parent = $dat->{$image}->{parent};
my $volid = undef;
my $volid = undef;
if ($parent && $parent =~ m/^(\S+)@(\S+)$/) {
my ($basename) = ($1);
$volid = "$storeid:$basename/$volname";
} else {
$volid = "$storeid:$volname";
}
my ($basename) = ($1);
$volid = "$storeid:$basename/$volname";
} else {
$volid = "$storeid:$volname";
}
my $owner = $dat->{$volname}->{vmid};
if ($vollist) {
my $found = grep { $_ eq $volid } @$vollist;
next if !$found;
} else {
next if defined ($vmid) && ($owner ne $vmid);
}
my $owner = $dat->{$volname}->{vmid};
if ($vollist) {
my $found = grep { $_ eq $volid } @$vollist;
next if !$found;
} else {
next if defined ($vmid) && ($owner ne $vmid);
}
my $info = $dat->{$volname};
$info->{volid} = $volid;
push @$res, $info;
}
my $info = $dat->{$volname};
$info->{volid} = $volid;
push @$res, $info;
}
}
return $res;
@ -526,9 +527,9 @@ sub status {
my $active = 0;
eval {
($free, $used) = zfs_get_pool_stats($scfg);
$active = 1;
$total = $free + $used;
($free, $used) = zfs_get_pool_stats($scfg);
$active = 1;
$total = $free + $used;
};
warn $@ if $@;
@ -598,21 +599,21 @@ sub volume_has_feature {
my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
my $features = {
snapshot => { current => 1, snap => 1},
clone => { base => 1},
template => { current => 1},
copy => { base => 1, current => 1},
snapshot => { current => 1, snap => 1},
clone => { base => 1},
template => { current => 1},
copy => { base => 1, current => 1},
};
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
$class->parse_volname($volname);
$class->parse_volname($volname);
my $key = undef;
if ($snapname) {
$key = 'snap';
$key = 'snap';
} else {
$key = $isBase ? 'base' : 'current';
$key = $isBase ? 'base' : 'current';
}
return 1 if $features->{$feature}->{$key};