[pve-devel] [PATCH ZFSPlugin] Add support for creating LXC via this storage type. Only support for Comstar based LUNs currently.
Michael Rasmussen
mir at datanom.net
Mon Oct 24 18:10:02 CEST 2016
Signed-off-by: Michael Rasmussen <mir at datanom.net>
---
PVE/Storage/ZFSPlugin.pm | 209 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 203 insertions(+), 6 deletions(-)
diff --git a/PVE/Storage/ZFSPlugin.pm b/PVE/Storage/ZFSPlugin.pm
index ca25402..f4203c6 100644
--- a/PVE/Storage/ZFSPlugin.pm
+++ b/PVE/Storage/ZFSPlugin.pm
@@ -4,7 +4,7 @@ use strict;
use warnings;
use IO::File;
use POSIX;
-use PVE::Tools qw(run_command);
+use PVE::Tools qw(run_command dir_glob_foreach);
use PVE::Storage::ZFSPoolPlugin;
use PVE::RPCEnvironment;
@@ -13,7 +13,6 @@ use PVE::Storage::LunCmd::Comstar;
use PVE::Storage::LunCmd::Istgt;
use PVE::Storage::LunCmd::Iet;
-
my @ssh_opts = ('-o', 'BatchMode=yes');
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
my $id_rsa_path = '/etc/pve/priv/zfs';
@@ -155,6 +154,151 @@ sub zfs_get_lun_number {
return $class->zfs_request($scfg, undef, 'list_view', $guid);
}
+sub os_request {
+ my ($cmd, $noerr, $timeout) = @_;
+
+ $timeout = PVE::RPCEnvironment::is_worker() ? 60*60 : 5 if !$timeout;
+ $noerr = 0 if !$noerr;
+
+ 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) : $text;
+}
+
+sub bail_out {
+ my ($class, $storeid, $scfg, $volname, $err) = @_;
+
+ $class->free_image($storeid, $scfg, $volname);
+ die $err;
+}
+
+sub disk_by_path {
+ my ($scfg, $lun) = @_;
+
+ my $path = "/dev/disk/by-path/ip-$scfg->{portal}:3260-iscsi-$scfg->{target}-lun-$lun";
+
+ return $path;
+}
+
+sub build_lun_list {
+ my ($scfg, $sid) = @_;
+
+ my $luns = {};
+ my $text = '';
+ my $exit = 0;
+
+ eval {
+ ($exit, $text) = os_request("iscsiadm -m session -r $sid -P3", 1);
+ };
+ if ($@) {
+ # An exist code of 22 means no active session otherwise an error
+ if ($exit != 22) {
+ die "$@";
+ }
+ }
+ if ($text =~ /.*Host Number:\s*(\d+)\s+State:\s+running(.*)/s) {
+ my $host = $1;
+ for (split /^/, $2) {
+ next unless /Channel\s+(\d+)\s+Id\s+(\d+)\s+Lun:\s+(\d+)/;
+ $luns->{$3} = "$host:".int($1).":$2:$3";
+ }
+ }
+
+ return $luns;
+}
+
+sub get_sid {
+ my ($scfg) = @_;
+ my $sid = -1;
+ my $text = '';
+ my $exit = 0;
+
+ eval {
+ ($exit, $text) = os_request("iscsiadm -m node -T $scfg->{target} -p $scfg->{portal} -s", 1);
+ };
+ if ($@) {
+ # An exist code of 21 or 22 means no active session otherwise an error
+ if ($exit != 21 || $exit != 22) {
+ die "$@";
+ }
+ }
+ if ($text =~ /.*\[sid\:\s*(\d+),\s*.*/) {
+ $sid = $1;
+ }
+
+ return $sid;
+}
+
+sub deactivate_luns {
+ # $luns contains a hash of luns to keep
+ my ($scfg, $luns) = @_;
+
+ $luns = {} if !$luns;
+ my $sid;
+ my $list = {};
+
+ eval {
+ $sid = get_sid($scfg);
+ };
+ die "$@" if @$;
+ return if $sid < 0;
+
+ eval {
+ $list = build_lun_list($scfg, $sid);
+
+ foreach my $key (keys %$list) {
+ next if exists($luns->{$key});
+ os_request("echo 1 > /sys/bus/scsi/devices/$list->{$key}/delete");
+ }
+ };
+ die "$@" if @$;
+}
+
+sub get_active_luns {
+ my ($class, $storeid, $scfg, $volname) = @_;
+
+ my $sid = 0;
+ my $luns = {};
+
+ eval {
+ $sid = get_sid($scfg);
+ };
+ if ($@) {
+ bail_out($class, $storeid, $scfg, $volname, $@);
+ }
+ if ($sid < 0) {
+ # We have no active sessions so make one
+ eval {
+ os_request("iscsiadm -m node -T $scfg->{target} -p $scfg->{portal} --login");
+ $sid = get_sid($scfg);
+ };
+ if ($@) {
+ bail_out($class, $storeid, $scfg, $volname, $@);
+ }
+ # Since no session existed prior to this call deactivate all LUN's found
+ deactivate_luns($scfg);
+ }
+ if ($sid >= 0) {
+ eval {
+ $luns = build_lun_list($scfg, $sid);
+ };
+ if ($@) {
+ bail_out($class, $storeid, $scfg, $volname, $@);
+ }
+ } else {
+ bail_out($class, $storeid, $scfg, $volname, "Missing iscsi session");
+ }
+
+ return $luns;
+}
+
# Configuration
sub type {
@@ -163,7 +307,7 @@ sub type {
sub plugindata {
return {
- content => [ {images => 1}, { images => 1 }],
+ content => [ { images => 1, rootdir => 1 }, { images => 1, rootdir => 1 }],
};
}
@@ -224,7 +368,11 @@ sub path {
my $guid = $class->zfs_get_lu_name($scfg, $name);
my $lun = $class->zfs_get_lun_number($scfg, $guid);
- my $path = "iscsi://$portal/$target/$lun";
+ my $path = disk_by_path($scfg, $lun);
+
+ if (! -l "$path") {
+ $path = "iscsi://$portal/$target/$lun";
+ }
return ($path, $vmid, $vtype);
}
@@ -374,10 +522,44 @@ sub deactivate_storage {
return 1;
}
+# Procedure for activating a LXC volume:
+#
+# if session does not exist
+# login to target
+# deactivate all luns in session
+# get list of active luns
+# get lun number to activate
+# make list of our luns (active + new lun)
+# rescan session
+# deactivate all luns except our luns
+#
+# Procedure for deactivating a LXC volume:
+# if session exists
+# get lun number to deactivate
+# deactivate lun
+#
sub activate_volume {
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
- die "unable to activate snapshot from remote zfs storage" if $snapname;
+ die "mode failure - unable to activate snapshot from remote zfs storage" if $snapname;
+
+ my $active_luns = get_active_luns($class, $storeid, $scfg, $volname);
+
+ my ($vtype, $name, $vmid) = $class->parse_volname($volname);
+ my $guid = $class->zfs_get_lu_name($scfg, $name);
+ my $lun = $class->zfs_get_lun_number($scfg, $guid);
+ $active_luns->{$lun} = "0:0:0:$lun";
+
+ eval {
+ my $sid = get_sid($scfg);
+ if ($sid >= 0) {
+ os_request("iscsiadm -m session -r $sid -R");
+ deactivate_luns($scfg, $active_luns);
+ }
+ };
+ if ($@) {
+ bail_out($class, $storeid, $scfg, $volname, $@);
+ }
return 1;
}
@@ -385,7 +567,22 @@ sub activate_volume {
sub deactivate_volume {
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
- die "unable to deactivate snapshot from remote zfs storage" if $snapname;
+ die "mode failure - unable to deactivate snapshot from remote zfs storage" if $snapname;
+
+ my $active_luns = get_active_luns($class, $storeid, $scfg, $volname);
+ my ($vtype, $name, $vmid) = $class->parse_volname($volname);
+ my $guid = $class->zfs_get_lu_name($scfg, $name);
+ my $lun = $class->zfs_get_lun_number($scfg, $guid);
+ delete $active_luns->{$lun};
+
+ eval {
+ my $sid = get_sid($scfg);
+ if ($sid >= 0) {
+ os_request("iscsiadm -m session -r $sid -R");
+ deactivate_luns($scfg, $active_luns);
+ }
+ };
+ die $@ if $@;
return 1;
}
--
2.1.4
----
This mail was virus scanned and spam checked before delivery.
This mail is also DKIM signed. See header dkim-signature.
More information about the pve-devel
mailing list