Merge pull request #131 from TheGrandWazoo/master

Version 2.3.0-1
This commit is contained in:
Kevin Scott Adams 2023-02-20 13:28:28 -05:00 committed by GitHub
commit 927e51a524
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1427 additions and 141 deletions

17
.github/stale.yml vendored Normal file
View File

@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

105
README.md
View File

@ -1,63 +1,66 @@
# FreeNAS ZFS over iSCSI interface [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=TCLNEMBUYQUXN&source=url) # TrueNAS ZFS over iSCSI interface [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=TCLNEMBUYQUXN&source=url)
## Thank you for all that have donated to the project ### Updates 2023-02-12<br/> - Added `systemctl restart pvescheduler.service` command to the package.
#### Roadmap
* Fix automated builds.
* Production - 'main' repo component.
* Package the patches with the deb package.
* Remove the need for the git dependency.
* Change to LWP::UserAgent
* Remove depenancy of the REST::Client because LWP::UserAgent is already installed and used by Proxmox VE.
* Change from FreeNAS to TrueNAS.
* Cleanup the FreeNAS repo and name everything to TrueNAS to be inline with the product.
* Add API key for direct TrueNAS services.
* Will be a new enable field and API key and will only be used by the plugin.
* You will still need the SSH keys, username, and password because of Proxmox VE using `iscsiadm` to get the list of disks.
* This is tricky because the format needs to be that of the output of 'zfs list' which is not part of the LunCmd but that of the backend Proxmox VE system and the API's do a bunch of JSON stuff.
## Thank you for all that have recently donated to the project - Updated 2022-06-04
Alexander Finkhäuser - Recurring
Bjarte Kvamme - Recurring
Jonathan Schober - Recurring
Frederic Silvi
Security Camera
Vincent Cui
Jakub Jochec
Mark Komarinski
Jesse Bryan
Maksym Vasylenko
Daniel Most
Velocity Host
Robert Hancock
Clevvi Technology Clevvi Technology
Mark Elkins - Reoccuring Mark Elkins
Marc Hodler Marc Hodler
Martin Gonzalez Martin Gonzalez
### 'main' repo (Follows a release branch - Current 2.x) Currently unavailable.
Will be production ready code that has been tested (as best as possible) from the 'testing' repo.
I have created a debian repo that holds a package to install scripts into the Proxmox VE system that will automatically do all the necessary patching when one or any combo of the following files are changed in the Proxmox VE stream: ### 'testing' repo (Follows the master branch)
``` Will be 'beta' code for features, bugs, and updates.
/usr/share/pve-manager/js/pvemanagerlib.js <- From package pve-manager
/usr/share/pve-docs/api-viewer/apidoc.js <- From package pve-docs
/usr/share/perl5/PVE/Storage/ZFSPlugin.pm <- From package libpve-storage-perl
```
It will also install the /usr/share/perl5/PVE/Storage/LunCmd/FreeNAS.pm (The FreeNAS API plugin), git and librest-client-perl
If you wish, you may remove the directory 'freenas-proxmox' where your system is currently ## New Installs.
housing the repo and then issue the following to have a clean system before installing the Issue the following from a command line:
package.
On Proxmox 5
```bash ```bash
apt install --reinstall pve-manager pve-docs libpve-storage-perl curl https://ksatechnologies.jfrog.io/artifactory/ksa-repo-gpg/ksatechnologies-release.gpg -o /etc/apt/trusted.gpg.d/ksatechnologies-release.gpg
``` curl https://ksatechnologies.jfrog.io/artifactory/ksa-repo-gpg/ksatechnologies-repo.list -o /etc/apt/sources.list.d/ksatechnologies-repo.list
On Proxmox 6
```bash
apt reinstall pve-manager pve-docs libpve-storage-perl
```
Issue the following to install the repo and get your Proxmox VE updating the FreeNAS patches automatically:
```bash
wget http://repo.ksatechnologies.com/debian/pve/ksatechnologies-release.gpg -O /etc/apt/trusted.gpg.d/ksatechnologies-repo.gpg
echo "deb http://repo.ksatechnologies.com/debian/pve stable freenas-proxmox" > /etc/apt/sources.list.d/ksatechnologies-repo.list
```
### I will be using a 'testing' repo to develop the new phase of the Proxmox VE FreeNAS plugin.
#### This next phase will introduce the following...
* Auto detection of the Proxmox VE version
* Auto detection of the FreeNAS version so it will use the V1 or V2 API's or you can select it manually via the Proxmox VE FreeNAS modal
* Remove the need for SSH keys and use the API
* This is tricky because the format needs to be that of the output of'zfs list' which is not part of the LunCmd but that of the backend Proxmox VE system and the API's do a bunch of JSON stuff.
#### If you'd like, you may also issue the following commands now or later to use the 'testing' repo.
#### Just comment the 'stable' line and uncomment the 'testing' line in
#### /etc/apt/sources.list.d/ksatechnologies-repo.list to use. 'testing' is disabled be default.
```bash
echo "" >> /etc/apt/sources.list.d/ksatechnologies-repo.list
echo "# deb http://repo.ksatechnologies.com/debian/pve testing freenas-proxmox" >> /etc/apt/sources.list.d/ksatechnologies-repo.list
``` ```
Then issue the following to install the package Then issue the following to install the package
``` ```bash
apt update apt update
apt install freenas-proxmox apt install freenas-proxmox
``` ```
Then just do your regular upgrade via apt to your system; the package will automatically Before freenas-proxmox-2.2.0-0-beta8 please issue the following:
issue all commands to patch the files. ```
systemctl restart pvescheduler.service
```
due to this post https://github.com/TheGrandWazoo/freenas-proxmox/issues/109#issuecomment-1367527917
Then just do your regular upgrade via apt at the command line or the Proxmox Update subsystem; the package will automatically issue all commands to patch the files.
```bash ```bash
apt update apt update
apt [full|dist]-upgrade apt [full|dist]-upgrade
@ -67,16 +70,16 @@ If you wish not to use the package you may remove it at anytime with
``` ```
apt [remove|purge] freenas-proxmox apt [remove|purge] freenas-proxmox
``` ```
This will place you back to a normal and unpatched Proxmox VE install. This will place you back to a normal and non-patched Proxmox VE install.
Please be aware that this plugin uses the FreeNAS APIs and NOT the ssh/scp interface like the other plugins use, but... #### NOTE: Please be aware that this plugin uses the TrueNAS APIs but still uses SSH keys due to the underlying Proxmox VE perl modules that use the ```iscsiadm``` command.
You will still need to configure the SSH connector for listing the ZFS Pools because this is currently being done in a Proxmox module (ZFSPoolPlugin.pm). To configure this please follow the steps at https://pve.proxmox.com/wiki/Storage:_ZFS_over_iSCSI that have to do with SSH between Proxmox VE and FreeNAS. The code segment should start out `mkdir /etc/pve/priv/zfs`. You will still need to configure the SSH connector for listing the ZFS Pools because this is currently being done in a Proxmox module (ZFSPoolPlugin.pm). To configure this please follow the steps at https://pve.proxmox.com/wiki/Storage:_ZFS_over_iSCSI that have to do with SSH between Proxmox VE and TrueNAS. The code segment should start out `mkdir /etc/pve/priv/zfs`.
1. Remember to follow the instructions mentioned above for the SSH keys. 1. Remember to follow the instructions mentioned above for the SSH keys.
1. Refresh the Proxmox GUI in your browser to load the new Javascript code. 2. Refresh the Proxmox GUI in your browser to load the new Javascript code.
1. Add your new FreeNAS ZFS-over-iSCSI storage using the FreeNAS-API. 3. Add your new TrueNAS ZFS-over-iSCSI storage using the TrueNAS-API.
1. Thanks for your support. 4. Thanks for your support.

View File

@ -27,6 +27,8 @@ my $runawayprevent = 0; # Recursion prevention variable
my $freenas_api_version = "v1.0"; # Default to v1.0 of the API's my $freenas_api_version = "v1.0"; # Default to v1.0 of the API's
my $freenas_api_methods = undef; # API Methods Nested HASH Ref my $freenas_api_methods = undef; # API Methods Nested HASH Ref
my $freenas_api_variables = undef; # API Variable Nested HASH Ref my $freenas_api_variables = undef; # API Variable Nested HASH Ref
my $truenas_version = undef;
my $truenas_release_type = "Production";
# FreeNAS/TrueNAS (CORE) API Versioning HashRef Matrix # FreeNAS/TrueNAS (CORE) API Versioning HashRef Matrix
my $freenas_api_version_matrix = { my $freenas_api_version_matrix = {
@ -197,52 +199,45 @@ sub run_list_view {
# #
# #
# # Optimized
sub run_list_lu { sub run_list_lu {
my ($scfg, $timeout, $method, $result_value_type, @params) = @_; my ($scfg, $timeout, $method, $result_value_type, @params) = @_;
my $object = $params[0]; my $object = $params[0];
syslog("info", (caller(0))[3] . " : called with (method=$method; result_value_type=$result_value_type; object=$object)");
my $result = undef; my $result = undef;
my $luns = freenas_list_lu($scfg); my $luns = freenas_list_lu($scfg);
foreach my $lun (@$luns) { syslog("info", (caller(0))[3] . " : called with (method: '$method'; result_value_type: '$result_value_type'; param[0]: '$object')");
syslog("info", (caller(0))[3] . " : Verifing '$lun->{$freenas_api_variables->{'extentpath'}}' and '$object'");
if ($dev_prefix . $lun->{$freenas_api_variables->{'extentpath'}} eq $object) {
$result = $result_value_type eq "lun-id" ? $lun->{$freenas_api_variables->{'lunid'}} : $dev_prefix . $lun->{$freenas_api_variables->{'extentpath'}};
syslog("info",(caller(0))[3] . "($object) '$result_value_type' found $result");
last;
}
}
if(!defined($result)) {
syslog("info", (caller(0))[3] . "($object) : $result_value_type : lun not found");
}
$object =~ s/^\Q$dev_prefix//;
syslog("info", (caller(0))[3] . " : TrueNAS object to find: '$object'");
if (defined($luns->{$object})) {
my $lu_object = $luns->{$object};
$result = $result_value_type eq "lun-id" ? $lu_object->{$freenas_api_variables->{'lunid'}} : $dev_prefix . $lu_object->{$freenas_api_variables->{'extentpath'}};
syslog("info",(caller(0))[3] . " '$object' with key '$result_value_type' found with value: '$result'");
} else {
syslog("info", (caller(0))[3] . " '$object' with key '$result_value_type' was not found");
}
return $result; return $result;
} }
# #
# #
# # Optimzed
sub run_list_extent { sub run_list_extent {
my ($scfg, $timeout, $method, @params) = @_; my ($scfg, $timeout, $method, @params) = @_;
my $object = $params[0]; my $object = $params[0];
syslog("info", (caller(0))[3] . " : called with (method: '$method'; params[0]: '$object')");
syslog("info", (caller(0))[3] . " : called with (method=$method; object=$object)");
my $result = undef; my $result = undef;
my $luns = freenas_list_lu($scfg); my $luns = freenas_list_lu($scfg);
foreach my $lun (@$luns) {
syslog("info", (caller(0))[3] . " : Verifing '$lun->{$freenas_api_variables->{'extentpath'}}' and '$object'");
if ($dev_prefix . $lun->{$freenas_api_variables->{'extentpath'}} eq $object) {
$result = $lun->{$freenas_api_variables->{'extentnaa'}};
syslog("info","FreeNAS::list_extent($object): naa found $result");
last;
}
}
if (!defined($result)) {
syslog("info","FreeNAS::list_extent($object): naa not found");
}
$object =~ s/^\Q$dev_prefix//;
syslog("info", (caller(0))[3] . " TrueNAS object to find: '$object'");
if (defined($luns->{$object})) {
my $lu_object = $luns->{$object};
$result = $lu_object->{$freenas_api_variables->{'extentnaa'}};
syslog("info",(caller(0))[3] . " '$object' wtih key '$freenas_api_variables->{'extentnaa'}' found with value: '$result'");
} else {
syslog("info",(caller(0))[3] . " '$object' with key '$freenas_api_variables->{'extentnaa'}' was not found");
}
return $result; return $result;
} }
@ -280,24 +275,24 @@ sub run_create_lu {
# #
# #
# # Optimzied
sub run_delete_lu { sub run_delete_lu {
my ($scfg, $timeout, $method, @params) = @_; my ($scfg, $timeout, $method, @params) = @_;
my $lun_path = $params[0]; my $lun_path = $params[0];
syslog("info", (caller(0))[3] . " : called with (method=$method; param[0]=$lun_path)"); syslog("info", (caller(0))[3] . " : called with (method: '$method'; param[0]: '$lun_path')");
my $luns = freenas_list_lu($scfg); my $luns = freenas_list_lu($scfg);
my $lun = undef; my $lun = undef;
my $link = undef; my $link = undef;
foreach my $item (@$luns) { $lun_path =~ s/^\Q$dev_prefix//;
if($dev_prefix . $item->{ $freenas_api_variables->{'extentpath'}} eq $lun_path) {
$lun = $item;
last;
}
}
die "Unable to find the lun $lun_path for $scfg->{target}" if !defined($lun); if (defined($luns->{$lun_path})) {
$lun = $luns->{$lun_path};
syslog("info",(caller(0))[3] . " lun: '$lun_path' found");
} else {
die "Unable to find the lun $lun_path for $scfg->{target}";
}
my $target_id = freenas_get_targetid($scfg); my $target_id = freenas_get_targetid($scfg);
die "Unable to find the target id for $scfg->{target}" if !defined($target_id); die "Unable to find the target id for $scfg->{target}" if !defined($target_id);
@ -353,24 +348,34 @@ sub freenas_api_connect {
$freenas_server_list->{$apihost}->getUseragent()->ssl_opts(SSL_verify_mode => SSL_VERIFY_NONE); $freenas_server_list->{$apihost}->getUseragent()->ssl_opts(SSL_verify_mode => SSL_VERIFY_NONE);
} }
# Check if the APIs are accessable via the selected host and scheme # Check if the APIs are accessable via the selected host and scheme
my $code = $freenas_server_list->{$apihost}->request('GET', $apiping)->responseCode(); my $api_response = $freenas_server_list->{$apihost}->request('GET', $apiping);
if ($code == 200) { # Successful connection my $code = $api_response->responseCode();
syslog("info", (caller(0))[3] . " : REST connection successful to '" . $apihost . "' using the '" . $scheme . "' protocol"); my $type = $api_response->responseHeader('Content-Type');
$runawayprevent = 0; syslog("info", (caller(0))[3] . " : REST connection header Content-Type:'" . $type . "'");
} elsif ($runawayprevent > 1) { # Make sure we are not recursion calling.
# Make sure we are not recursion calling.
if ($runawayprevent > 2) {
freenas_api_log_error($freenas_server_list->{$apihost}); freenas_api_log_error($freenas_server_list->{$apihost});
die "Loop recursion prevention"; die "Loop recursion prevention";
} elsif ($code == 302) { # A 302 from FreeNAS means it doesn't like v1.0 APIs. # Successful connection
} elsif ($code == 200 && ($type =~ /^text\/plain/ || $type =~ /^application\/json/)) {
syslog("info", (caller(0))[3] . " : REST connection successful to '" . $apihost . "' using the '" . $scheme . "' protocol");
$runawayprevent = 0;
# A 302 or 200 (We already check for the correct 'type' above with a 200 so why add additional conditionals).
# So change to v2.0 APIs.
} elsif ($code == 302 || $code == 200) {
syslog("info", (caller(0))[3] . " : Changing to v2.0 API's"); syslog("info", (caller(0))[3] . " : Changing to v2.0 API's");
$runawayprevent++; $runawayprevent++;
$apiping =~ s/v1\.0/v2\.0/; $apiping =~ s/v1\.0/v2\.0/;
freenas_api_connect($scfg); freenas_api_connect($scfg);
} elsif ($code == 307) { # A 307 from FreeNAS means rediect http to https. # A 307 from FreeNAS means rediect http to https.
} elsif ($code == 307) {
syslog("info", (caller(0))[3] . " : Redirecting to HTTPS protocol"); syslog("info", (caller(0))[3] . " : Redirecting to HTTPS protocol");
$runawayprevent++; $runawayprevent++;
$scfg->{freenas_use_ssl} = 1; $scfg->{freenas_use_ssl} = 1;
freenas_api_connect($scfg); freenas_api_connect($scfg);
} else { # For now, any other code we fail. # For now, any other code we fail.
} else {
freenas_api_log_error($freenas_server_list->{$apihost}); freenas_api_log_error($freenas_server_list->{$apihost});
die "Unable to connect to the FreeNAS API service at '" . $apihost . "' using the '" . $scheme . "' protocol"; die "Unable to connect to the FreeNAS API service at '" . $apihost . "' using the '" . $scheme . "' protocol";
} }
@ -399,16 +404,32 @@ sub freenas_api_check {
} else { } else {
$result = $freenas_rest_connection->responseContent(); $result = $freenas_rest_connection->responseContent();
} }
$result =~ s/^"//g; $result =~ s/"//g;
syslog("info", (caller(0))[3] . " : successful : Server version: " . $result); syslog("info", (caller(0))[3] . " : successful : Server version: " . $result);
$result =~ s/^((?!\-\d).*)\-(\d+)\.(\d+)\-([A-Za-z]*)(?(?=\-)\-(\d*)\-(\d*)|(\d?)\.?(\d?))//; if ($result =~ /^(TrueNAS|FreeNAS)-(\d+)\.(\d+)\-U(\d+)(?(?=\.)\.(\d+))$/) {
$product_name = $1; $product_name = $1;
my $freenas_version = sprintf("%02d%02d%02d%02d", $2, $3 || 0, $7 || 0, $8 || 0); $truenas_version = sprintf("%02d%02d%02d%02d", $2, $3 || 0, $4 || 0, $5 || 0);
syslog("info", (caller(0))[3] . " : ". $product_name . " Unformatted Version: " . $freenas_version); } elsif ($result =~ /^(TrueNAS)-(\d+)\.(\d+)(?(?=\-U\d+)-U(\d+)|-\w+)(?(?=\.).(\d+))$/) {
if ($freenas_version >= 11030100) { $product_name = $1;
$truenas_version = sprintf("%02d%02d%02d%02d", $2, $3 || 0, $4 || 0, $6 || 0);
$truenas_release_type = $5 || "Production";
} elsif ($result =~ /^(TrueNAS-SCALE)-(\d+)\.(\d+)(?(?=\-)-(\w+))\.(\d+)(?(?=\.)\.(\d+))(?(?=\-)-(\d+))$/) {
$product_name = $1;
$truenas_version = sprintf("%02d%02d%02d%02d", $2, $3 || 0, $5 || 0, $7 || 0);
$truenas_release_type = $4 || "Production";
} else {
$product_name = "Unknown";
$truenas_release_type = "Unknown";
syslog("error", (caller(0))[3] . " : Could not parse the version of TrueNAS.");
}
syslog("info", (caller(0))[3] . " : ". $product_name . " Unformatted Version: " . $truenas_version);
if ($truenas_version >= 11030100) {
$freenas_api_version = "v2.0"; $freenas_api_version = "v2.0";
$dev_prefix = "/dev/"; $dev_prefix = "/dev/";
} }
if ($truenas_release_type ne "Production") {
syslog("warn", (caller(0))[3] . " : The '" . $product_name . "' release type of '" . $truenas_release_type . "' may not worked due to unsupported changes.");
}
} else { } else {
syslog("info", (caller(0))[3] . " : REST Client already initialized"); syslog("info", (caller(0))[3] . " : REST Client already initialized");
} }
@ -512,10 +533,15 @@ sub freenas_iscsi_create_extent {
my $name = $lun_path; my $name = $lun_path;
$name =~ s/^.*\///; # all from last / $name =~ s/^.*\///; # all from last /
my $pool = $scfg->{'pool'};
# If TrueNAS-SCALE the slashes (/) need to be converted to dashes (-)
if ($product_name eq "TrueNAS-SCALE") { if ($product_name eq "TrueNAS-SCALE") {
$scfg->{'pool'} =~ s/\//-/; $pool =~ s/\//-/g;
syslog("info", (caller(0))[3] . " : TrueNAS-SCALE slash to dash conversion '" . $pool ."'");
} }
$name = $scfg->{'pool'} . ($product_name eq "TrueNAS-SCALE" ? '-' : '/') . $name; $name = $pool . ($product_name eq "TrueNAS-SCALE" ? '-' : '/') . $name;
syslog("info", (caller(0))[3] . " : " . $product_name . " extent '". $name . "'");
my $device = $lun_path; my $device = $lun_path;
$device =~ s/^\/dev\///; # strip /dev/ $device =~ s/^\/dev\///; # strip /dev/
@ -682,7 +708,7 @@ sub freenas_list_lu {
my $targets = freenas_iscsi_get_target($scfg); my $targets = freenas_iscsi_get_target($scfg);
my $target_id = freenas_get_targetid($scfg); my $target_id = freenas_get_targetid($scfg);
my @luns = (); my %lun_hash;
my $iscsi_lunid = undef; my $iscsi_lunid = undef;
if(defined($target_id)) { if(defined($target_id)) {
@ -694,21 +720,21 @@ sub freenas_list_lu {
foreach my $node (@$extents) { foreach my $node (@$extents) {
if($node->{'id'} == $item->{$freenas_api_variables->{'extentid'}}) { if($node->{'id'} == $item->{$freenas_api_variables->{'extentid'}}) {
if ($item->{$freenas_api_variables->{'lunid'}} =~ /(\d+)/) { if ($item->{$freenas_api_variables->{'lunid'}} =~ /(\d+)/) {
$iscsi_lunid = "$1"; if (defined($node)) {
$node->{$freenas_api_variables->{'lunid'}} .= "$1";
$lun_hash{$node->{$freenas_api_variables->{'extentpath'}}} = $node;
}
last;
} else { } else {
syslog("info", (caller(0))[3] . " : iscsi_lunid did not pass tainted testing"); syslog("warn", (caller(0))[3] . " : iscsi_lunid did not pass tainted testing");
next;
} }
$node->{$freenas_api_variables->{'lunid'}} .= $iscsi_lunid;
push(@luns , $node);
last;
} }
} }
} }
} }
} }
syslog("info", (caller(0))[3] . " : successful"); syslog("info", (caller(0))[3] . " : successful");
return \@luns; return \%lun_hash;
} }
# #

View File

@ -0,0 +1,147 @@
--- ZFSPlugin.pm.orig 2022-02-04 12:08:01.000000000 -0500
+++ ZFSPlugin.pm 2022-03-26 13:51:40.660068908 -0400
@@ -10,6 +10,7 @@
use base qw(PVE::Storage::ZFSPoolPlugin);
use PVE::Storage::LunCmd::Comstar;
+use PVE::Storage::LunCmd::FreeNAS;
use PVE::Storage::LunCmd::Istgt;
use PVE::Storage::LunCmd::Iet;
use PVE::Storage::LunCmd::LIO;
@@ -26,13 +27,14 @@
modify_lu => 1,
add_view => 1,
list_view => 1,
+ list_extent => 1,
list_lu => 1,
};
my $zfs_unknown_scsi_provider = sub {
my ($provider) = @_;
- die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
+ die "$provider: unknown iscsi provider. Available [comstar, freenas, istgt, iet, LIO]";
};
my $zfs_get_base = sub {
@@ -40,6 +42,8 @@
if ($scfg->{iscsiprovider} eq 'comstar') {
return PVE::Storage::LunCmd::Comstar::get_base;
+ } elsif ($scfg->{iscsiprovider} eq 'freenas') {
+ return PVE::Storage::LunCmd::FreeNAS::get_base;
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
return PVE::Storage::LunCmd::Istgt::get_base;
} elsif ($scfg->{iscsiprovider} eq 'iet') {
@@ -62,6 +66,8 @@
if ($lun_cmds->{$method}) {
if ($scfg->{iscsiprovider} eq 'comstar') {
$msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params);
+ } elsif ($scfg->{iscsiprovider} eq 'freenas') {
+ $msg = PVE::Storage::LunCmd::FreeNAS::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'iet') {
@@ -166,6 +172,15 @@
die "lun_number for guid $guid is not a number";
}
+# Part of the multipath enhancement
+sub zfs_get_wwid_number {
+ my ($class, $scfg, $guid) = @_;
+
+ die "could not find lun_number for guid $guid" if !$guid;
+
+ return $class->zfs_request($scfg, undef, 'list_extent', $guid);
+}
+
# Configuration
sub type {
@@ -184,6 +199,24 @@
description => "iscsi provider",
type => 'string',
},
+ # This is for FreeNAS iscsi and API intergration
+ # And some enhancements asked by the community
+ freenas_user => {
+ description => "FreeNAS API Username",
+ type => 'string',
+ },
+ freenas_password => {
+ description => "FreeNAS API Password",
+ type => 'string',
+ },
+ freenas_use_ssl => {
+ description => "FreeNAS API access via SSL",
+ type => 'boolean',
+ },
+ freenas_apiv4_host => {
+ description => "FreeNAS API Host",
+ type => 'string',
+ },
# this will disable write caching on comstar and istgt.
# it is not implemented for iet. iet blockio always operates with
# writethrough caching when not in readonly mode
@@ -211,14 +244,18 @@
nodes => { optional => 1 },
disable => { optional => 1 },
portal => { fixed => 1 },
- target => { fixed => 1 },
- pool => { fixed => 1 },
+ target => { fixed => 0 },
+ pool => { fixed => 0 },
blocksize => { fixed => 1 },
iscsiprovider => { fixed => 1 },
nowritecache => { optional => 1 },
sparse => { optional => 1 },
comstar_hg => { optional => 1 },
comstar_tg => { optional => 1 },
+ freenas_user => { optional => 1 },
+ freenas_password => { optional => 1 },
+ freenas_use_ssl => { optional => 1 },
+ freenas_apiv4_host => { optional => 1 },
lio_tpg => { optional => 1 },
content => { optional => 1 },
bwlimit => { optional => 1 },
@@ -243,6 +280,40 @@
my $path = "iscsi://$portal/$target/$lun";
+ # Multipath enhancement
+ eval {
+ my $wwid = $class->zfs_get_wwid_number($scfg, $guid);
+# syslog(info,"JD: path get_lun_number guid $guid");
+
+ if ($wwid =~ /^([-\@\w.]+)$/) {
+ $wwid = $1; # $data now untainted
+ } else {
+ die "Bad data in '$wwid'"; # log this somewhere
+ }
+ my $wwid_end = substr $wwid, 16;
+
+ my $mapper = '';
+ sleep 3;
+ run_command("iscsiadm -m session --rescan");
+ sleep 3;
+ my $line = `/usr/sbin/multipath -ll | grep \"$wwid_end\"`;
+ my ($mapper_device) = split(' ', $line);
+ $mapper_device = "" unless $mapper_device;
+ $mapper .= $mapper_device;
+
+ if ($mapper =~ /^([-\@\w.]+)$/) {
+ $mapper = $1; # $data now untainted
+ } else {
+ $mapper = '';
+ }
+
+# syslog(info,"Multipath mapper found: $mapper\n");
+ if ($mapper ne "") {
+ $path = "/dev/mapper/$mapper";
+ sleep 5;
+ }
+ };
+
return ($path, $vmid, $vtype);
}

View File

@ -1,10 +1,5 @@
<<<<<<< HEAD --- ZFSPlugin.pm.orig 2022-02-04 12:08:01.000000000 -0500
--- ZFSPlugin.pm.orig 2019-09-23 12:17:37.000000000 -0400 +++ ZFSPlugin.pm 2022-03-26 13:51:40.660068908 -0400
+++ ZFSPlugin.pm 2019-10-13 09:31:58.780554103 -0400
=======
--- ZFSPlugin.pm.orig 2019-09-03 04:24:37.000000000 -0400
+++ ZFSPlugin.pm 2019-09-22 13:54:51.570048336 -0400
>>>>>>> branch 'master' of https://github.com/TheGrandWazoo/freenas-proxmox.git
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
use base qw(PVE::Storage::ZFSPoolPlugin); use base qw(PVE::Storage::ZFSPoolPlugin);
@ -47,8 +42,8 @@
} elsif ($scfg->{iscsiprovider} eq 'istgt') { } elsif ($scfg->{iscsiprovider} eq 'istgt') {
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params); $msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'iet') { } elsif ($scfg->{iscsiprovider} eq 'iet') {
@@ -162,6 +168,15 @@ @@ -166,6 +172,15 @@
return $class->zfs_request($scfg, undef, 'list_view', $guid); die "lun_number for guid $guid is not a number";
} }
+# Part of the multipath enhancement +# Part of the multipath enhancement
@ -63,7 +58,7 @@
# Configuration # Configuration
sub type { sub type {
@@ -180,6 +195,24 @@ @@ -184,6 +199,24 @@
description => "iscsi provider", description => "iscsi provider",
type => 'string', type => 'string',
}, },
@ -88,7 +83,7 @@
# this will disable write caching on comstar and istgt. # this will disable write caching on comstar and istgt.
# it is not implemented for iet. iet blockio always operates with # it is not implemented for iet. iet blockio always operates with
# writethrough caching when not in readonly mode # writethrough caching when not in readonly mode
@@ -207,14 +240,18 @@ @@ -211,14 +244,18 @@
nodes => { optional => 1 }, nodes => { optional => 1 },
disable => { optional => 1 }, disable => { optional => 1 },
portal => { fixed => 1 }, portal => { fixed => 1 },
@ -109,7 +104,7 @@
lio_tpg => { optional => 1 }, lio_tpg => { optional => 1 },
content => { optional => 1 }, content => { optional => 1 },
bwlimit => { optional => 1 }, bwlimit => { optional => 1 },
@@ -239,6 +276,40 @@ @@ -243,6 +280,40 @@
my $path = "iscsi://$portal/$target/$lun"; my $path = "iscsi://$portal/$target/$lun";

View File

@ -0,0 +1,79 @@
--- apidoc.js.orig 2021-11-15 10:07:34.000000000 -0500
+++ apidoc.js 2021-12-06 08:04:01.648822707 -0500
@@ -44064,6 +44064,31 @@
"type" : "string",
"typetext" : "<string>"
},
+ "freenas_user" : {
+ "description" : "FreeNAS user for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_password" : {
+ "description" : "FreeNAS password for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_use_ssl" : {
+ "description" : "FreeNAS API access via SSL",
+ "optional" : 1,
+ "type" : "boolean",
+ "typetext" : "<boolean>"
+ },
+ "freenas_apiv4_host" : {
+ "description" : "FreeNAS API Host via IPv4",
+ "format" : "address",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"fuse" : {
"description" : "Mount CephFS through FUSE.",
"optional" : 1,
@@ -44275,6 +44300,12 @@
"type" : "boolean",
"typetext" : "<boolean>"
},
+ "target" : {
+ "description" : "iSCSI target.",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"transport" : {
"description" : "Gluster transport: tcp or rdma",
"enum" : [
@@ -44547,6 +44578,31 @@
"optional" : 1,
"type" : "string",
"typetext" : "<string>"
+ },
+ "freenas_user" : {
+ "description" : "FreeNAS user for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_password" : {
+ "description" : "FreeNAS password for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_use_ssl" : {
+ "description" : "FreeNAS API access via SSL",
+ "optional" : 1,
+ "type" : "boolean",
+ "typetext" : "<boolean>"
+ },
+ "freenas_apiv4_host" : {
+ "description" : "FreeNAS API Host via IPv4",
+ "format" : "address",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
},
"fuse" : {
"description" : "Mount CephFS through FUSE.",

View File

@ -1,6 +1,6 @@
--- apidoc.js.orig 2019-07-15 15:45:00.000000000 -0400 --- apidoc.js.orig 2021-11-15 10:07:34.000000000 -0500
+++ apidoc.js 2019-08-07 13:28:29.292382229 -0400 +++ apidoc.js 2021-12-06 08:04:01.648822707 -0500
@@ -35001,6 +35001,31 @@ @@ -44064,6 +44064,31 @@
"type" : "string", "type" : "string",
"typetext" : "<string>" "typetext" : "<string>"
}, },
@ -32,7 +32,7 @@
"fuse" : { "fuse" : {
"description" : "Mount CephFS through FUSE.", "description" : "Mount CephFS through FUSE.",
"optional" : 1, "optional" : 1,
@@ -35157,6 +35182,12 @@ @@ -44275,6 +44300,12 @@
"type" : "boolean", "type" : "boolean",
"typetext" : "<boolean>" "typetext" : "<boolean>"
}, },
@ -45,7 +45,7 @@
"transport" : { "transport" : {
"description" : "Gluster transport: tcp or rdma", "description" : "Gluster transport: tcp or rdma",
"enum" : [ "enum" : [
@@ -35362,6 +35393,31 @@ @@ -44547,6 +44578,31 @@
"optional" : 1, "optional" : 1,
"type" : "string", "type" : "string",
"typetext" : "<string>" "typetext" : "<string>"

View File

@ -0,0 +1,189 @@
--- pvemanagerlib.js.orig 2022-03-17 09:08:40.000000000 -0400
+++ pvemanagerlib.js 2022-04-03 08:54:10.229689187 -0400
@@ -8068,6 +8068,7 @@
alias: ['widget.pveiScsiProviderSelector'],
comboItems: [
['comstar', 'Comstar'],
+ ['freenas', 'FreeNAS-API'],
['istgt', 'istgt'],
['iet', 'IET'],
['LIO', 'LIO'],
@@ -49636,6 +49637,7 @@
data: {
isLIO: false,
isComstar: true,
+ isFreeNAS: false,
hasWriteCacheOption: true,
},
},
@@ -49648,10 +49650,26 @@
},
},
changeISCSIProvider: function(f, newVal, oldVal) {
+ var me = this;
var vm = this.getViewModel();
vm.set('isLIO', newVal === 'LIO');
vm.set('isComstar', newVal === 'comstar');
- vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
+ vm.set('isFreeNAS', newVal === 'freenas');
+ vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'freenas' || newVal === 'istgt');
+ if (newVal !== 'freenas') {
+ me.lookupReference('freenas_use_ssl_field').setValue(false);
+ me.lookupReference('freenas_apiv4_host_field').setValue('');
+ me.lookupReference('freenas_user_field').setValue('');
+ me.lookupReference('freenas_user_field').allowBlank = true;
+ me.lookupReference('freenas_password_field').setValue('');
+ me.lookupReference('freenas_password_field').allowBlank = true;
+ me.lookupReference('freenas_confirmpw_field').setValue('');
+ me.lookupReference('freenas_confirmpw_field').allowBlank = true;
+ } else {
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ me.lookupReference('freenas_password_field').allowBlank = false;
+ me.lookupReference('freenas_confirmpw_field').allowBlank = false;
+ }
},
},
@@ -49669,6 +49687,7 @@
},
setValues: function(values) {
+ values.freenas_confirmpw = values.freenas_password;
values.writecache = values.nowritecache ? 0 : 1;
this.callParent([values]);
},
@@ -49685,7 +49704,7 @@
allowBlank: false,
},
{
- xtype: me.isCreate ? 'textfield' : 'displayfield',
+ xtype: 'textfield',
name: 'pool',
value: '',
fieldLabel: gettext('Pool'),
@@ -49695,11 +49714,11 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'blocksize',
value: '4k',
- fieldLabel: gettext('Block Size'),
+ fieldLabel: gettext('ZFS Block Size'),
allowBlank: false,
},
{
- xtype: me.isCreate ? 'textfield' : 'displayfield',
+ xtype: 'textfield',
name: 'target',
value: '',
fieldLabel: gettext('Target'),
@@ -49710,9 +49729,34 @@
name: 'comstar_tg',
value: '',
fieldLabel: gettext('Target group'),
- bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
+ bind: {
+ hidden: '{!isComstar}'
+ },
allowBlank: true,
},
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'freenas_use_ssl',
+ reference: 'freenas_use_ssl_field',
+ inputId: 'freenas_use_ssl_field',
+ checked: false,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ uncheckedValue: 0,
+ fieldLabel: gettext('API use SSL'),
+ },
+ {
+ xtype: 'textfield',
+ name: 'freenas_user',
+ reference: 'freenas_user_field',
+ inputId: 'freenas_user_field',
+ value: '',
+ fieldLabel: gettext('API Username'),
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ },
];
me.column2 = [
@@ -49742,7 +49786,9 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'comstar_hg',
value: '',
- bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
+ bind: {
+ hidden: '{!isComstar}'
+ },
fieldLabel: gettext('Host group'),
allowBlank: true,
},
@@ -49750,9 +49796,62 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'lio_tpg',
value: '',
- bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
- allowBlank: false,
+ bind: {
+ hidden: '{!isLIO}'
+ },
fieldLabel: gettext('Target portal group'),
+ allowBlank: true
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_apiv4_host',
+ reference: 'freenas_apiv4_host_field',
+ value: '',
+ editable: true,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('API IPv4 Host'),
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_password',
+ reference: 'freenas_password_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('API Password'),
+ change: function(f, value) {
+ if (f.rendered) {
+ f.up().down('field[name=freenas_confirmpw]').validate();
+ }
+ },
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_confirmpw',
+ reference: 'freenas_confirmpw_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ submitValue: false,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('Confirm Password'),
+ validator: function(value) {
+ var pw = this.up().down('field[name=freenas_password]').getValue();
+ if (pw !== value) {
+ return "Passwords do not match!";
+ }
+ return true;
+ },
},
];

View File

@ -1,6 +1,6 @@
--- pvemanagerlib.js.orig 2021-05-27 08:28:35.000000000 -0400 --- pvemanagerlib.js.orig 2022-03-17 09:08:40.000000000 -0400
+++ pvemanagerlib.js 2021-06-10 11:03:15.380175988 -0400 +++ pvemanagerlib.js 2022-04-03 08:54:10.229689187 -0400
@@ -7900,6 +7900,7 @@ @@ -8068,6 +8068,7 @@
alias: ['widget.pveiScsiProviderSelector'], alias: ['widget.pveiScsiProviderSelector'],
comboItems: [ comboItems: [
['comstar', 'Comstar'], ['comstar', 'Comstar'],
@ -8,7 +8,7 @@
['istgt', 'istgt'], ['istgt', 'istgt'],
['iet', 'IET'], ['iet', 'IET'],
['LIO', 'LIO'], ['LIO', 'LIO'],
@@ -47367,6 +47368,7 @@ @@ -49636,6 +49637,7 @@
data: { data: {
isLIO: false, isLIO: false,
isComstar: true, isComstar: true,
@ -16,7 +16,7 @@
hasWriteCacheOption: true, hasWriteCacheOption: true,
}, },
}, },
@@ -47379,10 +47381,26 @@ @@ -49648,10 +49650,26 @@
}, },
}, },
changeISCSIProvider: function(f, newVal, oldVal) { changeISCSIProvider: function(f, newVal, oldVal) {
@ -44,7 +44,7 @@
}, },
}, },
@@ -47400,6 +47418,7 @@ @@ -49669,6 +49687,7 @@
}, },
setValues: function(values) { setValues: function(values) {
@ -52,7 +52,7 @@
values.writecache = values.nowritecache ? 0 : 1; values.writecache = values.nowritecache ? 0 : 1;
this.callParent([values]); this.callParent([values]);
}, },
@@ -47416,7 +47435,7 @@ @@ -49685,7 +49704,7 @@
allowBlank: false, allowBlank: false,
}, },
{ {
@ -61,7 +61,7 @@
name: 'pool', name: 'pool',
value: '', value: '',
fieldLabel: gettext('Pool'), fieldLabel: gettext('Pool'),
@@ -47426,11 +47445,11 @@ @@ -49695,11 +49714,11 @@
xtype: me.isCreate ? 'textfield' : 'displayfield', xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'blocksize', name: 'blocksize',
value: '4k', value: '4k',
@ -75,7 +75,7 @@
name: 'target', name: 'target',
value: '', value: '',
fieldLabel: gettext('Target'), fieldLabel: gettext('Target'),
@@ -47441,9 +47460,34 @@ @@ -49710,9 +49729,34 @@
name: 'comstar_tg', name: 'comstar_tg',
value: '', value: '',
fieldLabel: gettext('Target group'), fieldLabel: gettext('Target group'),
@ -111,7 +111,7 @@
]; ];
me.column2 = [ me.column2 = [
@@ -47473,7 +47517,9 @@ @@ -49742,7 +49786,9 @@
xtype: me.isCreate ? 'textfield' : 'displayfield', xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'comstar_hg', name: 'comstar_hg',
value: '', value: '',
@ -122,7 +122,7 @@
fieldLabel: gettext('Host group'), fieldLabel: gettext('Host group'),
allowBlank: true, allowBlank: true,
}, },
@@ -47481,9 +47527,62 @@ @@ -49750,9 +49796,62 @@
xtype: me.isCreate ? 'textfield' : 'displayfield', xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'lio_tpg', name: 'lio_tpg',
value: '', value: '',

View File

@ -0,0 +1,147 @@
--- ZFSPlugin.pm.orig 2022-02-04 12:08:01.000000000 -0500
+++ ZFSPlugin.pm 2022-03-26 13:51:40.660068908 -0400
@@ -10,6 +10,7 @@
use base qw(PVE::Storage::ZFSPoolPlugin);
use PVE::Storage::LunCmd::Comstar;
+use PVE::Storage::LunCmd::FreeNAS;
use PVE::Storage::LunCmd::Istgt;
use PVE::Storage::LunCmd::Iet;
use PVE::Storage::LunCmd::LIO;
@@ -26,13 +27,14 @@
modify_lu => 1,
add_view => 1,
list_view => 1,
+ list_extent => 1,
list_lu => 1,
};
my $zfs_unknown_scsi_provider = sub {
my ($provider) = @_;
- die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
+ die "$provider: unknown iscsi provider. Available [comstar, freenas, istgt, iet, LIO]";
};
my $zfs_get_base = sub {
@@ -40,6 +42,8 @@
if ($scfg->{iscsiprovider} eq 'comstar') {
return PVE::Storage::LunCmd::Comstar::get_base;
+ } elsif ($scfg->{iscsiprovider} eq 'freenas') {
+ return PVE::Storage::LunCmd::FreeNAS::get_base;
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
return PVE::Storage::LunCmd::Istgt::get_base;
} elsif ($scfg->{iscsiprovider} eq 'iet') {
@@ -62,6 +66,8 @@
if ($lun_cmds->{$method}) {
if ($scfg->{iscsiprovider} eq 'comstar') {
$msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params);
+ } elsif ($scfg->{iscsiprovider} eq 'freenas') {
+ $msg = PVE::Storage::LunCmd::FreeNAS::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'iet') {
@@ -166,6 +172,15 @@
die "lun_number for guid $guid is not a number";
}
+# Part of the multipath enhancement
+sub zfs_get_wwid_number {
+ my ($class, $scfg, $guid) = @_;
+
+ die "could not find lun_number for guid $guid" if !$guid;
+
+ return $class->zfs_request($scfg, undef, 'list_extent', $guid);
+}
+
# Configuration
sub type {
@@ -184,6 +199,24 @@
description => "iscsi provider",
type => 'string',
},
+ # This is for FreeNAS iscsi and API intergration
+ # And some enhancements asked by the community
+ freenas_user => {
+ description => "FreeNAS API Username",
+ type => 'string',
+ },
+ freenas_password => {
+ description => "FreeNAS API Password",
+ type => 'string',
+ },
+ freenas_use_ssl => {
+ description => "FreeNAS API access via SSL",
+ type => 'boolean',
+ },
+ freenas_apiv4_host => {
+ description => "FreeNAS API Host",
+ type => 'string',
+ },
# this will disable write caching on comstar and istgt.
# it is not implemented for iet. iet blockio always operates with
# writethrough caching when not in readonly mode
@@ -211,14 +244,18 @@
nodes => { optional => 1 },
disable => { optional => 1 },
portal => { fixed => 1 },
- target => { fixed => 1 },
- pool => { fixed => 1 },
+ target => { fixed => 0 },
+ pool => { fixed => 0 },
blocksize => { fixed => 1 },
iscsiprovider => { fixed => 1 },
nowritecache => { optional => 1 },
sparse => { optional => 1 },
comstar_hg => { optional => 1 },
comstar_tg => { optional => 1 },
+ freenas_user => { optional => 1 },
+ freenas_password => { optional => 1 },
+ freenas_use_ssl => { optional => 1 },
+ freenas_apiv4_host => { optional => 1 },
lio_tpg => { optional => 1 },
content => { optional => 1 },
bwlimit => { optional => 1 },
@@ -243,6 +280,40 @@
my $path = "iscsi://$portal/$target/$lun";
+ # Multipath enhancement
+ eval {
+ my $wwid = $class->zfs_get_wwid_number($scfg, $guid);
+# syslog(info,"JD: path get_lun_number guid $guid");
+
+ if ($wwid =~ /^([-\@\w.]+)$/) {
+ $wwid = $1; # $data now untainted
+ } else {
+ die "Bad data in '$wwid'"; # log this somewhere
+ }
+ my $wwid_end = substr $wwid, 16;
+
+ my $mapper = '';
+ sleep 3;
+ run_command("iscsiadm -m session --rescan");
+ sleep 3;
+ my $line = `/usr/sbin/multipath -ll | grep \"$wwid_end\"`;
+ my ($mapper_device) = split(' ', $line);
+ $mapper_device = "" unless $mapper_device;
+ $mapper .= $mapper_device;
+
+ if ($mapper =~ /^([-\@\w.]+)$/) {
+ $mapper = $1; # $data now untainted
+ } else {
+ $mapper = '';
+ }
+
+# syslog(info,"Multipath mapper found: $mapper\n");
+ if ($mapper ne "") {
+ $path = "/dev/mapper/$mapper";
+ sleep 5;
+ }
+ };
+
return ($path, $vmid, $vtype);
}

View File

@ -0,0 +1,147 @@
--- ZFSPlugin.pm.orig 2022-02-04 12:08:01.000000000 -0500
+++ ZFSPlugin.pm 2022-03-26 13:51:40.660068908 -0400
@@ -10,6 +10,7 @@
use base qw(PVE::Storage::ZFSPoolPlugin);
use PVE::Storage::LunCmd::Comstar;
+use PVE::Storage::LunCmd::FreeNAS;
use PVE::Storage::LunCmd::Istgt;
use PVE::Storage::LunCmd::Iet;
use PVE::Storage::LunCmd::LIO;
@@ -26,13 +27,14 @@
modify_lu => 1,
add_view => 1,
list_view => 1,
+ list_extent => 1,
list_lu => 1,
};
my $zfs_unknown_scsi_provider = sub {
my ($provider) = @_;
- die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
+ die "$provider: unknown iscsi provider. Available [comstar, freenas, istgt, iet, LIO]";
};
my $zfs_get_base = sub {
@@ -40,6 +42,8 @@
if ($scfg->{iscsiprovider} eq 'comstar') {
return PVE::Storage::LunCmd::Comstar::get_base;
+ } elsif ($scfg->{iscsiprovider} eq 'freenas') {
+ return PVE::Storage::LunCmd::FreeNAS::get_base;
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
return PVE::Storage::LunCmd::Istgt::get_base;
} elsif ($scfg->{iscsiprovider} eq 'iet') {
@@ -62,6 +66,8 @@
if ($lun_cmds->{$method}) {
if ($scfg->{iscsiprovider} eq 'comstar') {
$msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params);
+ } elsif ($scfg->{iscsiprovider} eq 'freenas') {
+ $msg = PVE::Storage::LunCmd::FreeNAS::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'iet') {
@@ -166,6 +172,15 @@
die "lun_number for guid $guid is not a number";
}
+# Part of the multipath enhancement
+sub zfs_get_wwid_number {
+ my ($class, $scfg, $guid) = @_;
+
+ die "could not find lun_number for guid $guid" if !$guid;
+
+ return $class->zfs_request($scfg, undef, 'list_extent', $guid);
+}
+
# Configuration
sub type {
@@ -184,6 +199,24 @@
description => "iscsi provider",
type => 'string',
},
+ # This is for FreeNAS iscsi and API intergration
+ # And some enhancements asked by the community
+ freenas_user => {
+ description => "FreeNAS API Username",
+ type => 'string',
+ },
+ freenas_password => {
+ description => "FreeNAS API Password",
+ type => 'string',
+ },
+ freenas_use_ssl => {
+ description => "FreeNAS API access via SSL",
+ type => 'boolean',
+ },
+ freenas_apiv4_host => {
+ description => "FreeNAS API Host",
+ type => 'string',
+ },
# this will disable write caching on comstar and istgt.
# it is not implemented for iet. iet blockio always operates with
# writethrough caching when not in readonly mode
@@ -211,14 +244,18 @@
nodes => { optional => 1 },
disable => { optional => 1 },
portal => { fixed => 1 },
- target => { fixed => 1 },
- pool => { fixed => 1 },
+ target => { fixed => 0 },
+ pool => { fixed => 0 },
blocksize => { fixed => 1 },
iscsiprovider => { fixed => 1 },
nowritecache => { optional => 1 },
sparse => { optional => 1 },
comstar_hg => { optional => 1 },
comstar_tg => { optional => 1 },
+ freenas_user => { optional => 1 },
+ freenas_password => { optional => 1 },
+ freenas_use_ssl => { optional => 1 },
+ freenas_apiv4_host => { optional => 1 },
lio_tpg => { optional => 1 },
content => { optional => 1 },
bwlimit => { optional => 1 },
@@ -243,6 +280,40 @@
my $path = "iscsi://$portal/$target/$lun";
+ # Multipath enhancement
+ eval {
+ my $wwid = $class->zfs_get_wwid_number($scfg, $guid);
+# syslog(info,"JD: path get_lun_number guid $guid");
+
+ if ($wwid =~ /^([-\@\w.]+)$/) {
+ $wwid = $1; # $data now untainted
+ } else {
+ die "Bad data in '$wwid'"; # log this somewhere
+ }
+ my $wwid_end = substr $wwid, 16;
+
+ my $mapper = '';
+ sleep 3;
+ run_command("iscsiadm -m session --rescan");
+ sleep 3;
+ my $line = `/usr/sbin/multipath -ll | grep \"$wwid_end\"`;
+ my ($mapper_device) = split(' ', $line);
+ $mapper_device = "" unless $mapper_device;
+ $mapper .= $mapper_device;
+
+ if ($mapper =~ /^([-\@\w.]+)$/) {
+ $mapper = $1; # $data now untainted
+ } else {
+ $mapper = '';
+ }
+
+# syslog(info,"Multipath mapper found: $mapper\n");
+ if ($mapper ne "") {
+ $path = "/dev/mapper/$mapper";
+ sleep 5;
+ }
+ };
+
return ($path, $vmid, $vtype);
}

View File

@ -0,0 +1,79 @@
--- apidoc.js.orig 2021-11-15 10:07:34.000000000 -0500
+++ apidoc.js 2021-12-06 08:04:01.648822707 -0500
@@ -44064,6 +44064,31 @@
"type" : "string",
"typetext" : "<string>"
},
+ "freenas_user" : {
+ "description" : "FreeNAS user for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_password" : {
+ "description" : "FreeNAS password for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_use_ssl" : {
+ "description" : "FreeNAS API access via SSL",
+ "optional" : 1,
+ "type" : "boolean",
+ "typetext" : "<boolean>"
+ },
+ "freenas_apiv4_host" : {
+ "description" : "FreeNAS API Host via IPv4",
+ "format" : "address",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"fuse" : {
"description" : "Mount CephFS through FUSE.",
"optional" : 1,
@@ -44275,6 +44300,12 @@
"type" : "boolean",
"typetext" : "<boolean>"
},
+ "target" : {
+ "description" : "iSCSI target.",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"transport" : {
"description" : "Gluster transport: tcp or rdma",
"enum" : [
@@ -44547,6 +44578,31 @@
"optional" : 1,
"type" : "string",
"typetext" : "<string>"
+ },
+ "freenas_user" : {
+ "description" : "FreeNAS user for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_password" : {
+ "description" : "FreeNAS password for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_use_ssl" : {
+ "description" : "FreeNAS API access via SSL",
+ "optional" : 1,
+ "type" : "boolean",
+ "typetext" : "<boolean>"
+ },
+ "freenas_apiv4_host" : {
+ "description" : "FreeNAS API Host via IPv4",
+ "format" : "address",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
},
"fuse" : {
"description" : "Mount CephFS through FUSE.",

View File

@ -0,0 +1,79 @@
--- apidoc.js.orig 2021-11-15 10:07:34.000000000 -0500
+++ apidoc.js 2021-12-06 08:04:01.648822707 -0500
@@ -44064,6 +44064,31 @@
"type" : "string",
"typetext" : "<string>"
},
+ "freenas_user" : {
+ "description" : "FreeNAS user for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_password" : {
+ "description" : "FreeNAS password for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_use_ssl" : {
+ "description" : "FreeNAS API access via SSL",
+ "optional" : 1,
+ "type" : "boolean",
+ "typetext" : "<boolean>"
+ },
+ "freenas_apiv4_host" : {
+ "description" : "FreeNAS API Host via IPv4",
+ "format" : "address",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"fuse" : {
"description" : "Mount CephFS through FUSE.",
"optional" : 1,
@@ -44275,6 +44300,12 @@
"type" : "boolean",
"typetext" : "<boolean>"
},
+ "target" : {
+ "description" : "iSCSI target.",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"transport" : {
"description" : "Gluster transport: tcp or rdma",
"enum" : [
@@ -44547,6 +44578,31 @@
"optional" : 1,
"type" : "string",
"typetext" : "<string>"
+ },
+ "freenas_user" : {
+ "description" : "FreeNAS user for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_password" : {
+ "description" : "FreeNAS password for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "freenas_use_ssl" : {
+ "description" : "FreeNAS API access via SSL",
+ "optional" : 1,
+ "type" : "boolean",
+ "typetext" : "<boolean>"
+ },
+ "freenas_apiv4_host" : {
+ "description" : "FreeNAS API Host via IPv4",
+ "format" : "address",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
},
"fuse" : {
"description" : "Mount CephFS through FUSE.",

View File

@ -0,0 +1,189 @@
--- pvemanagerlib.js.orig 2022-03-17 09:08:40.000000000 -0400
+++ pvemanagerlib.js 2022-04-03 08:54:10.229689187 -0400
@@ -8068,6 +8068,7 @@
alias: ['widget.pveiScsiProviderSelector'],
comboItems: [
['comstar', 'Comstar'],
+ ['freenas', 'FreeNAS-API'],
['istgt', 'istgt'],
['iet', 'IET'],
['LIO', 'LIO'],
@@ -49636,6 +49637,7 @@
data: {
isLIO: false,
isComstar: true,
+ isFreeNAS: false,
hasWriteCacheOption: true,
},
},
@@ -49648,10 +49650,26 @@
},
},
changeISCSIProvider: function(f, newVal, oldVal) {
+ var me = this;
var vm = this.getViewModel();
vm.set('isLIO', newVal === 'LIO');
vm.set('isComstar', newVal === 'comstar');
- vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
+ vm.set('isFreeNAS', newVal === 'freenas');
+ vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'freenas' || newVal === 'istgt');
+ if (newVal !== 'freenas') {
+ me.lookupReference('freenas_use_ssl_field').setValue(false);
+ me.lookupReference('freenas_apiv4_host_field').setValue('');
+ me.lookupReference('freenas_user_field').setValue('');
+ me.lookupReference('freenas_user_field').allowBlank = true;
+ me.lookupReference('freenas_password_field').setValue('');
+ me.lookupReference('freenas_password_field').allowBlank = true;
+ me.lookupReference('freenas_confirmpw_field').setValue('');
+ me.lookupReference('freenas_confirmpw_field').allowBlank = true;
+ } else {
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ me.lookupReference('freenas_password_field').allowBlank = false;
+ me.lookupReference('freenas_confirmpw_field').allowBlank = false;
+ }
},
},
@@ -49669,6 +49687,7 @@
},
setValues: function(values) {
+ values.freenas_confirmpw = values.freenas_password;
values.writecache = values.nowritecache ? 0 : 1;
this.callParent([values]);
},
@@ -49685,7 +49704,7 @@
allowBlank: false,
},
{
- xtype: me.isCreate ? 'textfield' : 'displayfield',
+ xtype: 'textfield',
name: 'pool',
value: '',
fieldLabel: gettext('Pool'),
@@ -49695,11 +49714,11 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'blocksize',
value: '4k',
- fieldLabel: gettext('Block Size'),
+ fieldLabel: gettext('ZFS Block Size'),
allowBlank: false,
},
{
- xtype: me.isCreate ? 'textfield' : 'displayfield',
+ xtype: 'textfield',
name: 'target',
value: '',
fieldLabel: gettext('Target'),
@@ -49710,9 +49729,34 @@
name: 'comstar_tg',
value: '',
fieldLabel: gettext('Target group'),
- bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
+ bind: {
+ hidden: '{!isComstar}'
+ },
allowBlank: true,
},
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'freenas_use_ssl',
+ reference: 'freenas_use_ssl_field',
+ inputId: 'freenas_use_ssl_field',
+ checked: false,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ uncheckedValue: 0,
+ fieldLabel: gettext('API use SSL'),
+ },
+ {
+ xtype: 'textfield',
+ name: 'freenas_user',
+ reference: 'freenas_user_field',
+ inputId: 'freenas_user_field',
+ value: '',
+ fieldLabel: gettext('API Username'),
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ },
];
me.column2 = [
@@ -49742,7 +49786,9 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'comstar_hg',
value: '',
- bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
+ bind: {
+ hidden: '{!isComstar}'
+ },
fieldLabel: gettext('Host group'),
allowBlank: true,
},
@@ -49750,9 +49796,62 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'lio_tpg',
value: '',
- bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
- allowBlank: false,
+ bind: {
+ hidden: '{!isLIO}'
+ },
fieldLabel: gettext('Target portal group'),
+ allowBlank: true
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_apiv4_host',
+ reference: 'freenas_apiv4_host_field',
+ value: '',
+ editable: true,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('API IPv4 Host'),
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_password',
+ reference: 'freenas_password_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('API Password'),
+ change: function(f, value) {
+ if (f.rendered) {
+ f.up().down('field[name=freenas_confirmpw]').validate();
+ }
+ },
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_confirmpw',
+ reference: 'freenas_confirmpw_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ submitValue: false,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('Confirm Password'),
+ validator: function(value) {
+ var pw = this.up().down('field[name=freenas_password]').getValue();
+ if (pw !== value) {
+ return "Passwords do not match!";
+ }
+ return true;
+ },
},
];

View File

@ -0,0 +1,189 @@
--- pvemanagerlib.js.orig 2022-03-17 09:08:40.000000000 -0400
+++ pvemanagerlib.js 2022-04-03 08:54:10.229689187 -0400
@@ -8068,6 +8068,7 @@
alias: ['widget.pveiScsiProviderSelector'],
comboItems: [
['comstar', 'Comstar'],
+ ['freenas', 'FreeNAS-API'],
['istgt', 'istgt'],
['iet', 'IET'],
['LIO', 'LIO'],
@@ -49636,6 +49637,7 @@
data: {
isLIO: false,
isComstar: true,
+ isFreeNAS: false,
hasWriteCacheOption: true,
},
},
@@ -49648,10 +49650,26 @@
},
},
changeISCSIProvider: function(f, newVal, oldVal) {
+ var me = this;
var vm = this.getViewModel();
vm.set('isLIO', newVal === 'LIO');
vm.set('isComstar', newVal === 'comstar');
- vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
+ vm.set('isFreeNAS', newVal === 'freenas');
+ vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'freenas' || newVal === 'istgt');
+ if (newVal !== 'freenas') {
+ me.lookupReference('freenas_use_ssl_field').setValue(false);
+ me.lookupReference('freenas_apiv4_host_field').setValue('');
+ me.lookupReference('freenas_user_field').setValue('');
+ me.lookupReference('freenas_user_field').allowBlank = true;
+ me.lookupReference('freenas_password_field').setValue('');
+ me.lookupReference('freenas_password_field').allowBlank = true;
+ me.lookupReference('freenas_confirmpw_field').setValue('');
+ me.lookupReference('freenas_confirmpw_field').allowBlank = true;
+ } else {
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ me.lookupReference('freenas_password_field').allowBlank = false;
+ me.lookupReference('freenas_confirmpw_field').allowBlank = false;
+ }
},
},
@@ -49669,6 +49687,7 @@
},
setValues: function(values) {
+ values.freenas_confirmpw = values.freenas_password;
values.writecache = values.nowritecache ? 0 : 1;
this.callParent([values]);
},
@@ -49685,7 +49704,7 @@
allowBlank: false,
},
{
- xtype: me.isCreate ? 'textfield' : 'displayfield',
+ xtype: 'textfield',
name: 'pool',
value: '',
fieldLabel: gettext('Pool'),
@@ -49695,11 +49714,11 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'blocksize',
value: '4k',
- fieldLabel: gettext('Block Size'),
+ fieldLabel: gettext('ZFS Block Size'),
allowBlank: false,
},
{
- xtype: me.isCreate ? 'textfield' : 'displayfield',
+ xtype: 'textfield',
name: 'target',
value: '',
fieldLabel: gettext('Target'),
@@ -49710,9 +49729,34 @@
name: 'comstar_tg',
value: '',
fieldLabel: gettext('Target group'),
- bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
+ bind: {
+ hidden: '{!isComstar}'
+ },
allowBlank: true,
},
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'freenas_use_ssl',
+ reference: 'freenas_use_ssl_field',
+ inputId: 'freenas_use_ssl_field',
+ checked: false,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ uncheckedValue: 0,
+ fieldLabel: gettext('API use SSL'),
+ },
+ {
+ xtype: 'textfield',
+ name: 'freenas_user',
+ reference: 'freenas_user_field',
+ inputId: 'freenas_user_field',
+ value: '',
+ fieldLabel: gettext('API Username'),
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ },
];
me.column2 = [
@@ -49742,7 +49786,9 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'comstar_hg',
value: '',
- bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
+ bind: {
+ hidden: '{!isComstar}'
+ },
fieldLabel: gettext('Host group'),
allowBlank: true,
},
@@ -49750,9 +49796,62 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'lio_tpg',
value: '',
- bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
- allowBlank: false,
+ bind: {
+ hidden: '{!isLIO}'
+ },
fieldLabel: gettext('Target portal group'),
+ allowBlank: true
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_apiv4_host',
+ reference: 'freenas_apiv4_host_field',
+ value: '',
+ editable: true,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('API IPv4 Host'),
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_password',
+ reference: 'freenas_password_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('API Password'),
+ change: function(f, value) {
+ if (f.rendered) {
+ f.up().down('field[name=freenas_confirmpw]').validate();
+ }
+ },
+ },
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_confirmpw',
+ reference: 'freenas_confirmpw_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ submitValue: false,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('Confirm Password'),
+ validator: function(value) {
+ var pw = this.up().down('field[name=freenas_password]').getValue();
+ if (pw !== value) {
+ return "Passwords do not match!";
+ }
+ return true;
+ },
},
];