X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FStorage%2FISCSIPlugin.pm;h=a79fcb08c56df17e1570f732eec8986bd7751c0e;hb=5ef50a826296707af689d21cd8a782e26ae745dd;hp=f430897a58b7fc04ac1bf94565f173e0d4f730ca;hpb=32437ed2791882342928e081bcbffeb9c70cdc59;p=pve-storage.git diff --git a/PVE/Storage/ISCSIPlugin.pm b/PVE/Storage/ISCSIPlugin.pm index f430897..a79fcb0 100644 --- a/PVE/Storage/ISCSIPlugin.pm +++ b/PVE/Storage/ISCSIPlugin.pm @@ -2,13 +2,14 @@ package PVE::Storage::ISCSIPlugin; use strict; use warnings; + use File::stat; use IO::Dir; use IO::File; -use PVE::Tools qw(run_command file_read_firstline trim dir_glob_regex dir_glob_foreach); -use PVE::Storage::Plugin; + use PVE::JSONSchema qw(get_standard_option); -use Net::Ping; +use PVE::Storage::Plugin; +use PVE::Tools qw(run_command file_read_firstline trim dir_glob_regex dir_glob_foreach $IPV4RE $IPV6RE); use base qw(PVE::Storage::Plugin); @@ -41,16 +42,20 @@ sub iscsi_session_list { my $res = {}; - run_command($cmd, outfunc => sub { - my $line = shift; + eval { + run_command($cmd, errmsg => 'iscsi session scan failed', outfunc => sub { + my $line = shift; - if ($line =~ m/^tcp:\s+\[(\S+)\]\s+\S+\s+(\S+)\s*$/) { - my ($session, $target) = ($1, $2); - # there can be several sessions per target (multipath) - push @{$res->{$target}}, $session; - - } - }); + if ($line =~ m/^tcp:\s+\[(\S+)\]\s+\S+\s+(\S+)(\s+\S+)?\s*$/) { + my ($session, $target) = ($1, $2); + # there can be several sessions per target (multipath) + push @{$res->{$target}}, $session; + } + }); + }; + if (my $err = $@) { + die $err if $err !~ m/: No active sessions.$/i; + } return $res; } @@ -58,10 +63,9 @@ sub iscsi_session_list { sub iscsi_test_portal { my ($portal) = @_; - my ($server, $port) = split(':', $portal); - my $p = Net::Ping->new("tcp", 2); - $p->port_number($port || 3260); - return $p->ping($server); + my ($server, $port) = PVE::Tools::parse_host_and_port($portal); + return 0 if !$server; + return PVE::Network::tcp_ping($server, $port || 3260, 2); } sub iscsi_discovery { @@ -69,17 +73,14 @@ sub iscsi_discovery { check_iscsi_support (); - my $cmd = [$ISCSIADM, '--mode', 'discovery', '--type', 'sendtargets', - '--portal', $portal]; - my $res = {}; - return $res if !iscsi_test_portal($portal); # fixme: raise exception here? + my $cmd = [$ISCSIADM, '--mode', 'discovery', '--type', 'sendtargets', '--portal', $portal]; run_command($cmd, outfunc => sub { my $line = shift; - if ($line =~ m/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+)\,\S+\s+(\S+)\s*$/) { + if ($line =~ m/^((?:$IPV4RE|\[$IPV6RE\]):\d+)\,\S+\s+(\S+)\s*$/) { my $portal = $1; my $target = $2; # one target can have more than one portal (multipath). @@ -93,22 +94,20 @@ sub iscsi_discovery { sub iscsi_login { my ($target, $portal_in) = @_; - check_iscsi_support (); + check_iscsi_support(); - eval { iscsi_discovery ($portal_in); }; + eval { iscsi_discovery($portal_in); }; warn $@ if $@; - my $cmd = [$ISCSIADM, '--mode', 'node', '--targetname', $target, '--login']; - run_command($cmd); + run_command([$ISCSIADM, '--mode', 'node', '--targetname', $target, '--login']); } sub iscsi_logout { my ($target, $portal) = @_; - check_iscsi_support (); + check_iscsi_support(); - my $cmd = [$ISCSIADM, '--mode', 'node', '--targetname', $target, '--logout']; - run_command($cmd); + run_command([$ISCSIADM, '--mode', 'node', '--targetname', $target, '--logout']); } my $rescan_filename = "/var/run/pve-iscsi-rescan.lock"; @@ -134,7 +133,7 @@ sub iscsi_session_rescan { } foreach my $session (@$session_list) { - my $cmd = [$ISCSIADM, '--mode', 'session', '-r', $session, '-R']; + my $cmd = [$ISCSIADM, '--mode', 'session', '--sid', $session, '--rescan']; eval { run_command($cmd, outfunc => sub {}); }; warn $@ if $@; } @@ -147,11 +146,11 @@ sub load_stable_scsi_paths { my $stabledir = "/dev/disk/by-id"; if (my $dh = IO::Dir->new($stabledir)) { - while (defined(my $tmp = $dh->read)) { + foreach my $tmp (sort $dh->read) { # exclude filenames with part in name (same disk but partitions) - # use only filenames with scsi(with multipath i have the same device + # use only filenames with scsi(with multipath i have the same device # with dm-uuid-mpath , dm-name and scsi in name) - if($tmp !~ m/-part\d+$/ && $tmp =~ m/^scsi-/) { + if($tmp !~ m/-part\d+$/ && ($tmp =~ m/^scsi-/ || $tmp =~ m/^dm-uuid-mpath-/)) { my $path = "$stabledir/$tmp"; my $bdevdest = readlink($path); if ($bdevdest && $bdevdest =~ m|^../../([^/]+)|) { @@ -195,8 +194,8 @@ sub iscsi_device_list { } return if !$bdev; - #check multipath - if (-d "/sys/block/$bdev/holders") { + #check multipath + if (-d "/sys/block/$bdev/holders") { my $multipathdev = dir_glob_regex("/sys/block/$bdev/holders", '[A-Za-z]\S*'); $bdev = $multipathdev if $multipathdev; } @@ -210,15 +209,15 @@ sub iscsi_device_list { my $volid = "$channel.$id.$lun.$blockdev"; $res->{$target}->{$volid} = { - 'format' => 'raw', - 'size' => int($size * 512), + 'format' => 'raw', + 'size' => int($size * 512), 'vmid' => 0, # not assigned to any vm 'channel' => int($channel), 'id' => int($id), 'lun' => int($lun), }; - #print "TEST: $target $session $host,$bus,$tg,$lun $blockdev\n"; + #print "TEST: $target $session $host,$bus,$tg,$lun $blockdev\n"; }); }); @@ -235,6 +234,7 @@ sub type { sub plugindata { return { content => [ {images => 1, none => 1}, { images => 1 }], + select_existing => 1, }; } @@ -258,6 +258,7 @@ sub options { nodes => { optional => 1}, disable => { optional => 1}, content => { optional => 1}, + bwlimit => { optional => 1 }, }; } @@ -267,17 +268,19 @@ sub parse_volname { my ($class, $volname) = @_; if ($volname =~ m!^\d+\.\d+\.\d+\.(\S+)$!) { - return ('images', $1, undef); + return ('images', $1, undef, undef, undef, undef, 'raw'); } die "unable to parse iscsi volume name '$volname'\n"; } -sub path { - my ($class, $scfg, $volname) = @_; +sub filesystem_path { + my ($class, $scfg, $volname, $snapname) = @_; + + die "snapshot is not possible on iscsi storage\n" if defined($snapname); my ($vtype, $name, $vmid) = $class->parse_volname($volname); - + my $path = "/dev/disk/by-id/$name"; return wantarray ? ($path, $vmid, $vtype) : $path; @@ -290,7 +293,7 @@ sub create_base { } sub clone_image { - my ($class, $scfg, $storeid, $volname, $vmid) = @_; + my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_; die "can't clone images in iscsi storage\n"; } @@ -307,6 +310,20 @@ sub free_image { die "can't free space in iscsi storage\n"; } +# list all luns regardless of set content_types, since we need it for +# listing in the gui and we can only have images anyway +sub list_volumes { + my ($class, $storeid, $scfg, $vmid, $content_types) = @_; + + my $res = $class->list_images($storeid, $scfg, $vmid); + + for my $item (@$res) { + $item->{content} = 'images'; # we only have images + } + + return $res; +} + sub list_images { my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_; @@ -342,12 +359,17 @@ sub list_images { return $res; } +sub iscsi_session { + my ($cache, $target) = @_; + $cache->{iscsi_sessions} = iscsi_session_list() if !$cache->{iscsi_sessions}; + return $cache->{iscsi_sessions}->{$target}; +} + sub status { my ($class, $storeid, $scfg, $cache) = @_; - $cache->{iscsi_sessions} = iscsi_session_list() if !$cache->{iscsi_sessions}; - - my $active = defined($cache->{iscsi_sessions}->{$scfg->{target}}); + my $session = iscsi_session($cache, $scfg->{target}); + my $active = defined($session) ? 1 : 0; return (0, 0, 0, $active); } @@ -357,15 +379,14 @@ sub activate_storage { return if !check_iscsi_support(1); - $cache->{iscsi_sessions} = iscsi_session_list() if !$cache->{iscsi_sessions}; + my $session = iscsi_session($cache, $scfg->{target}); - my $iscsi_sess = $cache->{iscsi_sessions}->{$scfg->{target}}; - if (!defined ($iscsi_sess)) { + if (!defined ($session)) { eval { iscsi_login($scfg->{target}, $scfg->{portal}); }; warn $@ if $@; } else { # make sure we get all devices - iscsi_session_rescan($iscsi_sess); + iscsi_session_rescan($session); } } @@ -374,11 +395,7 @@ sub deactivate_storage { return if !check_iscsi_support(1); - $cache->{iscsi_sessions} = iscsi_session_list() if !$cache->{iscsi_sessions}; - - my $iscsi_sess = $cache->{iscsi_sessions}->{$scfg->{target}}; - - if (defined ($iscsi_sess)) { + if (defined(iscsi_session($cache, $scfg->{target}))) { iscsi_logout($scfg->{target}, $scfg->{portal}); } } @@ -398,6 +415,21 @@ sub volume_resize { sub volume_has_feature { my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_; + my $features = { + copy => { current => 1}, + }; + + my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) = + $class->parse_volname($volname); + + my $key = undef; + if($snapname){ + $key = 'snap'; + }else{ + $key = $isBase ? 'base' : 'current'; + } + return 1 if $features->{$feature}->{$key}; + return undef; }