Merge pull request #172 from TheGrandWazoo/feature_bearer_token
Feature bearer token
This commit is contained in:
		
						commit
						c35329f77d
					
				
							
								
								
									
										275
									
								
								README.md
								
								
								
								
							
							
						
						
									
										275
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -1,98 +1,227 @@
 | 
				
			||||||
# FreeNAS ZFS over iSCSI interface  [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=TCLNEMBUYQUXN&source=url)
 | 
					# TrueNAS ZFS over iSCSI Plugin for Proxmox VE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Currently trying JFrog for the repo. Just changing the Automation and making sure all works.<br/>I am currently testing an should have at least the repos up for production and testing. You will need to update your repos with the new location and gpg. I will have instructions on this page.
 | 
					## 📢: ATTENTION 2023-08-16 📢: New repos are now online at [Cloudsmith](#new-installs).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Also currently developing for TrueNAS-Core 13 to provide fixes to support all the [Free|True]NAS family.
 | 
					## Activity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Thank you for all that have recently donated to the project.
 | 
					<details>
 | 
				
			||||||
    Daniel Most
 | 
					 <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 [](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
 | 
					    Maksym Vasylenko
 | 
				
			||||||
    Alexander Finkhäuser - Reoccuring
 | 
					    Daniel Most
 | 
				
			||||||
    Bjarte Kvamme - Reoccuring
 | 
					    Velocity Host
 | 
				
			||||||
    Jonathan Schober - Reoccuring
 | 
					    Robert Hancock
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
## And thanks to all that have donated to the project in the past.
 | 
					 | 
				
			||||||
    Clevvi Technology
 | 
					    Clevvi Technology
 | 
				
			||||||
    Mark Elkins - Reoccuring
 | 
					    Mark Elkins
 | 
				
			||||||
    Marc Hodler
 | 
					    Marc Hodler
 | 
				
			||||||
    Martin Gonzalez
 | 
					    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:
 | 
					Their donations have allowed for:
 | 
				
			||||||
```
 | 
					- A 4 Node Proxmox VE Cluster for testing and development.
 | 
				
			||||||
/usr/share/pve-manager/js/pvemanagerlib.js    <- From package pve-manager
 | 
					  - Spin up old and new revisions of FreeNAS and TrueNAS.
 | 
				
			||||||
/usr/share/pve-docs/api-viewer/apidoc.js      <- From package pve-docs
 | 
					- 10Gb Ethernet Testing.
 | 
				
			||||||
/usr/share/perl5/PVE/Storage/ZFSPlugin.pm     <- From package libpve-storage-perl
 | 
					- Multihomed configuration testing.
 | 
				
			||||||
```
 | 
					  - In progress and as best I can in a flat network.
 | 
				
			||||||
It will also install the /usr/share/perl5/PVE/Storage/LunCmd/FreeNAS.pm (The FreeNAS API plugin), git and librest-client-perl
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you wish, you may remove the directory 'freenas-proxmox' where your system is currently
 | 
					## Roadmap
 | 
				
			||||||
housing the repo and then issue the following to have a clean system before installing the
 | 
					<details><summary>Roadmap details</summary>
 | 
				
			||||||
package.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
On Proxmox 5
 | 
					* Update the documentation - <i>In Progress</i>.
 | 
				
			||||||
```bash
 | 
					  * Restructure the main README.md for better readability. 
 | 
				
			||||||
apt install --reinstall pve-manager pve-docs libpve-storage-perl
 | 
					  * 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
 | 
					</details>
 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
apt reinstall pve-manager pve-docs libpve-storage-perl
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
On Proxmox 7
 | 
					## New Install Instructions
 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
apt reinstall pve-manager pve-docs libpve-storage-perl
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
## Changing in the near future.
 | 
					 | 
				
			||||||
Issue the following to install the repo and get your Proxmox VE updating the FreeNAS patches automatically:
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
wget http://repo.ksatechnologies.com/debian/pve/ksatechnologies-release.gpg -O /etc/apt/trusted.gpg.d/ksatechnologies-repo.gpg
 | 
					 | 
				
			||||||
echo "deb http://repo.ksatechnologies.com/debian/pve stable freenas-proxmox" > /etc/apt/sources.list.d/ksatechnologies-repo.list
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
### I will be using a 'testing' repo to develop the new phase of the Proxmox VE FreeNAS plugin.
 | 
					### Select at least one `Step 1.x` based on your preference. Can be combined.
 | 
				
			||||||
#### This next phase will introduce the following...
 | 
					 | 
				
			||||||
* Auto detection of the Proxmox VE version
 | 
					 | 
				
			||||||
* Auto detection of the FreeNAS version so it will use the V1 or V2 API's or you can select it manually via the Proxmox VE FreeNAS modal
 | 
					 | 
				
			||||||
* Remove the need for SSH keys and use the API
 | 
					 | 
				
			||||||
  * This is tricky because the format needs to be that of the output of'zfs list' which is not part of the LunCmd but that of the backend Proxmox VE system and the API's do a bunch of JSON stuff.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### If you'd like, you may also issue the following commands now or later to use the 'testing' repo.
 | 
					<details><summary>Step 1.0: For stable releases. <b>Enabled</b> by default.</summary>
 | 
				
			||||||
#### Just comment the 'stable' line and uncomment the 'testing' line in 
 | 
					 | 
				
			||||||
#### /etc/apt/sources.list.d/ksatechnologies-repo.list to use. 'testing' is disabled be default.
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
echo "" >> /etc/apt/sources.list.d/ksatechnologies-repo.list
 | 
					 | 
				
			||||||
echo "# deb http://repo.ksatechnologies.com/debian/pve testing freenas-proxmox" >> /etc/apt/sources.list.d/ksatechnologies-repo.list
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Then issue the following to install the package
 | 
					 ### truenas-proxmox repo - Currently follows the 2.0 branch.
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
apt update
 | 
					 | 
				
			||||||
apt install freenas-proxmox
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Then just do your regular upgrade via apt to your system; the package will automatically
 | 
					 Select one of the following GPG Key locations based on your preference.
 | 
				
			||||||
issue all commands to patch the files.
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
apt update
 | 
					 | 
				
			||||||
apt [full|dist]-upgrade
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you wish not to use the package you may remove it at anytime with
 | 
					 ```bash
 | 
				
			||||||
```
 | 
					 # Preferred - based on documentation. Copy and paste to bash command line:
 | 
				
			||||||
apt [remove|purge] freenas-proxmox
 | 
					 keyring_location=/usr/share/keyrings/ksatechnologies-truenas-proxmox-keyring.gpg
 | 
				
			||||||
```
 | 
					 ```
 | 
				
			||||||
This will place you back to a normal and unpatched Proxmox VE install.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Please be aware that this plugin uses the FreeNAS APIs and NOT the ssh/scp interface like the other plugins use, but...
 | 
					 ```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. 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.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -128,10 +128,13 @@ sub run_lun_command {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    syslog("info",(caller(0))[3] . " : $method(@params)");
 | 
					    syslog("info",(caller(0))[3] . " : $method(@params)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if(!defined($scfg->{'freenas_user'}) || !defined($scfg->{'freenas_password'})) {
 | 
					    if (defined($scfg->{'truenas_token_auth'}) && $scfg->{'truenas_token_auth'}) {
 | 
				
			||||||
        die "Undefined freenas_user and/or freenas_password.";
 | 
					        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}}) {
 | 
					    if (!defined $freenas_server_list->{defined($scfg->{freenas_apiv4_host}) ? $scfg->{freenas_apiv4_host} : $scfg->{portal}}) {
 | 
				
			||||||
        freenas_api_check($scfg);
 | 
					        freenas_api_check($scfg);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -341,7 +344,13 @@ sub freenas_api_connect {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    $freenas_server_list->{$apihost}->setHost($scheme . '://' . $apihost);
 | 
					    $freenas_server_list->{$apihost}->setHost($scheme . '://' . $apihost);
 | 
				
			||||||
    $freenas_server_list->{$apihost}->addHeader('Content-Type', 'application/json');
 | 
					    $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 using SSL, don't verify SSL certs
 | 
				
			||||||
    if ($scfg->{freenas_use_ssl}) {
 | 
					    if ($scfg->{freenas_use_ssl}) {
 | 
				
			||||||
        $freenas_server_list->{$apihost}->getUseragent()->ssl_opts(verify_hostname => 0);
 | 
					        $freenas_server_list->{$apihost}->getUseragent()->ssl_opts(verify_hostname => 0);
 | 
				
			||||||
| 
						 | 
					@ -354,16 +363,16 @@ sub freenas_api_connect {
 | 
				
			||||||
    syslog("info", (caller(0))[3] . " : REST connection header Content-Type:'" . $type . "'");
 | 
					    syslog("info", (caller(0))[3] . " : REST connection header Content-Type:'" . $type . "'");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Make sure we are not recursion calling.
 | 
					    # Make sure we are not recursion calling.
 | 
				
			||||||
    if ($runawayprevent > 1) {
 | 
					    if ($runawayprevent > 2) {
 | 
				
			||||||
        freenas_api_log_error($freenas_server_list->{$apihost});
 | 
					        freenas_api_log_error($freenas_server_list->{$apihost});
 | 
				
			||||||
        die "Loop recursion prevention";
 | 
					        die "Loop recursion prevention";
 | 
				
			||||||
    # Successful connection
 | 
					    # Successful connection
 | 
				
			||||||
    } elsif ($code == 200 && ($type =~ /^text\/plain/ || $type =~ /^application\/json/)) {
 | 
					    } elsif ($code == 200 && ($type =~ /^text\/plain/ || $type =~ /^application\/json/)) {
 | 
				
			||||||
        syslog("info", (caller(0))[3] . " : REST connection successful to '" . $apihost . "' using the '" . $scheme . "' protocol");
 | 
					        syslog("info", (caller(0))[3] . " : REST connection successful to '" . $apihost . "' using the '" . $scheme . "' protocol");
 | 
				
			||||||
        $runawayprevent = 0;
 | 
					        $runawayprevent = 0;
 | 
				
			||||||
    # A 302 or 200 with Content-Type not 'text/plain' from {True|Free}NAS means it doesn't like v1.0 APIs.
 | 
					    # 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.
 | 
					    # So change to v2.0 APIs.
 | 
				
			||||||
    } elsif ($code == 302 || ($code == 200 && $type !~ /^text\/plain/)) {
 | 
					    } elsif ($code == 302 || $code == 200) {
 | 
				
			||||||
        syslog("info", (caller(0))[3] . " : Changing to v2.0 API's");
 | 
					        syslog("info", (caller(0))[3] . " : Changing to v2.0 API's");
 | 
				
			||||||
        $runawayprevent++;
 | 
					        $runawayprevent++;
 | 
				
			||||||
        $apiping =~ s/v1\.0/v2\.0/;
 | 
					        $apiping =~ s/v1\.0/v2\.0/;
 | 
				
			||||||
| 
						 | 
					@ -533,11 +542,15 @@ sub freenas_iscsi_create_extent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    my $name = $lun_path;
 | 
					    my $name = $lun_path;
 | 
				
			||||||
    $name  =~ s/^.*\///; # all from last /
 | 
					    $name  =~ s/^.*\///; # all from last /
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    my $pool = $scfg->{'pool'};
 | 
					    my $pool = $scfg->{'pool'};
 | 
				
			||||||
 | 
					    # If TrueNAS-SCALE the slashes (/) need to be converted to dashes (-)
 | 
				
			||||||
    if ($product_name eq "TrueNAS-SCALE") {
 | 
					    if ($product_name eq "TrueNAS-SCALE") {
 | 
				
			||||||
        $pool =~ s/\//-/g;
 | 
					        $pool =~ s/\//-/g;
 | 
				
			||||||
 | 
					        syslog("info", (caller(0))[3] . " : TrueNAS-SCALE slash to dash conversion '" . $pool ."'");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    $name  = $pool . ($product_name eq "TrueNAS-SCALE" ? '-' : '/') . $name;
 | 
					    $name  = $pool . ($product_name eq "TrueNAS-SCALE" ? '-' : '/') . $name;
 | 
				
			||||||
 | 
					    syslog("info", (caller(0))[3] . " : " . $product_name . " extent '". $name . "'");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    my $device = $lun_path;
 | 
					    my $device = $lun_path;
 | 
				
			||||||
    $device =~ s/^\/dev\///; # strip /dev/
 | 
					    $device =~ s/^\/dev\///; # strip /dev/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
--- ZFSPlugin.pm.orig	2022-02-04 12:08:01.000000000 -0500
 | 
					--- ZFSPlugin.pm.orig	2023-12-31 09:56:18.895228853 -0500
 | 
				
			||||||
+++ ZFSPlugin.pm	2022-03-26 13:51:40.660068908 -0400
 | 
					+++ ZFSPlugin.pm	2023-12-31 09:57:08.830488875 -0500
 | 
				
			||||||
@@ -10,6 +10,7 @@
 | 
					@@ -10,6 +10,7 @@
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
 use base qw(PVE::Storage::ZFSPoolPlugin);
 | 
					 use base qw(PVE::Storage::ZFSPoolPlugin);
 | 
				
			||||||
| 
						 | 
					@ -58,7 +58,7 @@
 | 
				
			||||||
 # Configuration
 | 
					 # Configuration
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
 sub type {
 | 
					 sub type {
 | 
				
			||||||
@@ -184,6 +199,24 @@
 | 
					@@ -184,6 +199,32 @@
 | 
				
			||||||
 	    description => "iscsi provider",
 | 
					 	    description => "iscsi provider",
 | 
				
			||||||
 	    type => 'string',
 | 
					 	    type => 'string',
 | 
				
			||||||
 	},
 | 
					 	},
 | 
				
			||||||
| 
						 | 
					@ -69,9 +69,17 @@
 | 
				
			||||||
+	    type => 'string',
 | 
					+	    type => 'string',
 | 
				
			||||||
+	},
 | 
					+	},
 | 
				
			||||||
+	freenas_password => {
 | 
					+	freenas_password => {
 | 
				
			||||||
+	    description => "FreeNAS API Password",
 | 
					+	    description => "FreeNAS API Password (Deprecated)",
 | 
				
			||||||
+	    type => 'string',
 | 
					+	    type => 'string',
 | 
				
			||||||
+	},
 | 
					+	},
 | 
				
			||||||
 | 
					+	truenas_secret => {
 | 
				
			||||||
 | 
					+	    description => "TrueNAS API Secret",
 | 
				
			||||||
 | 
					+	    type => 'string',
 | 
				
			||||||
 | 
					+	},
 | 
				
			||||||
 | 
					+	truenas_token_auth => {
 | 
				
			||||||
 | 
					+	    description => "TrueNAS API Authentication with Token",
 | 
				
			||||||
 | 
					+	    type => 'boolean',
 | 
				
			||||||
 | 
					+	},
 | 
				
			||||||
+	freenas_use_ssl => {
 | 
					+	freenas_use_ssl => {
 | 
				
			||||||
+	    description => "FreeNAS API access via SSL",
 | 
					+	    description => "FreeNAS API access via SSL",
 | 
				
			||||||
+	    type => 'boolean',
 | 
					+	    type => 'boolean',
 | 
				
			||||||
| 
						 | 
					@ -83,7 +91,7 @@
 | 
				
			||||||
 	# this will disable write caching on comstar and istgt.
 | 
					 	# this will disable write caching on comstar and istgt.
 | 
				
			||||||
 	# it is not implemented for iet. iet blockio always operates with
 | 
					 	# it is not implemented for iet. iet blockio always operates with
 | 
				
			||||||
 	# writethrough caching when not in readonly mode
 | 
					 	# writethrough caching when not in readonly mode
 | 
				
			||||||
@@ -211,14 +244,18 @@
 | 
					@@ -211,14 +252,20 @@
 | 
				
			||||||
 	nodes => { optional => 1 },
 | 
					 	nodes => { optional => 1 },
 | 
				
			||||||
 	disable => { optional => 1 },
 | 
					 	disable => { optional => 1 },
 | 
				
			||||||
 	portal => { fixed => 1 },
 | 
					 	portal => { fixed => 1 },
 | 
				
			||||||
| 
						 | 
					@ -99,12 +107,14 @@
 | 
				
			||||||
 	comstar_tg => { optional => 1 },
 | 
					 	comstar_tg => { optional => 1 },
 | 
				
			||||||
+	freenas_user => { optional => 1 },
 | 
					+	freenas_user => { optional => 1 },
 | 
				
			||||||
+	freenas_password => { optional => 1 },
 | 
					+	freenas_password => { optional => 1 },
 | 
				
			||||||
 | 
					+	truenas_secret => { optional => 1 },
 | 
				
			||||||
 | 
					+	truenas_token_auth => { optional => 1 },
 | 
				
			||||||
+	freenas_use_ssl => { optional => 1 },
 | 
					+	freenas_use_ssl => { optional => 1 },
 | 
				
			||||||
+	freenas_apiv4_host => { optional => 1 },
 | 
					+	freenas_apiv4_host => { optional => 1 },
 | 
				
			||||||
 	lio_tpg => { optional => 1 },
 | 
					 	lio_tpg => { optional => 1 },
 | 
				
			||||||
 	content => { optional => 1 },
 | 
					 	content => { optional => 1 },
 | 
				
			||||||
 	bwlimit => { optional => 1 },
 | 
					 	bwlimit => { optional => 1 },
 | 
				
			||||||
@@ -243,6 +280,40 @@
 | 
					@@ -243,6 +290,40 @@
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
     my $path = "iscsi://$portal/$target/$lun";
 | 
					     my $path = "iscsi://$portal/$target/$lun";
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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.",
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
--- apidoc.js.orig	2021-11-15 10:07:34.000000000 -0500
 | 
					--- apidoc.js.orig      2023-08-16 06:03:55.000000000 -0400
 | 
				
			||||||
+++ apidoc.js	2021-12-06 08:04:01.648822707 -0500
 | 
					+++ apidoc.js   2023-12-26 14:45:47.202566775 -0500
 | 
				
			||||||
@@ -44064,6 +44064,31 @@
 | 
					@@ -47579,6 +47579,37 @@
 | 
				
			||||||
                            "type" : "string",
 | 
					                            "type" : "string",
 | 
				
			||||||
                            "typetext" : "<string>"
 | 
					                            "typetext" : "<string>"
 | 
				
			||||||
                         },
 | 
					                         },
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,13 @@
 | 
				
			||||||
+                           "typetext" : "<string>"
 | 
					+                           "typetext" : "<string>"
 | 
				
			||||||
+                        },
 | 
					+                        },
 | 
				
			||||||
+                        "freenas_password" : {
 | 
					+                        "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,
 | 
					+                           "optional" : 1,
 | 
				
			||||||
+                           "type" : "string",
 | 
					+                           "type" : "string",
 | 
				
			||||||
+                           "typetext" : "<string>"
 | 
					+                           "typetext" : "<string>"
 | 
				
			||||||
| 
						 | 
					@ -32,7 +38,7 @@
 | 
				
			||||||
                         "fuse" : {
 | 
					                         "fuse" : {
 | 
				
			||||||
                            "description" : "Mount CephFS through FUSE.",
 | 
					                            "description" : "Mount CephFS through FUSE.",
 | 
				
			||||||
                            "optional" : 1,
 | 
					                            "optional" : 1,
 | 
				
			||||||
@@ -44275,6 +44300,12 @@
 | 
					@@ -47798,6 +47829,12 @@
 | 
				
			||||||
                            "type" : "boolean",
 | 
					                            "type" : "boolean",
 | 
				
			||||||
                            "typetext" : "<boolean>"
 | 
					                            "typetext" : "<boolean>"
 | 
				
			||||||
                         },
 | 
					                         },
 | 
				
			||||||
| 
						 | 
					@ -45,7 +51,7 @@
 | 
				
			||||||
                         "transport" : {
 | 
					                         "transport" : {
 | 
				
			||||||
                            "description" : "Gluster transport: tcp or rdma",
 | 
					                            "description" : "Gluster transport: tcp or rdma",
 | 
				
			||||||
                            "enum" : [
 | 
					                            "enum" : [
 | 
				
			||||||
@@ -44547,6 +44578,31 @@
 | 
					@@ -48097,6 +48134,37 @@
 | 
				
			||||||
                      "optional" : 1,
 | 
					                      "optional" : 1,
 | 
				
			||||||
                      "type" : "string",
 | 
					                      "type" : "string",
 | 
				
			||||||
                      "typetext" : "<string>"
 | 
					                      "typetext" : "<string>"
 | 
				
			||||||
| 
						 | 
					@ -57,7 +63,13 @@
 | 
				
			||||||
+                     "typetext" : "<string>"
 | 
					+                     "typetext" : "<string>"
 | 
				
			||||||
+                  },
 | 
					+                  },
 | 
				
			||||||
+                  "freenas_password" : {
 | 
					+                  "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,
 | 
					+                     "optional" : 1,
 | 
				
			||||||
+                     "type" : "string",
 | 
					+                     "type" : "string",
 | 
				
			||||||
+                     "typetext" : "<string>"
 | 
					+                     "typetext" : "<string>"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,58 +1,162 @@
 | 
				
			||||||
--- pvemanagerlib.js.orig	2022-03-17 09:08:40.000000000 -0400
 | 
					--- pvemanagerlib.js.orig	2023-12-30 15:36:27.913505863 -0500
 | 
				
			||||||
+++ pvemanagerlib.js	2022-04-03 08:54:10.229689187 -0400
 | 
					+++ pvemanagerlib.js	2024-01-02 09:30:56.000000000 -0500
 | 
				
			||||||
@@ -8068,6 +8068,7 @@
 | 
					@@ -9228,6 +9228,7 @@
 | 
				
			||||||
     alias: ['widget.pveiScsiProviderSelector'],
 | 
					     alias: ['widget.pveiScsiProviderSelector'],
 | 
				
			||||||
     comboItems: [
 | 
					     comboItems: [
 | 
				
			||||||
 	['comstar', 'Comstar'],
 | 
					 	['comstar', 'Comstar'],
 | 
				
			||||||
+	['freenas', 'FreeNAS-API'],
 | 
					+    ['freenas', 'FreeNAS/TrueNAS API'],
 | 
				
			||||||
 	['istgt', 'istgt'],
 | 
					 	['istgt', 'istgt'],
 | 
				
			||||||
 	['iet', 'IET'],
 | 
					 	['iet', 'IET'],
 | 
				
			||||||
 	['LIO', 'LIO'],
 | 
					 	['LIO', 'LIO'],
 | 
				
			||||||
@@ -49636,6 +49637,7 @@
 | 
					@@ -58017,16 +58018,24 @@
 | 
				
			||||||
 | 
					 	me.callParent();
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					 });
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					 Ext.define('PVE.storage.ZFSInputPanel', {
 | 
				
			||||||
 | 
					     extend: 'PVE.panel.StorageBase',
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					     viewModel: {
 | 
				
			||||||
 | 
					 	parent: null,
 | 
				
			||||||
 	data: {
 | 
					 	data: {
 | 
				
			||||||
 | 
					+isComstar: true,
 | 
				
			||||||
 | 
					+	    isFreeNAS: false,
 | 
				
			||||||
 	    isLIO: false,
 | 
					 	    isLIO: false,
 | 
				
			||||||
 	    isComstar: true,
 | 
					-	    isComstar: true,
 | 
				
			||||||
+        isFreeNAS: false,
 | 
					+	    isToken: false,
 | 
				
			||||||
 	    hasWriteCacheOption: true,
 | 
					 	    hasWriteCacheOption: true,
 | 
				
			||||||
 	},
 | 
					 	},
 | 
				
			||||||
 | 
					+formulas: {
 | 
				
			||||||
 | 
					+            hideUsername: function(get) {
 | 
				
			||||||
 | 
					+                return (!get('isFreeNAS') || !(get('isFreeNAS') && !get('isToken')));
 | 
				
			||||||
 | 
					+            },
 | 
				
			||||||
 | 
					+	},
 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
@@ -49648,10 +49650,26 @@
 | 
					 
 | 
				
			||||||
 | 
					     controller: {
 | 
				
			||||||
 | 
					@@ -58034,13 +58043,42 @@
 | 
				
			||||||
 | 
					 	control: {
 | 
				
			||||||
 | 
					 	    'field[name=iscsiprovider]': {
 | 
				
			||||||
 | 
					 		change: 'changeISCSIProvider',
 | 
				
			||||||
 | 
					+},
 | 
				
			||||||
 | 
					+	    'field[name=truenas_token_auth]': {
 | 
				
			||||||
 | 
					+		change: 'changeUsername',
 | 
				
			||||||
 	    },
 | 
					 	    },
 | 
				
			||||||
 	},
 | 
					 	},
 | 
				
			||||||
 	changeISCSIProvider: function(f, newVal, oldVal) {
 | 
					 	changeISCSIProvider: function(f, newVal, oldVal) {
 | 
				
			||||||
+	    var me = this;
 | 
					+var me = this;
 | 
				
			||||||
 	    var vm = this.getViewModel();
 | 
					 	    var vm = this.getViewModel();
 | 
				
			||||||
 	    vm.set('isLIO', newVal === 'LIO');
 | 
					 	    vm.set('isLIO', newVal === 'LIO');
 | 
				
			||||||
 	    vm.set('isComstar', newVal === 'comstar');
 | 
					 	    vm.set('isComstar', newVal === 'comstar');
 | 
				
			||||||
-	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
 | 
					-	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
 | 
				
			||||||
+	    vm.set('isFreeNAS', newVal === 'freenas');
 | 
					+	    vm.set('isFreeNAS', newVal === 'freenas');
 | 
				
			||||||
+	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'freenas' || newVal === 'istgt');
 | 
					+        vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'freenas' || newVal === 'istgt');
 | 
				
			||||||
+	    if (newVal !== 'freenas') {
 | 
					+        if (newVal !== 'freenas') {
 | 
				
			||||||
+		me.lookupReference('freenas_use_ssl_field').setValue(false);
 | 
					+            me.lookupReference('freenas_use_ssl_field').setValue(false);
 | 
				
			||||||
+		me.lookupReference('freenas_apiv4_host_field').setValue('');
 | 
					+            me.lookupReference('truenas_token_auth_field').setValue(false);
 | 
				
			||||||
+		me.lookupReference('freenas_user_field').setValue('');
 | 
					+            me.lookupReference('freenas_apiv4_host_field').setValue('');
 | 
				
			||||||
+		me.lookupReference('freenas_user_field').allowBlank = true;
 | 
					+            me.lookupReference('freenas_user_field').setValue('');
 | 
				
			||||||
+		me.lookupReference('freenas_password_field').setValue('');
 | 
					+            me.lookupReference('freenas_user_field').allowBlank = true;
 | 
				
			||||||
+		me.lookupReference('freenas_password_field').allowBlank = true;
 | 
					+            me.lookupReference('truenas_secret_field').setValue('');
 | 
				
			||||||
+		me.lookupReference('freenas_confirmpw_field').setValue('');
 | 
					+            me.lookupReference('truenas_secret_field').allowBlank = true;
 | 
				
			||||||
+		me.lookupReference('freenas_confirmpw_field').allowBlank = true;
 | 
					+            me.lookupReference('truenas_confirm_secret_field').setValue('');
 | 
				
			||||||
+	    } else {
 | 
					+            me.lookupReference('truenas_confirm_secret_field').allowBlank = true;
 | 
				
			||||||
+		me.lookupReference('freenas_user_field').allowBlank = false;
 | 
					+        } else {
 | 
				
			||||||
+		me.lookupReference('freenas_password_field').allowBlank = false;
 | 
					+            me.lookupReference('freenas_user_field').allowBlank = false;
 | 
				
			||||||
+		me.lookupReference('freenas_confirmpw_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('');
 | 
				
			||||||
 | 
					+        }
 | 
				
			||||||
 	},
 | 
					 	},
 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
@@ -49669,6 +49687,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) {
 | 
					     setValues: function(values) {
 | 
				
			||||||
+        values.freenas_confirmpw = values.freenas_password;
 | 
					-	values.writecache = values.nowritecache ? 0 : 1;
 | 
				
			||||||
 	values.writecache = values.nowritecache ? 0 : 1;
 | 
					-	this.callParent([values]);
 | 
				
			||||||
 	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]);
 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
@@ -49685,7 +49704,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,
 | 
					 		allowBlank: false,
 | 
				
			||||||
 	    },
 | 
					 	    },
 | 
				
			||||||
 	    {
 | 
					 	    {
 | 
				
			||||||
| 
						 | 
					@ -61,7 +165,7 @@
 | 
				
			||||||
 		name: 'pool',
 | 
					 		name: 'pool',
 | 
				
			||||||
 		value: '',
 | 
					 		value: '',
 | 
				
			||||||
 		fieldLabel: gettext('Pool'),
 | 
					 		fieldLabel: gettext('Pool'),
 | 
				
			||||||
@@ -49695,11 +49714,11 @@
 | 
					@@ -58084,11 +58172,11 @@
 | 
				
			||||||
 		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | 
					 		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | 
				
			||||||
 		name: 'blocksize',
 | 
					 		name: 'blocksize',
 | 
				
			||||||
 		value: '4k',
 | 
					 		value: '4k',
 | 
				
			||||||
| 
						 | 
					@ -75,7 +179,7 @@
 | 
				
			||||||
 		name: 'target',
 | 
					 		name: 'target',
 | 
				
			||||||
 		value: '',
 | 
					 		value: '',
 | 
				
			||||||
 		fieldLabel: gettext('Target'),
 | 
					 		fieldLabel: gettext('Target'),
 | 
				
			||||||
@@ -49710,9 +49729,34 @@
 | 
					@@ -58099,8 +58187,59 @@
 | 
				
			||||||
 		name: 'comstar_tg',
 | 
					 		name: 'comstar_tg',
 | 
				
			||||||
 		value: '',
 | 
					 		value: '',
 | 
				
			||||||
 		fieldLabel: gettext('Target group'),
 | 
					 		fieldLabel: gettext('Target group'),
 | 
				
			||||||
| 
						 | 
					@ -84,7 +188,7 @@
 | 
				
			||||||
+		    hidden: '{!isComstar}'
 | 
					+		    hidden: '{!isComstar}'
 | 
				
			||||||
+		},
 | 
					+		},
 | 
				
			||||||
 		allowBlank: true,
 | 
					 		allowBlank: true,
 | 
				
			||||||
 	    },
 | 
					+},
 | 
				
			||||||
+	    {
 | 
					+	    {
 | 
				
			||||||
+		xtype: 'proxmoxcheckbox',
 | 
					+		xtype: 'proxmoxcheckbox',
 | 
				
			||||||
+		name: 'freenas_use_ssl',
 | 
					+		name: 'freenas_use_ssl',
 | 
				
			||||||
| 
						 | 
					@ -98,6 +202,32 @@
 | 
				
			||||||
+		fieldLabel: gettext('API use SSL'),
 | 
					+		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',
 | 
					+		xtype: 'textfield',
 | 
				
			||||||
+		name: 'freenas_user',
 | 
					+		name: 'freenas_user',
 | 
				
			||||||
+		reference: 'freenas_user_field',
 | 
					+		reference: 'freenas_user_field',
 | 
				
			||||||
| 
						 | 
					@ -105,13 +235,12 @@
 | 
				
			||||||
+		value: '',
 | 
					+		value: '',
 | 
				
			||||||
+		fieldLabel: gettext('API Username'),
 | 
					+		fieldLabel: gettext('API Username'),
 | 
				
			||||||
+		bind: {
 | 
					+		bind: {
 | 
				
			||||||
+		    hidden: '{!isFreeNAS}'
 | 
					+		    hidden: '{hideUsername}'
 | 
				
			||||||
+		},
 | 
					+		},
 | 
				
			||||||
+	    },
 | 
					 	    },
 | 
				
			||||||
 	];
 | 
					 	];
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
 	me.column2 = [
 | 
					@@ -58131,7 +58270,9 @@
 | 
				
			||||||
@@ -49742,7 +49786,9 @@
 | 
					 | 
				
			||||||
 		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | 
					 		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | 
				
			||||||
 		name: 'comstar_hg',
 | 
					 		name: 'comstar_hg',
 | 
				
			||||||
 		value: '',
 | 
					 		value: '',
 | 
				
			||||||
| 
						 | 
					@ -122,18 +251,19 @@
 | 
				
			||||||
 		fieldLabel: gettext('Host group'),
 | 
					 		fieldLabel: gettext('Host group'),
 | 
				
			||||||
 		allowBlank: true,
 | 
					 		allowBlank: true,
 | 
				
			||||||
 	    },
 | 
					 	    },
 | 
				
			||||||
@@ -49750,9 +49796,62 @@
 | 
					@@ -58139,15 +58280,32 @@
 | 
				
			||||||
 		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | 
					 		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | 
				
			||||||
 		name: 'lio_tpg',
 | 
					 		name: 'lio_tpg',
 | 
				
			||||||
 		value: '',
 | 
					 		value: '',
 | 
				
			||||||
-		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
 | 
					-		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
 | 
				
			||||||
-		allowBlank: false,
 | 
					-		allowBlank: false,
 | 
				
			||||||
 | 
					-		fieldLabel: gettext('Target portal group'),
 | 
				
			||||||
+		bind: {
 | 
					+		bind: {
 | 
				
			||||||
+		    hidden: '{!isLIO}'
 | 
					+		    hidden: '{!isLIO}'
 | 
				
			||||||
+		},
 | 
					+		},
 | 
				
			||||||
 		fieldLabel: gettext('Target portal group'),
 | 
					+				fieldLabel: gettext('Target portal group'),
 | 
				
			||||||
+		allowBlank: true
 | 
					+	    allowBlank: true
 | 
				
			||||||
+	    },
 | 
					 	    },
 | 
				
			||||||
+	    {
 | 
					+	    {
 | 
				
			||||||
+		xtype: 'proxmoxtextfield',
 | 
					+		xtype: 'proxmoxtextfield',
 | 
				
			||||||
+		name: 'freenas_apiv4_host',
 | 
					+		name: 'freenas_apiv4_host',
 | 
				
			||||||
| 
						 | 
					@ -146,44 +276,14 @@
 | 
				
			||||||
+		},
 | 
					+		},
 | 
				
			||||||
+		fieldLabel: gettext('API IPv4 Host'),
 | 
					+		fieldLabel: gettext('API IPv4 Host'),
 | 
				
			||||||
+	    },
 | 
					+	    },
 | 
				
			||||||
+	    {
 | 
					+	    tnsecret,
 | 
				
			||||||
+		xtype: 'proxmoxtextfield',
 | 
					+	    tnconfirmsecret,
 | 
				
			||||||
+		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;
 | 
					 | 
				
			||||||
+		},
 | 
					 | 
				
			||||||
 	    },
 | 
					 | 
				
			||||||
 	];
 | 
					 	];
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
 | 
					 	me.callParent();
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					 });
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					 Ext.define('PVE.storage.ZFSPoolSelector', {
 | 
				
			||||||
 | 
					     extend: 'PVE.form.ComboBoxSetStoreNode',
 | 
				
			||||||
 | 
					     alias: 'widget.pveZFSPoolSelector',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -1,189 +0,0 @@
 | 
				
			||||||
--- 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;
 | 
					 | 
				
			||||||
+		},
 | 
					 | 
				
			||||||
 	    },
 | 
					 | 
				
			||||||
 	];
 | 
					 | 
				
			||||||
 
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
--- ZFSPlugin.pm.orig	2022-02-04 12:08:01.000000000 -0500
 | 
					--- ZFSPlugin.pm.orig	2023-12-31 09:56:18.895228853 -0500
 | 
				
			||||||
+++ ZFSPlugin.pm	2022-03-26 13:51:40.660068908 -0400
 | 
					+++ ZFSPlugin.pm	2023-12-31 09:57:08.830488875 -0500
 | 
				
			||||||
@@ -10,6 +10,7 @@
 | 
					@@ -10,6 +10,7 @@
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
 use base qw(PVE::Storage::ZFSPoolPlugin);
 | 
					 use base qw(PVE::Storage::ZFSPoolPlugin);
 | 
				
			||||||
| 
						 | 
					@ -58,7 +58,7 @@
 | 
				
			||||||
 # Configuration
 | 
					 # Configuration
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
 sub type {
 | 
					 sub type {
 | 
				
			||||||
@@ -184,6 +199,24 @@
 | 
					@@ -184,6 +199,32 @@
 | 
				
			||||||
 	    description => "iscsi provider",
 | 
					 	    description => "iscsi provider",
 | 
				
			||||||
 	    type => 'string',
 | 
					 	    type => 'string',
 | 
				
			||||||
 	},
 | 
					 	},
 | 
				
			||||||
| 
						 | 
					@ -69,9 +69,17 @@
 | 
				
			||||||
+	    type => 'string',
 | 
					+	    type => 'string',
 | 
				
			||||||
+	},
 | 
					+	},
 | 
				
			||||||
+	freenas_password => {
 | 
					+	freenas_password => {
 | 
				
			||||||
+	    description => "FreeNAS API Password",
 | 
					+	    description => "FreeNAS API Password (Deprecated)",
 | 
				
			||||||
+	    type => 'string',
 | 
					+	    type => 'string',
 | 
				
			||||||
+	},
 | 
					+	},
 | 
				
			||||||
 | 
					+	truenas_secret => {
 | 
				
			||||||
 | 
					+	    description => "TrueNAS API Secret",
 | 
				
			||||||
 | 
					+	    type => 'string',
 | 
				
			||||||
 | 
					+	},
 | 
				
			||||||
 | 
					+	truenas_token_auth => {
 | 
				
			||||||
 | 
					+	    description => "TrueNAS API Authentication with Token",
 | 
				
			||||||
 | 
					+	    type => 'boolean',
 | 
				
			||||||
 | 
					+	},
 | 
				
			||||||
+	freenas_use_ssl => {
 | 
					+	freenas_use_ssl => {
 | 
				
			||||||
+	    description => "FreeNAS API access via SSL",
 | 
					+	    description => "FreeNAS API access via SSL",
 | 
				
			||||||
+	    type => 'boolean',
 | 
					+	    type => 'boolean',
 | 
				
			||||||
| 
						 | 
					@ -83,7 +91,7 @@
 | 
				
			||||||
 	# this will disable write caching on comstar and istgt.
 | 
					 	# this will disable write caching on comstar and istgt.
 | 
				
			||||||
 	# it is not implemented for iet. iet blockio always operates with
 | 
					 	# it is not implemented for iet. iet blockio always operates with
 | 
				
			||||||
 	# writethrough caching when not in readonly mode
 | 
					 	# writethrough caching when not in readonly mode
 | 
				
			||||||
@@ -211,14 +244,18 @@
 | 
					@@ -211,14 +252,20 @@
 | 
				
			||||||
 	nodes => { optional => 1 },
 | 
					 	nodes => { optional => 1 },
 | 
				
			||||||
 	disable => { optional => 1 },
 | 
					 	disable => { optional => 1 },
 | 
				
			||||||
 	portal => { fixed => 1 },
 | 
					 	portal => { fixed => 1 },
 | 
				
			||||||
| 
						 | 
					@ -99,12 +107,14 @@
 | 
				
			||||||
 	comstar_tg => { optional => 1 },
 | 
					 	comstar_tg => { optional => 1 },
 | 
				
			||||||
+	freenas_user => { optional => 1 },
 | 
					+	freenas_user => { optional => 1 },
 | 
				
			||||||
+	freenas_password => { optional => 1 },
 | 
					+	freenas_password => { optional => 1 },
 | 
				
			||||||
 | 
					+	truenas_secret => { optional => 1 },
 | 
				
			||||||
 | 
					+	truenas_token_auth => { optional => 1 },
 | 
				
			||||||
+	freenas_use_ssl => { optional => 1 },
 | 
					+	freenas_use_ssl => { optional => 1 },
 | 
				
			||||||
+	freenas_apiv4_host => { optional => 1 },
 | 
					+	freenas_apiv4_host => { optional => 1 },
 | 
				
			||||||
 	lio_tpg => { optional => 1 },
 | 
					 	lio_tpg => { optional => 1 },
 | 
				
			||||||
 	content => { optional => 1 },
 | 
					 	content => { optional => 1 },
 | 
				
			||||||
 	bwlimit => { optional => 1 },
 | 
					 	bwlimit => { optional => 1 },
 | 
				
			||||||
@@ -243,6 +280,40 @@
 | 
					@@ -243,6 +290,40 @@
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
     my $path = "iscsi://$portal/$target/$lun";
 | 
					     my $path = "iscsi://$portal/$target/$lun";
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
| 
						 | 
					@ -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
											
										
									
								
							| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
--- apidoc.js.orig	2021-11-15 10:07:34.000000000 -0500
 | 
					--- apidoc.js.orig	2024-01-06 13:02:06.730512378 -0500
 | 
				
			||||||
+++ apidoc.js	2021-12-06 08:04:01.648822707 -0500
 | 
					+++ apidoc.js	2024-01-06 13:02:55.349787105 -0500
 | 
				
			||||||
@@ -44064,6 +44064,31 @@
 | 
					@@ -50336,6 +50336,37 @@
 | 
				
			||||||
                            "type" : "string",
 | 
					                            "type" : "string",
 | 
				
			||||||
                            "typetext" : "<string>"
 | 
					                            "typetext" : "<string>"
 | 
				
			||||||
                         },
 | 
					                         },
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,13 @@
 | 
				
			||||||
+                           "typetext" : "<string>"
 | 
					+                           "typetext" : "<string>"
 | 
				
			||||||
+                        },
 | 
					+                        },
 | 
				
			||||||
+                        "freenas_password" : {
 | 
					+                        "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,
 | 
					+                           "optional" : 1,
 | 
				
			||||||
+                           "type" : "string",
 | 
					+                           "type" : "string",
 | 
				
			||||||
+                           "typetext" : "<string>"
 | 
					+                           "typetext" : "<string>"
 | 
				
			||||||
| 
						 | 
					@ -32,7 +38,7 @@
 | 
				
			||||||
                         "fuse" : {
 | 
					                         "fuse" : {
 | 
				
			||||||
                            "description" : "Mount CephFS through FUSE.",
 | 
					                            "description" : "Mount CephFS through FUSE.",
 | 
				
			||||||
                            "optional" : 1,
 | 
					                            "optional" : 1,
 | 
				
			||||||
@@ -44275,6 +44300,12 @@
 | 
					@@ -50555,6 +50586,12 @@
 | 
				
			||||||
                            "type" : "boolean",
 | 
					                            "type" : "boolean",
 | 
				
			||||||
                            "typetext" : "<boolean>"
 | 
					                            "typetext" : "<boolean>"
 | 
				
			||||||
                         },
 | 
					                         },
 | 
				
			||||||
| 
						 | 
					@ -45,7 +51,7 @@
 | 
				
			||||||
                         "transport" : {
 | 
					                         "transport" : {
 | 
				
			||||||
                            "description" : "Gluster transport: tcp or rdma",
 | 
					                            "description" : "Gluster transport: tcp or rdma",
 | 
				
			||||||
                            "enum" : [
 | 
					                            "enum" : [
 | 
				
			||||||
@@ -44547,6 +44578,31 @@
 | 
					@@ -50854,6 +50891,37 @@
 | 
				
			||||||
                      "optional" : 1,
 | 
					                      "optional" : 1,
 | 
				
			||||||
                      "type" : "string",
 | 
					                      "type" : "string",
 | 
				
			||||||
                      "typetext" : "<string>"
 | 
					                      "typetext" : "<string>"
 | 
				
			||||||
| 
						 | 
					@ -57,7 +63,13 @@
 | 
				
			||||||
+                     "typetext" : "<string>"
 | 
					+                     "typetext" : "<string>"
 | 
				
			||||||
+                  },
 | 
					+                  },
 | 
				
			||||||
+                  "freenas_password" : {
 | 
					+                  "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,
 | 
					+                     "optional" : 1,
 | 
				
			||||||
+                     "type" : "string",
 | 
					+                     "type" : "string",
 | 
				
			||||||
+                     "typetext" : "<string>"
 | 
					+                     "typetext" : "<string>"
 | 
				
			||||||
| 
						 | 
					@ -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',
 | 
				
			||||||
| 
						 | 
					@ -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
											
										
									
								
							
		Loading…
	
		Reference in New Issue