1 package PVE
::Storage
::ZFSPlugin
;
7 use PVE
::Tools
qw(run_command);
8 use PVE
::Storage
::ZFSPoolPlugin
;
9 use PVE
::RPCEnvironment
;
11 use base
qw(PVE::Storage::ZFSPoolPlugin);
12 use PVE
::Storage
::LunCmd
::Comstar
;
13 use PVE
::Storage
::LunCmd
::Istgt
;
14 use PVE
::Storage
::LunCmd
::Iet
;
15 use PVE
::Storage
::LunCmd
::LIO
;
18 my @ssh_opts = ('-o', 'BatchMode=yes');
19 my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
20 my $id_rsa_path = '/etc/pve/priv/zfs';
32 my $zfs_unknown_scsi_provider = sub {
35 die "$provider: unknown iscsi provider. Available [comstar, istgt, iet, LIO]";
38 my $zfs_get_base = sub {
41 if ($scfg->{iscsiprovider
} eq 'comstar') {
42 return PVE
::Storage
::LunCmd
::Comstar
::get_base
;
43 } elsif ($scfg->{iscsiprovider
} eq 'istgt') {
44 return PVE
::Storage
::LunCmd
::Istgt
::get_base
;
45 } elsif ($scfg->{iscsiprovider
} eq 'iet') {
46 return PVE
::Storage
::LunCmd
::Iet
::get_base
;
47 } elsif ($scfg->{iscsiprovider
} eq 'LIO') {
48 return PVE
::Storage
::LunCmd
::LIO
::get_base
;
50 $zfs_unknown_scsi_provider->($scfg->{iscsiprovider
});
55 my ($class, $scfg, $timeout, $method, @params) = @_;
57 $timeout = PVE
::RPCEnvironment-
>is_worker() ?
60*60 : 10
62 if ($lun_cmds->{$method}) {
63 if ($scfg->{iscsiprovider
} eq 'comstar') {
64 $msg = PVE
::Storage
::LunCmd
::Comstar
::run_lun_command
($scfg, $timeout, $method, @params);
65 } elsif ($scfg->{iscsiprovider
} eq 'istgt') {
66 $msg = PVE
::Storage
::LunCmd
::Istgt
::run_lun_command
($scfg, $timeout, $method, @params);
67 } elsif ($scfg->{iscsiprovider
} eq 'iet') {
68 $msg = PVE
::Storage
::LunCmd
::Iet
::run_lun_command
($scfg, $timeout, $method, @params);
69 } elsif ($scfg->{iscsiprovider
} eq 'LIO') {
70 $msg = PVE
::Storage
::LunCmd
::LIO
::run_lun_command
($scfg, $timeout, $method, @params);
72 $zfs_unknown_scsi_provider->($scfg->{iscsiprovider
});
76 my $target = 'root@' . $scfg->{portal
};
78 my $cmd = [@ssh_cmd, '-i', "$id_rsa_path/$scfg->{portal}_id_rsa", $target];
80 if ($method eq 'zpool_list') {
81 push @$cmd, 'zpool', 'list';
83 push @$cmd, 'zfs', $method;
93 run_command
($cmd, outfunc
=> $output, timeout
=> $timeout);
100 my ($class, $scfg, $zvol) = @_;
102 my $base = $zfs_get_base->($scfg);
104 $zvol = ($class->parse_volname($zvol))[1];
106 my $object = ($zvol =~ /^.+\/.+/) ? "$base/$zvol
" : "$base/$scfg->{pool
}/$zvol";
108 my $lu_name = $class->zfs_request($scfg, undef, 'list_lu', $object);
110 return $lu_name if $lu_name;
112 die "Could
not find lu_name
for zvol
$zvol";
115 sub zfs_add_lun_mapping_entry {
116 my ($class, $scfg, $zvol, $guid) = @_;
118 if (!defined($guid)) {
119 $guid = $class->zfs_get_lu_name($scfg, $zvol);
122 $class->zfs_request($scfg, undef, 'add_view', $guid);
126 my ($class, $scfg, $zvol) = @_;
128 my $guid = $class->zfs_get_lu_name($scfg, $zvol);
130 $class->zfs_request($scfg, undef, 'delete_lu', $guid);
134 my ($class, $scfg, $zvol) = @_;
136 my $base = $zfs_get_base->($scfg);
137 my $guid = $class->zfs_request($scfg, undef, 'create_lu', "$base/$scfg->{pool
}/$zvol");
143 my ($class, $scfg, $zvol) = @_;
145 my $base = $zfs_get_base->($scfg);
146 $class->zfs_request($scfg, undef, 'import_lu', "$base/$scfg->{pool
}/$zvol");
150 my ($class, $scfg, $zvol, $size) = @_;
152 my $guid = $class->zfs_get_lu_name($scfg, $zvol);
154 $class->zfs_request($scfg, undef, 'modify_lu', "${size
}K
", $guid);
157 sub zfs_get_lun_number {
158 my ($class, $scfg, $guid) = @_;
160 die "could
not find lun_number
for guid
$guid" if !$guid;
162 if ($class->zfs_request($scfg, undef, 'list_view', $guid) =~ /^(\d+)$/) {
166 die "lun_number
for guid
$guid is not a number
";
177 content => [ {images => 1}, { images => 1 }],
184 description => "iscsi provider
",
187 # this will disable write caching on comstar and istgt.
188 # it is not implemented for iet. iet blockio always operates with
189 # writethrough caching when not in readonly mode
191 description => "disable
write caching on the target
",
195 description => "target group
for comstar views
",
199 description => "host group
for comstar views
",
203 description => "target portal group
for Linux LIO targets
",
211 nodes => { optional => 1 },
212 disable => { optional => 1 },
213 portal => { fixed => 1 },
214 target => { fixed => 1 },
215 pool => { fixed => 1 },
216 blocksize => { fixed => 1 },
217 iscsiprovider => { fixed => 1 },
218 nowritecache => { optional => 1 },
219 sparse => { optional => 1 },
220 comstar_hg => { optional => 1 },
221 comstar_tg => { optional => 1 },
222 lio_tpg => { optional => 1 },
223 content => { optional => 1 },
224 bwlimit => { optional => 1 },
228 # Storage implementation
231 my ($class, $scfg, $volname, $storeid, $snapname) = @_;
233 die "direct access to snapshots
not implemented
"
234 if defined($snapname);
236 my ($vtype, $name, $vmid) = $class->parse_volname($volname);
238 my $target = $scfg->{target};
239 my $portal = $scfg->{portal};
241 my $guid = $class->zfs_get_lu_name($scfg, $name);
242 my $lun = $class->zfs_get_lun_number($scfg, $guid);
244 my $path = "iscsi
://$portal/$target/$lun";
246 return ($path, $vmid, $vtype);
250 my ($class, $storeid, $scfg, $volname) = @_;
252 my $snap = '__base__';
254 my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
255 $class->parse_volname($volname);
257 die "create_base
not possible with base image
\n" if $isBase;
260 $newname =~ s/^vm-/base-/;
262 my $newvolname = $basename ? "$basename/$newname" : "$newname";
264 $class->zfs_delete_lu($scfg, $name);
265 $class->zfs_request($scfg, undef, 'rename', "$scfg->{pool
}/$name", "$scfg->{pool}/$newname");
267 my $guid = $class->zfs_create_lu($scfg, $newname);
268 $class->zfs_add_lun_mapping_entry($scfg, $newname, $guid);
270 my $running = undef; #fixme : is create_base always offline ?
272 $class->volume_snapshot($scfg, $storeid, $newname, $snap, $running);
278 my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
280 my $name = $class->SUPER::clone_image($scfg, $storeid, $volname, $vmid, $snap);
282 # get ZFS dataset name from PVE volname
283 my (undef, $clonedname) = $class->parse_volname($name);
285 my $guid = $class->zfs_create_lu($scfg, $clonedname);
286 $class->zfs_add_lun_mapping_entry($scfg, $clonedname, $guid);
292 my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
294 die "unsupported format
'$fmt'" if $fmt ne 'raw';
296 die "illegal name
'$name' - should be
'vm-$vmid-*'\n"
297 if $name && $name !~ m/^vm-$vmid-/;
301 $volname = $class->find_free_diskname($storeid, $scfg, $vmid, $fmt) if !$volname;
303 $class->zfs_create_zvol($scfg, $volname, $size);
305 my $guid = $class->zfs_create_lu($scfg, $volname);
306 $class->zfs_add_lun_mapping_entry($scfg, $volname, $guid);
312 my ($class, $storeid, $scfg, $volname, $isBase) = @_;
314 my ($vtype, $name, $vmid) = $class->parse_volname($volname);
316 $class->zfs_delete_lu($scfg, $name);
318 eval { $class->zfs_delete_zvol($scfg, $name); };
320 my $guid = $class->zfs_create_lu($scfg, $name);
321 $class->zfs_add_lun_mapping_entry($scfg, $name, $guid);
329 my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
331 $volname = ($class->parse_volname($volname))[1];
333 my $new_size = $class->SUPER::volume_resize($scfg, $storeid, $volname, $size, $running);
335 $class->zfs_resize_lu($scfg, $volname, $new_size);
340 sub volume_snapshot_delete {
341 my ($class, $scfg, $storeid, $volname, $snap, $running) = @_;
343 $volname = ($class->parse_volname($volname))[1];
345 $class->zfs_request($scfg, undef, 'destroy', "$scfg->{pool
}/$volname\@$snap");
348 sub volume_snapshot_rollback {
349 my ($class, $scfg, $storeid, $volname, $snap) = @_;
351 $volname = ($class->parse_volname($volname))[1];
353 $class->zfs_delete_lu($scfg, $volname);
355 $class->zfs_request($scfg, undef, 'rollback', "$scfg->{pool
}/$volname\@$snap");
357 $class->zfs_import_lu($scfg, $volname);
359 $class->zfs_add_lun_mapping_entry($scfg, $volname);
362 sub storage_can_replicate {
363 my ($class, $scfg, $storeid, $format) = @_;
368 sub volume_has_feature {
369 my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
372 snapshot => { current => 1, snap => 1},
373 clone => { base => 1},
374 template => { current => 1},
375 copy => { base => 1, current => 1},
378 my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
379 $class->parse_volname($volname);
386 $key = $isBase ? 'base' : 'current';
389 return 1 if $features->{$feature}->{$key};
394 sub activate_storage {
395 my ($class, $storeid, $scfg, $cache) = @_;
400 sub deactivate_storage {
401 my ($class, $storeid, $scfg, $cache) = @_;
406 sub activate_volume {
407 my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
409 die "unable to activate snapshot from remote zfs storage
" if $snapname;
414 sub deactivate_volume {
415 my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
417 die "unable to deactivate snapshot from remote zfs storage
" if $snapname;