]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage/ISCSIPlugin.pm
fix prune-backups validation (again)
[pve-storage.git] / PVE / Storage / ISCSIPlugin.pm
index e456c0d1a3afbed77b8cd918120cd09c37ef5e32..a79fcb08c56df17e1570f732eec8986bd7751c0e 100644 (file)
@@ -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);
 
@@ -44,11 +45,11 @@ sub iscsi_session_list {
     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*$/) {
+
+           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;   
+               push @{$res->{$target}}, $session;
            }
        });
     };
@@ -62,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 {
@@ -73,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).
@@ -97,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";
@@ -138,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 $@;
     }
@@ -151,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|^../../([^/]+)|) {
@@ -199,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;
            }
@@ -214,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";
        });
 
     });
@@ -239,6 +234,7 @@ sub type {
 sub plugindata {
     return {
        content => [ {images => 1, none => 1}, { images => 1 }],
+       select_existing => 1,
     };
 }
 
@@ -262,6 +258,7 @@ sub options {
         nodes => { optional => 1},
        disable => { optional => 1},
        content => { optional => 1},
+       bwlimit => { optional => 1 },
     };
 }
 
@@ -278,10 +275,12 @@ sub parse_volname {
 }
 
 sub filesystem_path {
-    my ($class, $scfg, $volname) = @_;
+    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;
@@ -311,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) = @_;
 
@@ -346,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);
 }
@@ -361,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);
     }
 }
 
@@ -378,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});
     }
 }