From 3b219e80378f04d47aedcf04fc2a931772bac4c0 Mon Sep 17 00:00:00 2001 From: Michael Rasmussen Date: Wed, 23 Oct 2013 02:53:08 +0200 Subject: [PATCH] Use ssh key stored in pmxcfg. Use ssh -i /etc/pve/priv/zfs/portal_id_rsa for remote commands Signed-off-by: Michael Rasmussen --- PVE/Storage/LunCmd/Comstar.pm | 141 +++--- PVE/Storage/LunCmd/Iet.pm | 7 +- PVE/Storage/LunCmd/Istgt.pm | 861 +++++++++++++++++----------------- PVE/Storage/ZFSPlugin.pm | 335 ++++++------- 4 files changed, 674 insertions(+), 670 deletions(-) diff --git a/PVE/Storage/LunCmd/Comstar.pm b/PVE/Storage/LunCmd/Comstar.pm index 8c01d55..45ad6a5 100644 --- a/PVE/Storage/LunCmd/Comstar.pm +++ b/PVE/Storage/LunCmd/Comstar.pm @@ -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 $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 ($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; } diff --git a/PVE/Storage/LunCmd/Iet.pm b/PVE/Storage/LunCmd/Iet.pm index e378b9f..98c062b 100644 --- a/PVE/Storage/LunCmd/Iet.pm +++ b/PVE/Storage/LunCmd/Iet.pm @@ -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); }; diff --git a/PVE/Storage/LunCmd/Istgt.pm b/PVE/Storage/LunCmd/Istgt.pm index 5c05a3d..9bbdfa0 100644 --- a/PVE/Storage/LunCmd/Istgt.pm +++ b/PVE/Storage/LunCmd/Istgt.pm @@ -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"; - }; - - $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 ''; - - return $msg; + $err .= "$line"; + }; + + $target = 'root@' . $scfg->{portal}; + + 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; }; 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 = ''; - - $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"; - - return $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"; + + foreach my $conf (@{$SETTINGS->{$lun}->{luns}}) { + $config .= "$conf->{lun} Storage " . $conf->{Storage}; + $config .= ' ' . $size_with_unit->($conf->{Size}) . "\n"; + } + $config .= "\n"; + + 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; - - return "LUN$i"; + 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; + + return "LUN$i"; }; my $init_lu_name = sub { - 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; - } + 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; + } }; 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; - - return $conf->{lun}; + 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; + + return $conf->{lun}; }; my $parser = sub { - my ($scfg) = @_; - - my $lun = undef; - my $line = 0; - - my $config = $get_config->($scfg); - my @cfgfile = split "\n", $config; - - 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 ($scfg) = @_; + + my $lun = undef; + my $line = 0; + + my $config = $get_config->($scfg); + my @cfgfile = split "\n", $config; + + 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 $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 ($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 $create_lun = sub { - 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' $!"; - - 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; + 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' $!"; + + 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; }; my $delete_lun = sub { - my ($scfg, $timeout, $method, @params) = @_; - my $res = (); - my $file = "/tmp/config$$"; - - my $target = $SETTINGS->{current}; - my $luns = (); - - 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' $!"; - - 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 ($scfg, $timeout, $method, @params) = @_; + my $res = (); + my $file = "/tmp/config$$"; + + my $target = $SETTINGS->{current}; + my $luns = (); + + 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' $!"; + + 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, - }; - } - - return $cmdmap; + 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, + }; + } + + return $cmdmap; }; my $modify_lun = sub { - 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); + 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); }; 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}; + + $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, '-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->{post_exe} && ref $res->{post_exe} eq 'CODE') { + $res->{post_exe}->(); + } + + if ($res->{msg}) { + $msg = $res->{msg}; + } - $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]; - } - - 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}->(); - } - - if ($res->{msg}) { - $msg = $res->{msg}; - } - - return $msg; + return $msg; } sub get_base { - return '/dev/zvol'; + return '/dev/zvol'; } -1; \ No newline at end of file +1; diff --git a/PVE/Storage/ZFSPlugin.pm b/PVE/Storage/ZFSPlugin.pm index 1c0acc6..d077cfb 100644 --- a/PVE/Storage/ZFSPlugin.pm +++ b/PVE/Storage/ZFSPlugin.pm @@ -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) = @_; - - 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}); - } + 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}); + } }; 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'; - } - - $target = 'root@' . $scfg->{portal}; - - my $cmd = [@ssh_cmd, $target, $zfscmd, $method, @params]; - - $msg = ''; - - my $output = sub { - my $line = shift; - $msg .= "$line\n"; - }; - - run_command($cmd, outfunc => $output, timeout => $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'; + } + + $target = 'root@' . $scfg->{portal}; + + my $cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target, $zfscmd, $method, @params]; + + $msg = ''; + + my $output = sub { + my $line = shift; + $msg .= "$line\n"; + }; + + 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; - } - - if ($reminder) { - $size = ceil($size); - } - return $size; + 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; } 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 (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; - } + 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; + } + + $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 $pool = $values[0]; - my $image = $values[1]; - - 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; - } - - $list->{$pool}->{$image} = { - name => $image, - size => $zvol->{size}, - parent => $parent, - format => 'raw', - vmid => $owner - }; + my @values = split('/', $zvol->{name}); + + my $pool = $values[0]; + my $image = $values[1]; + + 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; + } + + $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 $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 ($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 $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}; -- 2.39.2