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:
committed by
Dietmar Maurer
parent
86f00da603
commit
3b219e8037
@ -8,34 +8,35 @@ use Data::Dumper;
|
|||||||
|
|
||||||
my @ssh_opts = ('-o', 'BatchMode=yes');
|
my @ssh_opts = ('-o', 'BatchMode=yes');
|
||||||
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
|
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
|
||||||
|
my $id_rsa_path = '/etc/pve/priv/zfs';
|
||||||
|
|
||||||
my $get_lun_cmd_map = sub {
|
my $get_lun_cmd_map = sub {
|
||||||
my ($method) = @_;
|
my ($method) = @_;
|
||||||
|
|
||||||
my $stmfadmcmd = "/usr/sbin/stmfadm";
|
my $stmfadmcmd = "/usr/sbin/stmfadm";
|
||||||
my $sbdadmcmd = "/usr/sbin/sbdadm";
|
my $sbdadmcmd = "/usr/sbin/sbdadm";
|
||||||
|
|
||||||
my $cmdmap = {
|
my $cmdmap = {
|
||||||
create_lu => { cmd => $stmfadmcmd, method => 'create-lu' },
|
create_lu => { cmd => $stmfadmcmd, method => 'create-lu' },
|
||||||
delete_lu => { cmd => $stmfadmcmd, method => 'delete-lu' },
|
delete_lu => { cmd => $stmfadmcmd, method => 'delete-lu' },
|
||||||
import_lu => { cmd => $stmfadmcmd, method => 'import-lu' },
|
import_lu => { cmd => $stmfadmcmd, method => 'import-lu' },
|
||||||
modify_lu => { cmd => $stmfadmcmd, method => 'modify-lu' },
|
modify_lu => { cmd => $stmfadmcmd, method => 'modify-lu' },
|
||||||
add_view => { cmd => $stmfadmcmd, method => 'add-view' },
|
add_view => { cmd => $stmfadmcmd, method => 'add-view' },
|
||||||
list_view => { cmd => $stmfadmcmd, method => 'list-view' },
|
list_view => { cmd => $stmfadmcmd, method => 'list-view' },
|
||||||
list_lu => { cmd => $sbdadmcmd, method => 'list-lu' },
|
list_lu => { cmd => $sbdadmcmd, method => 'list-lu' },
|
||||||
};
|
};
|
||||||
|
|
||||||
die "unknown command '$method'" unless exists $cmdmap->{$method};
|
die "unknown command '$method'" unless exists $cmdmap->{$method};
|
||||||
|
|
||||||
return $cmdmap->{$method};
|
return $cmdmap->{$method};
|
||||||
};
|
};
|
||||||
|
|
||||||
sub get_base {
|
sub get_base {
|
||||||
return '/dev/zvol/rdsk';
|
return '/dev/zvol/rdsk';
|
||||||
}
|
}
|
||||||
|
|
||||||
sub run_lun_command {
|
sub run_lun_command {
|
||||||
my ($scfg, $timeout, $method, @params) = @_;
|
my ($scfg, $timeout, $method, @params) = @_;
|
||||||
|
|
||||||
my $msg = '';
|
my $msg = '';
|
||||||
my $luncmd;
|
my $luncmd;
|
||||||
@ -45,57 +46,57 @@ sub run_lun_command {
|
|||||||
|
|
||||||
my $output = sub {
|
my $output = sub {
|
||||||
my $line = shift;
|
my $line = shift;
|
||||||
$msg .= "$line\n";
|
$msg .= "$line\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
if ($method eq 'create_lu') {
|
if ($method eq 'create_lu') {
|
||||||
my $prefix = '600144f';
|
my $prefix = '600144f';
|
||||||
my $digest = md5_hex($params[0]);
|
my $digest = md5_hex($params[0]);
|
||||||
$digest =~ /(\w{7}(.*))/;
|
$digest =~ /(\w{7}(.*))/;
|
||||||
$guid = "$prefix$2";
|
$guid = "$prefix$2";
|
||||||
@params = ('-p', 'wcd=false', '-p', "guid=$guid", @params);
|
@params = ('-p', 'wcd=false', '-p', "guid=$guid", @params);
|
||||||
} elsif ($method eq 'modify_lu') {
|
} elsif ($method eq 'modify_lu') {
|
||||||
@params = ('-s', @params);
|
@params = ('-s', @params);
|
||||||
} elsif ($method eq 'list_view') {
|
} elsif ($method eq 'list_view') {
|
||||||
@params = ('-l', @params);
|
@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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elsif ($method eq 'list_lu') {
|
} elsif ($method eq 'list_lu') {
|
||||||
my $object = $guid;
|
$guid = $params[0];
|
||||||
my @lines = split /\n/, $msg;
|
@params = undef;
|
||||||
$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;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,7 @@ my $OLD_CONFIG = undef;
|
|||||||
my @ssh_opts = ('-o', 'BatchMode=yes');
|
my @ssh_opts = ('-o', 'BatchMode=yes');
|
||||||
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
|
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
|
||||||
my @scp_cmd = ('/usr/bin/scp', @ssh_opts);
|
my @scp_cmd = ('/usr/bin/scp', @ssh_opts);
|
||||||
|
my $id_rsa_path = '/etc/pve/priv/zfs';
|
||||||
my $ietadm = '/usr/sbin/ietadm';
|
my $ietadm = '/usr/sbin/ietadm';
|
||||||
|
|
||||||
my $execute_command = sub {
|
my $execute_command = sub {
|
||||||
@ -59,9 +60,9 @@ my $execute_command = sub {
|
|||||||
$target = 'root@' . $scfg->{portal};
|
$target = 'root@' . $scfg->{portal};
|
||||||
|
|
||||||
if ($exec eq 'scp') {
|
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 {
|
} else {
|
||||||
$cmd = [@ssh_cmd, $target, $method, @params];
|
$cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $method, @params];
|
||||||
}
|
}
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
@ -103,7 +104,7 @@ my $read_config = sub {
|
|||||||
|
|
||||||
$target = 'root@' . $scfg->{portal};
|
$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 {
|
eval {
|
||||||
run_command($cmd, outfunc => $output, errfunc => $errfunc, timeout => $timeout);
|
run_command($cmd, outfunc => $output, errfunc => $errfunc, timeout => $timeout);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,12 +10,12 @@ use PVE::Tools qw(run_command file_read_firstline trim dir_glob_regex dir_glob_f
|
|||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
my @CONFIG_FILES = (
|
my @CONFIG_FILES = (
|
||||||
'/usr/local/etc/istgt/istgt.conf', # FreeBSD, FreeNAS
|
'/usr/local/etc/istgt/istgt.conf', # FreeBSD, FreeNAS
|
||||||
'/var/etc/iscsi/istgt.conf' # NAS4Free
|
'/var/etc/iscsi/istgt.conf' # NAS4Free
|
||||||
);
|
);
|
||||||
my @DAEMONS = (
|
my @DAEMONS = (
|
||||||
'/usr/local/etc/rc.d/istgt', # FreeBSD, FreeNAS
|
'/usr/local/etc/rc.d/istgt', # FreeBSD, FreeNAS
|
||||||
'/var/etc/rc.d/istgt' # NAS4Free
|
'/var/etc/rc.d/istgt' # NAS4Free
|
||||||
);
|
);
|
||||||
|
|
||||||
# A logical unit can max have 63 LUNs
|
# A logical unit can max have 63 LUNs
|
||||||
@ -31,6 +31,7 @@ my $OLD_CONFIG = undef;
|
|||||||
my @ssh_opts = ('-o', 'BatchMode=yes');
|
my @ssh_opts = ('-o', 'BatchMode=yes');
|
||||||
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
|
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
|
||||||
my @scp_cmd = ('/usr/bin/scp', @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/):
|
#Current SIGHUP reload limitations (http://www.peach.ne.jp/archives/istgt/):
|
||||||
#
|
#
|
||||||
@ -59,57 +60,57 @@ sub get_base;
|
|||||||
sub run_lun_command;
|
sub run_lun_command;
|
||||||
|
|
||||||
my $read_config = sub {
|
my $read_config = sub {
|
||||||
my ($scfg, $timeout, $method) = @_;
|
my ($scfg, $timeout, $method) = @_;
|
||||||
|
|
||||||
my $msg = '';
|
my $msg = '';
|
||||||
my $err = undef;
|
my $err = undef;
|
||||||
my $luncmd = 'cat';
|
my $luncmd = 'cat';
|
||||||
my $target;
|
my $target;
|
||||||
$timeout = 10 if !$timeout;
|
$timeout = 10 if !$timeout;
|
||||||
|
|
||||||
my $output = sub {
|
my $output = sub {
|
||||||
my $line = shift;
|
my $line = shift;
|
||||||
$msg .= "$line\n";
|
$msg .= "$line\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
my $errfunc = sub {
|
my $errfunc = sub {
|
||||||
my $line = shift;
|
my $line = shift;
|
||||||
$err .= "$line";
|
$err .= "$line";
|
||||||
};
|
};
|
||||||
|
|
||||||
$target = 'root@' . $scfg->{portal};
|
$target = 'root@' . $scfg->{portal};
|
||||||
|
|
||||||
my $daemon = 0;
|
my $daemon = 0;
|
||||||
foreach my $config (@CONFIG_FILES) {
|
foreach my $config (@CONFIG_FILES) {
|
||||||
$err = undef;
|
$err = undef;
|
||||||
my $cmd = [@ssh_cmd, $target, $luncmd, $config];
|
my $cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $luncmd, $config];
|
||||||
eval {
|
eval {
|
||||||
run_command($cmd, outfunc => $output, errfunc => $errfunc, timeout => $timeout);
|
run_command($cmd, outfunc => $output, errfunc => $errfunc, timeout => $timeout);
|
||||||
};
|
};
|
||||||
do {
|
do {
|
||||||
$err = undef;
|
$err = undef;
|
||||||
$DAEMON = $DAEMONS[$daemon];
|
$DAEMON = $DAEMONS[$daemon];
|
||||||
$CONFIG_FILE = $config;
|
$CONFIG_FILE = $config;
|
||||||
last;
|
last;
|
||||||
} unless $@;
|
} unless $@;
|
||||||
$daemon++;
|
$daemon++;
|
||||||
}
|
}
|
||||||
die $err if ($err && $err !~ /No such file or directory/);
|
die $err if ($err && $err !~ /No such file or directory/);
|
||||||
die "No configuration found. Install istgt on $scfg->{portal}" if $msg eq '';
|
die "No configuration found. Install istgt on $scfg->{portal}" if $msg eq '';
|
||||||
|
|
||||||
return $msg;
|
return $msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $get_config = sub {
|
my $get_config = sub {
|
||||||
my ($scfg) = @_;
|
my ($scfg) = @_;
|
||||||
my @conf = undef;
|
my @conf = undef;
|
||||||
|
|
||||||
my $config = $read_config->($scfg, undef, 'get_config');
|
my $config = $read_config->($scfg, undef, 'get_config');
|
||||||
die "Missing config file" unless $config;
|
die "Missing config file" unless $config;
|
||||||
|
|
||||||
$OLD_CONFIG = $config;
|
$OLD_CONFIG = $config;
|
||||||
|
|
||||||
return $config;
|
return $config;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $parse_size = sub {
|
my $parse_size = sub {
|
||||||
@ -118,25 +119,25 @@ my $parse_size = sub {
|
|||||||
return 0 if !$text;
|
return 0 if !$text;
|
||||||
|
|
||||||
if ($text =~ m/^(\d+(\.\d+)?)([TGMK]B)?$/) {
|
if ($text =~ m/^(\d+(\.\d+)?)([TGMK]B)?$/) {
|
||||||
my ($size, $reminder, $unit) = ($1, $2, $3);
|
my ($size, $reminder, $unit) = ($1, $2, $3);
|
||||||
return $size if !$unit;
|
return $size if !$unit;
|
||||||
if ($unit eq 'KB') {
|
if ($unit eq 'KB') {
|
||||||
$size *= 1024;
|
$size *= 1024;
|
||||||
} elsif ($unit eq 'MB') {
|
} elsif ($unit eq 'MB') {
|
||||||
$size *= 1024*1024;
|
$size *= 1024*1024;
|
||||||
} elsif ($unit eq 'GB') {
|
} elsif ($unit eq 'GB') {
|
||||||
$size *= 1024*1024*1024;
|
$size *= 1024*1024*1024;
|
||||||
} elsif ($unit eq 'TB') {
|
} elsif ($unit eq 'TB') {
|
||||||
$size *= 1024*1024*1024*1024;
|
$size *= 1024*1024*1024*1024;
|
||||||
}
|
}
|
||||||
if ($reminder) {
|
if ($reminder) {
|
||||||
$size = ceil($size);
|
$size = ceil($size);
|
||||||
}
|
}
|
||||||
return $size;
|
return $size;
|
||||||
} elsif ($text =~ /^auto$/i) {
|
} elsif ($text =~ /^auto$/i) {
|
||||||
return 'AUTO';
|
return 'AUTO';
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,435 +146,435 @@ my $size_with_unit = sub {
|
|||||||
|
|
||||||
return '0KB' if !$size;
|
return '0KB' if !$size;
|
||||||
|
|
||||||
return $size if $size eq 'AUTO';
|
return $size if $size eq 'AUTO';
|
||||||
|
|
||||||
if ($size =~ m/^\d+$/) {
|
if ($size =~ m/^\d+$/) {
|
||||||
++$n and $size /= 1024 until $size < 1024;
|
++$n and $size /= 1024 until $size < 1024;
|
||||||
if ($size =~ /\./) {
|
if ($size =~ /\./) {
|
||||||
return sprintf "%.2f%s", $size, ( qw[bytes KB MB GB TB] )[ $n ];
|
return sprintf "%.2f%s", $size, ( qw[bytes KB MB GB TB] )[ $n ];
|
||||||
} else {
|
} else {
|
||||||
return sprintf "%d%s", $size, ( qw[bytes KB MB GB TB] )[ $n ];
|
return sprintf "%d%s", $size, ( qw[bytes KB MB GB TB] )[ $n ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
die "$size: Not a number";
|
die "$size: Not a number";
|
||||||
};
|
};
|
||||||
|
|
||||||
my $lun_dumper = sub {
|
my $lun_dumper = sub {
|
||||||
my ($lun) = @_;
|
my ($lun) = @_;
|
||||||
my $config = '';
|
my $config = '';
|
||||||
|
|
||||||
$config .= "\n[$lun]\n";
|
$config .= "\n[$lun]\n";
|
||||||
$config .= 'TargetName ' . $SETTINGS->{$lun}->{TargetName} . "\n";
|
$config .= 'TargetName ' . $SETTINGS->{$lun}->{TargetName} . "\n";
|
||||||
$config .= 'Mapping ' . $SETTINGS->{$lun}->{Mapping} . "\n";
|
$config .= 'Mapping ' . $SETTINGS->{$lun}->{Mapping} . "\n";
|
||||||
$config .= 'AuthGroup ' . $SETTINGS->{$lun}->{AuthGroup} . "\n";
|
$config .= 'AuthGroup ' . $SETTINGS->{$lun}->{AuthGroup} . "\n";
|
||||||
$config .= 'UnitType ' . $SETTINGS->{$lun}->{UnitType} . "\n";
|
$config .= 'UnitType ' . $SETTINGS->{$lun}->{UnitType} . "\n";
|
||||||
$config .= 'QueueDepth ' . $SETTINGS->{$lun}->{QueueDepth} . "\n";
|
$config .= 'QueueDepth ' . $SETTINGS->{$lun}->{QueueDepth} . "\n";
|
||||||
|
|
||||||
foreach my $conf (@{$SETTINGS->{$lun}->{luns}}) {
|
foreach my $conf (@{$SETTINGS->{$lun}->{luns}}) {
|
||||||
$config .= "$conf->{lun} Storage " . $conf->{Storage};
|
$config .= "$conf->{lun} Storage " . $conf->{Storage};
|
||||||
$config .= ' ' . $size_with_unit->($conf->{Size}) . "\n";
|
$config .= ' ' . $size_with_unit->($conf->{Size}) . "\n";
|
||||||
}
|
}
|
||||||
$config .= "\n";
|
$config .= "\n";
|
||||||
|
|
||||||
return $config;
|
return $config;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $get_lu_name = sub {
|
my $get_lu_name = sub {
|
||||||
my ($target) = @_;
|
my ($target) = @_;
|
||||||
my $used = ();
|
my $used = ();
|
||||||
my $i;
|
my $i;
|
||||||
|
|
||||||
if (! exists $SETTINGS->{$target}->{used}) {
|
if (! exists $SETTINGS->{$target}->{used}) {
|
||||||
for ($i = 0; $i < $MAX_LUNS; $i++) {
|
for ($i = 0; $i < $MAX_LUNS; $i++) {
|
||||||
$used->{$i} = 0;
|
$used->{$i} = 0;
|
||||||
}
|
}
|
||||||
foreach my $lun (@{$SETTINGS->{$target}->{luns}}) {
|
foreach my $lun (@{$SETTINGS->{$target}->{luns}}) {
|
||||||
$lun->{lun} =~ /^LUN(\d+)$/;
|
$lun->{lun} =~ /^LUN(\d+)$/;
|
||||||
$used->{$1} = 1;
|
$used->{$1} = 1;
|
||||||
}
|
}
|
||||||
$SETTINGS->{$target}->{used} = $used;
|
$SETTINGS->{$target}->{used} = $used;
|
||||||
}
|
}
|
||||||
|
|
||||||
$used = $SETTINGS->{$target}->{used};
|
$used = $SETTINGS->{$target}->{used};
|
||||||
for ($i = 0; $i < $MAX_LUNS; $i++) {
|
for ($i = 0; $i < $MAX_LUNS; $i++) {
|
||||||
last unless $used->{$i};
|
last unless $used->{$i};
|
||||||
}
|
}
|
||||||
$SETTINGS->{$target}->{used}->{$i} = 1;
|
$SETTINGS->{$target}->{used}->{$i} = 1;
|
||||||
|
|
||||||
return "LUN$i";
|
return "LUN$i";
|
||||||
};
|
};
|
||||||
|
|
||||||
my $init_lu_name = sub {
|
my $init_lu_name = sub {
|
||||||
my ($target) = @_;
|
my ($target) = @_;
|
||||||
my $used = ();
|
my $used = ();
|
||||||
|
|
||||||
if (! exists($SETTINGS->{$target}->{used})) {
|
if (! exists($SETTINGS->{$target}->{used})) {
|
||||||
for (my $i = 0; $i < $MAX_LUNS; $i++) {
|
for (my $i = 0; $i < $MAX_LUNS; $i++) {
|
||||||
$used->{$i} = 0;
|
$used->{$i} = 0;
|
||||||
}
|
}
|
||||||
$SETTINGS->{$target}->{used} = $used;
|
$SETTINGS->{$target}->{used} = $used;
|
||||||
}
|
}
|
||||||
foreach my $lun (@{$SETTINGS->{$target}->{luns}}) {
|
foreach my $lun (@{$SETTINGS->{$target}->{luns}}) {
|
||||||
$lun->{lun} =~ /^LUN(\d+)$/;
|
$lun->{lun} =~ /^LUN(\d+)$/;
|
||||||
$SETTINGS->{$target}->{used}->{$1} = 1;
|
$SETTINGS->{$target}->{used}->{$1} = 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
my $free_lu_name = sub {
|
my $free_lu_name = sub {
|
||||||
my ($target, $lu_name) = @_;
|
my ($target, $lu_name) = @_;
|
||||||
|
|
||||||
$lu_name =~ /^LUN(\d+)$/;
|
$lu_name =~ /^LUN(\d+)$/;
|
||||||
$SETTINGS->{$target}->{used}->{$1} = 0;
|
$SETTINGS->{$target}->{used}->{$1} = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $make_lun = sub {
|
my $make_lun = sub {
|
||||||
my ($path) = @_;
|
my ($path) = @_;
|
||||||
|
|
||||||
my $target = $SETTINGS->{current};
|
my $target = $SETTINGS->{current};
|
||||||
die 'Maximum number of LUNs per target is 63' if scalar @{$SETTINGS->{$target}->{luns}} >= $MAX_LUNS;
|
die 'Maximum number of LUNs per target is 63' if scalar @{$SETTINGS->{$target}->{luns}} >= $MAX_LUNS;
|
||||||
|
|
||||||
my $lun = $get_lu_name->($target);
|
my $lun = $get_lu_name->($target);
|
||||||
my $conf = {
|
my $conf = {
|
||||||
lun => $lun,
|
lun => $lun,
|
||||||
Storage => $path,
|
Storage => $path,
|
||||||
Size => 'AUTO',
|
Size => 'AUTO',
|
||||||
};
|
};
|
||||||
push @{$SETTINGS->{$target}->{luns}}, $conf;
|
push @{$SETTINGS->{$target}->{luns}}, $conf;
|
||||||
|
|
||||||
return $conf->{lun};
|
return $conf->{lun};
|
||||||
};
|
};
|
||||||
|
|
||||||
my $parser = sub {
|
my $parser = sub {
|
||||||
my ($scfg) = @_;
|
my ($scfg) = @_;
|
||||||
|
|
||||||
my $lun = undef;
|
my $lun = undef;
|
||||||
my $line = 0;
|
my $line = 0;
|
||||||
|
|
||||||
my $config = $get_config->($scfg);
|
my $config = $get_config->($scfg);
|
||||||
my @cfgfile = split "\n", $config;
|
my @cfgfile = split "\n", $config;
|
||||||
|
|
||||||
foreach (@cfgfile) {
|
foreach (@cfgfile) {
|
||||||
$line++;
|
$line++;
|
||||||
if ($_ =~ /^\s*\[(PortalGroup\d+)\]\s*/) {
|
if ($_ =~ /^\s*\[(PortalGroup\d+)\]\s*/) {
|
||||||
$lun = undef;
|
$lun = undef;
|
||||||
$SETTINGS->{$1} = ();
|
$SETTINGS->{$1} = ();
|
||||||
} elsif ($_ =~ /^\s*\[(InitiatorGroup\d+)\]\s*/) {
|
} elsif ($_ =~ /^\s*\[(InitiatorGroup\d+)\]\s*/) {
|
||||||
$lun = undef;
|
$lun = undef;
|
||||||
$SETTINGS->{$1} = ();
|
$SETTINGS->{$1} = ();
|
||||||
} elsif ($_ =~ /^\s*PidFile\s+"?([\w\/\.]+)"?\s*/) {
|
} elsif ($_ =~ /^\s*PidFile\s+"?([\w\/\.]+)"?\s*/) {
|
||||||
$lun = undef;
|
$lun = undef;
|
||||||
$SETTINGS->{pidfile} = $1;
|
$SETTINGS->{pidfile} = $1;
|
||||||
} elsif ($_ =~ /^\s*NodeBase\s+"?([\w\-\.]+)"?\s*/) {
|
} elsif ($_ =~ /^\s*NodeBase\s+"?([\w\-\.]+)"?\s*/) {
|
||||||
$lun = undef;
|
$lun = undef;
|
||||||
$SETTINGS->{nodebase} = $1;
|
$SETTINGS->{nodebase} = $1;
|
||||||
} elsif ($_ =~ /^\s*\[(LogicalUnit\d+)\]\s*/) {
|
} elsif ($_ =~ /^\s*\[(LogicalUnit\d+)\]\s*/) {
|
||||||
$lun = $1;
|
$lun = $1;
|
||||||
$SETTINGS->{$lun} = ();
|
$SETTINGS->{$lun} = ();
|
||||||
$SETTINGS->{targets}++;
|
$SETTINGS->{targets}++;
|
||||||
} elsif ($lun) {
|
} elsif ($lun) {
|
||||||
next if (($_ =~ /^\s*#/) || ($_ =~ /^\s*$/));
|
next if (($_ =~ /^\s*#/) || ($_ =~ /^\s*$/));
|
||||||
if ($_ =~ /^\s*(\w+)\s+(.+)\s*/) {
|
if ($_ =~ /^\s*(\w+)\s+(.+)\s*/) {
|
||||||
#next if $2 =~ /^Option.*/;
|
#next if $2 =~ /^Option.*/;
|
||||||
$SETTINGS->{$lun}->{$1} = $2;
|
$SETTINGS->{$lun}->{$1} = $2;
|
||||||
$SETTINGS->{$lun}->{$1} =~ s/^\s+|\s+$|"\s*//g;
|
$SETTINGS->{$lun}->{$1} =~ s/^\s+|\s+$|"\s*//g;
|
||||||
} else {
|
} else {
|
||||||
die "$line: parse error [$_]";
|
die "$line: parse error [$_]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$CONFIG .= "$_\n" unless $lun;
|
$CONFIG .= "$_\n" unless $lun;
|
||||||
}
|
}
|
||||||
|
|
||||||
$CONFIG =~ s/\n$//;
|
$CONFIG =~ s/\n$//;
|
||||||
die "$scfg->{target}: Target not found" unless $SETTINGS->{targets};
|
die "$scfg->{target}: Target not found" unless $SETTINGS->{targets};
|
||||||
my $max = $SETTINGS->{targets};
|
my $max = $SETTINGS->{targets};
|
||||||
my $base = get_base;
|
my $base = get_base;
|
||||||
|
|
||||||
for (my $i = 1; $i <= $max; $i++) {
|
for (my $i = 1; $i <= $max; $i++) {
|
||||||
my $target = $SETTINGS->{nodebase}.':'.$SETTINGS->{"LogicalUnit$i"}->{TargetName};
|
my $target = $SETTINGS->{nodebase}.':'.$SETTINGS->{"LogicalUnit$i"}->{TargetName};
|
||||||
if ($target eq $scfg->{target}) {
|
if ($target eq $scfg->{target}) {
|
||||||
my $lu = ();
|
my $lu = ();
|
||||||
while ((my $key, my $val) = each(%{$SETTINGS->{"LogicalUnit$i"}})) {
|
while ((my $key, my $val) = each(%{$SETTINGS->{"LogicalUnit$i"}})) {
|
||||||
if ($key =~ /^LUN\d+/) {
|
if ($key =~ /^LUN\d+/) {
|
||||||
if ($val =~ /^Storage\s+([\w\/\-]+)\s+(\w+)/) {
|
if ($val =~ /^Storage\s+([\w\/\-]+)\s+(\w+)/) {
|
||||||
my $storage = $1;
|
my $storage = $1;
|
||||||
my $size = $parse_size->($2);
|
my $size = $parse_size->($2);
|
||||||
my $conf = undef;
|
my $conf = undef;
|
||||||
if ($storage =~ /^$base\/$scfg->{pool}\/([\w\-]+)$/) {
|
if ($storage =~ /^$base\/$scfg->{pool}\/([\w\-]+)$/) {
|
||||||
$conf = {
|
$conf = {
|
||||||
lun => $key,
|
lun => $key,
|
||||||
Storage => $storage,
|
Storage => $storage,
|
||||||
Size => $size,
|
Size => $size,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
push @$lu, $conf if $conf;
|
push @$lu, $conf if $conf;
|
||||||
}
|
}
|
||||||
delete $SETTINGS->{"LogicalUnit$i"}->{$key};
|
delete $SETTINGS->{"LogicalUnit$i"}->{$key};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$SETTINGS->{"LogicalUnit$i"}->{luns} = $lu;
|
$SETTINGS->{"LogicalUnit$i"}->{luns} = $lu;
|
||||||
$SETTINGS->{current} = "LogicalUnit$i";
|
$SETTINGS->{current} = "LogicalUnit$i";
|
||||||
$init_lu_name->("LogicalUnit$i");
|
$init_lu_name->("LogicalUnit$i");
|
||||||
} else {
|
} else {
|
||||||
$CONFIG .= $lun_dumper->("LogicalUnit$i");
|
$CONFIG .= $lun_dumper->("LogicalUnit$i");
|
||||||
delete $SETTINGS->{"LogicalUnit$i"};
|
delete $SETTINGS->{"LogicalUnit$i"};
|
||||||
$SETTINGS->{targets}--;
|
$SETTINGS->{targets}--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
die "$scfg->{target}: Target not found" unless $SETTINGS->{targets} > 0;
|
die "$scfg->{target}: Target not found" unless $SETTINGS->{targets} > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $list_lun = sub {
|
my $list_lun = sub {
|
||||||
my ($scfg, $timeout, $method, @params) = @_;
|
my ($scfg, $timeout, $method, @params) = @_;
|
||||||
my $name = undef;
|
my $name = undef;
|
||||||
|
|
||||||
my $object = $params[0];
|
my $object = $params[0];
|
||||||
for my $key (keys %$SETTINGS) {
|
for my $key (keys %$SETTINGS) {
|
||||||
next unless $key =~ /^LogicalUnit\d+$/;
|
next unless $key =~ /^LogicalUnit\d+$/;
|
||||||
foreach my $lun (@{$SETTINGS->{$key}->{luns}}) {
|
foreach my $lun (@{$SETTINGS->{$key}->{luns}}) {
|
||||||
if ($lun->{Storage} =~ /^$object$/) {
|
if ($lun->{Storage} =~ /^$object$/) {
|
||||||
return $lun->{Storage};
|
return $lun->{Storage};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $name;
|
return $name;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $create_lun = sub {
|
my $create_lun = sub {
|
||||||
my ($scfg, $timeout, $method, @params) = @_;
|
my ($scfg, $timeout, $method, @params) = @_;
|
||||||
my $res = ();
|
my $res = ();
|
||||||
my $file = "/tmp/config$$";
|
my $file = "/tmp/config$$";
|
||||||
|
|
||||||
if ($list_lun->($scfg, $timeout, $method, @params)) {
|
if ($list_lun->($scfg, $timeout, $method, @params)) {
|
||||||
die "$params[0]: LUN exists";
|
die "$params[0]: LUN exists";
|
||||||
}
|
}
|
||||||
my $lun = $params[0];
|
my $lun = $params[0];
|
||||||
$lun = $make_lun->($lun);
|
$lun = $make_lun->($lun);
|
||||||
my $config = $lun_dumper->($SETTINGS->{current});
|
my $config = $lun_dumper->($SETTINGS->{current});
|
||||||
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
|
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
|
||||||
|
|
||||||
print $fh $CONFIG;
|
print $fh $CONFIG;
|
||||||
print $fh $config;
|
print $fh $config;
|
||||||
close $fh;
|
close $fh;
|
||||||
@params = ($CONFIG_FILE);
|
@params = ($CONFIG_FILE);
|
||||||
$res = {
|
$res = {
|
||||||
cmd => 'scp',
|
cmd => 'scp',
|
||||||
method => $file,
|
method => $file,
|
||||||
params => \@params,
|
params => \@params,
|
||||||
msg => $lun,
|
msg => $lun,
|
||||||
post_exe => sub {
|
post_exe => sub {
|
||||||
unlink $file;
|
unlink $file;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $delete_lun = sub {
|
my $delete_lun = sub {
|
||||||
my ($scfg, $timeout, $method, @params) = @_;
|
my ($scfg, $timeout, $method, @params) = @_;
|
||||||
my $res = ();
|
my $res = ();
|
||||||
my $file = "/tmp/config$$";
|
my $file = "/tmp/config$$";
|
||||||
|
|
||||||
my $target = $SETTINGS->{current};
|
my $target = $SETTINGS->{current};
|
||||||
my $luns = ();
|
my $luns = ();
|
||||||
|
|
||||||
foreach my $conf (@{$SETTINGS->{$target}->{luns}}) {
|
foreach my $conf (@{$SETTINGS->{$target}->{luns}}) {
|
||||||
if ($conf->{Storage} =~ /^$params[0]$/) {
|
if ($conf->{Storage} =~ /^$params[0]$/) {
|
||||||
$free_lu_name->($target, $conf->{lun});
|
$free_lu_name->($target, $conf->{lun});
|
||||||
} else {
|
} else {
|
||||||
push @$luns, $conf;
|
push @$luns, $conf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$SETTINGS->{$target}->{luns} = $luns;
|
$SETTINGS->{$target}->{luns} = $luns;
|
||||||
|
|
||||||
my $config = $lun_dumper->($SETTINGS->{current});
|
my $config = $lun_dumper->($SETTINGS->{current});
|
||||||
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
|
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
|
||||||
|
|
||||||
print $fh $CONFIG;
|
print $fh $CONFIG;
|
||||||
print $fh $config;
|
print $fh $config;
|
||||||
close $fh;
|
close $fh;
|
||||||
@params = ($CONFIG_FILE);
|
@params = ($CONFIG_FILE);
|
||||||
$res = {
|
$res = {
|
||||||
cmd => 'scp',
|
cmd => 'scp',
|
||||||
method => $file,
|
method => $file,
|
||||||
params => \@params,
|
params => \@params,
|
||||||
post_exe => sub {
|
post_exe => sub {
|
||||||
unlink $file;
|
unlink $file;
|
||||||
run_lun_command($scfg, undef, 'add_view', 'restart');
|
run_lun_command($scfg, undef, 'add_view', 'restart');
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $import_lun = sub {
|
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 $add_view = sub {
|
||||||
my ($scfg, $timeout, $method, @params) = @_;
|
my ($scfg, $timeout, $method, @params) = @_;
|
||||||
my $cmdmap;
|
my $cmdmap;
|
||||||
|
|
||||||
if (@params && $params[0] eq 'restart') {
|
if (@params && $params[0] eq 'restart') {
|
||||||
@params = ('restart', '1>&2', '>', '/dev/null');
|
@params = ('restart', '1>&2', '>', '/dev/null');
|
||||||
$cmdmap = {
|
$cmdmap = {
|
||||||
cmd => 'ssh',
|
cmd => 'ssh',
|
||||||
method => $DAEMON,
|
method => $DAEMON,
|
||||||
params => \@params,
|
params => \@params,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@params = ('-HUP', '$(cat '. "$SETTINGS->{pidfile})");
|
@params = ('-HUP', '$(cat '. "$SETTINGS->{pidfile})");
|
||||||
$cmdmap = {
|
$cmdmap = {
|
||||||
cmd => 'ssh',
|
cmd => 'ssh',
|
||||||
method => 'kill',
|
method => 'kill',
|
||||||
params => \@params,
|
params => \@params,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return $cmdmap;
|
return $cmdmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $modify_lun = sub {
|
my $modify_lun = sub {
|
||||||
my ($scfg, $timeout, $method, @params) = @_;
|
my ($scfg, $timeout, $method, @params) = @_;
|
||||||
|
|
||||||
# Current SIGHUP reload limitations
|
# Current SIGHUP reload limitations
|
||||||
# LU connected by the initiator can't be reloaded by SIGHUP.
|
# LU connected by the initiator can't be reloaded by SIGHUP.
|
||||||
# Until above limitation persists modifying a LUN will require
|
# Until above limitation persists modifying a LUN will require
|
||||||
# a restart of the daemon breaking all current connections
|
# a restart of the daemon breaking all current connections
|
||||||
#die 'Modify a connected LUN is not currently supported by istgt';
|
#die 'Modify a connected LUN is not currently supported by istgt';
|
||||||
@params = ('restart', @params);
|
@params = ('restart', @params);
|
||||||
|
|
||||||
return $add_view->($scfg, $timeout, $method, @params);
|
return $add_view->($scfg, $timeout, $method, @params);
|
||||||
};
|
};
|
||||||
|
|
||||||
my $list_view = sub {
|
my $list_view = sub {
|
||||||
my ($scfg, $timeout, $method, @params) = @_;
|
my ($scfg, $timeout, $method, @params) = @_;
|
||||||
my $lun = undef;
|
my $lun = undef;
|
||||||
|
|
||||||
my $object = $params[0];
|
my $object = $params[0];
|
||||||
for my $key (keys %$SETTINGS) {
|
for my $key (keys %$SETTINGS) {
|
||||||
next unless $key =~ /^LogicalUnit\d+$/;
|
next unless $key =~ /^LogicalUnit\d+$/;
|
||||||
foreach my $lun (@{$SETTINGS->{$key}->{luns}}) {
|
foreach my $lun (@{$SETTINGS->{$key}->{luns}}) {
|
||||||
if ($lun->{Storage} =~ /^$object$/) {
|
if ($lun->{Storage} =~ /^$object$/) {
|
||||||
if ($lun->{lun} =~ /^LUN(\d+)/) {
|
if ($lun->{lun} =~ /^LUN(\d+)/) {
|
||||||
return $1;
|
return $1;
|
||||||
}
|
}
|
||||||
die "$lun->{Storage}: Missing LUN";
|
die "$lun->{Storage}: Missing LUN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $lun;
|
return $lun;
|
||||||
};
|
};
|
||||||
|
|
||||||
my $get_lun_cmd_map = sub {
|
my $get_lun_cmd_map = sub {
|
||||||
my ($method) = @_;
|
my ($method) = @_;
|
||||||
|
|
||||||
my $cmdmap = {
|
my $cmdmap = {
|
||||||
create_lu => { cmd => $create_lun },
|
create_lu => { cmd => $create_lun },
|
||||||
delete_lu => { cmd => $delete_lun },
|
delete_lu => { cmd => $delete_lun },
|
||||||
import_lu => { cmd => $import_lun },
|
import_lu => { cmd => $import_lun },
|
||||||
modify_lu => { cmd => $modify_lun },
|
modify_lu => { cmd => $modify_lun },
|
||||||
add_view => { cmd => $add_view },
|
add_view => { cmd => $add_view },
|
||||||
list_view => { cmd => $list_view },
|
list_view => { cmd => $list_view },
|
||||||
list_lu => { cmd => $list_lun },
|
list_lu => { cmd => $list_lun },
|
||||||
};
|
};
|
||||||
|
|
||||||
die "unknown command '$method'" unless exists $cmdmap->{$method};
|
die "unknown command '$method'" unless exists $cmdmap->{$method};
|
||||||
|
|
||||||
return $cmdmap->{$method};
|
return $cmdmap->{$method};
|
||||||
};
|
};
|
||||||
|
|
||||||
sub run_lun_command {
|
sub run_lun_command {
|
||||||
my ($scfg, $timeout, $method, @params) = @_;
|
my ($scfg, $timeout, $method, @params) = @_;
|
||||||
|
|
||||||
my $msg = '';
|
my $msg = '';
|
||||||
my $luncmd;
|
my $luncmd;
|
||||||
my $target;
|
my $target;
|
||||||
my $cmd;
|
my $cmd;
|
||||||
my $res;
|
my $res;
|
||||||
$timeout = 10 if !$timeout;
|
$timeout = 10 if !$timeout;
|
||||||
my $is_add_view = 0;
|
my $is_add_view = 0;
|
||||||
|
|
||||||
my $output = sub {
|
my $output = sub {
|
||||||
my $line = shift;
|
my $line = shift;
|
||||||
$msg .= "$line\n";
|
$msg .= "$line\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
$target = 'root@' . $scfg->{portal};
|
$target = 'root@' . $scfg->{portal};
|
||||||
|
|
||||||
$parser->($scfg) unless $SETTINGS;
|
$parser->($scfg) unless $SETTINGS;
|
||||||
my $cmdmap = $get_lun_cmd_map->($method);
|
my $cmdmap = $get_lun_cmd_map->($method);
|
||||||
if ($method eq 'add_view') {
|
if ($method eq 'add_view') {
|
||||||
$is_add_view = 1 ;
|
$is_add_view = 1 ;
|
||||||
$timeout = 15;
|
$timeout = 15;
|
||||||
}
|
}
|
||||||
if (ref $cmdmap->{cmd} eq 'CODE') {
|
if (ref $cmdmap->{cmd} eq 'CODE') {
|
||||||
$res = $cmdmap->{cmd}->($scfg, $timeout, $method, @params);
|
$res = $cmdmap->{cmd}->($scfg, $timeout, $method, @params);
|
||||||
if (ref $res) {
|
if (ref $res) {
|
||||||
$method = $res->{method};
|
$method = $res->{method};
|
||||||
@params = @{$res->{params}};
|
@params = @{$res->{params}};
|
||||||
if ($res->{cmd} eq 'scp') {
|
if ($res->{cmd} 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 {
|
} else {
|
||||||
$cmd = [@ssh_cmd, $target, $method, @params];
|
$cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $method, @params];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$luncmd = $cmdmap->{cmd};
|
$luncmd = $cmdmap->{cmd};
|
||||||
$method = $cmdmap->{method};
|
$method = $cmdmap->{method};
|
||||||
$cmd = [@ssh_cmd, $target, $luncmd, $method, @params];
|
$cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $luncmd, $method, @params];
|
||||||
}
|
}
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
run_command($cmd, outfunc => $output, timeout => $timeout);
|
run_command($cmd, outfunc => $output, timeout => $timeout);
|
||||||
};
|
};
|
||||||
if ($@ && $is_add_view) {
|
if ($@ && $is_add_view) {
|
||||||
my $err = $@;
|
my $err = $@;
|
||||||
if ($OLD_CONFIG) {
|
if ($OLD_CONFIG) {
|
||||||
my $err1 = undef;
|
my $err1 = undef;
|
||||||
my $file = "/tmp/config$$";
|
my $file = "/tmp/config$$";
|
||||||
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
|
open(my $fh, '>', $file) or die "Could not open file '$file' $!";
|
||||||
print $fh $OLD_CONFIG;
|
print $fh $OLD_CONFIG;
|
||||||
close $fh;
|
close $fh;
|
||||||
$cmd = [@scp_cmd, $file, $CONFIG_FILE];
|
$cmd = [@scp_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $file, $CONFIG_FILE];
|
||||||
eval {
|
eval {
|
||||||
run_command($cmd, outfunc => $output, timeout => $timeout);
|
run_command($cmd, outfunc => $output, timeout => $timeout);
|
||||||
};
|
};
|
||||||
$err1 = $@ if $@;
|
$err1 = $@ if $@;
|
||||||
unlink $file;
|
unlink $file;
|
||||||
die "$err\n$err1" if $err1;
|
die "$err\n$err1" if $err1;
|
||||||
eval {
|
eval {
|
||||||
run_lun_command($scfg, undef, 'add_view', 'restart');
|
run_lun_command($scfg, undef, 'add_view', 'restart');
|
||||||
};
|
};
|
||||||
die "$err\n$@" if ($@);
|
die "$err\n$@" if ($@);
|
||||||
}
|
}
|
||||||
die $err;
|
die $err;
|
||||||
} elsif ($@) {
|
} elsif ($@) {
|
||||||
die $@;
|
die $@;
|
||||||
} elsif ($is_add_view) {
|
} elsif ($is_add_view) {
|
||||||
$OLD_CONFIG = undef;
|
$OLD_CONFIG = undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($res->{post_exe} && ref $res->{post_exe} eq 'CODE') {
|
if ($res->{post_exe} && ref $res->{post_exe} eq 'CODE') {
|
||||||
$res->{post_exe}->();
|
$res->{post_exe}->();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($res->{msg}) {
|
if ($res->{msg}) {
|
||||||
$msg = $res->{msg};
|
$msg = $res->{msg};
|
||||||
}
|
}
|
||||||
|
|
||||||
return $msg;
|
return $msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_base {
|
sub get_base {
|
||||||
return '/dev/zvol';
|
return '/dev/zvol';
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
@ -14,35 +14,36 @@ use PVE::Storage::LunCmd::Iet;
|
|||||||
|
|
||||||
my @ssh_opts = ('-o', 'BatchMode=yes');
|
my @ssh_opts = ('-o', 'BatchMode=yes');
|
||||||
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
|
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
|
||||||
|
my $id_rsa_path = '/etc/pve/priv/zfs';
|
||||||
|
|
||||||
my $lun_cmds = {
|
my $lun_cmds = {
|
||||||
create_lu => 1,
|
create_lu => 1,
|
||||||
delete_lu => 1,
|
delete_lu => 1,
|
||||||
import_lu => 1,
|
import_lu => 1,
|
||||||
modify_lu => 1,
|
modify_lu => 1,
|
||||||
add_view => 1,
|
add_view => 1,
|
||||||
list_view => 1,
|
list_view => 1,
|
||||||
list_lu => 1,
|
list_lu => 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
my $zfs_unknown_scsi_provider = sub {
|
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 $zfs_get_base = sub {
|
||||||
my ($scfg) = @_;
|
my ($scfg) = @_;
|
||||||
|
|
||||||
if ($scfg->{iscsiprovider} eq 'comstar') {
|
if ($scfg->{iscsiprovider} eq 'comstar') {
|
||||||
return PVE::Storage::LunCmd::Comstar::get_base;
|
return PVE::Storage::LunCmd::Comstar::get_base;
|
||||||
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
|
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
|
||||||
return PVE::Storage::LunCmd::Istgt::get_base;
|
return PVE::Storage::LunCmd::Istgt::get_base;
|
||||||
} elsif ($scfg->{iscsiprovider} eq 'iet') {
|
} elsif ($scfg->{iscsiprovider} eq 'iet') {
|
||||||
return PVE::Storage::LunCmd::Iet::get_base;
|
return PVE::Storage::LunCmd::Iet::get_base;
|
||||||
} else {
|
} else {
|
||||||
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
|
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
sub zfs_request {
|
sub zfs_request {
|
||||||
@ -51,41 +52,41 @@ sub zfs_request {
|
|||||||
my $cmdmap;
|
my $cmdmap;
|
||||||
my $zfscmd;
|
my $zfscmd;
|
||||||
my $target;
|
my $target;
|
||||||
my $msg;
|
my $msg;
|
||||||
|
|
||||||
$timeout = 5 if !$timeout;
|
$timeout = 5 if !$timeout;
|
||||||
|
|
||||||
if ($lun_cmds->{$method}) {
|
if ($lun_cmds->{$method}) {
|
||||||
if ($scfg->{iscsiprovider} eq 'comstar') {
|
if ($scfg->{iscsiprovider} eq 'comstar') {
|
||||||
$msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params);
|
$msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params);
|
||||||
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
|
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
|
||||||
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
|
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
|
||||||
} elsif ($scfg->{iscsiprovider} eq 'iet') {
|
} elsif ($scfg->{iscsiprovider} eq 'iet') {
|
||||||
$msg = PVE::Storage::LunCmd::Iet::run_lun_command($scfg, $timeout, $method, @params);
|
$msg = PVE::Storage::LunCmd::Iet::run_lun_command($scfg, $timeout, $method, @params);
|
||||||
} else {
|
} else {
|
||||||
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
|
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($method eq 'zpool_list') {
|
if ($method eq 'zpool_list') {
|
||||||
$zfscmd = 'zpool';
|
$zfscmd = 'zpool';
|
||||||
$method = 'list',
|
$method = 'list',
|
||||||
} else {
|
} else {
|
||||||
$zfscmd = 'zfs';
|
$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 $output = sub {
|
||||||
my $line = shift;
|
my $line = shift;
|
||||||
$msg .= "$line\n";
|
$msg .= "$line\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
run_command($cmd, outfunc => $output, timeout => $timeout);
|
run_command($cmd, outfunc => $output, timeout => $timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $msg;
|
return $msg;
|
||||||
}
|
}
|
||||||
@ -96,24 +97,24 @@ sub zfs_parse_size {
|
|||||||
return 0 if !$text;
|
return 0 if !$text;
|
||||||
|
|
||||||
if ($text =~ m/^(\d+(\.\d+)?)([TGMK])?$/) {
|
if ($text =~ m/^(\d+(\.\d+)?)([TGMK])?$/) {
|
||||||
my ($size, $reminder, $unit) = ($1, $2, $3);
|
my ($size, $reminder, $unit) = ($1, $2, $3);
|
||||||
return $size if !$unit;
|
return $size if !$unit;
|
||||||
if ($unit eq 'K') {
|
if ($unit eq 'K') {
|
||||||
$size *= 1024;
|
$size *= 1024;
|
||||||
} elsif ($unit eq 'M') {
|
} elsif ($unit eq 'M') {
|
||||||
$size *= 1024*1024;
|
$size *= 1024*1024;
|
||||||
} elsif ($unit eq 'G') {
|
} elsif ($unit eq 'G') {
|
||||||
$size *= 1024*1024*1024;
|
$size *= 1024*1024*1024;
|
||||||
} elsif ($unit eq 'T') {
|
} elsif ($unit eq 'T') {
|
||||||
$size *= 1024*1024*1024*1024;
|
$size *= 1024*1024*1024*1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($reminder) {
|
if ($reminder) {
|
||||||
$size = ceil($size);
|
$size = ceil($size);
|
||||||
}
|
}
|
||||||
return $size;
|
return $size;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,16 +125,16 @@ sub zfs_get_pool_stats {
|
|||||||
my $used = 0;
|
my $used = 0;
|
||||||
|
|
||||||
my $text = zfs_request($scfg, undef, 'get', '-o', 'value', '-Hp',
|
my $text = zfs_request($scfg, undef, 'get', '-o', 'value', '-Hp',
|
||||||
'available,used', $scfg->{pool});
|
'available,used', $scfg->{pool});
|
||||||
|
|
||||||
my @lines = split /\n/, $text;
|
my @lines = split /\n/, $text;
|
||||||
|
|
||||||
if($lines[0] =~ /^(\d+)$/) {
|
if($lines[0] =~ /^(\d+)$/) {
|
||||||
$available = $1;
|
$available = $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($lines[1] =~ /^(\d+)$/) {
|
if($lines[1] =~ /^(\d+)$/) {
|
||||||
$used = $1;
|
$used = $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ($available, $used);
|
return ($available, $used);
|
||||||
@ -148,28 +149,28 @@ sub zfs_parse_zvol_list {
|
|||||||
|
|
||||||
my @lines = split /\n/, $text;
|
my @lines = split /\n/, $text;
|
||||||
foreach my $line (@lines) {
|
foreach my $line (@lines) {
|
||||||
if ($line =~ /^(.+)\s+([a-zA-Z0-9\.]+|\-)\s+(.+)$/) {
|
if ($line =~ /^(.+)\s+([a-zA-Z0-9\.]+|\-)\s+(.+)$/) {
|
||||||
my $zvol = {};
|
my $zvol = {};
|
||||||
my $name;
|
my $name;
|
||||||
my $disk;
|
my $disk;
|
||||||
my @zvols = split /\//, $1;
|
my @zvols = split /\//, $1;
|
||||||
my $pool = $zvols[0];
|
my $pool = $zvols[0];
|
||||||
|
|
||||||
if (scalar(@zvols) == 2 && $zvols[0] !~ /^rpool$/) {
|
if (scalar(@zvols) == 2 && $zvols[0] !~ /^rpool$/) {
|
||||||
$disk = $zvols[1];
|
$disk = $zvols[1];
|
||||||
next unless $disk =~ m!^(\w+)-(\d+)-(\w+)-(\d+)$!;
|
next unless $disk =~ m!^(\w+)-(\d+)-(\w+)-(\d+)$!;
|
||||||
$name = $pool . '/' . $disk;
|
$name = $pool . '/' . $disk;
|
||||||
} else {
|
} else {
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
$zvol->{name} = $name;
|
$zvol->{name} = $name;
|
||||||
$zvol->{size} = zfs_parse_size($2);
|
$zvol->{size} = zfs_parse_size($2);
|
||||||
if ($3 !~ /^-$/) {
|
if ($3 !~ /^-$/) {
|
||||||
$zvol->{origin} = $3;
|
$zvol->{origin} = $3;
|
||||||
}
|
}
|
||||||
push @$list, $zvol;
|
push @$list, $zvol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
@ -179,7 +180,7 @@ sub zfs_get_lu_name {
|
|||||||
my ($scfg, $zvol) = @_;
|
my ($scfg, $zvol) = @_;
|
||||||
my $object;
|
my $object;
|
||||||
|
|
||||||
my $base = $zfs_get_base->($scfg);
|
my $base = $zfs_get_base->($scfg);
|
||||||
if ($zvol =~ /^.+\/.+/) {
|
if ($zvol =~ /^.+\/.+/) {
|
||||||
$object = "$base/$zvol";
|
$object = "$base/$zvol";
|
||||||
} else {
|
} else {
|
||||||
@ -188,7 +189,7 @@ sub zfs_get_lu_name {
|
|||||||
|
|
||||||
my $lu_name = zfs_request($scfg, undef, 'list_lu', $object);
|
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";
|
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");
|
my $text = zfs_request($scfg, undef, 'get', '-Hp', 'volsize', "$scfg->{pool}/$zvol");
|
||||||
|
|
||||||
if($text =~ /volsize\s(\d+)/){
|
if($text =~ /volsize\s(\d+)/){
|
||||||
return $1;
|
return $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
die "Could not get zvol size";
|
die "Could not get zvol size";
|
||||||
@ -209,7 +210,7 @@ sub zfs_add_lun_mapping_entry {
|
|||||||
my ($scfg, $zvol, $guid) = @_;
|
my ($scfg, $zvol, $guid) = @_;
|
||||||
|
|
||||||
if (! defined($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);
|
zfs_request($scfg, undef, 'add_view', $guid);
|
||||||
@ -226,7 +227,7 @@ sub zfs_delete_lu {
|
|||||||
sub zfs_create_lu {
|
sub zfs_create_lu {
|
||||||
my ($scfg, $zvol) = @_;
|
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");
|
my $guid = zfs_request($scfg, undef, 'create_lu', "$base/$scfg->{pool}/$zvol");
|
||||||
|
|
||||||
return $guid;
|
return $guid;
|
||||||
@ -235,7 +236,7 @@ sub zfs_create_lu {
|
|||||||
sub zfs_import_lu {
|
sub zfs_import_lu {
|
||||||
my ($scfg, $zvol) = @_;
|
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");
|
zfs_request($scfg, undef, 'import_lu', "$base/$scfg->{pool}/$zvol");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,26 +277,26 @@ sub zfs_list_zvol {
|
|||||||
|
|
||||||
my $list = ();
|
my $list = ();
|
||||||
foreach my $zvol (@$zvols) {
|
foreach my $zvol (@$zvols) {
|
||||||
my @values = split('/', $zvol->{name});
|
my @values = split('/', $zvol->{name});
|
||||||
|
|
||||||
my $pool = $values[0];
|
my $pool = $values[0];
|
||||||
my $image = $values[1];
|
my $image = $values[1];
|
||||||
|
|
||||||
next if $image !~ m/^((vm|base)-(\d+)-\S+)$/;
|
next if $image !~ m/^((vm|base)-(\d+)-\S+)$/;
|
||||||
my $owner = $3;
|
my $owner = $3;
|
||||||
|
|
||||||
my $parent = $zvol->{origin};
|
my $parent = $zvol->{origin};
|
||||||
if($zvol->{origin} && $zvol->{origin} =~ m/^$scfg->{pool}\/(\S+)$/){
|
if($zvol->{origin} && $zvol->{origin} =~ m/^$scfg->{pool}\/(\S+)$/){
|
||||||
$parent = $1;
|
$parent = $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$list->{$pool}->{$image} = {
|
$list->{$pool}->{$image} = {
|
||||||
name => $image,
|
name => $image,
|
||||||
size => $zvol->{size},
|
size => $zvol->{size},
|
||||||
parent => $parent,
|
parent => $parent,
|
||||||
format => 'raw',
|
format => 'raw',
|
||||||
vmid => $owner
|
vmid => $owner
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return $list;
|
return $list;
|
||||||
@ -309,16 +310,16 @@ sub type {
|
|||||||
|
|
||||||
sub plugindata {
|
sub plugindata {
|
||||||
return {
|
return {
|
||||||
content => [ {images => 1}, { images => 1 }],
|
content => [ {images => 1}, { images => 1 }],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub properties {
|
sub properties {
|
||||||
return {
|
return {
|
||||||
iscsiprovider => {
|
iscsiprovider => {
|
||||||
description => "iscsi provider",
|
description => "iscsi provider",
|
||||||
type => 'string',
|
type => 'string',
|
||||||
},
|
},
|
||||||
blocksize => {
|
blocksize => {
|
||||||
description => "block size",
|
description => "block size",
|
||||||
type => 'string',
|
type => 'string',
|
||||||
@ -331,11 +332,11 @@ sub options {
|
|||||||
nodes => { optional => 1 },
|
nodes => { optional => 1 },
|
||||||
disable => { optional => 1 },
|
disable => { optional => 1 },
|
||||||
portal => { fixed => 1 },
|
portal => { fixed => 1 },
|
||||||
target => { fixed => 1 },
|
target => { fixed => 1 },
|
||||||
pool => { fixed => 1 },
|
pool => { fixed => 1 },
|
||||||
blocksize => { fixed => 1 },
|
blocksize => { fixed => 1 },
|
||||||
iscsiprovider => { fixed => 1 },
|
iscsiprovider => { fixed => 1 },
|
||||||
content => { optional => 1 },
|
content => { optional => 1 },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +346,7 @@ sub parse_volname {
|
|||||||
my ($class, $volname) = @_;
|
my ($class, $volname) = @_;
|
||||||
|
|
||||||
if ($volname =~ m/^(((base|vm)-(\d+)-\S+)\/)?((base)?(vm)?-(\d+)-\S+)$/) {
|
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";
|
die "unable to parse zfs volume name '$volname'\n";
|
||||||
@ -448,7 +449,7 @@ sub alloc_image {
|
|||||||
die "unsupported format '$fmt'" if $fmt ne 'raw';
|
die "unsupported format '$fmt'" if $fmt ne 'raw';
|
||||||
|
|
||||||
die "illegal name '$name' - sould be 'vm-$vmid-*'\n"
|
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);
|
$name = &$find_free_diskname($storeid, $scfg, $vmid);
|
||||||
|
|
||||||
@ -487,31 +488,31 @@ sub list_images {
|
|||||||
|
|
||||||
if (my $dat = $cache->{zfs}->{$zfspool}) {
|
if (my $dat = $cache->{zfs}->{$zfspool}) {
|
||||||
|
|
||||||
foreach my $image (keys %$dat) {
|
foreach my $image (keys %$dat) {
|
||||||
|
|
||||||
my $volname = $dat->{$image}->{name};
|
my $volname = $dat->{$image}->{name};
|
||||||
my $parent = $dat->{$image}->{parent};
|
my $parent = $dat->{$image}->{parent};
|
||||||
|
|
||||||
my $volid = undef;
|
my $volid = undef;
|
||||||
if ($parent && $parent =~ m/^(\S+)@(\S+)$/) {
|
if ($parent && $parent =~ m/^(\S+)@(\S+)$/) {
|
||||||
my ($basename) = ($1);
|
my ($basename) = ($1);
|
||||||
$volid = "$storeid:$basename/$volname";
|
$volid = "$storeid:$basename/$volname";
|
||||||
} else {
|
} else {
|
||||||
$volid = "$storeid:$volname";
|
$volid = "$storeid:$volname";
|
||||||
}
|
}
|
||||||
|
|
||||||
my $owner = $dat->{$volname}->{vmid};
|
my $owner = $dat->{$volname}->{vmid};
|
||||||
if ($vollist) {
|
if ($vollist) {
|
||||||
my $found = grep { $_ eq $volid } @$vollist;
|
my $found = grep { $_ eq $volid } @$vollist;
|
||||||
next if !$found;
|
next if !$found;
|
||||||
} else {
|
} else {
|
||||||
next if defined ($vmid) && ($owner ne $vmid);
|
next if defined ($vmid) && ($owner ne $vmid);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $info = $dat->{$volname};
|
my $info = $dat->{$volname};
|
||||||
$info->{volid} = $volid;
|
$info->{volid} = $volid;
|
||||||
push @$res, $info;
|
push @$res, $info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $res;
|
return $res;
|
||||||
@ -526,9 +527,9 @@ sub status {
|
|||||||
my $active = 0;
|
my $active = 0;
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
($free, $used) = zfs_get_pool_stats($scfg);
|
($free, $used) = zfs_get_pool_stats($scfg);
|
||||||
$active = 1;
|
$active = 1;
|
||||||
$total = $free + $used;
|
$total = $free + $used;
|
||||||
};
|
};
|
||||||
warn $@ if $@;
|
warn $@ if $@;
|
||||||
|
|
||||||
@ -598,21 +599,21 @@ sub volume_has_feature {
|
|||||||
my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
|
my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
|
||||||
|
|
||||||
my $features = {
|
my $features = {
|
||||||
snapshot => { current => 1, snap => 1},
|
snapshot => { current => 1, snap => 1},
|
||||||
clone => { base => 1},
|
clone => { base => 1},
|
||||||
template => { current => 1},
|
template => { current => 1},
|
||||||
copy => { base => 1, current => 1},
|
copy => { base => 1, current => 1},
|
||||||
};
|
};
|
||||||
|
|
||||||
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
|
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
|
||||||
$class->parse_volname($volname);
|
$class->parse_volname($volname);
|
||||||
|
|
||||||
my $key = undef;
|
my $key = undef;
|
||||||
|
|
||||||
if ($snapname) {
|
if ($snapname) {
|
||||||
$key = 'snap';
|
$key = 'snap';
|
||||||
} else {
|
} else {
|
||||||
$key = $isBase ? 'base' : 'current';
|
$key = $isBase ? 'base' : 'current';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1 if $features->{$feature}->{$key};
|
return 1 if $features->{$feature}->{$key};
|
||||||
|
|||||||
Reference in New Issue
Block a user