Compare commits

...

49 Commits
v2.0 ... master

Author SHA1 Message Date
Kevin Scott Adams 29b110f5e2
Merge pull request #173 from TheGrandWazoo/develop
Develop
2024-01-06 14:26:17 -05:00
Kevin Scott Adams c35329f77d
Merge pull request #172 from TheGrandWazoo/feature_bearer_token
Feature bearer token
2024-01-06 14:17:00 -05:00
Kevin Scott Adams b9dd1d6f89 Update for Proxmox 8 and Bearer Token
- Patch updates for Proxmox VE 8
- Update to select Basic or Bearer authentication.
2024-01-06 13:43:35 -05:00
Kevin Scott Adams 466d819a89
Merge pull request #160 from TheGrandWazoo/master
Merge to feature_bearer_token
2023-08-19 10:53:01 -04:00
Kevin Scott Adams ea3637d29a
Update README.md
- Update README.md to be more structured and selective from a visitors view.
- Update the Roadmap section.
- Update the Donators list.
- Update the New Install Instructions section to allow the visitor to select the GPG location they want to use.
- Update the Activity section.
- Fix spelling errors.
2023-08-19 10:46:39 -04:00
Kevin Scott Adams b6e34be5e5
Update README.md for typo
- Fixed testing repo name in install section.
2023-08-16 09:05:06 -04:00
Kevin Scott Adams ca48a9e517
Update README.md for new repos
- Updated anchor.
- Added documentation to roadmap.
2023-08-16 09:03:20 -04:00
Kevin Scott Adams 871c720026
Merge pull request #157 from TheGrandWazoo/TheGrandWazoo-readme-patch-2
Update README.md
2023-08-16 08:54:47 -04:00
Kevin Scott Adams 65c1c250df
Update README.md
- Change announcement for the Cloudsmith repos.
- Changed the New Install section to include instructions for stable and development repos.
2023-08-16 08:54:15 -04:00
Kevin Scott Adams 80c5eda63a
Merge pull request #155 from TheGrandWazoo/TheGrandWazoo-patch-1
Update README.md
2023-08-09 13:07:11 -04:00
Kevin Scott Adams 3977be6daa
Update README.md
Changed Attention description to notify that a new repo is on the horizon.
2023-08-09 13:02:43 -04:00
Kevin Scott Adams a86bf3eb95
Update README.md
Update README.md

- Added ATTENTION due to JFrog canceling my subscription.
2023-07-13 09:09:22 -04:00
Kevin Scott Adams 0997a68048 Import Proxmox stock PVE Manager Lib.
- Imported the stock Proxmox pvemanagerlib.js from Proxmox 7.4-3.
2023-06-12 17:19:16 -04:00
Kevin Scott Adams d507706996 Remove previous commmit.
- Forgot to change branches.
2023-06-12 17:17:56 -04:00
Kevin Scott Adams 9de5aaf81b Import stock pvemanagerlib.js.
- Imported stock pvemanagerlib.js from Proxmox 7.4-3 to develop and
create patches against.
2023-06-12 17:16:29 -04:00
Kevin Scott Adams dc5a5c2be9
Merge pull request #130 from TheGrandWazoo/revert-129-2.0
Revert "2.0"
2023-02-20 13:24:48 -05:00
Kevin Scott Adams c1f453e15c
Revert "2.0" 2023-02-20 13:24:07 -05:00
Kevin Scott Adams 6141b6c784
Merge pull request #129 from TheGrandWazoo/2.0
2.0
2023-02-20 13:07:21 -05:00
Kevin Scott Adams b05124592f Update README.md
- Updated Roadmap and Updates.
- Removed Attention
- Added a note about systemctl restart pvescheduler.service before
2.2.0-0-beta8.
2023-02-12 17:14:15 -05:00
Kevin Scott Adams 9021ec22b7 Fix recursion error.
- When SSL redirect is enabled on TrueNAS and a change from V1 to V2
api's needs to happen then we overrun the limit of 1 on the recursion
loop. Set it to 2.
- Added some logging for TrueNAS-Scale conversion from slash (/) to dash
(-).
2022-06-05 18:57:52 -04:00
Kevin Scott Adams d2f5c2b27f Update readme.MD.
- Updated new repo install.
- Updated Roadmap.
- Cleanup old information.
- Updated Donation list.
- Changed FreeNAS to TrueNAS in most of the instructions.
2022-06-04 09:58:34 -04:00
Kevin Scott Adams a2e395658d
Update README.md 2022-05-31 16:58:53 -04:00
Kevin Scott Adams 4039df8a59
Update README.md 2022-05-31 16:56:05 -04:00
Kevin Scott Adams aea45c992f
Update README.md 2022-05-25 21:46:55 -04:00
Kevin Scott Adams 2e9d736ebd
Update README.md 2022-05-25 21:45:15 -04:00
Kevin Scott Adams 7ecd64f79a
Update README.md 2022-05-25 21:34:58 -04:00
Kevin Scott Adams dfaf7b5c8d
Merge pull request #119 from TheGrandWazoo/master
Merge master to develop
2022-05-22 08:04:48 -04:00
Kevin Scott Adams 0b760eefc3 Fix TrueNAS-Scale slash replacement.
- When changing from slashes (/) to dashes (-), I did not provide the
global parameter so a Storage/Tank/Disks would turn out to be
Storage-Tank/Disks causing a iSCSI: Failed to connect to LUN :
iscsi_service failed with : iscsi_service_reconnect_if_loggedin. Can not
reconnect right now.
2022-05-21 15:19:46 -04:00
Kevin Scott Adams c3b6f38c61 Fix TrueNAS-Scale parsing.
- TrueNAS-Scale returns 'application/json' so we need to catch that also
on the return code of 200 from a version API call.
2022-05-21 14:21:05 -04:00
Kevin Scott Adams dc3c724d45 Merge branch 'master' of https://github.com/TheGrandWazoo/freenas-proxmox.git 2022-05-20 12:40:08 -04:00
Kevin Scott Adams 75f63b56d1 Update plugin for TrueNAS 13
- Created conditional to parse new TrueNAS 13 version.
- Created conditional to check for a 200 and that the Content-Type is
text/html so it will change to v2.0 of the API's. This is new behavior
in TrueNAS-Core 13.
2022-05-20 12:39:55 -04:00
Kevin Scott Adams 50a474bea1
Update README.md
Updated Donators - Thank you again.
Updated messages of repo and development status.
2022-05-20 10:02:17 -04:00
Kevin Scott Adams bfb1962503
Update README.md 2022-05-11 15:45:14 -04:00
Kevin Scott Adams 85a67077b2 Optimize methods.
- Instead of using foreach loops to iterate through an array change to
using a hash which the key is the value we are looking for.
2022-04-13 16:29:24 -04:00
Kevin Scott Adams 4663fca8b0 Trigger a build.
- Just touch the README.md to trigger.
2022-04-03 13:25:58 -04:00
Kevin Scott Adams e4c9f12f03 Update README.md
- Trigger a build.
2022-04-03 11:10:13 -04:00
Kevin Scott Adams 8da7d98538 Update README.md
- Need to trigger a build.
2022-04-03 11:03:29 -04:00
Kevin Scott Adams 7976b1cfe8 Update README.md
- Possible outage due to lack of fundings.
2022-04-03 10:51:11 -04:00
Kevin Scott Adams 780c6590fe Update patches and some fixes.
- Add the true path to the debug statement when comparing targets.
- Add patch set for ZFSPlugin.pm for Storage lib 7.1-1
- Add patch set for pvemanagerlib.js for pve-manager version 7.1-11
- Add patch set for apidoc.js for pve-docs version 7.1-2.
- Create stable-7 directory for future installs based on Proxmox major
version each modules version.
2022-04-03 09:18:31 -04:00
Kevin Scott Adams 08bd48f35c
Merge pull request #111 from hans00/master
Fix bug for TrueNAS-SCALE
2022-03-02 08:57:03 -05:00
Hans 4b0ec91508
Don't replace scfg data
Fix TheGrandWazoo/freenas-proxmox#107
2022-02-24 01:07:32 +08:00
Kevin Scott Adams bcf0f78514
Create stale.yml 2021-11-21 21:35:35 -05:00
Kevin Scott Adams 36f8ec7f1e
Merge pull request #106 from TheGrandWazoo/master
Fixes for Proxmox 6 and 7 with TrueNAS-Scale support.
2021-08-08 10:14:07 -04:00
Kevin Scott Adams bd9c2e27ee
Merge pull request #97 from TheGrandWazoo/master
Damn copy and paste.
2021-04-13 14:37:16 -04:00
Kevin Scott Adams 9b95a08ed4
Merge pull request #94 from TheGrandWazoo/master
Merge fixes
2021-03-20 15:15:33 -04:00
Kevin Scott Adams 837399e62f
Merge pull request #80 from TheGrandWazoo/master
Merge request to v2.0 branch.
2020-10-13 07:31:17 -04:00
Kevin Scott Adams e1657ca395
Merge pull request #73 from TheGrandWazoo/master
Fix issue with JSON variable names in V1.0 api
2020-09-10 15:47:00 -04:00
Kevin Scott Adams 324b893a7f
Merge pull request #70 from TheGrandWazoo/master
Update branch 2.0
2020-09-02 16:44:44 -04:00
Kevin Scott Adams a11d7de0c3
Merge pull request #66 from TheGrandWazoo/master
Rework the error routine so it will not error out.
2020-08-27 13:33:31 -04:00
24 changed files with 171836 additions and 225 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

265
README.md
View File

@ -1,82 +1,227 @@
# 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 Plugin for Proxmox VE
## Thank you for all that have donated to the project
## 📢: ATTENTION 2023-08-16 📢: New repos are now online at [Cloudsmith](#new-installs).
## Activity
<details>
<summary>Expand to see the activity tree</summary>
<blockquote>
<details>
<summary>2023-08-18</summary>
- Update and cleanup the README.md
</details>
<details><summary>2023-08-16</summary>
- Fixed repos. https://github.com/TheGrandWazoo/freenas-proxmox/issues/151, https://github.com/TheGrandWazoo/freenas-proxmox/issues/152, https://github.com/TheGrandWazoo/freenas-proxmox/issues/153 See [New Installs](#new-installs).
- Fixed PayPal issues. https://github.com/TheGrandWazoo/freenas-proxmox/issues/154
- Updated README.md
</details>
<details><summary>2023-08-12</summary>
- Fixed postinst issue with Windows-based EOL. https://github.com/TheGrandWazoo/freenas-proxmox/issues/149
</details>
<details><summary>2023-02-12</summary>
- Added `systemctl restart pvescheduler.service` command to the package based on https://github.com/TheGrandWazoo/freenas-proxmox/issues/109#issuecomment-1367527917
</details>
</blockquote>
</details>
## Donations [![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)
<details>Donators<summary>Thank you for all that have donated to the project - Updated 2023-08-18</summary>
Alexander Finkhäuser - Recurring
Bjarte Kvamme - Recurring
Jonathan Schober - Recurring
Carlos Galvez from Security Camera
Sebastian Fischer
Eugene van der Merwe
Martin Gonzalez
Jakub Jochec
Frederic Silvi
Vincent Cui
Mark Komarinski
Jesse Bryan
Maksym Vasylenko
Daniel Most
Velocity Host
Robert Hancock
Clevvi Technology
Mark Elkins - Reoccuring
Mark Elkins
Marc Hodler
Martin Gonzalez
</details>
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:
```
/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
Their donations have allowed for:
- A 4 Node Proxmox VE Cluster for testing and development.
- Spin up old and new revisions of FreeNAS and TrueNAS.
- 10Gb Ethernet Testing.
- Multihomed configuration testing.
- In progress and as best I can in a flat network.
If you wish, you may remove the directory 'freenas-proxmox' where your system is currently
housing the repo and then issue the following to have a clean system before installing the
package.
## Roadmap
<details><summary>Roadmap details</summary>
On Proxmox 5
```bash
apt install --reinstall pve-manager pve-docs libpve-storage-perl
```
* Update the documentation - <i>In Progress</i>.
* Restructure the main README.md for better readability.
* Add some screenshots.
* Fix Max Lun Limit issue.
* https://github.com/TheGrandWazoo/freenas-proxmox/issues/150
* Fix automated builds - <i>In Progress</i>.
* Production - 'main' repo component.
* Autoinstall the SSH keys.
* Tech spike to see if it is even doable.
* Hashicorp Vault integration.
* Pull in secrets from a Hashicorp Vault service.
* Tech spike to see if it is even doable.
* Package the patches with the deb package.
* Remove the need for git dependency.
* Change to LWP::UserAgent
* Remove dependency of the REST::Client because LWP::UserAgent is already installed and used by Proxmox VE.
* Change from FreeNAS to TrueNAS - <i>In Progress</i>.
* Cleanup the FreeNAS repo and name everything to TrueNAS to be inline with the product.
* Add API key for direct TrueNAS services - <i>In Progress</i>.
* 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.
On Proxmox 6
```bash
apt reinstall pve-manager pve-docs libpve-storage-perl
```
</details>
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
```
## New Install Instructions
### 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.
### Select at least one `Step 1.x` based on your preference. Can be combined.
#### 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
```
<details><summary>Step 1.0: For stable releases. <b>Enabled</b> by default.</summary>
Then issue the following to install the package
```
apt update
apt install freenas-proxmox
```
### truenas-proxmox repo - Currently follows the 2.0 branch.
Then just do your regular upgrade via apt to your system; the package will automatically
issue all commands to patch the files.
```bash
apt update
apt [full|dist]-upgrade
```
Select one of the following GPG Key locations based on your preference.
If you wish not to use the package you may remove it at anytime with
```
apt [remove|purge] freenas-proxmox
```
This will place you back to a normal and unpatched Proxmox VE install.
```bash
# Preferred - based on documentation. Copy and paste to bash command line:
keyring_location=/usr/share/keyrings/ksatechnologies-truenas-proxmox-keyring.gpg
```
Please be aware that this plugin uses the FreeNAS APIs and NOT the ssh/scp interface like the other plugins use, but...
```bash
# Alternative - If you wish to continue with the old ways. Copy and paste to bash command line:
keyring_location=/etc/apt/trusted.gpg.d/ksatechnologies-truenas-proxmox.gpg
```
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`.
Copy and paste to bash command line to load the GPG key to the location selected above:
```bash
curl -1sLf 'https://dl.cloudsmith.io/public/ksatechnologies/truenas-proxmox/gpg.284C106104A8CE6D.key' | gpg --dearmor >> ${keyring_location}
```
Copy and paste the following code to bash command line to create '/etc/apt/sources.list.d/ksatechnologies-repo.list'
```bash
cat << EOF > /etc/apt/sources.list.d/ksatechnologies-repo.list
# Source: KSATechnologies
# Site: https://cloudsmith.io
# Repository: KSATechnologies / truenas-proxmox
# Description: TrueNAS plugin for Proxmox VE - Production
deb [signed-by=${keyring_location}] https://dl.cloudsmith.io/public/ksatechnologies/truenas-proxmox/deb/debian any-version main
EOF
```
</details>
<details><summary>Step 1.1: For development releases. <i>Disabled</i> by default.</summary>
### truenas-proxmox-testing repo - Follows the master branch and you wish to test before a stable release (beta).
Select one of the following GPG Key locations based on your preference.
```bash
# Preferred - based on documentation. Copy and paste to bash command line:
keyring_location=/usr/share/keyrings/ksatechnologies-truenas-proxmox-testing-keyring.gpg
```
```bash
# Alternative - If you wish to continue with the old ways. Copy and paste to bash command line:
keyring_location=/etc/apt/trusted.gpg.d/ksatechnologies-truenas-proxmox-testing.gpg
```
Copy and paste to bash command line to load the GPG key to the location selected above:
```bash
curl -1sLf 'https://dl.cloudsmith.io/public/ksatechnologies/truenas-proxmox-testing/gpg.CACC9EE03F2DFFCC.key' | gpg --dearmor >> ${keyring_location}
```
Copy and paste the following code to bash command line to create '/etc/apt/sources.list.d/ksatechnologies-testing-repo.list'
```bash
cat << EOF > /etc/apt/sources.list.d/ksatechnologies-testing-repo.list
# Source: KSATechnologies
# Site: https://cloudsmith.io
# Repository: KSATechnologies / truenas-proxmox-testing
# Description: TrueNAS plugin for Proxmox VE - Testing
deb [signed-by=${keyring_location}] https://dl.cloudsmith.io/public/ksatechnologies/truenas-proxmox-testing/deb/debian any-version main
EOF
```
</details>
<details><summary>Step 2.0: Next step after completing any combination of the 1.x steps</summary>
### Update apt
Then issue the following to install the package
```bash
apt update
apt install freenas-proxmox
```
</details>
<details><summary>Step 3.0: Maintenance.</summary>
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
apt update
apt [full|dist]-upgrade
```
</details>
</details>
## Uninstall truenas-proxmox
<details><summary>If you wish not to use the package you may remove it at anytime with the following:</summary>
```
apt [remove|purge] freenas-proxmox
```
This will place you back to a normal and non-patched Proxmox VE install.
</details>
## Notes:
### 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 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. 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_methods = undef; # API Methods 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
my $freenas_api_version_matrix = {
@ -126,10 +128,13 @@ sub run_lun_command {
syslog("info",(caller(0))[3] . " : $method(@params)");
if(!defined($scfg->{'freenas_user'}) || !defined($scfg->{'freenas_password'})) {
die "Undefined freenas_user and/or freenas_password.";
if (defined($scfg->{'truenas_token_auth'}) && $scfg->{'truenas_token_auth'}) {
if (!defined($scfg->{'truenas_secret'})) {
die "Undefined `truenas_secret` variable.";
}
} elsif (!defined($scfg->{'freenas_user'}) || !defined($scfg->{'freenas_password'})) {
die "Undefined `freenas_user` and/or `freenas_password` variables.";
}
if (!defined $freenas_server_list->{defined($scfg->{freenas_apiv4_host}) ? $scfg->{freenas_apiv4_host} : $scfg->{portal}}) {
freenas_api_check($scfg);
}
@ -197,52 +202,45 @@ sub run_list_view {
#
#
#
# Optimized
sub run_list_lu {
my ($scfg, $timeout, $method, $result_value_type, @params) = @_;
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 $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 = $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");
}
syslog("info", (caller(0))[3] . " : called with (method: '$method'; result_value_type: '$result_value_type'; param[0]: '$object')");
$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;
}
#
#
#
# Optimzed
sub run_list_extent {
my ($scfg, $timeout, $method, @params) = @_;
my $object = $params[0];
syslog("info", (caller(0))[3] . " : called with (method=$method; object=$object)");
syslog("info", (caller(0))[3] . " : called with (method: '$method'; params[0]: '$object')");
my $result = undef;
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;
}
@ -280,24 +278,24 @@ sub run_create_lu {
#
#
#
# Optimzied
sub run_delete_lu {
my ($scfg, $timeout, $method, @params) = @_;
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 $lun = undef;
my $link = undef;
foreach my $item (@$luns) {
if($dev_prefix . $item->{ $freenas_api_variables->{'extentpath'}} eq $lun_path) {
$lun = $item;
last;
}
}
$lun_path =~ s/^\Q$dev_prefix//;
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);
die "Unable to find the target id for $scfg->{target}" if !defined($target_id);
@ -346,31 +344,47 @@ sub freenas_api_connect {
}
$freenas_server_list->{$apihost}->setHost($scheme . '://' . $apihost);
$freenas_server_list->{$apihost}->addHeader('Content-Type', 'application/json');
$freenas_server_list->{$apihost}->addHeader('Authorization', 'Basic ' . encode_base64($scfg->{freenas_user} . ':' . $scfg->{freenas_password}));
if (defined($scfg->{'truenas_token_auth'})) {
syslog("info", (caller(0))[3] . " : Authentication using Bearer Token Auth");
$freenas_server_list->{$apihost}->addHeader('Authorization', 'Bearer ' . $scfg->{truenas_secret});
} else {
syslog("info", (caller(0))[3] . " : Authentication using Basic Auth");
$freenas_server_list->{$apihost}->addHeader('Authorization', 'Basic ' . encode_base64($scfg->{freenas_user} . ':' . $scfg->{freenas_password}));
}
# If using SSL, don't verify SSL certs
if ($scfg->{freenas_use_ssl}) {
$freenas_server_list->{$apihost}->getUseragent()->ssl_opts(verify_hostname => 0);
$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
my $code = $freenas_server_list->{$apihost}->request('GET', $apiping)->responseCode();
if ($code == 200) { # Successful connection
syslog("info", (caller(0))[3] . " : REST connection successful to '" . $apihost . "' using the '" . $scheme . "' protocol");
$runawayprevent = 0;
} elsif ($runawayprevent > 1) { # Make sure we are not recursion calling.
my $api_response = $freenas_server_list->{$apihost}->request('GET', $apiping);
my $code = $api_response->responseCode();
my $type = $api_response->responseHeader('Content-Type');
syslog("info", (caller(0))[3] . " : REST connection header Content-Type:'" . $type . "'");
# Make sure we are not recursion calling.
if ($runawayprevent > 2) {
freenas_api_log_error($freenas_server_list->{$apihost});
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");
$runawayprevent++;
$apiping =~ s/v1\.0/v2\.0/;
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");
$runawayprevent++;
$scfg->{freenas_use_ssl} = 1;
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});
die "Unable to connect to the FreeNAS API service at '" . $apihost . "' using the '" . $scheme . "' protocol";
}
@ -399,16 +413,32 @@ sub freenas_api_check {
} else {
$result = $freenas_rest_connection->responseContent();
}
$result =~ s/^"//g;
$result =~ s/"//g;
syslog("info", (caller(0))[3] . " : successful : Server version: " . $result);
$result =~ s/^((?!\-\d).*)\-(\d+)\.(\d+)\-([A-Za-z]*)(?(?=\-)\-(\d*)\-(\d*)|(\d?)\.?(\d?))//;
$product_name = $1;
my $freenas_version = sprintf("%02d%02d%02d%02d", $2, $3 || 0, $7 || 0, $8 || 0);
syslog("info", (caller(0))[3] . " : ". $product_name . " Unformatted Version: " . $freenas_version);
if ($freenas_version >= 11030100) {
if ($result =~ /^(TrueNAS|FreeNAS)-(\d+)\.(\d+)\-U(\d+)(?(?=\.)\.(\d+))$/) {
$product_name = $1;
$truenas_version = sprintf("%02d%02d%02d%02d", $2, $3 || 0, $4 || 0, $5 || 0);
} elsif ($result =~ /^(TrueNAS)-(\d+)\.(\d+)(?(?=\-U\d+)-U(\d+)|-\w+)(?(?=\.).(\d+))$/) {
$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";
$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 {
syslog("info", (caller(0))[3] . " : REST Client already initialized");
}
@ -512,10 +542,15 @@ sub freenas_iscsi_create_extent {
my $name = $lun_path;
$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") {
$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;
$device =~ s/^\/dev\///; # strip /dev/
@ -682,7 +717,7 @@ sub freenas_list_lu {
my $targets = freenas_iscsi_get_target($scfg);
my $target_id = freenas_get_targetid($scfg);
my @luns = ();
my %lun_hash;
my $iscsi_lunid = undef;
if(defined($target_id)) {
@ -694,21 +729,21 @@ sub freenas_list_lu {
foreach my $node (@$extents) {
if($node->{'id'} == $item->{$freenas_api_variables->{'extentid'}}) {
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 {
syslog("info", (caller(0))[3] . " : iscsi_lunid did not pass tainted testing");
next;
syslog("warn", (caller(0))[3] . " : iscsi_lunid did not pass tainted testing");
}
$node->{$freenas_api_variables->{'lunid'}} .= $iscsi_lunid;
push(@luns , $node);
last;
}
}
}
}
}
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

@ -0,0 +1,157 @@
--- ZFSPlugin.pm.orig 2023-12-31 09:56:18.895228853 -0500
+++ ZFSPlugin.pm 2023-12-31 09:57:08.830488875 -0500
@@ -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,32 @@
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 (Deprecated)",
+ type => 'string',
+ },
+ truenas_secret => {
+ description => "TrueNAS API Secret",
+ type => 'string',
+ },
+ truenas_token_auth => {
+ description => "TrueNAS API Authentication with Token",
+ type => 'boolean',
+ },
+ 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 +252,20 @@
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 },
+ truenas_secret => { optional => 1 },
+ truenas_token_auth => { optional => 1 },
+ freenas_use_ssl => { optional => 1 },
+ freenas_apiv4_host => { optional => 1 },
lio_tpg => { optional => 1 },
content => { optional => 1 },
bwlimit => { optional => 1 },
@@ -243,6 +290,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 2019-09-23 12:17:37.000000000 -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
--- ZFSPlugin.pm.orig 2023-12-31 09:56:18.895228853 -0500
+++ ZFSPlugin.pm 2023-12-31 09:57:08.830488875 -0500
@@ -10,6 +10,7 @@
use base qw(PVE::Storage::ZFSPoolPlugin);
@ -47,8 +42,8 @@
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'iet') {
@@ -162,6 +168,15 @@
return $class->zfs_request($scfg, undef, 'list_view', $guid);
@@ -166,6 +172,15 @@
die "lun_number for guid $guid is not a number";
}
+# Part of the multipath enhancement
@ -63,7 +58,7 @@
# Configuration
sub type {
@@ -180,6 +195,24 @@
@@ -184,6 +199,32 @@
description => "iscsi provider",
type => 'string',
},
@ -74,9 +69,17 @@
+ type => 'string',
+ },
+ freenas_password => {
+ description => "FreeNAS API Password",
+ description => "FreeNAS API Password (Deprecated)",
+ type => 'string',
+ },
+ truenas_secret => {
+ description => "TrueNAS API Secret",
+ type => 'string',
+ },
+ truenas_token_auth => {
+ description => "TrueNAS API Authentication with Token",
+ type => 'boolean',
+ },
+ freenas_use_ssl => {
+ description => "FreeNAS API access via SSL",
+ type => 'boolean',
@ -88,7 +91,7 @@
# 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
@@ -207,14 +240,18 @@
@@ -211,14 +252,20 @@
nodes => { optional => 1 },
disable => { optional => 1 },
portal => { fixed => 1 },
@ -104,12 +107,14 @@
comstar_tg => { optional => 1 },
+ freenas_user => { optional => 1 },
+ freenas_password => { optional => 1 },
+ truenas_secret => { optional => 1 },
+ truenas_token_auth => { optional => 1 },
+ freenas_use_ssl => { optional => 1 },
+ freenas_apiv4_host => { optional => 1 },
lio_tpg => { optional => 1 },
content => { optional => 1 },
bwlimit => { optional => 1 },
@@ -239,6 +276,40 @@
@@ -243,6 +290,40 @@
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

@ -0,0 +1,91 @@
--- apidoc.js.orig 2024-01-06 13:02:06.730512378 -0500
+++ apidoc.js 2024-01-06 13:02:55.349787105 -0500
@@ -50336,6 +50336,37 @@
"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 (Deprecated)",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "truenas_secret" : {
+ "description" : "TrueNAS Secret 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,
@@ -50555,6 +50586,12 @@
"type" : "boolean",
"typetext" : "<boolean>"
},
+ "target" : {
+ "description" : "iSCSI target.",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"transport" : {
"description" : "Gluster transport: tcp or rdma",
"enum" : [
@@ -50854,6 +50891,37 @@
"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 (Deprecated)",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "truenas_secret" : {
+ "description" : "TrueNAS secret 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 2019-08-07 13:28:29.292382229 -0400
@@ -35001,6 +35001,31 @@
--- apidoc.js.orig 2023-08-16 06:03:55.000000000 -0400
+++ apidoc.js 2023-12-26 14:45:47.202566775 -0500
@@ -47579,6 +47579,37 @@
"type" : "string",
"typetext" : "<string>"
},
@ -11,7 +11,13 @@
+ "typetext" : "<string>"
+ },
+ "freenas_password" : {
+ "description" : "FreeNAS password for API access",
+ "description" : "FreeNAS password for API access (Deprecated)",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "truenas_secret" : {
+ "description" : "TrueNAS Secret for API access",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
@ -32,7 +38,7 @@
"fuse" : {
"description" : "Mount CephFS through FUSE.",
"optional" : 1,
@@ -35157,6 +35182,12 @@
@@ -47798,6 +47829,12 @@
"type" : "boolean",
"typetext" : "<boolean>"
},
@ -45,7 +51,7 @@
"transport" : {
"description" : "Gluster transport: tcp or rdma",
"enum" : [
@@ -35362,6 +35393,31 @@
@@ -48097,6 +48134,37 @@
"optional" : 1,
"type" : "string",
"typetext" : "<string>"
@ -57,7 +63,13 @@
+ "typetext" : "<string>"
+ },
+ "freenas_password" : {
+ "description" : "FreeNAS password for API access",
+ "description" : "FreeNAS password for API access (Deprecated)",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "truenas_secret" : {
+ "description" : "TrueNAS secret for API access",
+ "optional" : 1,
+ "type" : "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,58 +1,162 @@
--- pvemanagerlib.js.orig 2021-05-27 08:28:35.000000000 -0400
+++ pvemanagerlib.js 2021-06-10 11:03:15.380175988 -0400
@@ -7900,6 +7900,7 @@
--- pvemanagerlib.js.orig 2023-12-30 15:36:27.913505863 -0500
+++ pvemanagerlib.js 2024-01-02 09:30:56.000000000 -0500
@@ -9228,6 +9228,7 @@
alias: ['widget.pveiScsiProviderSelector'],
comboItems: [
['comstar', 'Comstar'],
+ ['freenas', 'FreeNAS-API'],
+ ['freenas', 'FreeNAS/TrueNAS API'],
['istgt', 'istgt'],
['iet', 'IET'],
['LIO', 'LIO'],
@@ -47367,6 +47368,7 @@
@@ -58017,16 +58018,24 @@
me.callParent();
},
});
+
Ext.define('PVE.storage.ZFSInputPanel', {
extend: 'PVE.panel.StorageBase',
viewModel: {
parent: null,
data: {
+isComstar: true,
+ isFreeNAS: false,
isLIO: false,
isComstar: true,
+ isFreeNAS: false,
- isComstar: true,
+ isToken: false,
hasWriteCacheOption: true,
},
+formulas: {
+ hideUsername: function(get) {
+ return (!get('isFreeNAS') || !(get('isFreeNAS') && !get('isToken')));
+ },
+ },
},
@@ -47379,10 +47381,26 @@
controller: {
@@ -58034,13 +58043,42 @@
control: {
'field[name=iscsiprovider]': {
change: 'changeISCSIProvider',
+},
+ 'field[name=truenas_token_auth]': {
+ change: 'changeUsername',
},
},
changeISCSIProvider: function(f, newVal, oldVal) {
+ var me = this;
+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;
+ }
+ vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'freenas' || newVal === 'istgt');
+ if (newVal !== 'freenas') {
+ me.lookupReference('freenas_use_ssl_field').setValue(false);
+ me.lookupReference('truenas_token_auth_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('truenas_secret_field').setValue('');
+ me.lookupReference('truenas_secret_field').allowBlank = true;
+ me.lookupReference('truenas_confirm_secret_field').setValue('');
+ me.lookupReference('truenas_confirm_secret_field').allowBlank = true;
+ } else {
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ me.lookupReference('truenas_secret_field').allowBlank = false;
+ me.lookupReference('truenas_confirm_secret_field').allowBlank = false;
+ }
+ },
+ changeUsername: function(f, newVal, oldVal) {
+ var me = this;
+ var vm = me.getViewModel();
+ vm.set('isToken', newVal);
+ me.lookupReference('freenas_user_field').allowBlank = newVal;
+ if (newVal) {
+ me.lookupReference('freenas_user_field').setValue('');
+ }
},
},
@@ -47400,6 +47418,7 @@
@@ -58053,28 +58091,78 @@
values.nowritecache = values.writecache ? 0 : 1;
delete values.writecache;
+ console.warn(values.freenas_password);
+ if (values.freenas_password) {
+ values.truenas_secret = values.freenas_password;
+ }
+ console.warn(values.truenas_secret);
return me.callParent([values]);
},
setValues: function(values) {
+ values.freenas_confirmpw = values.freenas_password;
values.writecache = values.nowritecache ? 0 : 1;
this.callParent([values]);
- values.writecache = values.nowritecache ? 0 : 1;
- this.callParent([values]);
+ if (values.freenas_password) {
+ values.truenas_secret = values.freenas_password;
+ }
+ values.truenas_confirm_secret = values.truenas_secret;
+ values.writecache = values.nowritecache ? 0 : 1;
+ this.callParent([values]);
},
@@ -47416,7 +47435,7 @@
initComponent: function() {
- var me = this;
+ var me = this;
+
+ var tnsecret = Ext.create('Ext.form.TextField', {
+ xtype: 'proxmoxtextfield',
+ name: 'truenas_secret',
+ reference: 'truenas_secret_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=truenas_confirm_secret]').validate();
+ }
+ },
+ });
- me.column1 = [
- {
- xtype: me.isCreate ? 'textfield' : 'displayfield',
- name: 'portal',
+ var tnconfirmsecret = Ext.create('Ext.form.TextField', {
+ xtype: 'proxmoxtextfield',
+ name: 'truenas_confirm_secret',
+ reference: 'truenas_confirm_secret_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ submitValue: false,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('Confirm API Password'),
+ validator: function(value) {
+ var pw = me.up().down('field[name=truenas_secret]').getValue();
+ if (pw !== value) {
+ return "Secrets do not match!";
+ }
+ return true;
+ },
+ });
+
+ me.column1 = [
+ {
+ xtype: me.isCreate ? 'textfield' : 'displayfield',
+ name: 'portal',
value: '',
fieldLabel: gettext('Portal'),
allowBlank: false,
},
{
@ -61,7 +165,7 @@
name: 'pool',
value: '',
fieldLabel: gettext('Pool'),
@@ -47426,11 +47445,11 @@
@@ -58084,11 +58172,11 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'blocksize',
value: '4k',
@ -75,7 +179,7 @@
name: 'target',
value: '',
fieldLabel: gettext('Target'),
@@ -47441,9 +47460,34 @@
@@ -58099,8 +58187,59 @@
name: 'comstar_tg',
value: '',
fieldLabel: gettext('Target group'),
@ -84,7 +188,7 @@
+ hidden: '{!isComstar}'
+ },
allowBlank: true,
},
+},
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'freenas_use_ssl',
@ -98,6 +202,32 @@
+ fieldLabel: gettext('API use SSL'),
+ },
+ {
+ xtype: 'proxmoxcheckbox',
+ name: 'truenas_token_auth',
+ reference: 'truenas_token_auth_field',
+ inputId: 'truenas_use_token_auth_field',
+ checked: false,
+ listeners: {
+ change: function(field, newValue) {
+ if (newValue === true) {
+ tnsecret.labelEl.update('API Token');
+ tnconfirmsecret.labelEl.update('Confirm API Token');
+ me.lookupReference('freenas_user_field').setValue('');
+ me.lookupReference('freenas_user_field').allowBlank = true;
+ } else {
+ tnsecret.labelEl.update('API Password');
+ tnconfirmsecret.labelEl.update('Confirm API Password');
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ }
+ },
+ },
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ uncheckedValue: 0,
+ fieldLabel: gettext('API Token Auth'),
+ },
+ {
+ xtype: 'textfield',
+ name: 'freenas_user',
+ reference: 'freenas_user_field',
@ -105,13 +235,12 @@
+ value: '',
+ fieldLabel: gettext('API Username'),
+ bind: {
+ hidden: '{!isFreeNAS}'
+ hidden: '{hideUsername}'
+ },
+ },
},
];
me.column2 = [
@@ -47473,7 +47517,9 @@
@@ -58131,7 +58270,9 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'comstar_hg',
value: '',
@ -122,18 +251,19 @@
fieldLabel: gettext('Host group'),
allowBlank: true,
},
@@ -47481,9 +47527,62 @@
@@ -58139,15 +58280,32 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'lio_tpg',
value: '',
- bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
- allowBlank: false,
- fieldLabel: gettext('Target portal group'),
+ bind: {
+ hidden: '{!isLIO}'
+ },
fieldLabel: gettext('Target portal group'),
+ allowBlank: true
+ },
+ fieldLabel: gettext('Target portal group'),
+ allowBlank: true
},
+ {
+ xtype: 'proxmoxtextfield',
+ name: 'freenas_apiv4_host',
@ -146,44 +276,14 @@
+ },
+ 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;
+ },
},
+ tnsecret,
+ tnconfirmsecret,
];
me.callParent();
},
});
+
Ext.define('PVE.storage.ZFSPoolSelector', {
extend: 'PVE.form.ComboBoxSetStoreNode',
alias: 'widget.pveZFSPoolSelector',

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,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;
+ },
},
];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,157 @@
--- ZFSPlugin.pm.orig 2023-12-31 09:56:18.895228853 -0500
+++ ZFSPlugin.pm 2023-12-31 09:57:08.830488875 -0500
@@ -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,32 @@
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 (Deprecated)",
+ type => 'string',
+ },
+ truenas_secret => {
+ description => "TrueNAS API Secret",
+ type => 'string',
+ },
+ truenas_token_auth => {
+ description => "TrueNAS API Authentication with Token",
+ type => 'boolean',
+ },
+ 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 +252,20 @@
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 },
+ truenas_secret => { optional => 1 },
+ truenas_token_auth => { optional => 1 },
+ freenas_use_ssl => { optional => 1 },
+ freenas_apiv4_host => { optional => 1 },
lio_tpg => { optional => 1 },
content => { optional => 1 },
bwlimit => { optional => 1 },
@@ -243,6 +290,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,422 @@
package PVE::Storage::ZFSPlugin;
use strict;
use warnings;
use IO::File;
use POSIX;
use PVE::Tools qw(run_command);
use PVE::Storage::ZFSPoolPlugin;
use PVE::RPCEnvironment;
use base qw(PVE::Storage::ZFSPoolPlugin);
use PVE::Storage::LunCmd::Comstar;
use PVE::Storage::LunCmd::Istgt;
use PVE::Storage::LunCmd::Iet;
use PVE::Storage::LunCmd::LIO;
my @ssh_opts = ('-o', 'BatchMode=yes');
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
my $id_rsa_path = '/etc/pve/priv/zfs';
my $lun_cmds = {
create_lu => 1,
delete_lu => 1,
import_lu => 1,
modify_lu => 1,
add_view => 1,
list_view => 1,
list_lu => 1,
};
my $zfs_unknown_scsi_provider = sub {
my ($provider) = @_;
die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
};
my $zfs_get_base = sub {
my ($scfg) = @_;
if ($scfg->{iscsiprovider} eq 'comstar') {
return PVE::Storage::LunCmd::Comstar::get_base;
} elsif ($scfg->{iscsiprovider} eq 'istgt') {
return PVE::Storage::LunCmd::Istgt::get_base;
} elsif ($scfg->{iscsiprovider} eq 'iet') {
return PVE::Storage::LunCmd::Iet::get_base;
} elsif ($scfg->{iscsiprovider} eq 'LIO') {
return PVE::Storage::LunCmd::LIO::get_base;
} else {
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
}
};
sub zfs_request {
my ($class, $scfg, $timeout, $method, @params) = @_;
$timeout = PVE::RPCEnvironment->is_worker() ? 60*60 : 10
if !$timeout;
my $msg = '';
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 'istgt') {
$msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'iet') {
$msg = PVE::Storage::LunCmd::Iet::run_lun_command($scfg, $timeout, $method, @params);
} elsif ($scfg->{iscsiprovider} eq 'LIO') {
$msg = PVE::Storage::LunCmd::LIO::run_lun_command($scfg, $timeout, $method, @params);
} else {
$zfs_unknown_scsi_provider->($scfg->{iscsiprovider});
}
} else {
my $target = 'root@' . $scfg->{portal};
my $cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target];
if ($method eq 'zpool_list') {
push @$cmd, 'zpool', 'list';
} else {
push @$cmd, 'zfs', $method;
}
push @$cmd, @params;
my $output = sub {
my $line = shift;
$msg .= "$line\n";
};
run_command($cmd, outfunc => $output, timeout => $timeout);
}
return $msg;
}
sub zfs_get_lu_name {
my ($class, $scfg, $zvol) = @_;
my $base = $zfs_get_base->($scfg);
$zvol = ($class->parse_volname($zvol))[1];
my $object = ($zvol =~ /^.+\/.+/) ? "$base/$zvol" : "$base/$scfg->{pool}/$zvol";
my $lu_name = $class->zfs_request($scfg, undef, 'list_lu', $object);
return $lu_name if $lu_name;
die "Could not find lu_name for zvol $zvol";
}
sub zfs_add_lun_mapping_entry {
my ($class, $scfg, $zvol, $guid) = @_;
if (!defined($guid)) {
$guid = $class->zfs_get_lu_name($scfg, $zvol);
}
$class->zfs_request($scfg, undef, 'add_view', $guid);
}
sub zfs_delete_lu {
my ($class, $scfg, $zvol) = @_;
my $guid = $class->zfs_get_lu_name($scfg, $zvol);
$class->zfs_request($scfg, undef, 'delete_lu', $guid);
}
sub zfs_create_lu {
my ($class, $scfg, $zvol) = @_;
my $base = $zfs_get_base->($scfg);
my $guid = $class->zfs_request($scfg, undef, 'create_lu', "$base/$scfg->{pool}/$zvol");
return $guid;
}
sub zfs_import_lu {
my ($class, $scfg, $zvol) = @_;
my $base = $zfs_get_base->($scfg);
$class->zfs_request($scfg, undef, 'import_lu', "$base/$scfg->{pool}/$zvol");
}
sub zfs_resize_lu {
my ($class, $scfg, $zvol, $size) = @_;
my $guid = $class->zfs_get_lu_name($scfg, $zvol);
$class->zfs_request($scfg, undef, 'modify_lu', "${size}K", $guid);
}
sub zfs_get_lun_number {
my ($class, $scfg, $guid) = @_;
die "could not find lun_number for guid $guid" if !$guid;
if ($class->zfs_request($scfg, undef, 'list_view', $guid) =~ /^(\d+)$/) {
return $1;
}
die "lun_number for guid $guid is not a number";
}
# Configuration
sub type {
return 'zfs';
}
sub plugindata {
return {
content => [ {images => 1}, { images => 1 }],
};
}
sub properties {
return {
iscsiprovider => {
description => "iscsi provider",
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
nowritecache => {
description => "disable write caching on the target",
type => 'boolean',
},
comstar_tg => {
description => "target group for comstar views",
type => 'string',
},
comstar_hg => {
description => "host group for comstar views",
type => 'string',
},
lio_tpg => {
description => "target portal group for Linux LIO targets",
type => 'string',
},
};
}
sub options {
return {
nodes => { optional => 1 },
disable => { optional => 1 },
portal => { fixed => 1 },
target => { fixed => 1 },
pool => { fixed => 1 },
blocksize => { fixed => 1 },
iscsiprovider => { fixed => 1 },
nowritecache => { optional => 1 },
sparse => { optional => 1 },
comstar_hg => { optional => 1 },
comstar_tg => { optional => 1 },
lio_tpg => { optional => 1 },
content => { optional => 1 },
bwlimit => { optional => 1 },
};
}
# Storage implementation
sub path {
my ($class, $scfg, $volname, $storeid, $snapname) = @_;
die "direct access to snapshots not implemented"
if defined($snapname);
my ($vtype, $name, $vmid) = $class->parse_volname($volname);
my $target = $scfg->{target};
my $portal = $scfg->{portal};
my $guid = $class->zfs_get_lu_name($scfg, $name);
my $lun = $class->zfs_get_lun_number($scfg, $guid);
my $path = "iscsi://$portal/$target/$lun";
return ($path, $vmid, $vtype);
}
sub create_base {
my ($class, $storeid, $scfg, $volname) = @_;
my $snap = '__base__';
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
$class->parse_volname($volname);
die "create_base not possible with base image\n" if $isBase;
my $newname = $name;
$newname =~ s/^vm-/base-/;
my $newvolname = $basename ? "$basename/$newname" : "$newname";
$class->zfs_delete_lu($scfg, $name);
$class->zfs_request($scfg, undef, 'rename', "$scfg->{pool}/$name", "$scfg->{pool}/$newname");
my $guid = $class->zfs_create_lu($scfg, $newname);
$class->zfs_add_lun_mapping_entry($scfg, $newname, $guid);
my $running = undef; #fixme : is create_base always offline ?
$class->volume_snapshot($scfg, $storeid, $newname, $snap, $running);
return $newvolname;
}
sub clone_image {
my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
my $name = $class->SUPER::clone_image($scfg, $storeid, $volname, $vmid, $snap);
# get ZFS dataset name from PVE volname
my (undef, $clonedname) = $class->parse_volname($name);
my $guid = $class->zfs_create_lu($scfg, $clonedname);
$class->zfs_add_lun_mapping_entry($scfg, $clonedname, $guid);
return $name;
}
sub alloc_image {
my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
die "unsupported format '$fmt'" if $fmt ne 'raw';
die "illegal name '$name' - should be 'vm-$vmid-*'\n"
if $name && $name !~ m/^vm-$vmid-/;
my $volname = $name;
$volname = $class->find_free_diskname($storeid, $scfg, $vmid, $fmt) if !$volname;
$class->zfs_create_zvol($scfg, $volname, $size);
my $guid = $class->zfs_create_lu($scfg, $volname);
$class->zfs_add_lun_mapping_entry($scfg, $volname, $guid);
return $volname;
}
sub free_image {
my ($class, $storeid, $scfg, $volname, $isBase) = @_;
my ($vtype, $name, $vmid) = $class->parse_volname($volname);
$class->zfs_delete_lu($scfg, $name);
eval { $class->zfs_delete_zvol($scfg, $name); };
if (my $err = $@) {
my $guid = $class->zfs_create_lu($scfg, $name);
$class->zfs_add_lun_mapping_entry($scfg, $name, $guid);
die $err;
}
return undef;
}
sub volume_resize {
my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
$volname = ($class->parse_volname($volname))[1];
my $new_size = $class->SUPER::volume_resize($scfg, $storeid, $volname, $size, $running);
$class->zfs_resize_lu($scfg, $volname, $new_size);
return $new_size;
}
sub volume_snapshot_delete {
my ($class, $scfg, $storeid, $volname, $snap, $running) = @_;
$volname = ($class->parse_volname($volname))[1];
$class->zfs_request($scfg, undef, 'destroy', "$scfg->{pool}/$volname\@$snap");
}
sub volume_snapshot_rollback {
my ($class, $scfg, $storeid, $volname, $snap) = @_;
$volname = ($class->parse_volname($volname))[1];
$class->zfs_delete_lu($scfg, $volname);
$class->zfs_request($scfg, undef, 'rollback', "$scfg->{pool}/$volname\@$snap");
$class->zfs_import_lu($scfg, $volname);
$class->zfs_add_lun_mapping_entry($scfg, $volname);
}
sub storage_can_replicate {
my ($class, $scfg, $storeid, $format) = @_;
return 0;
}
sub volume_has_feature {
my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
my $features = {
snapshot => { current => 1, snap => 1},
clone => { base => 1},
template => { current => 1},
copy => { base => 1, current => 1},
};
my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
$class->parse_volname($volname);
my $key = undef;
if ($snapname) {
$key = 'snap';
} else {
$key = $isBase ? 'base' : 'current';
}
return 1 if $features->{$feature}->{$key};
return undef;
}
sub activate_storage {
my ($class, $storeid, $scfg, $cache) = @_;
return 1;
}
sub deactivate_storage {
my ($class, $storeid, $scfg, $cache) = @_;
return 1;
}
sub activate_volume {
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
die "unable to activate snapshot from remote zfs storage" if $snapname;
return 1;
}
sub deactivate_volume {
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
die "unable to deactivate snapshot from remote zfs storage" if $snapname;
return 1;
}
1;

View File

@ -0,0 +1,157 @@
--- ZFSPlugin.pm.orig 2023-12-31 09:56:18.895228853 -0500
+++ ZFSPlugin.pm 2023-12-31 09:57:08.830488875 -0500
@@ -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,32 @@
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 (Deprecated)",
+ type => 'string',
+ },
+ truenas_secret => {
+ description => "TrueNAS API Secret",
+ type => 'string',
+ },
+ truenas_token_auth => {
+ description => "TrueNAS API Authentication with Token",
+ type => 'boolean',
+ },
+ 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 +252,20 @@
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 },
+ truenas_secret => { optional => 1 },
+ truenas_token_auth => { optional => 1 },
+ freenas_use_ssl => { optional => 1 },
+ freenas_apiv4_host => { optional => 1 },
lio_tpg => { optional => 1 },
content => { optional => 1 },
bwlimit => { optional => 1 },
@@ -243,6 +290,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,91 @@
--- apidoc.js.orig 2024-01-06 13:02:06.730512378 -0500
+++ apidoc.js 2024-01-06 13:02:55.349787105 -0500
@@ -50336,6 +50336,37 @@
"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 (Deprecated)",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "truenas_secret" : {
+ "description" : "TrueNAS Secret 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,
@@ -50555,6 +50586,12 @@
"type" : "boolean",
"typetext" : "<boolean>"
},
+ "target" : {
+ "description" : "iSCSI target.",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"transport" : {
"description" : "Gluster transport: tcp or rdma",
"enum" : [
@@ -50854,6 +50891,37 @@
"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 (Deprecated)",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "truenas_secret" : {
+ "description" : "TrueNAS secret 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.",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
--- apidoc.js.orig 2024-01-06 13:02:06.730512378 -0500
+++ apidoc.js 2024-01-06 13:02:55.349787105 -0500
@@ -50336,6 +50336,37 @@
"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 (Deprecated)",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "truenas_secret" : {
+ "description" : "TrueNAS Secret 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,
@@ -50555,6 +50586,12 @@
"type" : "boolean",
"typetext" : "<boolean>"
},
+ "target" : {
+ "description" : "iSCSI target.",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
"transport" : {
"description" : "Gluster transport: tcp or rdma",
"enum" : [
@@ -50854,6 +50891,37 @@
"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 (Deprecated)",
+ "optional" : 1,
+ "type" : "string",
+ "typetext" : "<string>"
+ },
+ "truenas_secret" : {
+ "description" : "TrueNAS secret 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,289 @@
--- pvemanagerlib.js.orig 2023-12-30 15:36:27.913505863 -0500
+++ pvemanagerlib.js 2024-01-02 09:30:56.000000000 -0500
@@ -9228,6 +9228,7 @@
alias: ['widget.pveiScsiProviderSelector'],
comboItems: [
['comstar', 'Comstar'],
+ ['freenas', 'FreeNAS/TrueNAS API'],
['istgt', 'istgt'],
['iet', 'IET'],
['LIO', 'LIO'],
@@ -58017,16 +58018,24 @@
me.callParent();
},
});
+
Ext.define('PVE.storage.ZFSInputPanel', {
extend: 'PVE.panel.StorageBase',
viewModel: {
parent: null,
data: {
+isComstar: true,
+ isFreeNAS: false,
isLIO: false,
- isComstar: true,
+ isToken: false,
hasWriteCacheOption: true,
},
+formulas: {
+ hideUsername: function(get) {
+ return (!get('isFreeNAS') || !(get('isFreeNAS') && !get('isToken')));
+ },
+ },
},
controller: {
@@ -58034,13 +58043,42 @@
control: {
'field[name=iscsiprovider]': {
change: 'changeISCSIProvider',
+},
+ 'field[name=truenas_token_auth]': {
+ change: 'changeUsername',
},
},
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('truenas_token_auth_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('truenas_secret_field').setValue('');
+ me.lookupReference('truenas_secret_field').allowBlank = true;
+ me.lookupReference('truenas_confirm_secret_field').setValue('');
+ me.lookupReference('truenas_confirm_secret_field').allowBlank = true;
+ } else {
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ me.lookupReference('truenas_secret_field').allowBlank = false;
+ me.lookupReference('truenas_confirm_secret_field').allowBlank = false;
+ }
+ },
+ changeUsername: function(f, newVal, oldVal) {
+ var me = this;
+ var vm = me.getViewModel();
+ vm.set('isToken', newVal);
+ me.lookupReference('freenas_user_field').allowBlank = newVal;
+ if (newVal) {
+ me.lookupReference('freenas_user_field').setValue('');
+ }
},
},
@@ -58053,28 +58091,78 @@
values.nowritecache = values.writecache ? 0 : 1;
delete values.writecache;
+ console.warn(values.freenas_password);
+ if (values.freenas_password) {
+ values.truenas_secret = values.freenas_password;
+ }
+ console.warn(values.truenas_secret);
return me.callParent([values]);
},
setValues: function(values) {
- values.writecache = values.nowritecache ? 0 : 1;
- this.callParent([values]);
+ if (values.freenas_password) {
+ values.truenas_secret = values.freenas_password;
+ }
+ values.truenas_confirm_secret = values.truenas_secret;
+ values.writecache = values.nowritecache ? 0 : 1;
+ this.callParent([values]);
},
initComponent: function() {
- var me = this;
+ var me = this;
+
+ var tnsecret = Ext.create('Ext.form.TextField', {
+ xtype: 'proxmoxtextfield',
+ name: 'truenas_secret',
+ reference: 'truenas_secret_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=truenas_confirm_secret]').validate();
+ }
+ },
+ });
- me.column1 = [
- {
- xtype: me.isCreate ? 'textfield' : 'displayfield',
- name: 'portal',
+ var tnconfirmsecret = Ext.create('Ext.form.TextField', {
+ xtype: 'proxmoxtextfield',
+ name: 'truenas_confirm_secret',
+ reference: 'truenas_confirm_secret_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ submitValue: false,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('Confirm API Password'),
+ validator: function(value) {
+ var pw = me.up().down('field[name=truenas_secret]').getValue();
+ if (pw !== value) {
+ return "Secrets do not match!";
+ }
+ return true;
+ },
+ });
+
+ me.column1 = [
+ {
+ xtype: me.isCreate ? 'textfield' : 'displayfield',
+ name: 'portal',
value: '',
fieldLabel: gettext('Portal'),
allowBlank: false,
},
{
- xtype: me.isCreate ? 'textfield' : 'displayfield',
+ xtype: 'textfield',
name: 'pool',
value: '',
fieldLabel: gettext('Pool'),
@@ -58084,11 +58172,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'),
@@ -58099,8 +58187,59 @@
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: 'proxmoxcheckbox',
+ name: 'truenas_token_auth',
+ reference: 'truenas_token_auth_field',
+ inputId: 'truenas_use_token_auth_field',
+ checked: false,
+ listeners: {
+ change: function(field, newValue) {
+ if (newValue === true) {
+ tnsecret.labelEl.update('API Token');
+ tnconfirmsecret.labelEl.update('Confirm API Token');
+ me.lookupReference('freenas_user_field').setValue('');
+ me.lookupReference('freenas_user_field').allowBlank = true;
+ } else {
+ tnsecret.labelEl.update('API Password');
+ tnconfirmsecret.labelEl.update('Confirm API Password');
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ }
+ },
+ },
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ uncheckedValue: 0,
+ fieldLabel: gettext('API Token Auth'),
+ },
+ {
+ xtype: 'textfield',
+ name: 'freenas_user',
+ reference: 'freenas_user_field',
+ inputId: 'freenas_user_field',
+ value: '',
+ fieldLabel: gettext('API Username'),
+ bind: {
+ hidden: '{hideUsername}'
+ },
},
];
@@ -58131,7 +58270,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,
},
@@ -58139,15 +58280,32 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'lio_tpg',
value: '',
- bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
- allowBlank: false,
- fieldLabel: gettext('Target portal group'),
+ 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'),
+ },
+ tnsecret,
+ tnconfirmsecret,
];
me.callParent();
},
});
+
Ext.define('PVE.storage.ZFSPoolSelector', {
extend: 'PVE.form.ComboBoxSetStoreNode',
alias: 'widget.pveZFSPoolSelector',

View File

@ -0,0 +1,289 @@
--- pvemanagerlib.js.orig 2023-12-30 15:36:27.913505863 -0500
+++ pvemanagerlib.js 2024-01-02 09:30:56.000000000 -0500
@@ -9228,6 +9228,7 @@
alias: ['widget.pveiScsiProviderSelector'],
comboItems: [
['comstar', 'Comstar'],
+ ['freenas', 'FreeNAS/TrueNAS API'],
['istgt', 'istgt'],
['iet', 'IET'],
['LIO', 'LIO'],
@@ -58017,16 +58018,24 @@
me.callParent();
},
});
+
Ext.define('PVE.storage.ZFSInputPanel', {
extend: 'PVE.panel.StorageBase',
viewModel: {
parent: null,
data: {
+isComstar: true,
+ isFreeNAS: false,
isLIO: false,
- isComstar: true,
+ isToken: false,
hasWriteCacheOption: true,
},
+formulas: {
+ hideUsername: function(get) {
+ return (!get('isFreeNAS') || !(get('isFreeNAS') && !get('isToken')));
+ },
+ },
},
controller: {
@@ -58034,13 +58043,42 @@
control: {
'field[name=iscsiprovider]': {
change: 'changeISCSIProvider',
+},
+ 'field[name=truenas_token_auth]': {
+ change: 'changeUsername',
},
},
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('truenas_token_auth_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('truenas_secret_field').setValue('');
+ me.lookupReference('truenas_secret_field').allowBlank = true;
+ me.lookupReference('truenas_confirm_secret_field').setValue('');
+ me.lookupReference('truenas_confirm_secret_field').allowBlank = true;
+ } else {
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ me.lookupReference('truenas_secret_field').allowBlank = false;
+ me.lookupReference('truenas_confirm_secret_field').allowBlank = false;
+ }
+ },
+ changeUsername: function(f, newVal, oldVal) {
+ var me = this;
+ var vm = me.getViewModel();
+ vm.set('isToken', newVal);
+ me.lookupReference('freenas_user_field').allowBlank = newVal;
+ if (newVal) {
+ me.lookupReference('freenas_user_field').setValue('');
+ }
},
},
@@ -58053,28 +58091,78 @@
values.nowritecache = values.writecache ? 0 : 1;
delete values.writecache;
+ console.warn(values.freenas_password);
+ if (values.freenas_password) {
+ values.truenas_secret = values.freenas_password;
+ }
+ console.warn(values.truenas_secret);
return me.callParent([values]);
},
setValues: function(values) {
- values.writecache = values.nowritecache ? 0 : 1;
- this.callParent([values]);
+ if (values.freenas_password) {
+ values.truenas_secret = values.freenas_password;
+ }
+ values.truenas_confirm_secret = values.truenas_secret;
+ values.writecache = values.nowritecache ? 0 : 1;
+ this.callParent([values]);
},
initComponent: function() {
- var me = this;
+ var me = this;
+
+ var tnsecret = Ext.create('Ext.form.TextField', {
+ xtype: 'proxmoxtextfield',
+ name: 'truenas_secret',
+ reference: 'truenas_secret_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=truenas_confirm_secret]').validate();
+ }
+ },
+ });
- me.column1 = [
- {
- xtype: me.isCreate ? 'textfield' : 'displayfield',
- name: 'portal',
+ var tnconfirmsecret = Ext.create('Ext.form.TextField', {
+ xtype: 'proxmoxtextfield',
+ name: 'truenas_confirm_secret',
+ reference: 'truenas_confirm_secret_field',
+ inputType: me.isCreate ? '' : 'password',
+ value: '',
+ editable: true,
+ submitValue: false,
+ emptyText: Proxmox.Utils.noneText,
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ fieldLabel: gettext('Confirm API Password'),
+ validator: function(value) {
+ var pw = me.up().down('field[name=truenas_secret]').getValue();
+ if (pw !== value) {
+ return "Secrets do not match!";
+ }
+ return true;
+ },
+ });
+
+ me.column1 = [
+ {
+ xtype: me.isCreate ? 'textfield' : 'displayfield',
+ name: 'portal',
value: '',
fieldLabel: gettext('Portal'),
allowBlank: false,
},
{
- xtype: me.isCreate ? 'textfield' : 'displayfield',
+ xtype: 'textfield',
name: 'pool',
value: '',
fieldLabel: gettext('Pool'),
@@ -58084,11 +58172,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'),
@@ -58099,8 +58187,59 @@
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: 'proxmoxcheckbox',
+ name: 'truenas_token_auth',
+ reference: 'truenas_token_auth_field',
+ inputId: 'truenas_use_token_auth_field',
+ checked: false,
+ listeners: {
+ change: function(field, newValue) {
+ if (newValue === true) {
+ tnsecret.labelEl.update('API Token');
+ tnconfirmsecret.labelEl.update('Confirm API Token');
+ me.lookupReference('freenas_user_field').setValue('');
+ me.lookupReference('freenas_user_field').allowBlank = true;
+ } else {
+ tnsecret.labelEl.update('API Password');
+ tnconfirmsecret.labelEl.update('Confirm API Password');
+ me.lookupReference('freenas_user_field').allowBlank = false;
+ }
+ },
+ },
+ bind: {
+ hidden: '{!isFreeNAS}'
+ },
+ uncheckedValue: 0,
+ fieldLabel: gettext('API Token Auth'),
+ },
+ {
+ xtype: 'textfield',
+ name: 'freenas_user',
+ reference: 'freenas_user_field',
+ inputId: 'freenas_user_field',
+ value: '',
+ fieldLabel: gettext('API Username'),
+ bind: {
+ hidden: '{hideUsername}'
+ },
},
];
@@ -58131,7 +58270,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,
},
@@ -58139,15 +58280,32 @@
xtype: me.isCreate ? 'textfield' : 'displayfield',
name: 'lio_tpg',
value: '',
- bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
- allowBlank: false,
- fieldLabel: gettext('Target portal group'),
+ 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'),
+ },
+ tnsecret,
+ tnconfirmsecret,
];
me.callParent();
},
});
+
Ext.define('PVE.storage.ZFSPoolSelector', {
extend: 'PVE.form.ComboBoxSetStoreNode',
alias: 'widget.pveZFSPoolSelector',

File diff suppressed because it is too large Load Diff