mirror of
https://github.com/kolesa-team/pve-purestorage-plugin.git
synced 2026-08-12 21:53:06 -06:00
Merge pull request #48 from NojuHD/fc-support
Add support for SCSI (Fibre Channel)
This commit is contained in:
+88
-11
@@ -8,6 +8,7 @@ use Data::Dumper qw( Dumper ); # DEBUG
|
||||
use IO::File ();
|
||||
use Net::IP ();
|
||||
use File::Path ();
|
||||
use File::Spec ();
|
||||
|
||||
use PVE::JSONSchema ();
|
||||
use PVE::Network ();
|
||||
@@ -31,8 +32,9 @@ $Data::Dumper::Terse = 1; # Removes `$VAR1 =` in output
|
||||
$Data::Dumper::Indent = 1; # Outputs everything in one line
|
||||
$Data::Dumper::Useqq = 1; # Uses quotes for strings
|
||||
|
||||
my $purestorage_wwn_prefix = "624a9370";
|
||||
my $default_hgsuffix = "";
|
||||
my $purestorage_wwn_prefix = '624a9370';
|
||||
my $default_hgsuffix = '';
|
||||
my $default_protocol = 'iscsi';
|
||||
|
||||
my $DEBUG = 0;
|
||||
|
||||
@@ -76,29 +78,34 @@ sub properties {
|
||||
return {
|
||||
hgsuffix => {
|
||||
description => "Host group suffx.",
|
||||
type => "string",
|
||||
type => 'string',
|
||||
default => $default_hgsuffix
|
||||
},
|
||||
address => {
|
||||
description => "PureStorage Management IP address or DNS name.",
|
||||
type => "string"
|
||||
type => 'string'
|
||||
},
|
||||
token => {
|
||||
description => "Storage API token.",
|
||||
type => "string"
|
||||
type => 'string'
|
||||
},
|
||||
podname => {
|
||||
description => 'PureStorage pod name',
|
||||
description => "PureStorage pod name",
|
||||
type => 'string'
|
||||
},
|
||||
vnprefix => {
|
||||
description => 'Prefix to add to volume name before sending it to PureStorage array',
|
||||
description => "Prefix to add to volume name before sending it to PureStorage array",
|
||||
type => 'string'
|
||||
},
|
||||
check_ssl => {
|
||||
description => "Verify the server's TLS certificate",
|
||||
type => "boolean",
|
||||
default => "no"
|
||||
type => 'boolean',
|
||||
default => 'no'
|
||||
},
|
||||
protocol => {
|
||||
description => "Set storage protocol ( iscsi | fc | nvme )",
|
||||
type => 'string',
|
||||
default => $default_protocol
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -113,6 +120,7 @@ sub options {
|
||||
podname => { optional => 1 },
|
||||
vnprefix => { optional => 1 },
|
||||
check_ssl => { optional => 1 },
|
||||
protocol => { optional => 1 },
|
||||
nodes => { optional => 1 },
|
||||
disable => { optional => 1 },
|
||||
content => { optional => 1 },
|
||||
@@ -139,6 +147,57 @@ sub exec_command {
|
||||
}
|
||||
}
|
||||
|
||||
sub scsi_scan_new {
|
||||
print "Debug :: PVE::Storage::Custom::PureStoragePlugin::sub::scsi_scan_new\n" if $DEBUG;
|
||||
my $fc_base = '/sys/class/fc_host';
|
||||
my @fc_hosts = glob( "$fc_base/*" );
|
||||
|
||||
die "Error :: sub::scsi_scan_new did not find fibre channel hosts.\n" unless @fc_hosts;
|
||||
|
||||
foreach my $fc_host ( @fc_hosts ) {
|
||||
next unless ( $fc_host =~ m/^(\/sys\/class\/fc_host\/\w+)$/ );
|
||||
my $adapter = basename( $1 );
|
||||
my $scsi_host = File::Spec->catfile( "/sys/class/scsi_host/", $adapter );
|
||||
|
||||
if ( -d $scsi_host ) {
|
||||
open my $fh, '>', File::Spec->catfile( $scsi_host, "scan" ) or die "Error :: Cannot open file: $!";
|
||||
print $fh "- - -\n";
|
||||
close $fh;
|
||||
} else {
|
||||
warn "Warning :: SCSI host path $scsi_host does not exist.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub scsi_rescan_device {
|
||||
my ( $wwid ) = @_;
|
||||
print "Debug :: PVE::Storage::Custom::PureStoragePlugin::sub::scsi_rescan_device\n" if $DEBUG;
|
||||
die "Error :: sub::scsi_rescan_device did not recive a wwid.\n" unless $wwid;
|
||||
|
||||
foreach my $device ( glob( '/sys/class/scsi_device/*' ) ) {
|
||||
next unless ( $device =~ m/^(\/sys\/class\/scsi_device\/[\d\:\\]+)$/ );
|
||||
my $tmppath = $1;
|
||||
|
||||
my $wwid_file = File::Spec->catfile( $tmppath, "device/wwid" );
|
||||
next unless -f $wwid_file;
|
||||
|
||||
open( my $wwid_fh, '<', $wwid_file ) or die "Error :: Cannot open file: $!";
|
||||
my $tmpwwid = <$wwid_fh>;
|
||||
close( $wwid_fh );
|
||||
|
||||
$tmpwwid =~ s/^naa\.//;
|
||||
$tmpwwid = "3" . lc( $tmpwwid );
|
||||
chomp( $tmpwwid );
|
||||
|
||||
if ( $tmpwwid eq $wwid ) {
|
||||
open my $rescan, '>', File::Spec->catfile( $tmppath, "device/rescan" ) or die "Error :: Cannot open file: $!";
|
||||
print $rescan "1\n";
|
||||
close $rescan;
|
||||
}
|
||||
}
|
||||
exec_command( [ $cmd->{ multipath }, '-r', $wwid ], 1 );
|
||||
}
|
||||
|
||||
sub multipath_check {
|
||||
my ( $wwid ) = @_;
|
||||
my $output = `$cmd->{ "multipath" } -l $wwid`;
|
||||
@@ -651,7 +710,16 @@ sub purestorage_resize_volume {
|
||||
|
||||
my ( $path, $wwid ) = $class->purestorage_get_wwn( $scfg, $volname );
|
||||
|
||||
exec_command( [ $cmd->{ iscsiadm }, '--mode', 'node', '--rescan' ], 1 );
|
||||
my $protocol = $scfg->{ protocol } // $default_protocol;
|
||||
if ( $protocol eq 'iscsi' ) {
|
||||
exec_command( [ $cmd->{ iscsiadm }, '--mode', 'node', '--rescan' ], 1 );
|
||||
} elsif ( $protocol eq 'fc' ) {
|
||||
scsi_rescan_device( $wwid );
|
||||
} elsif ( $protocol eq 'nvme' ) {
|
||||
die qq{Error :: Protocol: "$protocol" isn't implemented yet.\n};
|
||||
} else {
|
||||
die qq{Error :: Protocol: "$protocol" isn't a valid protocol.\n};
|
||||
}
|
||||
|
||||
exec_command( [ $cmd->{ multipathd }, 'resize', 'map', $wwid ], 1 );
|
||||
|
||||
@@ -963,7 +1031,16 @@ sub map_volume {
|
||||
|
||||
print "Debug :: Mapping volume \"$volname\" with WWN: " . uc( $wwid ) . ".\n" if $DEBUG;
|
||||
|
||||
exec_command( [ $cmd->{ iscsiadm }, '--mode', 'session', '--rescan' ], 1 );
|
||||
my $protocol = $scfg->{ protocol } // $default_protocol;
|
||||
if ( $protocol eq 'iscsi' ) {
|
||||
exec_command( [ $cmd->{ iscsiadm }, '--mode', 'session', '--rescan' ], 1 );
|
||||
} elsif ( $protocol eq 'fc' ) {
|
||||
scsi_scan_new();
|
||||
} elsif ( $protocol eq 'nvme' ) {
|
||||
die qq{Error :: Protocol: "$protocol" isn't implemented yet.\n};
|
||||
} else {
|
||||
die qq{Error :: Protocol: "$protocol" isn't a valid protocol.\n};
|
||||
}
|
||||
|
||||
my $path_exists = sub {
|
||||
return -e $path;
|
||||
|
||||
@@ -131,6 +131,7 @@ purestorage: <storage_id>
|
||||
| vnprefix | (`optional`) The prefix to prepend to name of virtual disks. |
|
||||
| hgsuffix | (`optional`) A suffix that is appended to the hostname when the plugin interacts with the Pure Storage array. This can help differentiate hosts if necessary. |
|
||||
| content | Specifies the types of content that can be stored. For virtual machine disk images, use images. |
|
||||
| protocol | (`optional`, default is `iscsi`) Specifies the storage protocol (iscsi, fc) |
|
||||
|
||||
> **_NOTE:_** Ensure that the token and other sensitive information are kept secure and not exposed publicly.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user