Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 85 additions & 22 deletions PureStoragePlugin.pm
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,18 @@ sub properties {
default => 'no'
},
protocol => {
description => "Set storage protocol ( iscsi | fc | nvme )",
description => "Set storage protocol ( iscsi | iscsidirect | fc | nvme )",
type => 'string',
default => $default_protocol
},
target_addr => {
description => "Set storage iSCSI Target Portal address (only for protocol iscsidirect)",
type => 'string',
},
target_name => {
description => "Set storage iSCSI Target Name (only for protocol iscsidirect)",
type => 'string',
},
};
}

Expand All @@ -108,16 +116,18 @@ sub options {
address => { fixed => 1 },
token => { fixed => 1 },

hgsuffix => { optional => 1 },
vgname => { optional => 1 },
podname => { optional => 1 },
vnprefix => { optional => 1 },
check_ssl => { optional => 1 },
protocol => { optional => 1 },
nodes => { optional => 1 },
disable => { optional => 1 },
content => { optional => 1 },
format => { optional => 1 },
hgsuffix => { optional => 1 },
vgname => { optional => 1 },
podname => { optional => 1 },
vnprefix => { optional => 1 },
check_ssl => { optional => 1 },
protocol => { optional => 1 },
nodes => { optional => 1 },
disable => { optional => 1 },
content => { optional => 1 },
format => { optional => 1 },
target_addr => { optional => 1 },
target_name => { optional => 1 },
};
}

Expand Down Expand Up @@ -619,23 +629,30 @@ sub purestorage_get_wwn {
sub purestorage_volume_connection {
my ( $class, $scfg, $volname, $mode ) = @_;

my $method = $mode ? 'POST' : 'DELETE';
print "Debug :: PVE::Storage::Custom::PureStoragePlugin::sub::purestorage_volume_connection :: $method\n" if $DEBUG;

my $hname = PVE::INotify::nodename();
my $hgsuffix = $scfg->{ hgsuffix } // $default_hgsuffix;
$hname .= "-" . $hgsuffix if $hgsuffix ne "";

my $method;
my $name;
my $ignore;
if ( $mode ) {
my $ignore = '';
if ($mode == 0) {
$name = 'get volume connection';
$method = 'GET';
} elsif ($mode == -1) {
$name = 'delete volume connection';
$ignore = [ 'Volume has been destroyed.', 'Connection does not exist.' ];
$method = 'DELETE';
} elsif ($mode == 1) {
$name = 'create volume connection';
$ignore = 'Connection already exists.';
$method = 'POST';
} else {
$name = 'delete volume connection';
$ignore = [ 'Volume has been destroyed.', 'Connection does not exist.' ];
die ("Error :: PVE::Storage::Custom::PureStoragePlugin::sub::purestorage_volume_connection :: unknown mode $mode\n");
}

print "Debug :: PVE::Storage::Custom::PureStoragePlugin::sub::purestorage_volume_connection :: $method\n" if $DEBUG;

my $action = {
name => $name,
type => 'connections',
Expand All @@ -649,8 +666,22 @@ sub purestorage_volume_connection {

my $response = purestorage_api_request( $scfg, $action, 1 );

my $message = ( $response->{ errors } ? 'already ' : '' ) . ( $mode ? 'connected to' : 'disconnected from' );
print "Info :: Volume \"$volname\" is $message host \"$hname\".\n";
if ( $mode == 0 || $mode == 1 ) {
my $lun = 0;
$lun = $response->{ items }->[0]->{ lun } if $response->{ items }->[0] && $response->{ items }->[0]->{ volume }->{ name } eq purestorage_name( $scfg, $volname );
if ($lun) {
print "Info :: Volume \"$volname\" is " . ( $mode == 1 ? 'now ' : 'currently ' ) . "connected as LUN $lun to Host \"$hname\"\n";
return $lun;
} elsif ($mode == 0) {
print "Info :: Volume \"$volname\" is currently not connected to Host \"$hname\"\n";
return 0;
}
die ("Error :: Could not get LUN for Volume \"$volname\" on Host \"$hname\"\n") if ( !$response->{ errors } );
print "Info :: Volume \"$volname\" is already connected to Host \"$hname\"\n";
return 0;
}

print "Info :: Volume \"$volname\" is " . ( $response->{ errors } ? 'already ' : 'now ' ) . "disconnected from Host \"$hname\"\n";
return 1;
}

Expand Down Expand Up @@ -715,6 +746,11 @@ sub purestorage_remove_volume {
return 1;
}

sub get_protocol() {
my ( $class, $scfg ) = @_;
return $scfg->{ protocol } // $default_protocol;
}

sub purestorage_resize_volume {
my ( $class, $scfg, $volname, $size ) = @_;
print "Debug :: PVE::Storage::Custom::PureStoragePlugin::sub::purestorage_resize_volume\n" if $DEBUG;
Expand All @@ -731,6 +767,13 @@ sub purestorage_resize_volume {

my $serial = $response->{ items }->[0]->{ serial } or die "Error :: Failed to retrieve volume serial";

if ( $class->get_protocol($scfg) eq "iscsidirect" ) {
my $newsize = 0;
$newsize = $response->{ items }->[0]->{ provisioned } if ( $response->{ items }->[0]->{ name } eq purestorage_name( $scfg, $volname ) || $response->{ items }->[0]->{ source }->{ name } eq purestorage_name( $scfg, $volname ) );
die ("Error :: Could not get new size for Volume \"$volname\"\n") if (!$newsize);
return $newsize;
}

my ( $path, $wwid ) = get_device_path_wwn( $serial );

# return early if the volume is not mapped (normally should not happen)
Expand Down Expand Up @@ -895,6 +938,21 @@ sub filesystem_path {
# do we even need this?
my ( $vtype, undef, $vmid ) = $class->parse_volname( $volname );

if ( $class->get_protocol($scfg) eq "iscsidirect" ) {
# we need to explicitly call GET because otherwise we won't get the LUN id if the volume is already connected.
my $lun = $class->purestorage_volume_connection( $scfg, $volname, 0 );
if (!$lun) {
$lun = $class->purestorage_volume_connection( $scfg, $volname, 1 );
}

my $target = $scfg->{target_name};
my $portal = $scfg->{target_addr};
my $path = "iscsi://$portal/$target/$lun";

print ("Debug :: path: $path\n") if $DEBUG;
return ($path, $vmid, $vtype);
}

my ( $path, $wwid ) = $class->purestorage_get_wwn( $scfg, $volname );

if ( !defined( $path ) || !defined( $vmid ) || !defined( $vtype ) ) {
Expand Down Expand Up @@ -1033,11 +1091,14 @@ sub volume_size_info {
sub map_volume {
my ( $class, $storeid, $scfg, $volname, $snapname ) = @_;
print "Debug :: PVE::Storage::Custom::PureStoragePlugin::sub::map_volume\n" if $DEBUG;

return 0 if ( $class->get_protocol($scfg) eq "iscsidirect" );

my ( $path, $wwid ) = $class->purestorage_get_wwn( $scfg, $volname );

print "Debug :: Mapping volume \"$volname\" with WWN: " . uc( $wwid ) . ".\n" if $DEBUG;

my $protocol = $scfg->{ protocol } // $default_protocol;
my $protocol = $class->get_protocol($scfg);
if ( $protocol eq 'iscsi' || $protocol eq 'fc' ) {
scsi_scan_new( $protocol );
} elsif ( $protocol eq 'nvme' ) {
Expand All @@ -1064,6 +1125,8 @@ sub unmap_volume {
my ( $class, $storeid, $scfg, $volname, $snapname ) = @_;
print "Debug :: PVE::Storage::Custom::PureStoragePlugin::sub::unmap_volume\n" if $DEBUG;

return 0 if ( $class->get_protocol($scfg) eq "iscsidirect" );

my ( $path, $wwid ) = $class->purestorage_get_wwn( $scfg, $volname );
return 0 unless $path ne '' && -b $path;

Expand Down Expand Up @@ -1109,7 +1172,7 @@ sub deactivate_volume {

$class->unmap_volume( $storeid, $scfg, $volname, $snapname );

$class->purestorage_volume_connection( $scfg, $volname, 0 );
$class->purestorage_volume_connection( $scfg, $volname, -1 );

print "Info :: Volume \"$volname\" is deactivated.\n";

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This plugin enables the integration of Pure Storage arrays with Proxmox Virtual

Before installing and using this plugin, ensure that your Proxmox VE environment meets the following prerequisites.

### Multipath Configuration
### Multipath Configuration (not required for protocol iscsidirect)

To ensure correct operation with Pure Storage, you need to configure your multipath settings appropriately. Specifically, you need to set find_multipaths to no in your multipath.conf file. This setting disables the automatic detection of multipath devices, which is necessary for Pure Storage devices to be correctly recognized.

Expand Down Expand Up @@ -131,7 +131,9 @@ 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) |
| protocol | (`optional`, default is `iscsi`) Specifies the storage protocol (iscsi, iscsidirect, fc) |
| target_addr | (`optional`, only for protocol `iscsidirect`) Set storage iSCSI Target Portal address |
| target_name | (`optional`, only for protocol `iscsidirect`) Set storage iSCSI Target Name |

> **_NOTE:_** Ensure that the token and other sensitive information are kept secure and not exposed publicly.

Expand Down