[pve-devel] [PATCH v7 pve-storage 03/10] Basic iscsiadm interaction code
Fabian Grünbichler
f.gruenbichler at proxmox.com
Mon Aug 7 14:32:46 CEST 2017
high-level question:
would it make sense to wrap the iscsiadm calls once more? seems to me
like that might save a lot of duplication, and stuff like the -m and -p
parameters could become parameters of the wrapper.
On Tue, Jun 20, 2017 at 10:39:55PM +0200, mir at datanom.net wrote:
> From: Michael Rasmussen <mir at datanom.net>
>
> Signed-off-by: Michael Rasmussen <mir at datanom.net>
> ---
> PVE/Storage/FreeNASPlugin.pm | 119 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 119 insertions(+)
>
> diff --git a/PVE/Storage/FreeNASPlugin.pm b/PVE/Storage/FreeNASPlugin.pm
> index a50a2f6..e930cea 100644
> --- a/PVE/Storage/FreeNASPlugin.pm
> +++ b/PVE/Storage/FreeNASPlugin.pm
> @@ -22,6 +22,9 @@ my $rows_per_request = 50; # limit for get requests
> # in FreeNAS API is 20) can cause race conditions
> # on the FreeNAS host (seems like an unstable
> # pagination algorithm implemented in FreeNAS)
> +my $version;
> +my $target_prefix = 'iqn.2005-10.org.freenas.ctl'; # automatically prepended
> + # in FreeNAS
>
> # Configuration
>
> @@ -242,6 +245,121 @@ my $freenas_list_zvol = sub {
> return $list;
> };
>
> +my $os_request = sub {
> + my ($cmd, $noerr, $timeout) = @_;
> +
> + $timeout = 5 unless $timeout;
> + $noerr = 0 unless $noerr;
that should not be needed?
> +
> + my $text = '';
> +
> + my $output = sub {
> + my $line = shift;
> + $text .= "$line\n";
> + };
> +
> + my $exit_code = run_command($cmd, noerr => $noerr, errfunc => $output, outfunc => $output, timeout => $timeout);
> +
> + return wantarray ? ($exit_code, $text) : $exit_code;
> +};
> +
> +my $freenas_get_target_name = sub {
> + my ($scfg, $volname) = @_;
> + my $name = undef;
> +
whitespace error (blank lines should not contain spaces)
> + if ($volname =~ /^(vm|base)-(\d+)-/) {
> + $name = "vm-$2";
> + return "$target_prefix\:$name";
> + }
> +
> + return undef;
> +};
> +
> +my $get_sid = sub {
> + my ($scfg, $volname) = @_;
> + my $sid = -1;
> + my $text = '';
> + my $exit = 0;
> +
whitespace error
> + my $target = $freenas_get_target_name->($scfg, $volname);
> +
> + eval {
> + ($exit, $text) = $os_request->(
> + ['iscsiadm', '-m', 'node', '-T', $target, '-p', $scfg->{portal}, '-s'], 1, 60);
> + };
> + if ($@) {
> + # An exist code of 21 or 22 means no active session otherwise an error
> + if ($exit != 21 || $exit != 22) {
> + die "$@\n";
> + }
> + }
run_command with noerr does not work like this. if you pass noerr,
run_command will not die on a non-zero exit code, so $@ won't be defined
and you never take this if (well, you would if you run into the timeout,
or if the iscsiadm binary is missing, or ... - but then $exit is undef
anyway, so this is moot).
you need to check both $@ (timeout or other basic error) and $exit (for
the exit code), but separately.
also, please use the full binary path to be $PATH independent (this
applies to all the iscsiadm calls!).
> + if ($text =~ /.*\[sid\:\s*(\d+),\s*.*/) {
> + $sid = $1;
> + }
> +
> + return $sid;
> +};
> +
> +my $create_session = sub {
> + my ($scfg, $volname) = @_;
> + my $sid = -1;
> + my $exit = undef;
> +
whitespace
> + my $target = $freenas_get_target_name->($scfg, $volname);
> +
> + eval {
> + $exit = $os_request->(
> + ['iscsiadm', '-m', 'node', '-T', $target, '-p', $scfg->{portal}, '--login'], 1, 60);
> + if ($exit == 21) {
> + eval {
> + $os_request->(
> + ['iscsiadm', '-m', 'discovery', '-t', 'sendtargets', '-p', $scfg->{portal}], 0, 60);
> + $os_request->(
> + ['iscsiadm', '-m', 'node', '-T', $target, '-p', $scfg->{portal}, '--login'], 0, 60);
> + };
> + }
this one is a bit better - but what if the inner eval fails? shouldn't
we die then with some meaningful error message? note that $@ is not
propagated from inner to outer eval, so the error handling below is not
triggered.
> + };
> + if ($@) {
> + if ($exit == 21) {
this is wrong again, see above for get_sid.
> + eval {
> + $os_request->(
> + ['iscsiadm', '-m', 'discovery', '-t', 'sendtargets', '-p', $scfg->{portal}], 0, 60);
> + $os_request->(
> + ['iscsiadm', '-m', 'node', '-T', $target, '-p', $scfg->{portal}, '--login'], 0, 60);
> + };
see above?
> + } else {
> + die "$@\n";
> + }
> + }
> + eval {
> + $sid = $get_sid->($scfg, $volname);
> + };
> + die "$@\n" if $@;
> + die "Could not create session\n" if $sid < 0;
> +
whitespace
> + return $sid;
> +};
> +
> +my $delete_session = sub {
> + my ($scfg, $sid) = @_;
> +
whitespace
> + eval {
> + $os_request->(['iscsiadm', '-m', 'session', '-r', $sid, '--logout'], 0, 60);
> + };
> + warn "Delete session failed: $@\n" if $@;
> +};
> +
> +my $remove_local_lun = sub {
> + my ($id) = @_;
> +
whitespace
> + open (my $fh, '>', "/sys/bus/scsi/devices/$id/delete") or
> + warn "Remove local LUN failed: $!\n";
> + if ($fh) {
> + print $fh '1';
> + close $fh;
> + }
> +};
I'd prefer something like:
my $file = "/sys/...";
eval {
open(my $fh, '>', $file) or die "failed to open $file for writing: $!\n";
print {$fh} "1\n" or die "failed to write to $file\n";
close($fh);
};
die "Removal of local LUN failed: $@\n" if $@;
(or warn if it is really only a warning?)
> +
> # Storage implementation
>
> sub volume_size_info {
> @@ -256,6 +374,7 @@ sub volume_size_info {
> die "Could not get zfs volume size\n";
> }
>
> +
> sub parse_volname {
> my ($class, $volname) = @_;
>
I guess this last one was an accident?
> --
> 2.11.0
>
>
> ----
>
> This mail was virus scanned and spam checked before delivery.
> This mail is also DKIM signed. See header dkim-signature.
>
> _______________________________________________
> pve-devel mailing list
> pve-devel at pve.proxmox.com
> https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
More information about the pve-devel
mailing list