Allow multiple instances of the [Free|True}NAS REST::Client construct.

- When optimizing the code to remove the redundant calls to create a
'new' REST::Client this had a single variable to hold the instance. If
you were moving between two different servers then the variables would
not match the destination parameters of the [Free|True]NAS server.
Implemented a hashref of the construct of REST:Client with the hashref
being the IP address of the portal or API IP. Fixes #61.
- Remove some white spacing and superfluous code.
- Added some comments so I know what I was changing.
This commit is contained in:
Kevin Scott Adams 2020-07-14 17:51:45 -04:00
parent c3935785c0
commit 3e128e673c
1 changed files with 36 additions and 30 deletions

View File

@ -12,21 +12,23 @@ use REST::Client;
use MIME::Base64; use MIME::Base64;
use JSON; use JSON;
# Max LUNS per target on the iSCSI server # Global variable definitions
my $MAX_LUNS = 255; my $MAX_LUNS = 255; # Max LUNS per target on the iSCSI server
my $freenas_rest_connection = undef; my $freenas_server_list = undef; # API connection HashRef using the IP address of the server
my $freenas_global_config = undef; my $freenas_rest_connection = undef; # Pointer to entry in $freenas_server_list
my $freenas_global_config_list = undef; # IQN HashRef using the IP address of the server
my $freenas_global_config = undef; # Pointer to entry in $freenas_global_config_list
my $dev_prefix = ""; my $dev_prefix = "";
my $product_name = undef; my $product_name = undef;
my $apiping = '/api/v1.0/system/version/'; my $apiping = '/api/v1.0/system/version/'; # Initial API method for setup
my $runawayprevent = 0; my $runawayprevent = 0; # Recursion prevention variable
# FreeNAS API Definitions # FreeNAS API definitions
my $freenas_api_version = "v1.0"; # Default to v1.0 of the API's my $freenas_api_version = "v1.0"; # Default to v1.0 of the API's
my $freenas_api_methods = undef; # API Methods Nested HASH Ref my $freenas_api_methods = undef; # API Methods Nested HASH Ref
my $freenas_api_variables = undef; # API Variable Nested HASH Ref my $freenas_api_variables = undef; # API Variable Nested HASH Ref
# # FreeNAS/TrueNAS (CORE) API Versioning HashRef Matrix
my $freenas_api_version_matrix = { my $freenas_api_version_matrix = {
"v1.0" => { "v1.0" => {
"methods" => { "methods" => {
@ -117,7 +119,7 @@ sub get_base {
# #
# # Subroutine called from ZFSPlugin.pm
# #
sub run_lun_command { sub run_lun_command {
my ($scfg, $timeout, $method, @params) = @_; my ($scfg, $timeout, $method, @params) = @_;
@ -128,8 +130,6 @@ sub run_lun_command {
die "Undefined freenas_user and/or freenas_password."; die "Undefined freenas_user and/or freenas_password.";
} }
freenas_api_check($scfg, $timeout);
if($method eq "create_lu") { if($method eq "create_lu") {
return run_create_lu($scfg, $timeout, $method, @params); return run_create_lu($scfg, $timeout, $method, @params);
} }
@ -181,7 +181,7 @@ sub run_modify_lu {
} }
# #
# #
# #
sub run_list_view { sub run_list_view {
my ($scfg, $timeout, $method, @params) = @_; my ($scfg, $timeout, $method, @params) = @_;
@ -337,24 +337,24 @@ sub freenas_api_connect {
my $scheme = $scfg->{freenas_use_ssl} ? "https" : "http"; my $scheme = $scfg->{freenas_use_ssl} ? "https" : "http";
my $apihost = defined($scfg->{freenas_apiv4_host}) ? $scfg->{freenas_apiv4_host} : $scfg->{portal}; my $apihost = defined($scfg->{freenas_apiv4_host}) ? $scfg->{freenas_apiv4_host} : $scfg->{portal};
if (! defined $freenas_rest_connection) { if (! defined $freenas_server_list->{$apihost}) {
$freenas_rest_connection = REST::Client->new(); $freenas_server_list->{$apihost} = REST::Client->new();
} }
$freenas_rest_connection->setHost($scheme . '://' . $apihost); $freenas_server_list->{$apihost}->setHost($scheme . '://' . $apihost);
$freenas_rest_connection->addHeader('Content-Type', 'application/json'); $freenas_server_list->{$apihost}->addHeader('Content-Type', 'application/json');
$freenas_rest_connection->addHeader('Authorization', 'Basic ' . encode_base64($scfg->{freenas_user} . ':' . $scfg->{freenas_password})); $freenas_server_list->{$apihost}->addHeader('Authorization', 'Basic ' . encode_base64($scfg->{freenas_user} . ':' . $scfg->{freenas_password}));
# If using SSL, don't verify SSL certs # If using SSL, don't verify SSL certs
if ($scfg->{freenas_use_ssl}) { if ($scfg->{freenas_use_ssl}) {
$freenas_rest_connection->getUseragent()->ssl_opts(verify_hostname => 0); $freenas_server_list->{$apihost}->getUseragent()->ssl_opts(verify_hostname => 0);
$freenas_rest_connection->getUseragent()->ssl_opts(SSL_verify_mode => SSL_VERIFY_NONE); $freenas_server_list->{$apihost}->getUseragent()->ssl_opts(SSL_verify_mode => SSL_VERIFY_NONE);
} }
# Check if the APIs are accessable via the selected host and scheme # Check if the APIs are accessable via the selected host and scheme
my $code = $freenas_rest_connection->request('GET', $apiping)->responseCode(); my $code = $freenas_server_list->{$apihost}->request('GET', $apiping)->responseCode();
if ($code == 200) { # Successful connection if ($code == 200) { # Successful connection
syslog("info", (caller(0))[3] . " : REST connection successful to '" . $apihost . "' using the '" . $scheme . "' protocol"); syslog("info", (caller(0))[3] . " : REST connection successful to '" . $apihost . "' using the '" . $scheme . "' protocol");
$runawayprevent = 0; $runawayprevent = 0;
} elsif ($runawayprevent > 1) { # Make sure we are not recursion calling. } elsif ($runawayprevent > 1) { # Make sure we are not recursion calling.
freenas_api_log_error($freenas_rest_connection, "freenas_api_call"); freenas_api_log_error($freenas_server_list->{$apihost}, "freenas_api_call");
die "Loop recursion prevention"; die "Loop recursion prevention";
} elsif ($code == 302) { # A 302 from FreeNAS means it doesn't like v1.0 APIs. } elsif ($code == 302) { # A 302 from FreeNAS means it doesn't like v1.0 APIs.
syslog("info", (caller(0))[3] . " : Changing to v2.0 API's"); syslog("info", (caller(0))[3] . " : Changing to v2.0 API's");
@ -367,9 +367,10 @@ sub freenas_api_connect {
$scfg->{freenas_use_ssl} = 1; $scfg->{freenas_use_ssl} = 1;
freenas_api_connect($scfg); freenas_api_connect($scfg);
} else { # For now, any other code we fail. } else { # For now, any other code we fail.
freenas_api_log_error($freenas_rest_connection, "freenas_api_call"); freenas_api_log_error($freenas_server_list->{$apihost}, "freenas_api_call");
die "Unable to connect to the FreeNAS API service at '" . $apihost . "' using the '" . $scheme . "' protocol"; die "Unable to connect to the FreeNAS API service at '" . $apihost . "' using the '" . $scheme . "' protocol";
} }
$freenas_rest_connection = $freenas_server_list->{$apihost};
return; return;
} }
@ -380,10 +381,11 @@ sub freenas_api_connect {
sub freenas_api_check { sub freenas_api_check {
my ($scfg, $timeout) = @_; my ($scfg, $timeout) = @_;
my $result = {}; my $result = {};
my $apihost = defined($scfg->{freenas_apiv4_host}) ? $scfg->{freenas_apiv4_host} : $scfg->{portal};
syslog("info", (caller(0))[3] . " : called"); syslog("info", (caller(0))[3] . " : called");
if (! defined $freenas_rest_connection) { if (! defined $freenas_rest_connection->{$apihost}) {
freenas_api_connect($scfg); freenas_api_connect($scfg);
eval { eval {
$result = decode_json($freenas_rest_connection->responseContent()); $result = decode_json($freenas_rest_connection->responseContent());
@ -407,7 +409,7 @@ sub freenas_api_check {
syslog("info", (caller(0))[3] . " : Using " . $product_name ." API version " . $freenas_api_version); syslog("info", (caller(0))[3] . " : Using " . $product_name ." API version " . $freenas_api_version);
$freenas_api_methods = $freenas_api_version_matrix->{$freenas_api_version}->{'methods'}; $freenas_api_methods = $freenas_api_version_matrix->{$freenas_api_version}->{'methods'};
$freenas_api_variables = $freenas_api_version_matrix->{$freenas_api_version}->{'variables'}; $freenas_api_variables = $freenas_api_version_matrix->{$freenas_api_version}->{'variables'};
$freenas_global_config = (!defined($freenas_global_config)) ? freenas_iscsi_get_globalconfiguration($scfg) : $freenas_global_config; $freenas_global_config = $freenas_global_config_list->{$apihost} = (!defined($freenas_global_config_list->{$apihost})) ? freenas_iscsi_get_globalconfiguration($scfg) : $freenas_global_config_list->{$apihost};
return; return;
} }
@ -417,8 +419,9 @@ sub freenas_api_check {
# #
sub freenas_api_call { sub freenas_api_call {
my ($scfg, $method, $path, $data) = @_; my ($scfg, $method, $path, $data) = @_;
my $apihost = defined($scfg->{freenas_apiv4_host}) ? $scfg->{freenas_apiv4_host} : $scfg->{portal};
syslog("info", (caller(0))[3] . " : called"); syslog("info", (caller(0))[3] . " : called for host '" . $apihost . "'");
$method = uc($method); $method = uc($method);
if (! $method =~ /^(?>GET|DELETE|POST)$/) { if (! $method =~ /^(?>GET|DELETE|POST)$/) {
@ -426,9 +429,11 @@ sub freenas_api_call {
die "Invalid HTTP RESTful service method '$method' used."; die "Invalid HTTP RESTful service method '$method' used.";
} }
if (! defined $freenas_rest_connection) { if (! defined $freenas_server_list->{$apihost}) {
freenas_api_check($scfg); freenas_api_check($scfg);
} }
$freenas_rest_connection = $freenas_server_list->{$apihost};
$freenas_global_config = $freenas_global_config_list->{$apihost};
my $json_data = (defined $data) ? encode_json($data) : undef; my $json_data = (defined $data) ? encode_json($data) : undef;
$freenas_rest_connection->$method($path, $json_data); $freenas_rest_connection->$method($path, $json_data);
syslog("info", (caller(0))[3] . " : successful"); syslog("info", (caller(0))[3] . " : successful");
@ -450,10 +455,11 @@ sub freenas_api_log_error {
# #
sub freenas_iscsi_get_globalconfiguration { sub freenas_iscsi_get_globalconfiguration {
my ($scfg) = @_; my ($scfg) = @_;
syslog("info", (caller(0))[3] . " : called"); syslog("info", (caller(0))[3] . " : called");
freenas_api_call($scfg, 'GET', $freenas_api_methods->{'config'}->{'resource'}, $freenas_api_methods->{'config'}->{'get'}); freenas_api_call($scfg, 'GET', $freenas_api_methods->{'config'}->{'resource'}, $freenas_api_methods->{'config'}->{'get'});
my $code = $freenas_rest_connection->responseCode(); my $code = $freenas_rest_connection->responseCode();
if ($code == 200) { if ($code == 200) {
my $result = decode_json($freenas_rest_connection->responseContent()); my $result = decode_json($freenas_rest_connection->responseContent());
syslog("info", (caller(0))[3] . " : target_basename=" . $result->{$freenas_api_variables->{'basename'}}); syslog("info", (caller(0))[3] . " : target_basename=" . $result->{$freenas_api_variables->{'basename'}});