all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Max Carrara <m.carrara@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [RFC pve-storage 28/36] plugin: iscsi: factor helper functions into common module
Date: Wed, 17 Jul 2024 11:40:26 +0200	[thread overview]
Message-ID: <20240717094034.124857-29-m.carrara@proxmox.com> (raw)
In-Reply-To: <20240717094034.124857-1-m.carrara@proxmox.com>

Because the `iscsi_discovery` subroutine is used by `PVE::Storage`
directly, move it and all other helpers independent from the plugin
into the new `PVE::Storage::Common::ISCSI` module. As the name
suggests, this new module collects ISCSI-related functionalities and
utils.

Due to the `iscsi_discovery` sub being the only subroutine that was
actually used publicly, keep its original definition and let it wrap
its "new" version from the common module. Also add a deprecation
warning for any potential users.

The code of all moved subroutines stays the same, though the subs
themselves are now also documented and use prototypes.

Signed-off-by: Max Carrara <m.carrara@proxmox.com>
---
 src/PVE/Storage.pm              |   4 +-
 src/PVE/Storage/Common.pm       |   4 +
 src/PVE/Storage/Common/ISCSI.pm | 475 ++++++++++++++++++++++++++++++++
 src/PVE/Storage/Common/Makefile |   1 +
 src/PVE/Storage/ISCSIPlugin.pm  | 255 +----------------
 5 files changed, 498 insertions(+), 241 deletions(-)
 create mode 100644 src/PVE/Storage/Common/ISCSI.pm

diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
index 57b2038..3865b44 100755
--- a/src/PVE/Storage.pm
+++ b/src/PVE/Storage.pm
@@ -24,6 +24,8 @@ use PVE::RPCEnvironment;
 use PVE::SSHInfo;
 use PVE::RESTEnvironment qw(log_warn);
 
+use PVE::Storage::Common::ISCSI;
+
 use PVE::Storage::Plugin;
 use PVE::Storage::DirPlugin;
 use PVE::Storage::LVMPlugin;
@@ -1457,7 +1459,7 @@ sub scan_iscsi {
 	die "unable to parse/resolve portal address '${portal_in}'\n";
     }
 
-    return PVE::Storage::ISCSIPlugin::iscsi_discovery([ $portal ]);
+    return PVE::Storage::Common::ISCSI::iscsi_discovery([ $portal ]);
 }
 
 sub storage_default_format {
diff --git a/src/PVE/Storage/Common.pm b/src/PVE/Storage/Common.pm
index 3cc3c37..8a52498 100644
--- a/src/PVE/Storage/Common.pm
+++ b/src/PVE/Storage/Common.pm
@@ -40,6 +40,10 @@ be grouped in a submodule can also be found here.
 
 =over
 
+=item C<PVE::Storage::Common::ISCSI>
+
+Subroutines that provide ISCSI-related functionalities.
+
 =item C<PVE::Storage::Common::LVM>
 
 Utilities concerned with LVM, such as manipulating logical volumes.
diff --git a/src/PVE/Storage/Common/ISCSI.pm b/src/PVE/Storage/Common/ISCSI.pm
new file mode 100644
index 0000000..2eb7f65
--- /dev/null
+++ b/src/PVE/Storage/Common/ISCSI.pm
@@ -0,0 +1,475 @@
+package PVE::Storage::Common::ISCSI;
+
+use strict;
+use warnings;
+
+use File::stat;
+use IO::Dir;
+use IO::File;
+
+use PVE::Network;
+use PVE::Tools qw(
+    $IPV4RE
+    $IPV6RE
+    dir_glob_foreach
+    dir_glob_regex
+    file_read_firstline
+    run_command
+);
+
+use parent qw(Exporter);
+
+our @EXPORT_OK = qw(
+    assert_iscsi_support
+    iscsi_device_list
+    iscsi_discovery
+    iscsi_login
+    iscsi_logout
+    iscsi_portals
+    iscsi_session_list
+    iscsi_session_rescan
+    iscsi_test_portal
+);
+
+=pod
+
+=head1 NAME
+
+PVE::Storage::Common::ISCSI - Provides helper subroutines that wrap commonly used ISCSI commands
+
+=head1 FUNCTIONS
+
+=cut
+
+my $ISCSIADM = '/usr/bin/iscsiadm';
+my $found_iscsi_adm_exe;
+
+=pod
+
+=head3 assert_iscsi_support
+
+    $is_supported = assert_iscsi_support($noerr)
+
+Asserts whether ISCSI operations are supported by the host, raising an exception
+if they are not.
+
+Optionally, C<$noerr> may be set to C<1> in order to return C<undef> instead
+of raising an exception.
+
+ISCSI operations are considered to be supported if C</usr/bin/iscsiadm> exists
+and is executable by the current user.
+
+=cut
+
+sub assert_iscsi_support : prototype(;$) {
+    my ($noerr) = @_;
+    return $found_iscsi_adm_exe if $found_iscsi_adm_exe; # assume it won't be removed if ever found
+
+    $found_iscsi_adm_exe = -x $ISCSIADM;
+
+    if (!$found_iscsi_adm_exe) {
+	die "error: no iscsi support - please install open-iscsi\n" if !$noerr;
+	warn "warning: no iscsi support - please install open-iscsi\n";
+    }
+    return $found_iscsi_adm_exe;
+}
+
+# Example: 192.168.122.252:3260,1 iqn.2003-01.org.linux-iscsi.proxmox-nfs.x8664:sn.00567885ba8f
+my $ISCSI_TARGET_RE = qr/^((?:$IPV4RE|\[$IPV6RE\]):\d+)\,\S+\s+(\S+)\s*$/;
+
+=pod
+
+=head3 iscsi_session_list
+
+    $active_sessions = iscsi_session_list()
+
+Scans for active ISCSI sessions and returns a hash that maps each ISCSI target
+to a list of hashes describing the session.
+
+Asserts whether ISCSI is supported on the host beforehand.
+
+The returned hash has the following structure:
+
+    {
+	'iqn.1998-01.example.hostname.iscsi:name1' => [
+	    {
+		session_id => ...,
+		portal => ...,
+	    },
+	    ...
+	],
+	'iqn.1998-01.example.hostname.iscsi:name1001' => [
+	    {
+		session_id => ...,
+		portal => ...,
+	    },
+	    {
+		session_id => ...,
+		portal => ...,
+	    },
+	    ...
+	],
+	...
+    }
+
+=cut
+
+sub iscsi_session_list : prototype() {
+    assert_iscsi_support();
+
+    my $cmd = [$ISCSIADM, '--mode', 'session'];
+
+    my $res = {};
+    eval {
+	run_command($cmd, errmsg => 'iscsi session scan failed', outfunc => sub {
+	    my $line = shift;
+	    # example: tcp: [1] 192.168.122.252:3260,1 iqn.2003-01.org.linux-iscsi.proxmox-nfs.x8664:sn.00567885ba8f (non-flash)
+	    if ($line =~ m/^tcp:\s+\[(\S+)\]\s+((?:$IPV4RE|\[$IPV6RE\]):\d+)\,\S+\s+(\S+)\s+\S+?\s*$/) {
+		my ($session_id, $portal, $target) = ($1, $2, $3);
+		# there can be several sessions per target (multipath)
+		push @{$res->{$target}}, { session_id => $session_id, portal => $portal };
+	    }
+	});
+    };
+    if (my $err = $@) {
+	die $err if $err !~ m/: No active sessions.$/i;
+    }
+
+    return $res;
+}
+
+=pod
+
+=head3 iscsi_test_portal
+
+    $is_available = iscsi_test_portal($portal)
+
+Tests whether the given ISCSI C<$portal> can be reached by pinging it.
+
+=cut
+
+sub iscsi_test_portal : prototype($) {
+    my ($portal) = @_;
+
+    my ($server, $port) = PVE::Tools::parse_host_and_port($portal);
+    return 0 if !$server;
+    return PVE::Network::tcp_ping($server, $port || 3260, 2);
+}
+
+=pod
+
+=head3 iscsi_portals
+
+    $portals = iscsi_portals($target, $portal_in)
+
+Lists all available ISCSI portals whose target equals C<$target>.
+
+Should the lookup fail, a warning with the error message is emitted and a list
+only containing C<$portal_in> is returned as a fallback.
+
+=cut
+
+sub iscsi_portals : prototype($$) {
+    my ($target, $portal_in) = @_;
+
+    assert_iscsi_support();
+
+    my $res = [];
+    my $cmd = [$ISCSIADM, '--mode', 'node'];
+    eval {
+	run_command($cmd, outfunc => sub {
+	    my $line = shift;
+
+	    if ($line =~ $ISCSI_TARGET_RE) {
+		my ($portal, $portal_target) = ($1, $2);
+		if ($portal_target eq $target) {
+		    push @{$res}, $portal;
+		}
+	    }
+	});
+    };
+
+    if ($@) {
+	warn $@;
+	return [ $portal_in ];
+    }
+
+    return $res;
+}
+
+=pod
+
+=head3 iscsi_discovery
+
+    $discovered_targets = iscsi_discovery($portals)
+
+Scans each portal in C<$portals> for available ISCSI targets and returns a hash
+that maps each target to a list of portals.
+
+Asserts whether ISCSI is supported on the host beforehand.
+
+The returned hash has the following structure:
+
+    {
+	'iqn.1998-01.example.hostname.iscsi:name1' => [
+	    '172.16.64.177:3260',
+	    ...
+	],
+	'iqn.1998-01.example.hostname.iscsi:name1001' => [
+	    '172.16.64.178:3260',
+	    '172.16.64.179:3260',
+	    ...
+	],
+	...
+    }
+
+=cut
+
+sub iscsi_discovery : prototype($) {
+    my ($portals) = @_;
+
+    assert_iscsi_support();
+
+    my $res = {};
+    for my $portal ($portals->@*) {
+	next if !iscsi_test_portal($portal); # fixme: raise exception here?
+
+	my $cmd = [$ISCSIADM, '--mode', 'discovery', '--type', 'sendtargets', '--portal', $portal];
+	eval {
+	    run_command($cmd, outfunc => sub {
+		my $line = shift;
+
+		if ($line =~ $ISCSI_TARGET_RE) {
+		    my ($portal, $target) = ($1, $2);
+		    # one target can have more than one portal (multipath)
+		    # and sendtargets should return all of them in single call
+		    push @{$res->{$target}}, $portal;
+		}
+	    });
+	};
+
+	# In case of multipath we can stop after receiving targets from any available portal
+	last if scalar(keys %$res) > 0;
+    }
+
+    return $res;
+}
+
+=pod
+
+=head3 iscsi_login
+
+    iscsi_login($target, $portals)
+
+Logs in to the given ISCSI C<$target>. Will try to L<discover|/iscsi_discovery>
+any targets for all C<$portals> beforehand.
+
+Asserts whether ISCSI is supported on the host beforehand.
+
+=cut
+
+sub iscsi_login : prototype($$) {
+    my ($target, $portals) = @_;
+
+    assert_iscsi_support();
+
+    eval { iscsi_discovery($portals); };
+    warn $@ if $@;
+
+    run_command([$ISCSIADM, '--mode', 'node', '--targetname',  $target, '--login']);
+}
+
+=pod
+
+=head3 iscsi_logout
+
+    iscsi_logout($target)
+
+Logs out of the given ISCSI C<$target>.
+
+Asserts whether ISCSI is supported on the host beforehand.
+
+=cut
+
+sub iscsi_logout : prototype($) {
+    my ($target) = @_;
+
+    assert_iscsi_support();
+
+    run_command([$ISCSIADM, '--mode', 'node', '--targetname', $target, '--logout']);
+}
+
+=pod
+
+=head3 iscsi_session_rescan
+
+    iscsi_session_rescan($session_list)
+
+Rescans each ISCSI session in C<$session_list>.
+
+Asserts whether ISCSI is supported on the host beforehand.
+
+Frequent rescans are prevented by using a lock file located at
+C</var/run/pve-iscsi-rescan.lock>. The access time of the file is used to
+determine when the last rescan was performed.
+
+=cut
+
+my $rescan_filename = "/var/run/pve-iscsi-rescan.lock";
+
+sub iscsi_session_rescan : prototype($) {
+    my $session_list = shift;
+
+    assert_iscsi_support();
+
+    my $rstat = stat($rescan_filename);
+
+    if (!$rstat) {
+	if (my $fh = IO::File->new($rescan_filename, "a")) {
+	    utime undef, undef, $fh;
+	    close($fh);
+	}
+    } else {
+	my $atime = $rstat->atime;
+	my $tdiff = time() - $atime;
+	# avoid frequent rescans
+	return if !($tdiff < 0 || $tdiff > 10);
+	utime undef, undef, $rescan_filename;
+    }
+
+    foreach my $session (@$session_list) {
+	my $cmd = [$ISCSIADM, '--mode', 'session', '--sid', $session->{session_id}, '--rescan'];
+	eval { run_command($cmd, outfunc => sub {}); };
+	warn $@ if $@;
+    }
+}
+
+my sub load_stable_scsi_paths {
+
+    my $stable_paths = {};
+
+    my $stabledir = "/dev/disk/by-id";
+
+    if (my $dh = IO::Dir->new($stabledir)) {
+	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
+	   # with dm-uuid-mpath , dm-name and scsi in name)
+           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|^../../([^/]+)|) {
+		     $stable_paths->{$1}=$tmp;
+		 }
+	   }
+       }
+       $dh->close;
+    }
+    return $stable_paths;
+}
+
+=pod
+
+=head3 iscsi_device_list
+
+    $device_list = iscsi_device_list()
+
+Reads and parses the metadata of all ISCSI devices connected to the host,
+returning a nested hash that maps ISCSI targets to the parsed device data.
+
+Devices that cannot be parsed are silently ignored.
+
+The returned hash has the following structure:
+
+    {
+	'iqn.2024-07.tld.example.hostname:lun01' => {
+	    '0.0.1.scsi-360000000000000000e00000000010001' => {
+		'channel' => 0,
+		'format' => 'raw',
+		'id' => 0,
+		'lun' => 1,
+		'size' => '17179869184',
+		'vmid' => 0
+	    },
+	    ...
+	},
+	'iqn.2024-07.tld.example.hostname.lun02' => {
+	    '0.0.1.scsi-360000000000000000e00000000020001' => {
+		'channel' => 0,
+		'format' => 'raw',
+		'id' => 0,
+		'lun' => 1,
+		'size' => '17179869184',
+		'vmid' => 0
+	    },
+	    ...
+	},
+	...
+    }
+
+=cut
+
+sub iscsi_device_list : prototype() {
+
+    my $res = {};
+
+    my $dirname = '/sys/class/iscsi_session';
+
+    my $stable_paths = load_stable_scsi_paths();
+
+    dir_glob_foreach($dirname, 'session(\d+)', sub {
+	my ($ent, $session) = @_;
+
+	my $target = file_read_firstline("$dirname/$ent/targetname");
+	return if !$target;
+
+	my (undef, $host) = dir_glob_regex("$dirname/$ent/device", 'target(\d+):.*');
+	return if !defined($host);
+
+	dir_glob_foreach("/sys/bus/scsi/devices", "$host:" . '(\d+):(\d+):(\d+)', sub {
+	    my ($tmp, $channel, $id, $lun) = @_;
+
+	    my $type = file_read_firstline("/sys/bus/scsi/devices/$tmp/type");
+	    return if !defined($type) || $type ne '0'; # list disks only
+
+	    my $bdev;
+	    if (-d "/sys/bus/scsi/devices/$tmp/block") { # newer kernels
+		(undef, $bdev) = dir_glob_regex("/sys/bus/scsi/devices/$tmp/block/", '([A-Za-z]\S*)');
+	    } else {
+		(undef, $bdev) = dir_glob_regex("/sys/bus/scsi/devices/$tmp", 'block:(\S+)');
+	    }
+	    return if !$bdev;
+
+	    #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;
+	    }
+
+	    my $blockdev = $stable_paths->{$bdev};
+	    return if !$blockdev;
+
+	    my $size = file_read_firstline("/sys/block/$bdev/size");
+	    return if !$size;
+
+	    my $volid = "$channel.$id.$lun.$blockdev";
+
+	    $res->{$target}->{$volid} = {
+		'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";
+	});
+
+    });
+
+    return $res;
+}
+
+
+1;
diff --git a/src/PVE/Storage/Common/Makefile b/src/PVE/Storage/Common/Makefile
index 863f7c7..e15a47c 100644
--- a/src/PVE/Storage/Common/Makefile
+++ b/src/PVE/Storage/Common/Makefile
@@ -1,4 +1,5 @@
 SOURCES = \
+	  ISCSI.pm \
 	  LVM.pm \
 	  Path.pm \
 
diff --git a/src/PVE/Storage/ISCSIPlugin.pm b/src/PVE/Storage/ISCSIPlugin.pm
index 2bdd9a2..8a56cfe 100644
--- a/src/PVE/Storage/ISCSIPlugin.pm
+++ b/src/PVE/Storage/ISCSIPlugin.pm
@@ -8,254 +8,29 @@ use IO::Dir;
 use IO::File;
 
 use PVE::JSONSchema qw(get_standard_option);
+use PVE::Storage::Common qw(get_deprecation_warning);
+use PVE::Storage::Common::ISCSI qw(
+    assert_iscsi_support
+    iscsi_device_list
+    iscsi_login
+    iscsi_logout
+    iscsi_portals
+    iscsi_session_list
+    iscsi_session_rescan
+    iscsi_test_portal
+);
 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);
 
-# iscsi helper function
-
-my $ISCSIADM = '/usr/bin/iscsiadm';
-
-my $found_iscsi_adm_exe;
-my sub assert_iscsi_support {
-    my ($noerr) = @_;
-    return $found_iscsi_adm_exe if $found_iscsi_adm_exe; # assume it won't be removed if ever found
-
-    $found_iscsi_adm_exe = -x $ISCSIADM;
-
-    if (!$found_iscsi_adm_exe) {
-	die "error: no iscsi support - please install open-iscsi\n" if !$noerr;
-	warn "warning: no iscsi support - please install open-iscsi\n";
-    }
-    return $found_iscsi_adm_exe;
-}
-
-# Example: 192.168.122.252:3260,1 iqn.2003-01.org.linux-iscsi.proxmox-nfs.x8664:sn.00567885ba8f
-my $ISCSI_TARGET_RE = qr/^((?:$IPV4RE|\[$IPV6RE\]):\d+)\,\S+\s+(\S+)\s*$/;
-
-sub iscsi_session_list {
-    assert_iscsi_support();
-
-    my $cmd = [$ISCSIADM, '--mode', 'session'];
-
-    my $res = {};
-    eval {
-	run_command($cmd, errmsg => 'iscsi session scan failed', outfunc => sub {
-	    my $line = shift;
-	    # example: tcp: [1] 192.168.122.252:3260,1 iqn.2003-01.org.linux-iscsi.proxmox-nfs.x8664:sn.00567885ba8f (non-flash)
-	    if ($line =~ m/^tcp:\s+\[(\S+)\]\s+((?:$IPV4RE|\[$IPV6RE\]):\d+)\,\S+\s+(\S+)\s+\S+?\s*$/) {
-		my ($session_id, $portal, $target) = ($1, $2, $3);
-		# there can be several sessions per target (multipath)
-		push @{$res->{$target}}, { session_id => $session_id, portal => $portal };
-	    }
-	});
-    };
-    if (my $err = $@) {
-	die $err if $err !~ m/: No active sessions.$/i;
-    }
-
-    return $res;
-}
-
-sub iscsi_test_portal {
-    my ($portal) = @_;
-
-    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_portals {
-    my ($target, $portal_in) = @_;
-
-    assert_iscsi_support();
-
-    my $res = [];
-    my $cmd = [$ISCSIADM, '--mode', 'node'];
-    eval {
-	run_command($cmd, outfunc => sub {
-	    my $line = shift;
-
-	    if ($line =~ $ISCSI_TARGET_RE) {
-		my ($portal, $portal_target) = ($1, $2);
-		if ($portal_target eq $target) {
-		    push @{$res}, $portal;
-		}
-	    }
-	});
-    };
-
-    if ($@) {
-	warn $@;
-	return [ $portal_in ];
-    }
-
-    return $res;
-}
-
 sub iscsi_discovery {
     my ($portals) = @_;
 
-    assert_iscsi_support();
-
-    my $res = {};
-    for my $portal ($portals->@*) {
-	next if !iscsi_test_portal($portal); # fixme: raise exception here?
-
-	my $cmd = [$ISCSIADM, '--mode', 'discovery', '--type', 'sendtargets', '--portal', $portal];
-	eval {
-	    run_command($cmd, outfunc => sub {
-		my $line = shift;
-
-		if ($line =~ $ISCSI_TARGET_RE) {
-		    my ($portal, $target) = ($1, $2);
-		    # one target can have more than one portal (multipath)
-		    # and sendtargets should return all of them in single call
-		    push @{$res->{$target}}, $portal;
-		}
-	    });
-	};
-
-	# In case of multipath we can stop after receiving targets from any available portal
-	last if scalar(keys %$res) > 0;
-    }
-
-    return $res;
-}
-
-sub iscsi_login {
-    my ($target, $portals) = @_;
-
-    assert_iscsi_support();
-
-    eval { iscsi_discovery($portals); };
-    warn $@ if $@;
+    warn get_deprecation_warning(
+	"PVE::Storage::Common::ISCSI::iscsi_discovery"
+    );
 
-    run_command([$ISCSIADM, '--mode', 'node', '--targetname',  $target, '--login']);
-}
-
-sub iscsi_logout {
-    my ($target) = @_;
-
-    assert_iscsi_support();
-
-    run_command([$ISCSIADM, '--mode', 'node', '--targetname', $target, '--logout']);
-}
-
-my $rescan_filename = "/var/run/pve-iscsi-rescan.lock";
-
-sub iscsi_session_rescan {
-    my $session_list = shift;
-
-    assert_iscsi_support();
-
-    my $rstat = stat($rescan_filename);
-
-    if (!$rstat) {
-	if (my $fh = IO::File->new($rescan_filename, "a")) {
-	    utime undef, undef, $fh;
-	    close($fh);
-	}
-    } else {
-	my $atime = $rstat->atime;
-	my $tdiff = time() - $atime;
-	# avoid frequent rescans
-	return if !($tdiff < 0 || $tdiff > 10);
-	utime undef, undef, $rescan_filename;
-    }
-
-    foreach my $session (@$session_list) {
-	my $cmd = [$ISCSIADM, '--mode', 'session', '--sid', $session->{session_id}, '--rescan'];
-	eval { run_command($cmd, outfunc => sub {}); };
-	warn $@ if $@;
-    }
-}
-
-sub load_stable_scsi_paths {
-
-    my $stable_paths = {};
-
-    my $stabledir = "/dev/disk/by-id";
-
-    if (my $dh = IO::Dir->new($stabledir)) {
-	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
-	   # with dm-uuid-mpath , dm-name and scsi in name)
-           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|^../../([^/]+)|) {
-		     $stable_paths->{$1}=$tmp;
-		 }
-	   }
-       }
-       $dh->close;
-    }
-    return $stable_paths;
-}
-
-sub iscsi_device_list {
-
-    my $res = {};
-
-    my $dirname = '/sys/class/iscsi_session';
-
-    my $stable_paths = load_stable_scsi_paths();
-
-    dir_glob_foreach($dirname, 'session(\d+)', sub {
-	my ($ent, $session) = @_;
-
-	my $target = file_read_firstline("$dirname/$ent/targetname");
-	return if !$target;
-
-	my (undef, $host) = dir_glob_regex("$dirname/$ent/device", 'target(\d+):.*');
-	return if !defined($host);
-
-	dir_glob_foreach("/sys/bus/scsi/devices", "$host:" . '(\d+):(\d+):(\d+)', sub {
-	    my ($tmp, $channel, $id, $lun) = @_;
-
-	    my $type = file_read_firstline("/sys/bus/scsi/devices/$tmp/type");
-	    return if !defined($type) || $type ne '0'; # list disks only
-
-	    my $bdev;
-	    if (-d "/sys/bus/scsi/devices/$tmp/block") { # newer kernels
-		(undef, $bdev) = dir_glob_regex("/sys/bus/scsi/devices/$tmp/block/", '([A-Za-z]\S*)');
-	    } else {
-		(undef, $bdev) = dir_glob_regex("/sys/bus/scsi/devices/$tmp", 'block:(\S+)');
-	    }
-	    return if !$bdev;
-
-	    #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;
-	    }
-
-	    my $blockdev = $stable_paths->{$bdev};
-	    return if !$blockdev;
-
-	    my $size = file_read_firstline("/sys/block/$bdev/size");
-	    return if !$size;
-
-	    my $volid = "$channel.$id.$lun.$blockdev";
-
-	    $res->{$target}->{$volid} = {
-		'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";
-	});
-
-    });
-
-    return $res;
+    return PVE::Storage::Common::ISCSI::iscsi_discovery($portals);
 }
 
 # Configuration
-- 
2.39.2



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


  parent reply	other threads:[~2024-07-17  9:43 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-17  9:39 [pve-devel] [RFC pve-storage 00/36] Refactor / Cleanup of Storage Plugins Max Carrara
2024-07-17  9:39 ` [pve-devel] [RFC pve-storage 01/36] plugin: base: remove old fixme comments Max Carrara
2024-07-17 16:02   ` Thomas Lamprecht
2024-07-18  7:43     ` Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 02/36] plugin: btrfs: make plugin-specific helpers private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 03/36] plugin: cephfs: " Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 04/36] api: remove unused import of CIFS storage plugin Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 05/36] plugin: cifs: make plugin-specific helpers private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 06/36] api: remove unused import of LVM storage plugin Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 07/36] common: introduce common module Max Carrara
2024-12-13 15:40   ` Fiona Ebner
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 08/36] plugin: dir: move helper subs of directory plugin to common modules Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 09/36] plugin: lvm: move LVM helper subroutines into separate common module Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 10/36] api: replace usages of deprecated LVM helper subs with new ones Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 11/36] plugin: lvmthin: replace usages of deprecated LVM helpers " Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 12/36] plugin: lvmthin: move helper that lists thinpools to common LVM module Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 13/36] common: lvm: update code style Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 14/36] api: replace usages of deprecated LVM thin pool helper sub Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 15/36] plugin: btrfs: replace deprecated helpers from directory plugin Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 16/36] plugin: dir: factor storage methods into separate common subs Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 17/36] plugin: dir: factor path validity check into helper methods Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 18/36] plugin: btrfs: remove dependency on directory plugin Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 19/36] plugin: cifs: " Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 20/36] plugin: cephfs: " Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 21/36] plugin: nfs: " Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 22/36] plugin: btrfs: make helper methods private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 23/36] plugin: esxi: make helper subroutines private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 24/36] plugin: esxi: remove unused helper subroutine `query_vmdk_size` Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 25/36] plugin: esxi: make helper methods private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 26/36] plugin: gluster: make helper subroutines private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 27/36] plugin: iscsi-direct: make helper subroutine `iscsi_ls` private Max Carrara
2024-07-17  9:40 ` Max Carrara [this message]
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 29/36] plugin: iscsi: make helper subroutine `iscsi_session` private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 30/36] plugin: lvm: update definition of subroutine `check_tags` Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 31/36] plugin: lvmthin: update definition of subroutine `activate_lv` Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 32/36] plugin: nfs: make helper subroutines private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 33/36] plugin: rbd: update private sub signatures and make helpers private Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 34/36] common: zfs: introduce module for common ZFS helpers Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 35/36] plugin: zfspool: move helper `zfs_parse_zvol_list` to common module Max Carrara
2024-07-17  9:40 ` [pve-devel] [RFC pve-storage 36/36] plugin: zfspool: refactor method `zfs_request` into helper subroutine Max Carrara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240717094034.124857-29-m.carrara@proxmox.com \
    --to=m.carrara@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal