New Directory structure
- Just preping for a new install process.
This commit is contained in:
		
							parent
							
								
									4b46f2240f
								
							
						
					
					
						commit
						5d40ce4de6
					
				|  | @ -0,0 +1,4 @@ | ||||||
|  | /ZFSPlugin.pm | ||||||
|  | /ZFSPoolPlugin.pm | ||||||
|  | /ZFSPlugin-new.pm | ||||||
|  | /ZFSPlugin-newver.patch | ||||||
|  | @ -0,0 +1,546 @@ | ||||||
|  | package PVE::Storage::LunCmd::FreeNAS; | ||||||
|  | 
 | ||||||
|  | use strict; | ||||||
|  | use warnings; | ||||||
|  | use Data::Dumper; | ||||||
|  | use PVE::SafeSyslog; | ||||||
|  | use IO::Socket::SSL; | ||||||
|  | 
 | ||||||
|  | use REST::Client; | ||||||
|  | use MIME::Base64; | ||||||
|  | use JSON; | ||||||
|  | 
 | ||||||
|  | # Max LUNS per target on the iSCSI server | ||||||
|  | my $MAX_LUNS = 255; | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub get_base { | ||||||
|  |     return '/dev/zvol'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub run_lun_command { | ||||||
|  |     my ($scfg, $timeout, $method, @params) = @_; | ||||||
|  | 
 | ||||||
|  |     if(!defined($scfg->{'freenas_user'}) || !defined($scfg->{'freenas_password'})) { | ||||||
|  |         die "Undefined freenas_user and/or freenas_password."; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     syslog("info","FreeNAS::lun_command : $method(@params)"); | ||||||
|  | 
 | ||||||
|  |     if($method eq "create_lu") { | ||||||
|  |         return run_create_lu($scfg, $timeout, $method, @params); | ||||||
|  |     } | ||||||
|  |     if($method eq "delete_lu") { | ||||||
|  |         return run_delete_lu($scfg, $timeout, $method, @params); | ||||||
|  |     } | ||||||
|  |     if($method eq "import_lu") { | ||||||
|  |         return run_create_lu($scfg, $timeout, $method, @params); | ||||||
|  |     } | ||||||
|  |     if($method eq "modify_lu") { | ||||||
|  |         return run_modify_lu($scfg, $timeout, $method, @params); | ||||||
|  |     } | ||||||
|  |     if($method eq "add_view") { | ||||||
|  |         return run_add_view($scfg, $timeout, $method, @params); | ||||||
|  |     } | ||||||
|  |     if($method eq "list_view") { | ||||||
|  |         return run_list_view($scfg, $timeout, $method, @params); | ||||||
|  |     } | ||||||
|  |     if($method eq "list_extent") { | ||||||
|  |         return run_list_extent($scfg, $timeout, $method, @params); | ||||||
|  |     } | ||||||
|  |     if($method eq "list_lu") { | ||||||
|  |         return run_list_lu($scfg, $timeout, $method, "name", @params); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     syslog("error","FreeNAS::lun_command : unknown method $method"); | ||||||
|  |     return undef; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub run_add_view { | ||||||
|  |     return ''; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # a modify_lu occur by example on a zvol resize. we just need to destroy and recreate the lun with the same zvol. | ||||||
|  | # Be careful, the first param is the new size of the zvol, we must shift params | ||||||
|  | # | ||||||
|  | sub run_modify_lu { | ||||||
|  |     my ($scfg, $timeout, $method, @params) = @_; | ||||||
|  |     shift(@params); | ||||||
|  |     run_delete_lu($scfg, $timeout, $method, @params); | ||||||
|  |     return run_create_lu($scfg, $timeout, $method, @params); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub run_list_view { | ||||||
|  |     my ($scfg, $timeout, $method, @params) = @_; | ||||||
|  |     return run_list_lu($scfg, $timeout, $method, "lun-id", @params); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub run_list_lu { | ||||||
|  |     my ($scfg, $timeout, $method, $result_value_type, @params) = @_; | ||||||
|  |     my $object = $params[0]; | ||||||
|  |     my $result = undef; | ||||||
|  | 
 | ||||||
|  |     my $luns = freenas_list_lu($scfg); | ||||||
|  |     foreach my $lun (@$luns) { | ||||||
|  |         if ($lun->{'iscsi_target_extent_path'} =~ /^$object$/) { | ||||||
|  |             $result = $result_value_type eq "lun-id" ? $lun->{'iscsi_lunid'} : $lun->{'iscsi_target_extent_path'}; | ||||||
|  |             syslog("info","FreeNAS::list_lu($object):$result_value_type : lun found $result"); | ||||||
|  |             last; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if(!defined($result)) { | ||||||
|  |         syslog("info","FreeNAS::list_lu($object):$result_value_type : lun not found"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return $result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub run_list_extent { | ||||||
|  |     my ($scfg, $timeout, $method, @params) = @_; | ||||||
|  |     my $object = $params[0]; | ||||||
|  |     my $result = undef; | ||||||
|  | 
 | ||||||
|  |     my $luns = freenas_list_lu($scfg); | ||||||
|  |     foreach my $lun (@$luns) { | ||||||
|  |         if ($lun->{'iscsi_target_extent_path'} =~ /^$object$/) { | ||||||
|  |             $result = $lun->{'iscsi_target_extent_naa'}; | ||||||
|  |             syslog("info","FreeNAS::list_extent($object): naa found $result"); | ||||||
|  |             last; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     if (!defined($result)) { | ||||||
|  |         syslog("info","FreeNAS::list_extent($object): naa not found"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return $result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub run_create_lu { | ||||||
|  |     my ($scfg, $timeout, $method, @params) = @_; | ||||||
|  | 
 | ||||||
|  |     my $lun_path  = $params[0]; | ||||||
|  |     my $lun_id    = freenas_get_first_available_lunid($scfg); | ||||||
|  | 
 | ||||||
|  |     die "Maximum number of LUNs per target is $MAX_LUNS" if scalar $lun_id >= $MAX_LUNS; | ||||||
|  |     die "$params[0]: LUN $lun_path exists" if defined(run_list_lu($scfg, $timeout, $method, "name", @params)); | ||||||
|  | 
 | ||||||
|  |     my $target_id = freenas_get_targetid($scfg); | ||||||
|  |     die "Unable to find the target id for $scfg->{target}" if !defined($target_id); | ||||||
|  | 
 | ||||||
|  |     # Create the extent | ||||||
|  |     my $extent = freenas_iscsi_create_extent($scfg, $lun_path); | ||||||
|  | 
 | ||||||
|  |     # Associate the new extent to the target | ||||||
|  |     my $link = freenas_iscsi_create_target_to_extent($scfg, $target_id, $extent->{'id'}, $lun_id); | ||||||
|  | 
 | ||||||
|  |     if (defined($link)) { | ||||||
|  |        syslog("info","FreeNAS::create_lu(lun_path=$lun_path, lun_id=$lun_id) : sucessfull"); | ||||||
|  |     } else { | ||||||
|  |        die "Unable to create lun $lun_path"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ""; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub run_delete_lu { | ||||||
|  |     my ($scfg, $timeout, $method, @params) = @_; | ||||||
|  | 
 | ||||||
|  |     my $lun_path  = $params[0]; | ||||||
|  |     my $luns      = freenas_list_lu($scfg); | ||||||
|  |     my $lun       = undef; | ||||||
|  |     my $link      = undef; | ||||||
|  | 
 | ||||||
|  |     foreach my $item (@$luns) { | ||||||
|  |        if($item->{'iscsi_target_extent_path'} =~ /^$lun_path$/) { | ||||||
|  |          $lun = $item; | ||||||
|  |          last; | ||||||
|  |        } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     die "Unable to find the lun $lun_path for $scfg->{target}" if !defined($lun); | ||||||
|  | 
 | ||||||
|  |     my $target_id = freenas_get_targetid($scfg); | ||||||
|  |     die "Unable to find the target id for $scfg->{target}" if !defined($target_id); | ||||||
|  | 
 | ||||||
|  |     # find the target to extent | ||||||
|  |     my $target2extents = freenas_iscsi_get_target_to_extent($scfg); | ||||||
|  | 
 | ||||||
|  |     foreach my $item (@$target2extents) { | ||||||
|  |         if($item->{'iscsi_target'} == $target_id && | ||||||
|  |            $item->{'iscsi_lunid'} == $lun->{'iscsi_lunid'} && | ||||||
|  |            $item->{'iscsi_extent'} == $lun->{'id'}) { | ||||||
|  | 
 | ||||||
|  |             $link = $item; | ||||||
|  |             last; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     die "Unable to find the link for the lun $lun_path for $scfg->{target}" if !defined($link); | ||||||
|  | 
 | ||||||
|  |     # Remove the link | ||||||
|  |     my $remove_link = freenas_iscsi_remove_target_to_extent($scfg, $link->{'id'}); | ||||||
|  | 
 | ||||||
|  |     # Remove the extent | ||||||
|  |     my $remove_extent = freenas_iscsi_remove_extent($scfg, $lun->{'id'}); | ||||||
|  | 
 | ||||||
|  |     if($remove_link == 1 && $remove_extent == 1) { | ||||||
|  |         syslog("info","FreeNAS::delete_lu(lun_path=$lun_path) : sucessfull"); | ||||||
|  |     } else { | ||||||
|  |         die "Unable to delete lun $lun_path"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ""; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | ### FREENAS API CALLING ### | ||||||
|  | # | ||||||
|  | sub freenas_api_call { | ||||||
|  |     my ($scfg, $method, $path, $data) = @_; | ||||||
|  |     my $client = undef; | ||||||
|  |     my $scheme = $scfg->{freenas_use_ssl} ? "https" : "http"; | ||||||
|  |     my $apihost = defined($scfg->{freenas_apiv4_host}) ? $scfg->{freenas_apiv4_host} : $scfg->{portal}; | ||||||
|  |     my $apiping = '/api/v1.0/system/version/'; | ||||||
|  | 
 | ||||||
|  |     $client = REST::Client->new(); | ||||||
|  |     $client->setHost($scheme . '://' . $apihost); | ||||||
|  |     $client->addHeader('Content-Type'  , 'application/json'); | ||||||
|  |     $client->addHeader('Authorization' , 'Basic ' . encode_base64($scfg->{freenas_user} . ':' . $scfg->{freenas_password})); | ||||||
|  |     # If using SSL, don't verify SSL certs | ||||||
|  |     if ($scfg->{freenas_use_ssl}) { | ||||||
|  |         $client->getUseragent()->ssl_opts(verify_hostname => 0); | ||||||
|  |         $client->getUseragent()->ssl_opts(SSL_verify_mode => SSL_VERIFY_NONE); | ||||||
|  |     } | ||||||
|  |     # Check if the APIs are accessable via the selected host and scheme | ||||||
|  |     my $code = $client->request('GET', $apiping)->responseCode(); | ||||||
|  |     if ($code != 200) { | ||||||
|  |         freenas_api_log_error($client, "freenas_api_call"); | ||||||
|  |         die "Unable to connect to the FreeNAS API service at '" . $apihost . "' using the '" . $scheme . "' protocol"; | ||||||
|  |     } | ||||||
|  |     syslog("info","FreeNAS::api_call : setup : sucessfull"); | ||||||
|  |     if ($method eq 'GET') { | ||||||
|  |         $client->GET($path); | ||||||
|  |     } | ||||||
|  |     if ($method eq 'DELETE') { | ||||||
|  |         $client->DELETE($path); | ||||||
|  |     } | ||||||
|  |     if ($method eq 'POST') { | ||||||
|  |         $client->POST($path, encode_json($data)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return $client | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Writes the Response and Content to SysLog  | ||||||
|  | # | ||||||
|  | sub freenas_api_log_error { | ||||||
|  |     my ($client, $method) = @_; | ||||||
|  |     syslog("info","[ERROR]FreeNAS::API::" . $method . " : Response code: " . $client->responseCode()); | ||||||
|  |     syslog("info","[ERROR]FreeNAS::API::" . $method . " : Response content: " . $client->responseContent()); | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # | ||||||
|  | sub freenas_iscsi_get_globalconfiguration { | ||||||
|  |     my ($scfg) = @_; | ||||||
|  |     my $client = freenas_api_call($scfg, 'GET', "/api/v1.0/services/iscsi/globalconfiguration/", undef); | ||||||
|  |     my $code = $client->responseCode(); | ||||||
|  | 
 | ||||||
|  |     if ($code == 200) { | ||||||
|  |         my $result = decode_json($client->responseContent()); | ||||||
|  |         syslog("info","FreeNAS::API::get_globalconfig : target_basename=" . $result->{'iscsi_basename'}); | ||||||
|  |         return $result; | ||||||
|  |     } else { | ||||||
|  |         freenas_api_log_error($client, "get_globalconfig"); | ||||||
|  |         return undef; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Returns a list of all extents. | ||||||
|  | # http://api.freenas.org/resources/iscsi/index.html#get--api-v1.0-services-iscsi-extent- | ||||||
|  | # | ||||||
|  | sub freenas_iscsi_get_extent { | ||||||
|  |     my ($scfg) = @_; | ||||||
|  |     my $client = freenas_api_call($scfg, 'GET', "/api/v1.0/services/iscsi/extent/?limit=0", undef); | ||||||
|  | 
 | ||||||
|  |     my $code = $client->responseCode(); | ||||||
|  |     if ($code == 200) { | ||||||
|  |         my $result = decode_json($client->responseContent()); | ||||||
|  |         syslog("info","FreeNAS::API::get_extent : sucessfull"); | ||||||
|  |         return $result; | ||||||
|  |     } else { | ||||||
|  |         freenas_api_log_error($client, "get_extent"); | ||||||
|  |         return undef; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Create an extent on FreeNas | ||||||
|  | # http://api.freenas.org/resources/iscsi/index.html#create-resource | ||||||
|  | # Parameters: | ||||||
|  | #   - target config (scfg) | ||||||
|  | #   - lun_path | ||||||
|  | # | ||||||
|  | sub freenas_iscsi_create_extent { | ||||||
|  |     my ($scfg, $lun_path) = @_; | ||||||
|  | 
 | ||||||
|  |     my $name = $lun_path; | ||||||
|  |     $name  =~ s/^.*\///; # all from last / | ||||||
|  |     $name  = $scfg->{'pool'} . '/' . $name; | ||||||
|  | 
 | ||||||
|  |     my $device = $lun_path; | ||||||
|  |     $device =~ s/^\/dev\///; # strip /dev/ | ||||||
|  | 
 | ||||||
|  |     my $request = { | ||||||
|  |         "iscsi_target_extent_type"      => "Disk", | ||||||
|  |         "iscsi_target_extent_name"      => $name, | ||||||
|  |         "iscsi_target_extent_disk"      => $device, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     my $client = freenas_api_call($scfg, 'POST', "/api/v1.0/services/iscsi/extent/", $request); | ||||||
|  |     my $code = $client->responseCode(); | ||||||
|  |     if ($code == 201) { | ||||||
|  |         my $result = decode_json($client->responseContent()); | ||||||
|  |         syslog("info", "FreeNAS::API::create_extent(lun_path=" . $result->{'iscsi_target_extent_path'} . ") : sucessfull"); | ||||||
|  |         return $result; | ||||||
|  |     } else { | ||||||
|  |         freenas_api_log_error($client, "create_extent"); | ||||||
|  |         return undef; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Remove an extent by it's id | ||||||
|  | # http://api.freenas.org/resources/iscsi/index.html#delete-resource | ||||||
|  | # Parameters: | ||||||
|  | #    - scfg | ||||||
|  | #    - extent_id | ||||||
|  | # | ||||||
|  | sub freenas_iscsi_remove_extent { | ||||||
|  |     my ($scfg, $extent_id) = @_; | ||||||
|  | 
 | ||||||
|  |     my $client = freenas_api_call($scfg, 'DELETE', "/api/v1.0/services/iscsi/extent/$extent_id/", undef); | ||||||
|  |     my $code = $client->responseCode(); | ||||||
|  |     if ($code == 204) { | ||||||
|  |         syslog("info","FreeNAS::API::remove_extent(extent_id=$extent_id) : sucessfull"); | ||||||
|  |         return 1; | ||||||
|  |     } else { | ||||||
|  |         freenas_api_log_error($client, "remove_extent"); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Returns a list of all targets | ||||||
|  | # http://api.freenas.org/resources/iscsi/index.html#get--api-v1.0-services-iscsi-target- | ||||||
|  | # | ||||||
|  | sub freenas_iscsi_get_target { | ||||||
|  |     my ($scfg) = @_; | ||||||
|  | 
 | ||||||
|  |     my $client = freenas_api_call($scfg, 'GET', "/api/v1.0/services/iscsi/target/?limit=0", undef); | ||||||
|  |     my $code = $client->responseCode(); | ||||||
|  |     if ($code == 200) { | ||||||
|  |         my $result = decode_json($client->responseContent()); | ||||||
|  |         syslog("info","FreeNAS::API::get_target() : sucessfull"); | ||||||
|  |         return $result; | ||||||
|  |     } else { | ||||||
|  |         freenas_api_log_error($client, "get_target"); | ||||||
|  |         return undef; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Returns a list of associated extents to targets | ||||||
|  | # http://api.freenas.org/resources/iscsi/index.html#get--api-v1.0-services-iscsi-targettoextent- | ||||||
|  | # | ||||||
|  | sub freenas_iscsi_get_target_to_extent { | ||||||
|  |     my ($scfg) = @_; | ||||||
|  | 
 | ||||||
|  |     my $client = freenas_api_call($scfg, 'GET', "/api/v1.0/services/iscsi/targettoextent/?limit=0", undef); | ||||||
|  |     my $code = $client->responseCode(); | ||||||
|  |     if ($code == 200) { | ||||||
|  |         my $result = decode_json($client->responseContent()); | ||||||
|  |         syslog("info","FreeNAS::API::get_target_to_extent() : sucessfull"); | ||||||
|  |         # If 'iscsi_lunid' is undef then it is set to 'Auto' in FreeNAS | ||||||
|  |         # which should be '0' in our eyes. | ||||||
|  |         # This gave Proxmox 5.x and FreeNAS 11.1 a few issues. | ||||||
|  |         foreach my $item (@$result) { | ||||||
|  |             if (!defined($item->{'iscsi_lunid'})) { | ||||||
|  |                 $item->{'iscsi_lunid'} = 0; | ||||||
|  |                 syslog("info", "FreeNAS::API::get_target_to_extent() : change undef iscsi_lunid to 0"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return $result; | ||||||
|  |     } else { | ||||||
|  |         freenas_api_log_error($client, "get_target_to_extent"); | ||||||
|  |         return undef; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Associate a FreeNas extent to a FreeNas Target | ||||||
|  | # http://api.freenas.org/resources/iscsi/index.html#post--api-v1.0-services-iscsi-targettoextent- | ||||||
|  | # Parameters: | ||||||
|  | #   - target config (scfg) | ||||||
|  | #   - FreeNas Target ID | ||||||
|  | #   - FreeNas Extent ID | ||||||
|  | #   - Lun ID | ||||||
|  | # | ||||||
|  | sub freenas_iscsi_create_target_to_extent { | ||||||
|  |     my ($scfg, $target_id, $extent_id, $lun_id) = @_; | ||||||
|  | 
 | ||||||
|  |     my $request = { | ||||||
|  |         "iscsi_target"  => $target_id, | ||||||
|  |         "iscsi_extent"  => $extent_id, | ||||||
|  |         "iscsi_lunid"   => $lun_id | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     my $client = freenas_api_call($scfg, 'POST', "/api/v1.0/services/iscsi/targettoextent/", $request); | ||||||
|  |     my $code = $client->responseCode(); | ||||||
|  |     if ($code == 201) { | ||||||
|  |         my $result = decode_json($client->responseContent()); | ||||||
|  |         syslog("info","FreeNAS::API::create_target_to_extent(target_id=$target_id, extent_id=$extent_id, lun_id=$lun_id) : sucessfull"); | ||||||
|  |         return $result; | ||||||
|  |     } else { | ||||||
|  |         freenas_api_log_error($client, "create_target_to_extent"); | ||||||
|  |         return undef; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Remove a Target to extent by it's id | ||||||
|  | # http://api.freenas.org/resources/iscsi/index.html#delete--api-v1.0-services-iscsi-targettoextent-(int-id)- | ||||||
|  | # Parameters: | ||||||
|  | #    - scfg | ||||||
|  | #    - link_id | ||||||
|  | # | ||||||
|  | sub freenas_iscsi_remove_target_to_extent { | ||||||
|  |     my ($scfg, $link_id) = @_; | ||||||
|  | 
 | ||||||
|  |     my $client = freenas_api_call($scfg, 'DELETE', "/api/v1.0/services/iscsi/targettoextent/$link_id/", undef); | ||||||
|  |     my $code = $client->responseCode(); | ||||||
|  |     if ($code == 204) { | ||||||
|  |         syslog("info","FreeNAS::API::remove_target_to_extent(link_id=$link_id) : sucessfull"); | ||||||
|  |         return 1; | ||||||
|  |     } else { | ||||||
|  |         freenas_api_log_error($client, "remove_target_to_extent"); | ||||||
|  |         return 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Returns all luns associated to the current target defined by $scfg->{target} | ||||||
|  | # This method returns an array reference like "freenas_iscsi_get_extent" do | ||||||
|  | # but with an additionnal hash entry "iscsi_lunid" retrieved from "freenas_iscsi_get_target_to_extent" | ||||||
|  | # | ||||||
|  | sub freenas_list_lu { | ||||||
|  |     my ($scfg) = @_; | ||||||
|  | 
 | ||||||
|  |     my $targets   = freenas_iscsi_get_target($scfg); | ||||||
|  |     my $target_id = freenas_get_targetid($scfg); | ||||||
|  | 
 | ||||||
|  |     my @luns        = (); | ||||||
|  |     my $iscsi_lunid = undef; | ||||||
|  | 
 | ||||||
|  |     if(defined($target_id)) { | ||||||
|  |         my $target2extents = freenas_iscsi_get_target_to_extent($scfg); | ||||||
|  |         my $extents        = freenas_iscsi_get_extent($scfg); | ||||||
|  | 
 | ||||||
|  |         foreach my $item (@$target2extents) { | ||||||
|  |             if($item->{'iscsi_target'} == $target_id) { | ||||||
|  |                 foreach my $node (@$extents) { | ||||||
|  |                     if($node->{'id'} == $item->{'iscsi_extent'}) { | ||||||
|  |                         if ($item->{'iscsi_lunid'} =~ /(\d+)/) { | ||||||
|  |                             $iscsi_lunid = "$1"; | ||||||
|  |                         } else { | ||||||
|  |                             syslog("info", "FreeNAS::API::freenas_list_lu : iscsi_lunid did not pass tainted testing"); | ||||||
|  |                             next; | ||||||
|  |                         } | ||||||
|  |                         $node->{'iscsi_lunid'} .= $iscsi_lunid; | ||||||
|  |                         push(@luns , $node); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     syslog("info", "FreeNAS::API::freenas_list_lu : sucessfull"); | ||||||
|  |     return \@luns; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Returns the first available "lunid" (in all targets namespaces) | ||||||
|  | # | ||||||
|  | sub freenas_get_first_available_lunid { | ||||||
|  |     my ($scfg) = @_; | ||||||
|  | 
 | ||||||
|  |     my $target_id      = freenas_get_targetid($scfg); | ||||||
|  |     my $target2extents = freenas_iscsi_get_target_to_extent($scfg); | ||||||
|  |     my @luns           = (); | ||||||
|  | 
 | ||||||
|  |     foreach my $item (@$target2extents) { | ||||||
|  |         push(@luns, $item->{'iscsi_lunid'}) if ($item->{'iscsi_target'} == $target_id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     my @sorted_luns =  sort {$a <=> $b} @luns; | ||||||
|  |     my $lun_id      = 0; | ||||||
|  | 
 | ||||||
|  |     # find the first hole, if not, give the +1 of the last lun | ||||||
|  |     foreach my $lun (@sorted_luns) { | ||||||
|  |         last if $lun != $lun_id; | ||||||
|  |         $lun_id = $lun_id + 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     syslog("info", "FreeNAS::API::freenas_get_first_available_lunid : return $lun_id"); | ||||||
|  |     return $lun_id; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Returns the target id on FreeNas of the currently configured target of this PVE storage | ||||||
|  | # | ||||||
|  | sub freenas_get_targetid { | ||||||
|  |     my ($scfg) = @_; | ||||||
|  | 
 | ||||||
|  |     my $global    = freenas_iscsi_get_globalconfiguration($scfg); | ||||||
|  |     my $targets   = freenas_iscsi_get_target($scfg); | ||||||
|  |     my $target_id = undef; | ||||||
|  | 
 | ||||||
|  |     foreach my $target (@$targets) { | ||||||
|  |         my $iqn = $global->{'iscsi_basename'} . ':' . $target->{'iscsi_target_name'}; | ||||||
|  |         if($iqn eq $scfg->{target}) { | ||||||
|  |             $target_id = $target->{'id'}; | ||||||
|  |             last; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return $target_id; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 1; | ||||||
|  | @ -0,0 +1,140 @@ | ||||||
|  | --- ZFSPlugin.pm.orig	2018-10-03 11:02:46.000000000 -0400
 | ||||||
|  | +++ ZFSPlugin.pm	2018-10-28 21:27:44.794732848 -0400
 | ||||||
|  | @@ -10,6 +10,7 @@
 | ||||||
|  |   | ||||||
|  |  use base qw(PVE::Storage::ZFSPoolPlugin); | ||||||
|  |  use PVE::Storage::LunCmd::Comstar; | ||||||
|  | +use PVE::Storage::LunCmd::FreeNAS;
 | ||||||
|  |  use PVE::Storage::LunCmd::Istgt; | ||||||
|  |  use PVE::Storage::LunCmd::Iet; | ||||||
|  |  use PVE::Storage::LunCmd::LIO; | ||||||
|  | @@ -32,7 +33,7 @@
 | ||||||
|  |  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 +41,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 +65,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') { | ||||||
|  | @@ -160,6 +165,15 @@
 | ||||||
|  |      return $class->zfs_request($scfg, undef, 'list_view', $guid); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +# 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 { | ||||||
|  | @@ -178,6 +192,24 @@
 | ||||||
|  |  	    description => "iscsi provider", | ||||||
|  |  	    type => 'string', | ||||||
|  |  	}, | ||||||
|  | +	# This is for FreeNAS iscsi and API intergration
 | ||||||
|  | +	# And some enhancements asked by the community
 | ||||||
|  | +	freenas_user => {
 | ||||||
|  | +	    description => "FreeNAS API Username",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_password => {
 | ||||||
|  | +	    description => "FreeNAS API Password",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_use_ssl => {
 | ||||||
|  | +	    description => "FreeNAS API access via SSL",
 | ||||||
|  | +	    type => 'boolean',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_apiv4_host => {
 | ||||||
|  | +	    description => "FreeNAS API Host",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  |  	# this will disable write caching on comstar and istgt. | ||||||
|  |  	# it is not implemented for iet. iet blockio always operates with | ||||||
|  |  	# writethrough caching when not in readonly mode | ||||||
|  | @@ -205,14 +237,18 @@
 | ||||||
|  |  	nodes => { optional => 1 }, | ||||||
|  |  	disable => { optional => 1 }, | ||||||
|  |  	portal => { fixed => 1 }, | ||||||
|  | -	target => { fixed => 1 },
 | ||||||
|  | -	pool => { fixed => 1 },
 | ||||||
|  | +	target => { fixed => 0 },
 | ||||||
|  | +	pool => { fixed => 0 },
 | ||||||
|  |  	blocksize => { fixed => 1 }, | ||||||
|  |  	iscsiprovider => { fixed => 1 }, | ||||||
|  |  	nowritecache => { optional => 1 }, | ||||||
|  |  	sparse => { optional => 1 }, | ||||||
|  |  	comstar_hg => { optional => 1 }, | ||||||
|  |  	comstar_tg => { optional => 1 }, | ||||||
|  | +	freenas_user => { optional => 1 },
 | ||||||
|  | +	freenas_password => { optional => 1 },
 | ||||||
|  | +	freenas_use_ssl => { optional => 1 },
 | ||||||
|  | +	freenas_apiv4_host => { optional => 1 },
 | ||||||
|  |  	lio_tpg => { optional => 1 }, | ||||||
|  |  	content => { optional => 1 }, | ||||||
|  |  	bwlimit => { optional => 1 }, | ||||||
|  | @@ -237,6 +273,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 = `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,10 @@ | ||||||
|  | --- ZFSPlugin-5.0-33.pm	2018-12-15 09:29:56.586101170 -0500
 | ||||||
|  | +++ ZFSPlugin.pm	2018-12-15 09:24:08.393984276 -0500
 | ||||||
|  | @@ -27,6 +27,7 @@
 | ||||||
|  |      modify_lu   => 1, | ||||||
|  |      add_view    => 1, | ||||||
|  |      list_view   => 1, | ||||||
|  | +    list_extent => 1,
 | ||||||
|  |      list_lu     => 1, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | @ -0,0 +1,147 @@ | ||||||
|  | --- ZFSPlugin.pm.orig	2018-11-27 07:23:15.000000000 -0500
 | ||||||
|  | +++ ZFSPlugin.pm	2018-12-15 09:24:08.393984276 -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') { | ||||||
|  | @@ -160,6 +166,15 @@
 | ||||||
|  |      return $class->zfs_request($scfg, undef, 'list_view', $guid); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +# 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 { | ||||||
|  | @@ -178,6 +193,24 @@
 | ||||||
|  |  	    description => "iscsi provider", | ||||||
|  |  	    type => 'string', | ||||||
|  |  	}, | ||||||
|  | +	# This is for FreeNAS iscsi and API intergration
 | ||||||
|  | +	# And some enhancements asked by the community
 | ||||||
|  | +	freenas_user => {
 | ||||||
|  | +	    description => "FreeNAS API Username",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_password => {
 | ||||||
|  | +	    description => "FreeNAS API Password",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_use_ssl => {
 | ||||||
|  | +	    description => "FreeNAS API access via SSL",
 | ||||||
|  | +	    type => 'boolean',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_apiv4_host => {
 | ||||||
|  | +	    description => "FreeNAS API Host",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  |  	# this will disable write caching on comstar and istgt. | ||||||
|  |  	# it is not implemented for iet. iet blockio always operates with | ||||||
|  |  	# writethrough caching when not in readonly mode | ||||||
|  | @@ -205,14 +238,18 @@
 | ||||||
|  |  	nodes => { optional => 1 }, | ||||||
|  |  	disable => { optional => 1 }, | ||||||
|  |  	portal => { fixed => 1 }, | ||||||
|  | -	target => { fixed => 1 },
 | ||||||
|  | -	pool => { fixed => 1 },
 | ||||||
|  | +	target => { fixed => 0 },
 | ||||||
|  | +	pool => { fixed => 0 },
 | ||||||
|  |  	blocksize => { fixed => 1 }, | ||||||
|  |  	iscsiprovider => { fixed => 1 }, | ||||||
|  |  	nowritecache => { optional => 1 }, | ||||||
|  |  	sparse => { optional => 1 }, | ||||||
|  |  	comstar_hg => { optional => 1 }, | ||||||
|  |  	comstar_tg => { optional => 1 }, | ||||||
|  | +	freenas_user => { optional => 1 },
 | ||||||
|  | +	freenas_password => { optional => 1 },
 | ||||||
|  | +	freenas_use_ssl => { optional => 1 },
 | ||||||
|  | +	freenas_apiv4_host => { optional => 1 },
 | ||||||
|  |  	lio_tpg => { optional => 1 }, | ||||||
|  |  	content => { optional => 1 }, | ||||||
|  |  	bwlimit => { optional => 1 }, | ||||||
|  | @@ -237,6 +274,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 = `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,147 @@ | ||||||
|  | --- ZFSPlugin-5.0-34.pm	2018-12-21 12:52:21.764194866 -0500
 | ||||||
|  | +++ ZFSPlugin.pm	2018-12-21 12:53:08.663665081 -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') { | ||||||
|  | @@ -160,6 +166,15 @@
 | ||||||
|  |      return $class->zfs_request($scfg, undef, 'list_view', $guid); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +# 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 { | ||||||
|  | @@ -178,6 +193,24 @@
 | ||||||
|  |  	    description => "iscsi provider", | ||||||
|  |  	    type => 'string', | ||||||
|  |  	}, | ||||||
|  | +	# This is for FreeNAS iscsi and API intergration
 | ||||||
|  | +	# And some enhancements asked by the community
 | ||||||
|  | +	freenas_user => {
 | ||||||
|  | +	    description => "FreeNAS API Username",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_password => {
 | ||||||
|  | +	    description => "FreeNAS API Password",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_use_ssl => {
 | ||||||
|  | +	    description => "FreeNAS API access via SSL",
 | ||||||
|  | +	    type => 'boolean',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_apiv4_host => {
 | ||||||
|  | +	    description => "FreeNAS API Host",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  |  	# this will disable write caching on comstar and istgt. | ||||||
|  |  	# it is not implemented for iet. iet blockio always operates with | ||||||
|  |  	# writethrough caching when not in readonly mode | ||||||
|  | @@ -205,14 +238,18 @@
 | ||||||
|  |  	nodes => { optional => 1 }, | ||||||
|  |  	disable => { optional => 1 }, | ||||||
|  |  	portal => { fixed => 1 }, | ||||||
|  | -	target => { fixed => 1 },
 | ||||||
|  | -	pool => { fixed => 1 },
 | ||||||
|  | +	target => { fixed => 0 },
 | ||||||
|  | +	pool => { fixed => 0 },
 | ||||||
|  |  	blocksize => { fixed => 1 }, | ||||||
|  |  	iscsiprovider => { fixed => 1 }, | ||||||
|  |  	nowritecache => { optional => 1 }, | ||||||
|  |  	sparse => { optional => 1 }, | ||||||
|  |  	comstar_hg => { optional => 1 }, | ||||||
|  |  	comstar_tg => { optional => 1 }, | ||||||
|  | +	freenas_user => { optional => 1 },
 | ||||||
|  | +	freenas_password => { optional => 1 },
 | ||||||
|  | +	freenas_use_ssl => { optional => 1 },
 | ||||||
|  | +	freenas_apiv4_host => { optional => 1 },
 | ||||||
|  |  	lio_tpg => { optional => 1 }, | ||||||
|  |  	content => { optional => 1 }, | ||||||
|  |  	bwlimit => { optional => 1 }, | ||||||
|  | @@ -237,6 +274,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 = `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,147 @@ | ||||||
|  | --- ZFSPlugin.pm.orig	2019-02-07 09:14:12.000000000 -0500
 | ||||||
|  | +++ ZFSPlugin.pm	2019-02-26 20:53:29.096598801 -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') { | ||||||
|  | @@ -160,6 +166,15 @@
 | ||||||
|  |      return $class->zfs_request($scfg, undef, 'list_view', $guid); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +# 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 { | ||||||
|  | @@ -178,6 +193,24 @@
 | ||||||
|  |  	    description => "iscsi provider", | ||||||
|  |  	    type => 'string', | ||||||
|  |  	}, | ||||||
|  | +	# This is for FreeNAS iscsi and API intergration
 | ||||||
|  | +	# And some enhancements asked by the community
 | ||||||
|  | +	freenas_user => {
 | ||||||
|  | +	    description => "FreeNAS API Username",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_password => {
 | ||||||
|  | +	    description => "FreeNAS API Password",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_use_ssl => {
 | ||||||
|  | +	    description => "FreeNAS API access via SSL",
 | ||||||
|  | +	    type => 'boolean',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_apiv4_host => {
 | ||||||
|  | +	    description => "FreeNAS API Host",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  |  	# this will disable write caching on comstar and istgt. | ||||||
|  |  	# it is not implemented for iet. iet blockio always operates with | ||||||
|  |  	# writethrough caching when not in readonly mode | ||||||
|  | @@ -205,14 +238,18 @@
 | ||||||
|  |  	nodes => { optional => 1 }, | ||||||
|  |  	disable => { optional => 1 }, | ||||||
|  |  	portal => { fixed => 1 }, | ||||||
|  | -	target => { fixed => 1 },
 | ||||||
|  | -	pool => { fixed => 1 },
 | ||||||
|  | +	target => { fixed => 0 },
 | ||||||
|  | +	pool => { fixed => 0 },
 | ||||||
|  |  	blocksize => { fixed => 1 }, | ||||||
|  |  	iscsiprovider => { fixed => 1 }, | ||||||
|  |  	nowritecache => { optional => 1 }, | ||||||
|  |  	sparse => { optional => 1 }, | ||||||
|  |  	comstar_hg => { optional => 1 }, | ||||||
|  |  	comstar_tg => { optional => 1 }, | ||||||
|  | +	freenas_user => { optional => 1 },
 | ||||||
|  | +	freenas_password => { optional => 1 },
 | ||||||
|  | +	freenas_use_ssl => { optional => 1 },
 | ||||||
|  | +	freenas_apiv4_host => { optional => 1 },
 | ||||||
|  |  	lio_tpg => { optional => 1 }, | ||||||
|  |  	content => { optional => 1 }, | ||||||
|  |  	bwlimit => { optional => 1 }, | ||||||
|  | @@ -237,6 +274,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 = `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,147 @@ | ||||||
|  | --- ZFSPlugin.pm.orig	2019-04-30 09:54:55.000000000 -0400
 | ||||||
|  | +++ ZFSPlugin.pm	2019-05-11 10:32:36.326734352 -0400
 | ||||||
|  | @@ -10,6 +10,7 @@
 | ||||||
|  |   | ||||||
|  |  use base qw(PVE::Storage::ZFSPoolPlugin); | ||||||
|  |  use PVE::Storage::LunCmd::Comstar; | ||||||
|  | +use PVE::Storage::LunCmd::FreeNAS;
 | ||||||
|  |  use PVE::Storage::LunCmd::Istgt; | ||||||
|  |  use PVE::Storage::LunCmd::Iet; | ||||||
|  |  use PVE::Storage::LunCmd::LIO; | ||||||
|  | @@ -26,13 +27,14 @@
 | ||||||
|  |      modify_lu   => 1, | ||||||
|  |      add_view    => 1, | ||||||
|  |      list_view   => 1, | ||||||
|  | +    list_extent => 1,
 | ||||||
|  |      list_lu     => 1, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  my $zfs_unknown_scsi_provider = sub { | ||||||
|  |      my ($provider) = @_; | ||||||
|  |   | ||||||
|  | -    die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
 | ||||||
|  | +    die "$provider: unknown iscsi provider. Available [comstar, freenas, istgt, iet, LIO]";
 | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  my $zfs_get_base = sub { | ||||||
|  | @@ -40,6 +42,8 @@
 | ||||||
|  |   | ||||||
|  |      if ($scfg->{iscsiprovider} eq 'comstar') { | ||||||
|  |          return PVE::Storage::LunCmd::Comstar::get_base; | ||||||
|  | +    } elsif ($scfg->{iscsiprovider} eq 'freenas') {
 | ||||||
|  | +        return PVE::Storage::LunCmd::FreeNAS::get_base;
 | ||||||
|  |      } elsif ($scfg->{iscsiprovider} eq 'istgt') { | ||||||
|  |          return PVE::Storage::LunCmd::Istgt::get_base; | ||||||
|  |      } elsif ($scfg->{iscsiprovider} eq 'iet') { | ||||||
|  | @@ -62,6 +66,8 @@
 | ||||||
|  |      if ($lun_cmds->{$method}) { | ||||||
|  |          if ($scfg->{iscsiprovider} eq 'comstar') { | ||||||
|  |              $msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params); | ||||||
|  | +        } elsif ($scfg->{iscsiprovider} eq 'freenas') {
 | ||||||
|  | +            $msg = PVE::Storage::LunCmd::FreeNAS::run_lun_command($scfg, $timeout, $method, @params);
 | ||||||
|  |          } elsif ($scfg->{iscsiprovider} eq 'istgt') { | ||||||
|  |              $msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params); | ||||||
|  |          } elsif ($scfg->{iscsiprovider} eq 'iet') { | ||||||
|  | @@ -160,6 +166,15 @@
 | ||||||
|  |      return $class->zfs_request($scfg, undef, 'list_view', $guid); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +# 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 { | ||||||
|  | @@ -178,6 +193,24 @@
 | ||||||
|  |  	    description => "iscsi provider", | ||||||
|  |  	    type => 'string', | ||||||
|  |  	}, | ||||||
|  | +	# This is for FreeNAS iscsi and API intergration
 | ||||||
|  | +	# And some enhancements asked by the community
 | ||||||
|  | +	freenas_user => {
 | ||||||
|  | +	    description => "FreeNAS API Username",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_password => {
 | ||||||
|  | +	    description => "FreeNAS API Password",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_use_ssl => {
 | ||||||
|  | +	    description => "FreeNAS API access via SSL",
 | ||||||
|  | +	    type => 'boolean',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_apiv4_host => {
 | ||||||
|  | +	    description => "FreeNAS API Host",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  |  	# this will disable write caching on comstar and istgt. | ||||||
|  |  	# it is not implemented for iet. iet blockio always operates with | ||||||
|  |  	# writethrough caching when not in readonly mode | ||||||
|  | @@ -205,14 +238,18 @@
 | ||||||
|  |  	nodes => { optional => 1 }, | ||||||
|  |  	disable => { optional => 1 }, | ||||||
|  |  	portal => { fixed => 1 }, | ||||||
|  | -	target => { fixed => 1 },
 | ||||||
|  | -	pool => { fixed => 1 },
 | ||||||
|  | +	target => { fixed => 0 },
 | ||||||
|  | +	pool => { fixed => 0 },
 | ||||||
|  |  	blocksize => { fixed => 1 }, | ||||||
|  |  	iscsiprovider => { fixed => 1 }, | ||||||
|  |  	nowritecache => { optional => 1 }, | ||||||
|  |  	sparse => { optional => 1 }, | ||||||
|  |  	comstar_hg => { optional => 1 }, | ||||||
|  |  	comstar_tg => { optional => 1 }, | ||||||
|  | +	freenas_user => { optional => 1 },
 | ||||||
|  | +	freenas_password => { optional => 1 },
 | ||||||
|  | +	freenas_use_ssl => { optional => 1 },
 | ||||||
|  | +	freenas_apiv4_host => { optional => 1 },
 | ||||||
|  |  	lio_tpg => { optional => 1 }, | ||||||
|  |  	content => { optional => 1 }, | ||||||
|  |  	bwlimit => { optional => 1 }, | ||||||
|  | @@ -237,6 +274,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 = `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,147 @@ | ||||||
|  | --- ZFSPlugin.pm.orig	2019-06-25 06:54:50.000000000 -0400
 | ||||||
|  | +++ ZFSPlugin.pm	2019-07-16 13:36:48.817831174 -0400
 | ||||||
|  | @@ -10,6 +10,7 @@
 | ||||||
|  |   | ||||||
|  |  use base qw(PVE::Storage::ZFSPoolPlugin); | ||||||
|  |  use PVE::Storage::LunCmd::Comstar; | ||||||
|  | +use PVE::Storage::LunCmd::FreeNAS;
 | ||||||
|  |  use PVE::Storage::LunCmd::Istgt; | ||||||
|  |  use PVE::Storage::LunCmd::Iet; | ||||||
|  |  use PVE::Storage::LunCmd::LIO; | ||||||
|  | @@ -26,13 +27,14 @@
 | ||||||
|  |      modify_lu   => 1, | ||||||
|  |      add_view    => 1, | ||||||
|  |      list_view   => 1, | ||||||
|  | +    list_extent => 1,
 | ||||||
|  |      list_lu     => 1, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  my $zfs_unknown_scsi_provider = sub { | ||||||
|  |      my ($provider) = @_; | ||||||
|  |   | ||||||
|  | -    die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
 | ||||||
|  | +    die "$provider: unknown iscsi provider. Available [comstar, freenas, istgt, iet, LIO]";
 | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  my $zfs_get_base = sub { | ||||||
|  | @@ -40,6 +42,8 @@
 | ||||||
|  |   | ||||||
|  |      if ($scfg->{iscsiprovider} eq 'comstar') { | ||||||
|  |          return PVE::Storage::LunCmd::Comstar::get_base; | ||||||
|  | +    } elsif ($scfg->{iscsiprovider} eq 'freenas') {
 | ||||||
|  | +        return PVE::Storage::LunCmd::FreeNAS::get_base;
 | ||||||
|  |      } elsif ($scfg->{iscsiprovider} eq 'istgt') { | ||||||
|  |          return PVE::Storage::LunCmd::Istgt::get_base; | ||||||
|  |      } elsif ($scfg->{iscsiprovider} eq 'iet') { | ||||||
|  | @@ -62,6 +66,8 @@
 | ||||||
|  |      if ($lun_cmds->{$method}) { | ||||||
|  |          if ($scfg->{iscsiprovider} eq 'comstar') { | ||||||
|  |              $msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params); | ||||||
|  | +        } elsif ($scfg->{iscsiprovider} eq 'freenas') {
 | ||||||
|  | +            $msg = PVE::Storage::LunCmd::FreeNAS::run_lun_command($scfg, $timeout, $method, @params);
 | ||||||
|  |          } elsif ($scfg->{iscsiprovider} eq 'istgt') { | ||||||
|  |              $msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params); | ||||||
|  |          } elsif ($scfg->{iscsiprovider} eq 'iet') { | ||||||
|  | @@ -160,6 +166,15 @@
 | ||||||
|  |      return $class->zfs_request($scfg, undef, 'list_view', $guid); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +# 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 { | ||||||
|  | @@ -178,6 +193,24 @@
 | ||||||
|  |  	    description => "iscsi provider", | ||||||
|  |  	    type => 'string', | ||||||
|  |  	}, | ||||||
|  | +	# This is for FreeNAS iscsi and API intergration
 | ||||||
|  | +	# And some enhancements asked by the community
 | ||||||
|  | +	freenas_user => {
 | ||||||
|  | +	    description => "FreeNAS API Username",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_password => {
 | ||||||
|  | +	    description => "FreeNAS API Password",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_use_ssl => {
 | ||||||
|  | +	    description => "FreeNAS API access via SSL",
 | ||||||
|  | +	    type => 'boolean',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_apiv4_host => {
 | ||||||
|  | +	    description => "FreeNAS API Host",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  |  	# this will disable write caching on comstar and istgt. | ||||||
|  |  	# it is not implemented for iet. iet blockio always operates with | ||||||
|  |  	# writethrough caching when not in readonly mode | ||||||
|  | @@ -205,14 +238,18 @@
 | ||||||
|  |  	nodes => { optional => 1 }, | ||||||
|  |  	disable => { optional => 1 }, | ||||||
|  |  	portal => { fixed => 1 }, | ||||||
|  | -	target => { fixed => 1 },
 | ||||||
|  | -	pool => { fixed => 1 },
 | ||||||
|  | +	target => { fixed => 0 },
 | ||||||
|  | +	pool => { fixed => 0 },
 | ||||||
|  |  	blocksize => { fixed => 1 }, | ||||||
|  |  	iscsiprovider => { fixed => 1 }, | ||||||
|  |  	nowritecache => { optional => 1 }, | ||||||
|  |  	sparse => { optional => 1 }, | ||||||
|  |  	comstar_hg => { optional => 1 }, | ||||||
|  |  	comstar_tg => { optional => 1 }, | ||||||
|  | +	freenas_user => { optional => 1 },
 | ||||||
|  | +	freenas_password => { optional => 1 },
 | ||||||
|  | +	freenas_use_ssl => { optional => 1 },
 | ||||||
|  | +	freenas_apiv4_host => { optional => 1 },
 | ||||||
|  |  	lio_tpg => { optional => 1 }, | ||||||
|  |  	content => { optional => 1 }, | ||||||
|  |  	bwlimit => { optional => 1 }, | ||||||
|  | @@ -237,6 +274,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 = `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 @@ | ||||||
|  | /apidoc.js | ||||||
|  | @ -0,0 +1,66 @@ | ||||||
|  | --- apidoc.js.orig	2018-08-19 10:18:11.715767285 -0400
 | ||||||
|  | +++ apidoc.js.new	2018-08-19 10:17:09.364282178 -0400
 | ||||||
|  | @@ -27584,6 +27584,31 @@
 | ||||||
|  |                             "type" : "string", | ||||||
|  |                             "typetext" : "<string>" | ||||||
|  |                          }, | ||||||
|  | +                        "freenas_user" : {
 | ||||||
|  | +                           "description" : "FreeNAS user for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_password" : {
 | ||||||
|  | +                           "description" : "FreeNAS password for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_use_ssl" : {
 | ||||||
|  | +                           "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "boolean",
 | ||||||
|  | +                           "typetext" : "<boolean>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_apiv4_host" : {
 | ||||||
|  | +                           "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                           "format" : "address",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "content" : { | ||||||
|  |                             "description" : "Allowed content types.\n\nNOTE: the value 'rootdir' is used for Containers, and value 'images' for VMs.\n", | ||||||
|  |                             "format" : "pve-storage-content-list", | ||||||
|  | @@ -27948,6 +27973,31 @@
 | ||||||
|  |                       "optional" : 1, | ||||||
|  |                       "type" : "string", | ||||||
|  |                       "typetext" : "<string>" | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_user" : {
 | ||||||
|  | +                     "description" : "FreeNAS user for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_password" : {
 | ||||||
|  | +                     "description" : "FreeNAS password for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_use_ssl" : {
 | ||||||
|  | +                     "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "boolean",
 | ||||||
|  | +                     "typetext" : "<boolean>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_apiv4_host" : {
 | ||||||
|  | +                     "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                     "format" : "address",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  |                    }, | ||||||
|  |                    "content" : { | ||||||
|  |                       "description" : "Allowed content types.\n\nNOTE: the value 'rootdir' is used for Containers, and value 'images' for VMs.\n", | ||||||
|  | @ -0,0 +1,79 @@ | ||||||
|  | --- apidoc-5.2-9.js	2018-11-10 14:28:44.022355849 -0500
 | ||||||
|  | +++ apidoc.js	2018-11-10 15:49:38.873720011 -0500
 | ||||||
|  | @@ -32448,6 +32448,31 @@
 | ||||||
|  |                             "type" : "string", | ||||||
|  |                             "typetext" : "<string>" | ||||||
|  |                          }, | ||||||
|  | +                        "freenas_user" : {
 | ||||||
|  | +                           "description" : "FreeNAS user for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_password" : {
 | ||||||
|  | +                           "description" : "FreeNAS password for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_use_ssl" : {
 | ||||||
|  | +                           "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "boolean",
 | ||||||
|  | +                           "typetext" : "<boolean>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_apiv4_host" : {
 | ||||||
|  | +                           "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                           "format" : "address",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "fuse" : { | ||||||
|  |                             "description" : "Mount CephFS through FUSE.", | ||||||
|  |                             "optional" : 1, | ||||||
|  | @@ -32604,6 +32629,12 @@
 | ||||||
|  |                             "type" : "boolean", | ||||||
|  |                             "typetext" : "<boolean>" | ||||||
|  |                          }, | ||||||
|  | +                        "target" : {
 | ||||||
|  | +                           "description" : "iSCSI target.",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "transport" : { | ||||||
|  |                             "description" : "Gluster transport: tcp or rdma", | ||||||
|  |                             "enum" : [ | ||||||
|  | @@ -32810,6 +32841,31 @@
 | ||||||
|  |                       "optional" : 1, | ||||||
|  |                       "type" : "string", | ||||||
|  |                       "typetext" : "<string>" | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_user" : {
 | ||||||
|  | +                     "description" : "FreeNAS user for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_password" : {
 | ||||||
|  | +                     "description" : "FreeNAS password for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_use_ssl" : {
 | ||||||
|  | +                     "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "boolean",
 | ||||||
|  | +                     "typetext" : "<boolean>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_apiv4_host" : {
 | ||||||
|  | +                     "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                     "format" : "address",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  |                    }, | ||||||
|  |                    "fuse" : { | ||||||
|  |                       "description" : "Mount CephFS through FUSE.", | ||||||
|  | @ -0,0 +1,79 @@ | ||||||
|  | --- apidoc-5.3-1.js	2018-12-21 12:46:55.459865478 -0500
 | ||||||
|  | +++ apidoc.js	2018-12-06 15:50:21.487987807 -0500
 | ||||||
|  | @@ -33477,6 +33477,31 @@
 | ||||||
|  |                             "type" : "string", | ||||||
|  |                             "typetext" : "<string>" | ||||||
|  |                          }, | ||||||
|  | +                        "freenas_user" : {
 | ||||||
|  | +                           "description" : "FreeNAS user for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_password" : {
 | ||||||
|  | +                           "description" : "FreeNAS password for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_use_ssl" : {
 | ||||||
|  | +                           "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "boolean",
 | ||||||
|  | +                           "typetext" : "<boolean>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_apiv4_host" : {
 | ||||||
|  | +                           "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                           "format" : "address",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "fuse" : { | ||||||
|  |                             "description" : "Mount CephFS through FUSE.", | ||||||
|  |                             "optional" : 1, | ||||||
|  | @@ -33633,6 +33658,12 @@
 | ||||||
|  |                             "type" : "boolean", | ||||||
|  |                             "typetext" : "<boolean>" | ||||||
|  |                          }, | ||||||
|  | +                        "target" : {
 | ||||||
|  | +                           "description" : "iSCSI target.",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "transport" : { | ||||||
|  |                             "description" : "Gluster transport: tcp or rdma", | ||||||
|  |                             "enum" : [ | ||||||
|  | @@ -33840,6 +33871,31 @@
 | ||||||
|  |                       "optional" : 1, | ||||||
|  |                       "type" : "string", | ||||||
|  |                       "typetext" : "<string>" | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_user" : {
 | ||||||
|  | +                     "description" : "FreeNAS user for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_password" : {
 | ||||||
|  | +                     "description" : "FreeNAS password for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_use_ssl" : {
 | ||||||
|  | +                     "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "boolean",
 | ||||||
|  | +                     "typetext" : "<boolean>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_apiv4_host" : {
 | ||||||
|  | +                     "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                     "format" : "address",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  |                    }, | ||||||
|  |                    "fuse" : { | ||||||
|  |                       "description" : "Mount CephFS through FUSE.", | ||||||
|  | @ -0,0 +1,79 @@ | ||||||
|  | --- apidoc.js.orig	2019-02-20 06:20:05.000000000 -0500
 | ||||||
|  | +++ apidoc.js	2019-02-26 20:51:26.857204965 -0500
 | ||||||
|  | @@ -33709,6 +33709,31 @@
 | ||||||
|  |                             "type" : "string", | ||||||
|  |                             "typetext" : "<string>" | ||||||
|  |                          }, | ||||||
|  | +                        "freenas_user" : {
 | ||||||
|  | +                           "description" : "FreeNAS user for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_password" : {
 | ||||||
|  | +                           "description" : "FreeNAS password for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_use_ssl" : {
 | ||||||
|  | +                           "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "boolean",
 | ||||||
|  | +                           "typetext" : "<boolean>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_apiv4_host" : {
 | ||||||
|  | +                           "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                           "format" : "address",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "fuse" : { | ||||||
|  |                             "description" : "Mount CephFS through FUSE.", | ||||||
|  |                             "optional" : 1, | ||||||
|  | @@ -33865,6 +33890,12 @@
 | ||||||
|  |                             "type" : "boolean", | ||||||
|  |                             "typetext" : "<boolean>" | ||||||
|  |                          }, | ||||||
|  | +                        "target" : {
 | ||||||
|  | +                           "description" : "iSCSI target.",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "transport" : { | ||||||
|  |                             "description" : "Gluster transport: tcp or rdma", | ||||||
|  |                             "enum" : [ | ||||||
|  | @@ -34071,6 +34102,31 @@
 | ||||||
|  |                       "optional" : 1, | ||||||
|  |                       "type" : "string", | ||||||
|  |                       "typetext" : "<string>" | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_user" : {
 | ||||||
|  | +                     "description" : "FreeNAS user for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_password" : {
 | ||||||
|  | +                     "description" : "FreeNAS password for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_use_ssl" : {
 | ||||||
|  | +                     "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "boolean",
 | ||||||
|  | +                     "typetext" : "<boolean>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_apiv4_host" : {
 | ||||||
|  | +                     "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                     "format" : "address",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  |                    }, | ||||||
|  |                    "fuse" : { | ||||||
|  |                       "description" : "Mount CephFS through FUSE.", | ||||||
|  | @ -0,0 +1,79 @@ | ||||||
|  | --- apidoc.js.orig	2019-04-08 02:02:09.000000000 -0400
 | ||||||
|  | +++ apidoc.js	2019-05-11 10:34:28.305764709 -0400
 | ||||||
|  | @@ -34385,6 +34385,31 @@
 | ||||||
|  |                             "type" : "string", | ||||||
|  |                             "typetext" : "<string>" | ||||||
|  |                          }, | ||||||
|  | +                        "freenas_user" : {
 | ||||||
|  | +                           "description" : "FreeNAS user for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_password" : {
 | ||||||
|  | +                           "description" : "FreeNAS password for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_use_ssl" : {
 | ||||||
|  | +                           "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "boolean",
 | ||||||
|  | +                           "typetext" : "<boolean>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_apiv4_host" : {
 | ||||||
|  | +                           "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                           "format" : "address",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "fuse" : { | ||||||
|  |                             "description" : "Mount CephFS through FUSE.", | ||||||
|  |                             "optional" : 1, | ||||||
|  | @@ -34541,6 +34566,12 @@
 | ||||||
|  |                             "type" : "boolean", | ||||||
|  |                             "typetext" : "<boolean>" | ||||||
|  |                          }, | ||||||
|  | +                        "target" : {
 | ||||||
|  | +                           "description" : "iSCSI target.",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "transport" : { | ||||||
|  |                             "description" : "Gluster transport: tcp or rdma", | ||||||
|  |                             "enum" : [ | ||||||
|  | @@ -34748,6 +34779,31 @@
 | ||||||
|  |                       "optional" : 1, | ||||||
|  |                       "type" : "string", | ||||||
|  |                       "typetext" : "<string>" | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_user" : {
 | ||||||
|  | +                     "description" : "FreeNAS user for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_password" : {
 | ||||||
|  | +                     "description" : "FreeNAS password for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_use_ssl" : {
 | ||||||
|  | +                     "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "boolean",
 | ||||||
|  | +                     "typetext" : "<boolean>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_apiv4_host" : {
 | ||||||
|  | +                     "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                     "format" : "address",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  |                    }, | ||||||
|  |                    "fuse" : { | ||||||
|  |                       "description" : "Mount CephFS through FUSE.", | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | /pvemanagerlib.js | ||||||
|  | @ -0,0 +1,167 @@ | ||||||
|  | --- pvemanagerlib-5.2-10.js	2018-10-23 07:18:18.058603386 -0400
 | ||||||
|  | +++ pvemanagerlib.js	2018-10-23 15:29:52.573563883 -0400
 | ||||||
|  | @@ -5597,6 +5597,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -28583,6 +28584,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -28595,10 +28597,19 @@
 | ||||||
|  |  	    } | ||||||
|  |  	}, | ||||||
|  |  	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_password_field').setValue('');
 | ||||||
|  | +		me.lookupReference('freenas_confirmpw_field').setValue('');
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -28616,6 +28627,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -28632,7 +28644,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -28646,7 +28658,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'target', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Target'), | ||||||
|  | @@ -28657,8 +28669,28 @@
 | ||||||
|  |  		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: '',
 | ||||||
|  | +		allowBlank: false,
 | ||||||
|  | +		fieldLabel: gettext('API Username'),
 | ||||||
|  | +		bind: { hidden: '{!isFreeNAS}' },
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -28689,7 +28721,7 @@
 | ||||||
|  |  		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 | ||||||
|  |  	    }, | ||||||
|  | @@ -28697,9 +28729,60 @@
 | ||||||
|  |  		xtype: me.isCreate ? 'textfield' : 'displayfield', | ||||||
|  |  		name: 'lio_tpg', | ||||||
|  |  		value: '', | ||||||
|  | -		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
 | ||||||
|  | +		bind: { hidden: '{!isLIO}' },
 | ||||||
|  | +		fieldLabel: gettext('Target portal group'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: 'proxmoxtextfield',
 | ||||||
|  | +		name: 'freenas_apiv4_host',
 | ||||||
|  | +		reference: 'freenas_apiv4_host_field',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		editable: true,
 | ||||||
|  | +		allowBlank: true,
 | ||||||
|  | +		emptyText: Proxmox.Utils.noneText,
 | ||||||
|  | +		bind: { hidden: '{!isFreeNAS}' },
 | ||||||
|  | +		fieldLabel: gettext('API IPv4 Host'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: 'proxmoxtextfield',
 | ||||||
|  | +		name: 'freenas_password',
 | ||||||
|  | +		reference: 'freenas_password_field',
 | ||||||
|  | +		inputType: me.isCreate ? '' : 'password',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		editable: true,
 | ||||||
|  | +		deleteEmpty: true,
 | ||||||
|  | +		allowBlank: false,
 | ||||||
|  | +		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,
 | ||||||
|  | +		deleteEmpty: true,
 | ||||||
|  |  		allowBlank: false, | ||||||
|  | -		fieldLabel: gettext('Target portal group')
 | ||||||
|  | +		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,86 @@ | ||||||
|  | --- pvemanagerlib.js.orig	2018-07-30 23:13:28.045035059 -0400
 | ||||||
|  | +++ pvemanagerlib.js.new	2018-08-19 10:42:58.494724196 -0400
 | ||||||
|  | @@ -5379,6 +5379,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'] | ||||||
|  |      ] | ||||||
|  | @@ -27361,7 +27362,23 @@
 | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Target group'), | ||||||
|  |  		allowBlank: true | ||||||
|  | -	    }
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: 'proxmoxcheckbox',
 | ||||||
|  | +		name: 'freenas_use_ssl',
 | ||||||
|  | +		checked: false,
 | ||||||
|  | +		uncheckedValue: 0,
 | ||||||
|  | +		hidden: me.iscsiprovider !== "freenas",
 | ||||||
|  | +		fieldLabel: gettext('FreeNAS API use SSL')
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		name: 'freenas_user',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		hidden: me.iscsiprovider !== "freenas",
 | ||||||
|  | +		fieldLabel: gettext('FreeNAS User'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  |  	me.column2 = [ | ||||||
|  | @@ -27370,7 +27387,26 @@
 | ||||||
|  |  		name: 'iscsiprovider', | ||||||
|  |  		value: 'comstar', | ||||||
|  |  		fieldLabel: gettext('iSCSI Provider'), | ||||||
|  | -		allowBlank: false
 | ||||||
|  | +		allowBlank: false,
 | ||||||
|  | +		listeners: {
 | ||||||
|  | +			change: function(f, value) {
 | ||||||
|  | +				if (value === "freenas") {
 | ||||||
|  | +					me.down('field[name=freenas_use_ssl]').setHidden(false);
 | ||||||
|  | +					me.down('field[name=freenas_apiv4_host]').setHidden(false);
 | ||||||
|  | +					me.down('field[name=freenas_user]').setHidden(false);
 | ||||||
|  | +					me.down('field[name=freenas_password]').setHidden(false);
 | ||||||
|  | +				} else {
 | ||||||
|  | +					me.down('field[name=freenas_use_ssl]').setHidden(true);
 | ||||||
|  | +					me.down('field[name=freenas_use_ssl]').setValue(false);
 | ||||||
|  | +					me.down('field[name=freenas_apiv4_host]').setHidden(true);
 | ||||||
|  | +					me.down('field[name=freenas_apiv4_host]').setValue(false);
 | ||||||
|  | +					me.down('field[name=freenas_user]').setHidden(true);
 | ||||||
|  | +					me.down('field[name=freenas_user]').setValue('');
 | ||||||
|  | +					me.down('field[name=freenas_password]').setHidden(true);
 | ||||||
|  | +					me.down('field[name=freenas_password]').setValue('');
 | ||||||
|  | +				}
 | ||||||
|  | +			}
 | ||||||
|  | +		}
 | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  |  		xtype: 'proxmoxcheckbox', | ||||||
|  | @@ -27392,6 +27428,22 @@
 | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Host group'), | ||||||
|  |  		allowBlank: true | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		name: 'freenas_apiv4_host',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		hidden: me.iscsiprovider !== "freenas",
 | ||||||
|  | +		fieldLabel: gettext('API IPv4 Host'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		name: 'freenas_password',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		hidden: me.iscsiprovider !== "freenas",
 | ||||||
|  | +		fieldLabel: gettext('FreeNAS Password'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @ -0,0 +1,102 @@ | ||||||
|  | --- pvemanagerlib.js.5.2-8.js	2018-08-30 20:10:52.957313992 -0400
 | ||||||
|  | +++ pvemanagerlib.js.new	2018-09-01 16:20:05.131908768 -0400
 | ||||||
|  | @@ -28578,6 +28578,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -28590,11 +28591,18 @@
 | ||||||
|  |  	    } | ||||||
|  |  	}, | ||||||
|  |  	changeISCSIProvider: function(f, newVal, oldVal) { | ||||||
|  | +	    var me = this;
 | ||||||
|  |  	    var vm = this.getViewModel(); | ||||||
|  |  	    vm.set('isLIO', newVal === 'LIO'); | ||||||
|  |  	    vm.set('isComstar', newVal === 'comstar'); | ||||||
|  |  	    vm.set('isFreeNAS', newVal === 'freenas'); | ||||||
|  | -	    vm.set('hasWriteCacheOption', newVal === 'comstar' || newVal === 'istgt');
 | ||||||
|  | +	    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_password_field').setValue('');
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -28653,16 +28661,28 @@
 | ||||||
|  |  		name: 'comstar_tg', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Target group'), | ||||||
|  | -		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
 | ||||||
|  | +		bind: me.isCreate ? { hidden: '{!isComstar}' } : { hidden: '{!isComstar}' },
 | ||||||
|  |  		allowBlank: true | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | +		xtype: 'proxmoxcheckbox',
 | ||||||
|  | +		name: 'freenas_use_ssl',
 | ||||||
|  | +		reference: 'freenas_use_ssl_field',
 | ||||||
|  | +		inputId: 'freenas_use_ssl_field',
 | ||||||
|  | +		checked: false,
 | ||||||
|  | +		bind: me.isCreate ? { hidden: '{!isFreeNAS}' } : { hidden: '{!isFreeNAS}' },
 | ||||||
|  | +		uncheckedValue: 0,
 | ||||||
|  | +		fieldLabel: gettext('API use SSL')
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  |  		xtype: me.isCreate ? 'textfield' : 'displayfield', | ||||||
|  |  		name: 'freenas_user', | ||||||
|  | +		reference: 'freenas_user_field',
 | ||||||
|  | +		inputId: 'freenas_user_field',
 | ||||||
|  |  		value: '', | ||||||
|  | -		fieldLabel: gettext('FreeNAS User'),
 | ||||||
|  | +		fieldLabel: gettext('API Username'),
 | ||||||
|  |  		bind: me.isCreate ? { hidden: '{!isFreeNAS}' } : { hidden: '{!isFreeNAS}' }, | ||||||
|  | -		allowBlank: true
 | ||||||
|  | +		allowBlank: me.isFreeNAS ? false : true
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -28693,7 +28713,7 @@
 | ||||||
|  |  		xtype: me.isCreate ? 'textfield' : 'displayfield', | ||||||
|  |  		name: 'comstar_hg', | ||||||
|  |  		value: '', | ||||||
|  | -		bind: me.isCreate ? { disabled: '{!isComstar}' } : { hidden: '{!isComstar}' },
 | ||||||
|  | +		bind: me.isCreate ? { hidden: '{!isComstar}' } : { hidden: '{!isComstar}' },
 | ||||||
|  |  		fieldLabel: gettext('Host group'), | ||||||
|  |  		allowBlank: true | ||||||
|  |  	    }, | ||||||
|  | @@ -28701,9 +28721,27 @@
 | ||||||
|  |  		xtype: me.isCreate ? 'textfield' : 'displayfield', | ||||||
|  |  		name: 'lio_tpg', | ||||||
|  |  		value: '', | ||||||
|  | -		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
 | ||||||
|  | -		allowBlank: false,
 | ||||||
|  | -		fieldLabel: gettext('Target portal group')
 | ||||||
|  | +		bind: me.isCreate ? { hidden: '{!isLIO}' } : { hidden: '{!isLIO}' },
 | ||||||
|  | +		fieldLabel: gettext('Target portal group'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		name: 'freenas_apiv4_host',
 | ||||||
|  | +		reference: 'freenas_apiv4_host_field',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		bind: me.isCreate ? { hidden: '{!isFreeNAS}' } : { hidden: '{!isFreeNAS}' },
 | ||||||
|  | +		fieldLabel: gettext('API IPv4 Host'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		name: 'freenas_password',
 | ||||||
|  | +		reference: 'freenas_password_field',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		bind: me.isCreate ? { hidden: '{!isFreeNAS}' } : { hidden: '{!isFreeNAS}' },
 | ||||||
|  | +		fieldLabel: gettext('API Password'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @ -0,0 +1,169 @@ | ||||||
|  | --- pvemanagerlib-5.2-9.js	2018-10-16 07:17:21.915593478 -0400
 | ||||||
|  | +++ pvemanagerlib.js	2018-10-21 21:52:20.781740237 -0400
 | ||||||
|  | @@ -5597,6 +5597,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -28574,6 +28575,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -28586,10 +28588,19 @@
 | ||||||
|  |  	    } | ||||||
|  |  	}, | ||||||
|  |  	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_password_field').setValue('');
 | ||||||
|  | +		me.lookupReference('freenas_confirmpw_field').setValue('');
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -28607,6 +28618,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -28623,7 +28635,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -28637,7 +28649,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'target', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Target'), | ||||||
|  | @@ -28648,8 +28660,28 @@
 | ||||||
|  |  		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: '',
 | ||||||
|  | +		allowBlank: false,
 | ||||||
|  | +		fieldLabel: gettext('API Username'),
 | ||||||
|  | +		bind: { hidden: '{!isFreeNAS}' },
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -28680,7 +28712,7 @@
 | ||||||
|  |  		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 | ||||||
|  |  	    }, | ||||||
|  | @@ -28688,9 +28720,61 @@
 | ||||||
|  |  		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,
 | ||||||
|  | +                deleteEmpty: true,
 | ||||||
|  | +                allowBlank: true,
 | ||||||
|  | +                emptyText: Proxmox.Utils.noneText,
 | ||||||
|  | +		bind: { hidden: '{!isFreeNAS}' },
 | ||||||
|  | +		fieldLabel: gettext('API IPv4 Host'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: 'proxmoxtextfield',
 | ||||||
|  | +		name: 'freenas_password',
 | ||||||
|  | +		reference: 'freenas_password_field',
 | ||||||
|  | +                inputType: me.isCreate ? '' : 'password',
 | ||||||
|  | +                value: '',
 | ||||||
|  | +                editable: true,
 | ||||||
|  | +                deleteEmpty: true,
 | ||||||
|  | +                allowBlank: false,
 | ||||||
|  | +                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,
 | ||||||
|  | +                deleteEmpty: true,
 | ||||||
|  | +                allowBlank: false,
 | ||||||
|  | +		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,189 @@ | ||||||
|  | --- pvemanagerlib.js.orig	2019-02-20 13:40:43.000000000 -0500
 | ||||||
|  | +++ pvemanagerlib.js	2019-02-26 20:49:41.032327478 -0500
 | ||||||
|  | @@ -5920,6 +5920,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -30182,6 +30183,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -30194,10 +30196,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;
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -30215,6 +30233,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -30231,7 +30250,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -30241,11 +30260,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'), | ||||||
|  | @@ -30256,8 +30275,33 @@
 | ||||||
|  |  		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}'
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -30288,7 +30332,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 | ||||||
|  |  	    }, | ||||||
|  | @@ -30296,9 +30342,62 @@
 | ||||||
|  |  		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'),
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		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,172 @@ | ||||||
|  | --- pvemanagerlib-5.3-5.js	2018-12-21 12:34:35.727962756 -0500
 | ||||||
|  | +++ pvemanagerlib.js	2018-12-21 12:43:02.370462786 -0500
 | ||||||
|  | @@ -5854,6 +5854,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -29983,6 +29984,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -29995,10 +29997,19 @@
 | ||||||
|  |  	    } | ||||||
|  |  	}, | ||||||
|  |  	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_password_field').setValue('');
 | ||||||
|  | +		me.lookupReference('freenas_confirmpw_field').setValue('');
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -30016,6 +30027,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -30032,7 +30044,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -30042,11 +30054,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'), | ||||||
|  | @@ -30057,8 +30069,28 @@
 | ||||||
|  |  		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: '',
 | ||||||
|  | +		allowBlank: false,
 | ||||||
|  | +		fieldLabel: gettext('API Username'),
 | ||||||
|  | +		bind: { hidden: '{!isFreeNAS}' },
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -30089,7 +30121,7 @@
 | ||||||
|  |  		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 | ||||||
|  |  	    }, | ||||||
|  | @@ -30097,9 +30129,60 @@
 | ||||||
|  |  		xtype: me.isCreate ? 'textfield' : 'displayfield', | ||||||
|  |  		name: 'lio_tpg', | ||||||
|  |  		value: '', | ||||||
|  | -		bind: me.isCreate ? { disabled: '{!isLIO}' } : { hidden: '{!isLIO}' },
 | ||||||
|  | +		bind: { hidden: '{!isLIO}' },
 | ||||||
|  | +		fieldLabel: gettext('Target portal group'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: 'proxmoxtextfield',
 | ||||||
|  | +		name: 'freenas_apiv4_host',
 | ||||||
|  | +		reference: 'freenas_apiv4_host_field',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		editable: true,
 | ||||||
|  | +		allowBlank: true,
 | ||||||
|  | +		emptyText: Proxmox.Utils.noneText,
 | ||||||
|  | +		bind: { hidden: '{!isFreeNAS}' },
 | ||||||
|  | +		fieldLabel: gettext('API IPv4 Host'),
 | ||||||
|  | +		allowBlank: true
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: 'proxmoxtextfield',
 | ||||||
|  | +		name: 'freenas_password',
 | ||||||
|  | +		reference: 'freenas_password_field',
 | ||||||
|  | +		inputType: me.isCreate ? '' : 'password',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		editable: true,
 | ||||||
|  | +		deleteEmpty: true,
 | ||||||
|  | +		allowBlank: false,
 | ||||||
|  | +		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,
 | ||||||
|  | +		deleteEmpty: true,
 | ||||||
|  |  		allowBlank: false, | ||||||
|  | -		fieldLabel: gettext('Target portal group')
 | ||||||
|  | +		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,191 @@ | ||||||
|  | --- pvemanagerlib-5.3-6.js	2018-12-21 12:54:58.650421078 -0500
 | ||||||
|  | +++ pvemanagerlib.js	2019-02-01 13:52:17.906074280 -0500
 | ||||||
|  | @@ -5894,6 +5894,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -30085,6 +30086,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -30097,10 +30099,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;
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -30118,6 +30136,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -30134,7 +30153,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -30144,11 +30163,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'), | ||||||
|  | @@ -30159,8 +30178,33 @@
 | ||||||
|  |  		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}'
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -30191,7 +30235,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 | ||||||
|  |  	    }, | ||||||
|  | @@ -30199,9 +30245,64 @@
 | ||||||
|  |  		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'),
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		xtype: 'proxmoxtextfield',
 | ||||||
|  | +		name: 'freenas_password',
 | ||||||
|  | +		reference: 'freenas_password_field',
 | ||||||
|  | +		inputType: me.isCreate ? '' : 'password',
 | ||||||
|  | +		value: '',
 | ||||||
|  | +		editable: true,
 | ||||||
|  | +		deleteEmpty: 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,
 | ||||||
|  | +		deleteEmpty: true,
 | ||||||
|  | +		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,189 @@ | ||||||
|  | --- pvemanagerlib.js.orig	2019-01-11 04:23:42.000000000 -0500
 | ||||||
|  | +++ pvemanagerlib.js	2019-02-05 07:30:18.168655803 -0500
 | ||||||
|  | @@ -5894,6 +5894,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -30085,6 +30086,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -30097,10 +30099,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;
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -30118,6 +30136,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -30134,7 +30153,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -30144,11 +30163,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'), | ||||||
|  | @@ -30159,8 +30178,33 @@
 | ||||||
|  |  		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}'
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -30191,7 +30235,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 | ||||||
|  |  	    }, | ||||||
|  | @@ -30199,9 +30245,62 @@
 | ||||||
|  |  		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'),
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		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,189 @@ | ||||||
|  | --- pvemanagerlib.js.orig	2019-07-09 03:52:19.000000000 -0400
 | ||||||
|  | +++ pvemanagerlib.js	2019-07-16 13:59:37.658409977 -0400
 | ||||||
|  | @@ -6094,6 +6094,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -31700,6 +31701,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -31712,10 +31714,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;
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -31733,6 +31751,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -31749,7 +31768,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -31759,11 +31778,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'), | ||||||
|  | @@ -31774,8 +31793,33 @@
 | ||||||
|  |  		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}'
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -31806,7 +31850,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 | ||||||
|  |  	    }, | ||||||
|  | @@ -31814,9 +31860,62 @@
 | ||||||
|  |  		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'),
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		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,189 @@ | ||||||
|  | --- pvemanagerlib.js.orig	2019-07-26 04:14:56.000000000 -0400
 | ||||||
|  | +++ pvemanagerlib.js	2019-08-05 16:02:38.484913553 -0400
 | ||||||
|  | @@ -6094,6 +6094,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -31722,6 +31723,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -31734,10 +31736,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;
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -31755,6 +31773,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -31771,7 +31790,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -31781,11 +31800,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'), | ||||||
|  | @@ -31796,8 +31815,33 @@
 | ||||||
|  |  		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}'
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -31828,7 +31872,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 | ||||||
|  |  	    }, | ||||||
|  | @@ -31836,9 +31882,62 @@
 | ||||||
|  |  		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'),
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		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,189 @@ | ||||||
|  | --- pvemanagerlib.js.orig	2019-04-24 07:28:11.000000000 -0400
 | ||||||
|  | +++ pvemanagerlib.js	2019-05-11 10:33:38.130198999 -0400
 | ||||||
|  | @@ -6094,6 +6094,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -31483,6 +31484,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -31495,10 +31497,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;
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -31516,6 +31534,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -31532,7 +31551,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -31542,11 +31561,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'), | ||||||
|  | @@ -31557,8 +31576,33 @@
 | ||||||
|  |  		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}'
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -31589,7 +31633,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 | ||||||
|  |  	    }, | ||||||
|  | @@ -31597,9 +31643,62 @@
 | ||||||
|  |  		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'),
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		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,147 @@ | ||||||
|  | --- ZFSPlugin.pm.orig	2019-07-25 07:34:52.000000000 -0400
 | ||||||
|  | +++ ZFSPlugin.pm	2019-08-07 13:28:29.268383007 -0400
 | ||||||
|  | @@ -10,6 +10,7 @@
 | ||||||
|  |   | ||||||
|  |  use base qw(PVE::Storage::ZFSPoolPlugin); | ||||||
|  |  use PVE::Storage::LunCmd::Comstar; | ||||||
|  | +use PVE::Storage::LunCmd::FreeNAS;
 | ||||||
|  |  use PVE::Storage::LunCmd::Istgt; | ||||||
|  |  use PVE::Storage::LunCmd::Iet; | ||||||
|  |  use PVE::Storage::LunCmd::LIO; | ||||||
|  | @@ -26,13 +27,14 @@
 | ||||||
|  |      modify_lu   => 1, | ||||||
|  |      add_view    => 1, | ||||||
|  |      list_view   => 1, | ||||||
|  | +    list_extent => 1,
 | ||||||
|  |      list_lu     => 1, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  my $zfs_unknown_scsi_provider = sub { | ||||||
|  |      my ($provider) = @_; | ||||||
|  |   | ||||||
|  | -    die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
 | ||||||
|  | +    die "$provider: unknown iscsi provider. Available [comstar, freenas, istgt, iet, LIO]";
 | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  my $zfs_get_base = sub { | ||||||
|  | @@ -40,6 +42,8 @@
 | ||||||
|  |   | ||||||
|  |      if ($scfg->{iscsiprovider} eq 'comstar') { | ||||||
|  |          return PVE::Storage::LunCmd::Comstar::get_base; | ||||||
|  | +    } elsif ($scfg->{iscsiprovider} eq 'freenas') {
 | ||||||
|  | +        return PVE::Storage::LunCmd::FreeNAS::get_base;
 | ||||||
|  |      } elsif ($scfg->{iscsiprovider} eq 'istgt') { | ||||||
|  |          return PVE::Storage::LunCmd::Istgt::get_base; | ||||||
|  |      } elsif ($scfg->{iscsiprovider} eq 'iet') { | ||||||
|  | @@ -62,6 +66,8 @@
 | ||||||
|  |      if ($lun_cmds->{$method}) { | ||||||
|  |          if ($scfg->{iscsiprovider} eq 'comstar') { | ||||||
|  |              $msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params); | ||||||
|  | +        } elsif ($scfg->{iscsiprovider} eq 'freenas') {
 | ||||||
|  | +            $msg = PVE::Storage::LunCmd::FreeNAS::run_lun_command($scfg, $timeout, $method, @params);
 | ||||||
|  |          } elsif ($scfg->{iscsiprovider} eq 'istgt') { | ||||||
|  |              $msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params); | ||||||
|  |          } elsif ($scfg->{iscsiprovider} eq 'iet') { | ||||||
|  | @@ -160,6 +166,15 @@
 | ||||||
|  |      return $class->zfs_request($scfg, undef, 'list_view', $guid); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +# 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 { | ||||||
|  | @@ -178,6 +193,24 @@
 | ||||||
|  |  	    description => "iscsi provider", | ||||||
|  |  	    type => 'string', | ||||||
|  |  	}, | ||||||
|  | +	# This is for FreeNAS iscsi and API intergration
 | ||||||
|  | +	# And some enhancements asked by the community
 | ||||||
|  | +	freenas_user => {
 | ||||||
|  | +	    description => "FreeNAS API Username",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_password => {
 | ||||||
|  | +	    description => "FreeNAS API Password",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_use_ssl => {
 | ||||||
|  | +	    description => "FreeNAS API access via SSL",
 | ||||||
|  | +	    type => 'boolean',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_apiv4_host => {
 | ||||||
|  | +	    description => "FreeNAS API Host",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  |  	# this will disable write caching on comstar and istgt. | ||||||
|  |  	# it is not implemented for iet. iet blockio always operates with | ||||||
|  |  	# writethrough caching when not in readonly mode | ||||||
|  | @@ -205,14 +238,18 @@
 | ||||||
|  |  	nodes => { optional => 1 }, | ||||||
|  |  	disable => { optional => 1 }, | ||||||
|  |  	portal => { fixed => 1 }, | ||||||
|  | -	target => { fixed => 1 },
 | ||||||
|  | -	pool => { fixed => 1 },
 | ||||||
|  | +	target => { fixed => 0 },
 | ||||||
|  | +	pool => { fixed => 0 },
 | ||||||
|  |  	blocksize => { fixed => 1 }, | ||||||
|  |  	iscsiprovider => { fixed => 1 }, | ||||||
|  |  	nowritecache => { optional => 1 }, | ||||||
|  |  	sparse => { optional => 1 }, | ||||||
|  |  	comstar_hg => { optional => 1 }, | ||||||
|  |  	comstar_tg => { optional => 1 }, | ||||||
|  | +	freenas_user => { optional => 1 },
 | ||||||
|  | +	freenas_password => { optional => 1 },
 | ||||||
|  | +	freenas_use_ssl => { optional => 1 },
 | ||||||
|  | +	freenas_apiv4_host => { optional => 1 },
 | ||||||
|  |  	lio_tpg => { optional => 1 }, | ||||||
|  |  	content => { optional => 1 }, | ||||||
|  |  	bwlimit => { optional => 1 }, | ||||||
|  | @@ -237,6 +274,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 = `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,147 @@ | ||||||
|  | --- ZFSPlugin.pm.orig	2019-07-25 07:34:52.000000000 -0400
 | ||||||
|  | +++ ZFSPlugin.pm	2019-08-07 13:28:29.268383007 -0400
 | ||||||
|  | @@ -10,6 +10,7 @@
 | ||||||
|  |   | ||||||
|  |  use base qw(PVE::Storage::ZFSPoolPlugin); | ||||||
|  |  use PVE::Storage::LunCmd::Comstar; | ||||||
|  | +use PVE::Storage::LunCmd::FreeNAS;
 | ||||||
|  |  use PVE::Storage::LunCmd::Istgt; | ||||||
|  |  use PVE::Storage::LunCmd::Iet; | ||||||
|  |  use PVE::Storage::LunCmd::LIO; | ||||||
|  | @@ -26,13 +27,14 @@
 | ||||||
|  |      modify_lu   => 1, | ||||||
|  |      add_view    => 1, | ||||||
|  |      list_view   => 1, | ||||||
|  | +    list_extent => 1,
 | ||||||
|  |      list_lu     => 1, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  my $zfs_unknown_scsi_provider = sub { | ||||||
|  |      my ($provider) = @_; | ||||||
|  |   | ||||||
|  | -    die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
 | ||||||
|  | +    die "$provider: unknown iscsi provider. Available [comstar, freenas, istgt, iet, LIO]";
 | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  my $zfs_get_base = sub { | ||||||
|  | @@ -40,6 +42,8 @@
 | ||||||
|  |   | ||||||
|  |      if ($scfg->{iscsiprovider} eq 'comstar') { | ||||||
|  |          return PVE::Storage::LunCmd::Comstar::get_base; | ||||||
|  | +    } elsif ($scfg->{iscsiprovider} eq 'freenas') {
 | ||||||
|  | +        return PVE::Storage::LunCmd::FreeNAS::get_base;
 | ||||||
|  |      } elsif ($scfg->{iscsiprovider} eq 'istgt') { | ||||||
|  |          return PVE::Storage::LunCmd::Istgt::get_base; | ||||||
|  |      } elsif ($scfg->{iscsiprovider} eq 'iet') { | ||||||
|  | @@ -62,6 +66,8 @@
 | ||||||
|  |      if ($lun_cmds->{$method}) { | ||||||
|  |          if ($scfg->{iscsiprovider} eq 'comstar') { | ||||||
|  |              $msg = PVE::Storage::LunCmd::Comstar::run_lun_command($scfg, $timeout, $method, @params); | ||||||
|  | +        } elsif ($scfg->{iscsiprovider} eq 'freenas') {
 | ||||||
|  | +            $msg = PVE::Storage::LunCmd::FreeNAS::run_lun_command($scfg, $timeout, $method, @params);
 | ||||||
|  |          } elsif ($scfg->{iscsiprovider} eq 'istgt') { | ||||||
|  |              $msg = PVE::Storage::LunCmd::Istgt::run_lun_command($scfg, $timeout, $method, @params); | ||||||
|  |          } elsif ($scfg->{iscsiprovider} eq 'iet') { | ||||||
|  | @@ -160,6 +166,15 @@
 | ||||||
|  |      return $class->zfs_request($scfg, undef, 'list_view', $guid); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +# 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 { | ||||||
|  | @@ -178,6 +193,24 @@
 | ||||||
|  |  	    description => "iscsi provider", | ||||||
|  |  	    type => 'string', | ||||||
|  |  	}, | ||||||
|  | +	# This is for FreeNAS iscsi and API intergration
 | ||||||
|  | +	# And some enhancements asked by the community
 | ||||||
|  | +	freenas_user => {
 | ||||||
|  | +	    description => "FreeNAS API Username",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_password => {
 | ||||||
|  | +	    description => "FreeNAS API Password",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_use_ssl => {
 | ||||||
|  | +	    description => "FreeNAS API access via SSL",
 | ||||||
|  | +	    type => 'boolean',
 | ||||||
|  | +	},
 | ||||||
|  | +	freenas_apiv4_host => {
 | ||||||
|  | +	    description => "FreeNAS API Host",
 | ||||||
|  | +	    type => 'string',
 | ||||||
|  | +	},
 | ||||||
|  |  	# this will disable write caching on comstar and istgt. | ||||||
|  |  	# it is not implemented for iet. iet blockio always operates with | ||||||
|  |  	# writethrough caching when not in readonly mode | ||||||
|  | @@ -205,14 +238,18 @@
 | ||||||
|  |  	nodes => { optional => 1 }, | ||||||
|  |  	disable => { optional => 1 }, | ||||||
|  |  	portal => { fixed => 1 }, | ||||||
|  | -	target => { fixed => 1 },
 | ||||||
|  | -	pool => { fixed => 1 },
 | ||||||
|  | +	target => { fixed => 0 },
 | ||||||
|  | +	pool => { fixed => 0 },
 | ||||||
|  |  	blocksize => { fixed => 1 }, | ||||||
|  |  	iscsiprovider => { fixed => 1 }, | ||||||
|  |  	nowritecache => { optional => 1 }, | ||||||
|  |  	sparse => { optional => 1 }, | ||||||
|  |  	comstar_hg => { optional => 1 }, | ||||||
|  |  	comstar_tg => { optional => 1 }, | ||||||
|  | +	freenas_user => { optional => 1 },
 | ||||||
|  | +	freenas_password => { optional => 1 },
 | ||||||
|  | +	freenas_use_ssl => { optional => 1 },
 | ||||||
|  | +	freenas_apiv4_host => { optional => 1 },
 | ||||||
|  |  	lio_tpg => { optional => 1 }, | ||||||
|  |  	content => { optional => 1 }, | ||||||
|  |  	bwlimit => { optional => 1 }, | ||||||
|  | @@ -237,6 +274,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 = `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,79 @@ | ||||||
|  | --- apidoc.js.orig	2019-07-15 15:45:00.000000000 -0400
 | ||||||
|  | +++ apidoc.js	2019-08-07 13:28:29.292382229 -0400
 | ||||||
|  | @@ -35001,6 +35001,31 @@
 | ||||||
|  |                             "type" : "string", | ||||||
|  |                             "typetext" : "<string>" | ||||||
|  |                          }, | ||||||
|  | +                        "freenas_user" : {
 | ||||||
|  | +                           "description" : "FreeNAS user for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_password" : {
 | ||||||
|  | +                           "description" : "FreeNAS password for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_use_ssl" : {
 | ||||||
|  | +                           "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "boolean",
 | ||||||
|  | +                           "typetext" : "<boolean>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_apiv4_host" : {
 | ||||||
|  | +                           "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                           "format" : "address",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "fuse" : { | ||||||
|  |                             "description" : "Mount CephFS through FUSE.", | ||||||
|  |                             "optional" : 1, | ||||||
|  | @@ -35157,6 +35182,12 @@
 | ||||||
|  |                             "type" : "boolean", | ||||||
|  |                             "typetext" : "<boolean>" | ||||||
|  |                          }, | ||||||
|  | +                        "target" : {
 | ||||||
|  | +                           "description" : "iSCSI target.",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "transport" : { | ||||||
|  |                             "description" : "Gluster transport: tcp or rdma", | ||||||
|  |                             "enum" : [ | ||||||
|  | @@ -35362,6 +35393,31 @@
 | ||||||
|  |                       "optional" : 1, | ||||||
|  |                       "type" : "string", | ||||||
|  |                       "typetext" : "<string>" | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_user" : {
 | ||||||
|  | +                     "description" : "FreeNAS user for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_password" : {
 | ||||||
|  | +                     "description" : "FreeNAS password for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_use_ssl" : {
 | ||||||
|  | +                     "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "boolean",
 | ||||||
|  | +                     "typetext" : "<boolean>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_apiv4_host" : {
 | ||||||
|  | +                     "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                     "format" : "address",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  |                    }, | ||||||
|  |                    "fuse" : { | ||||||
|  |                       "description" : "Mount CephFS through FUSE.", | ||||||
|  | @ -0,0 +1,79 @@ | ||||||
|  | --- apidoc.js.orig	2019-07-15 15:45:00.000000000 -0400
 | ||||||
|  | +++ apidoc.js	2019-08-07 13:28:29.292382229 -0400
 | ||||||
|  | @@ -35001,6 +35001,31 @@
 | ||||||
|  |                             "type" : "string", | ||||||
|  |                             "typetext" : "<string>" | ||||||
|  |                          }, | ||||||
|  | +                        "freenas_user" : {
 | ||||||
|  | +                           "description" : "FreeNAS user for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_password" : {
 | ||||||
|  | +                           "description" : "FreeNAS password for API access",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_use_ssl" : {
 | ||||||
|  | +                           "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "boolean",
 | ||||||
|  | +                           "typetext" : "<boolean>"
 | ||||||
|  | +                        },
 | ||||||
|  | +                        "freenas_apiv4_host" : {
 | ||||||
|  | +                           "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                           "format" : "address",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "fuse" : { | ||||||
|  |                             "description" : "Mount CephFS through FUSE.", | ||||||
|  |                             "optional" : 1, | ||||||
|  | @@ -35157,6 +35182,12 @@
 | ||||||
|  |                             "type" : "boolean", | ||||||
|  |                             "typetext" : "<boolean>" | ||||||
|  |                          }, | ||||||
|  | +                        "target" : {
 | ||||||
|  | +                           "description" : "iSCSI target.",
 | ||||||
|  | +                           "optional" : 1,
 | ||||||
|  | +                           "type" : "string",
 | ||||||
|  | +                           "typetext" : "<string>"
 | ||||||
|  | +                        },
 | ||||||
|  |                          "transport" : { | ||||||
|  |                             "description" : "Gluster transport: tcp or rdma", | ||||||
|  |                             "enum" : [ | ||||||
|  | @@ -35362,6 +35393,31 @@
 | ||||||
|  |                       "optional" : 1, | ||||||
|  |                       "type" : "string", | ||||||
|  |                       "typetext" : "<string>" | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_user" : {
 | ||||||
|  | +                     "description" : "FreeNAS user for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_password" : {
 | ||||||
|  | +                     "description" : "FreeNAS password for API access",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_use_ssl" : {
 | ||||||
|  | +                     "description" : "FreeNAS API access via SSL",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "boolean",
 | ||||||
|  | +                     "typetext" : "<boolean>"
 | ||||||
|  | +                  },
 | ||||||
|  | +                  "freenas_apiv4_host" : {
 | ||||||
|  | +                     "description" : "FreeNAS API Host via IPv4",
 | ||||||
|  | +                     "format" : "address",
 | ||||||
|  | +                     "optional" : 1,
 | ||||||
|  | +                     "type" : "string",
 | ||||||
|  | +                     "typetext" : "<string>"
 | ||||||
|  |                    }, | ||||||
|  |                    "fuse" : { | ||||||
|  |                       "description" : "Mount CephFS through FUSE.", | ||||||
|  | @ -0,0 +1,189 @@ | ||||||
|  | --- pvemanagerlib.js.orig	2019-07-23 13:21:08.000000000 -0400
 | ||||||
|  | +++ pvemanagerlib.js	2019-08-07 13:28:29.304381840 -0400
 | ||||||
|  | @@ -6182,6 +6182,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -32977,6 +32978,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -32989,10 +32991,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;
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -33010,6 +33028,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -33026,7 +33045,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -33036,11 +33055,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'), | ||||||
|  | @@ -33051,8 +33070,33 @@
 | ||||||
|  |  		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}'
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -33083,7 +33127,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 | ||||||
|  |  	    }, | ||||||
|  | @@ -33091,9 +33137,62 @@
 | ||||||
|  |  		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'),
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		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,189 @@ | ||||||
|  | --- pvemanagerlib.js.orig	2019-07-23 13:21:08.000000000 -0400
 | ||||||
|  | +++ pvemanagerlib.js	2019-08-07 13:28:29.304381840 -0400
 | ||||||
|  | @@ -6182,6 +6182,7 @@
 | ||||||
|  |      alias: ['widget.pveiScsiProviderSelector'], | ||||||
|  |      comboItems: [ | ||||||
|  |  	['comstar', 'Comstar'], | ||||||
|  | +	['freenas', 'FreeNAS-API'],
 | ||||||
|  |  	[ 'istgt', 'istgt'], | ||||||
|  |  	[ 'iet', 'IET'], | ||||||
|  |  	[ 'LIO', 'LIO'] | ||||||
|  | @@ -32977,6 +32978,7 @@
 | ||||||
|  |  	data: { | ||||||
|  |  	    isLIO: false, | ||||||
|  |  	    isComstar: true, | ||||||
|  | +	    isFreeNAS: false,
 | ||||||
|  |  	    hasWriteCacheOption: true | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  | @@ -32989,10 +32991,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;
 | ||||||
|  | +	    }
 | ||||||
|  |  	} | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  | @@ -33010,6 +33028,7 @@
 | ||||||
|  |      }, | ||||||
|  |   | ||||||
|  |      setValues: function diff(values) { | ||||||
|  | +	values.freenas_confirmpw = values.freenas_password;
 | ||||||
|  |  	values.writecache = values.nowritecache ? 0 : 1; | ||||||
|  |  	this.callParent([values]); | ||||||
|  |      }, | ||||||
|  | @@ -33026,7 +33045,7 @@
 | ||||||
|  |  		allowBlank: false | ||||||
|  |  	    }, | ||||||
|  |  	    { | ||||||
|  | -		xtype: me.isCreate ? 'textfield' : 'displayfield',
 | ||||||
|  | +		xtype: 'textfield',
 | ||||||
|  |  		name: 'pool', | ||||||
|  |  		value: '', | ||||||
|  |  		fieldLabel: gettext('Pool'), | ||||||
|  | @@ -33036,11 +33055,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'), | ||||||
|  | @@ -33051,8 +33070,33 @@
 | ||||||
|  |  		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}'
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
|  | @@ -33083,7 +33127,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 | ||||||
|  |  	    }, | ||||||
|  | @@ -33091,9 +33137,62 @@
 | ||||||
|  |  		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'),
 | ||||||
|  | +	    },
 | ||||||
|  | +	    {
 | ||||||
|  | +		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;
 | ||||||
|  | +		}
 | ||||||
|  |  	    } | ||||||
|  |  	]; | ||||||
|  |   | ||||||
		Loading…
	
		Reference in New Issue