]>
Commit | Line | Data |
---|---|---|
c84106ed DC |
1 | package PVE::API2::Disks::ZFS; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use PVE::Diskmanage; | |
e698cbb9 | 7 | use PVE::JSONSchema qw(get_standard_option parse_property_string); |
f720f6c4 | 8 | use PVE::Systemd; |
c84106ed DC |
9 | use PVE::API2::Storage::Config; |
10 | use PVE::Storage; | |
11 | use PVE::Tools qw(run_command lock_file trim); | |
12 | ||
13 | use PVE::RPCEnvironment; | |
14 | use PVE::RESTHandler; | |
15 | ||
16 | use base qw(PVE::RESTHandler); | |
17 | ||
18 | my $ZPOOL = '/sbin/zpool'; | |
19 | my $ZFS = '/sbin/zfs'; | |
20 | ||
55553bd4 | 21 | sub get_pool_data { |
8b06da64 | 22 | die "zfsutils-linux not installed\n" if ! -f $ZPOOL; |
55553bd4 AL |
23 | |
24 | my $propnames = [qw(name size alloc free frag dedup health)]; | |
25 | my $numbers = { | |
26 | size => 1, | |
27 | alloc => 1, | |
28 | free => 1, | |
29 | frag => 1, | |
30 | dedup => 1, | |
31 | }; | |
32 | ||
55553bd4 | 33 | my $pools = []; |
8b06da64 | 34 | run_command([$ZPOOL, 'list', '-HpPLo', join(',', @$propnames)], outfunc => sub { |
55553bd4 AL |
35 | my ($line) = @_; |
36 | ||
8b06da64 TL |
37 | my @props = split('\s+', trim($line)); |
38 | my $pool = {}; | |
39 | for (my $i = 0; $i < scalar(@$propnames); $i++) { | |
40 | if ($numbers->{$propnames->[$i]}) { | |
41 | $pool->{$propnames->[$i]} = $props[$i] + 0; | |
42 | } else { | |
43 | $pool->{$propnames->[$i]} = $props[$i]; | |
55553bd4 | 44 | } |
8b06da64 | 45 | } |
55553bd4 | 46 | |
8b06da64 | 47 | push @$pools, $pool; |
55553bd4 AL |
48 | }); |
49 | ||
50 | return $pools; | |
51 | } | |
52 | ||
c84106ed DC |
53 | __PACKAGE__->register_method ({ |
54 | name => 'index', | |
55 | path => '', | |
56 | method => 'GET', | |
57 | proxyto => 'node', | |
58 | protected => 1, | |
59 | permissions => { | |
60 | check => ['perm', '/', ['Sys.Audit', 'Datastore.Audit'], any => 1], | |
61 | }, | |
62 | description => "List Zpools.", | |
63 | parameters => { | |
64 | additionalProperties => 0, | |
65 | properties => { | |
66 | node => get_standard_option('pve-node'), | |
67 | }, | |
68 | }, | |
69 | returns => { | |
70 | type => 'array', | |
71 | items => { | |
72 | type => 'object', | |
73 | properties => { | |
74 | name => { | |
75 | type => 'string', | |
76 | description => "", | |
77 | }, | |
78 | size => { | |
79 | type => 'integer', | |
80 | description => "", | |
81 | }, | |
82 | alloc => { | |
83 | type => 'integer', | |
84 | description => "", | |
85 | }, | |
86 | free => { | |
87 | type => 'integer', | |
88 | description => "", | |
89 | }, | |
90 | frag => { | |
91 | type => 'integer', | |
92 | description => "", | |
93 | }, | |
94 | dedup => { | |
95 | type => 'number', | |
96 | description => "", | |
97 | }, | |
98 | health => { | |
99 | type => 'string', | |
100 | description => "", | |
101 | }, | |
102 | }, | |
103 | }, | |
104 | links => [ { rel => 'child', href => "{name}" } ], | |
105 | }, | |
106 | code => sub { | |
107 | my ($param) = @_; | |
108 | ||
55553bd4 | 109 | return get_pool_data(); |
c84106ed DC |
110 | }}); |
111 | ||
112 | sub preparetree { | |
113 | my ($el) = @_; | |
114 | delete $el->{lvl}; | |
115 | if ($el->{children} && scalar(@{$el->{children}})) { | |
116 | $el->{leaf} = 0; | |
117 | foreach my $child (@{$el->{children}}) { | |
118 | preparetree($child); | |
119 | } | |
120 | } else { | |
121 | $el->{leaf} = 1; | |
122 | } | |
123 | } | |
124 | ||
125 | ||
126 | __PACKAGE__->register_method ({ | |
127 | name => 'detail', | |
128 | path => '{name}', | |
129 | method => 'GET', | |
130 | proxyto => 'node', | |
131 | protected => 1, | |
132 | permissions => { | |
133 | check => ['perm', '/', ['Sys.Audit', 'Datastore.Audit'], any => 1], | |
134 | }, | |
135 | description => "Get details about a zpool.", | |
136 | parameters => { | |
137 | additionalProperties => 0, | |
138 | properties => { | |
139 | node => get_standard_option('pve-node'), | |
140 | name => get_standard_option('pve-storage-id'), | |
141 | }, | |
142 | }, | |
143 | returns => { | |
4d12dbff DC |
144 | type => 'object', |
145 | properties => { | |
146 | name => { | |
147 | type => 'string', | |
148 | description => 'The name of the zpool.', | |
149 | }, | |
150 | state => { | |
151 | type => 'string', | |
152 | description => 'The state of the zpool.', | |
153 | }, | |
154 | status => { | |
155 | optional => 1, | |
156 | type => 'string', | |
157 | description => 'Information about the state of the zpool.', | |
158 | }, | |
159 | action => { | |
160 | optional => 1, | |
161 | type => 'string', | |
162 | description => 'Information about the recommended action to fix the state.', | |
163 | }, | |
164 | scan => { | |
977b80c8 | 165 | optional => 1, |
4d12dbff DC |
166 | type => 'string', |
167 | description => 'Information about the last/current scrub.', | |
168 | }, | |
b005f2f4 | 169 | errors => { |
4d12dbff DC |
170 | type => 'string', |
171 | description => 'Information about the errors on the zpool.', | |
172 | }, | |
173 | children => { | |
174 | type => 'array', | |
32f749b8 | 175 | description => "The pool configuration information, including the vdevs for each section (e.g. spares, cache), may be nested.", |
4d12dbff DC |
176 | items => { |
177 | type => 'object', | |
178 | properties => { | |
179 | name => { | |
180 | type => 'string', | |
32f749b8 | 181 | description => 'The name of the vdev or section.', |
4d12dbff DC |
182 | }, |
183 | state => { | |
32f749b8 | 184 | optional => 1, |
4d12dbff DC |
185 | type => 'string', |
186 | description => 'The state of the vdev.', | |
187 | }, | |
188 | read => { | |
32f749b8 | 189 | optional => 1, |
4d12dbff DC |
190 | type => 'number', |
191 | }, | |
192 | write => { | |
32f749b8 | 193 | optional => 1, |
4d12dbff DC |
194 | type => 'number', |
195 | }, | |
196 | cksum => { | |
32f749b8 | 197 | optional => 1, |
4d12dbff DC |
198 | type => 'number', |
199 | }, | |
200 | msg => { | |
201 | type => 'string', | |
202 | description => 'An optional message about the vdev.' | |
203 | } | |
204 | }, | |
205 | }, | |
206 | }, | |
207 | }, | |
c84106ed DC |
208 | }, |
209 | code => sub { | |
210 | my ($param) = @_; | |
211 | ||
212 | if (!-f $ZPOOL) { | |
213 | die "zfsutils-linux not installed\n"; | |
214 | } | |
215 | ||
216 | my $cmd = [$ZPOOL, 'status', '-P', $param->{name}]; | |
217 | ||
218 | my $pool = { | |
219 | lvl => 0, | |
220 | }; | |
c84106ed DC |
221 | |
222 | my $curfield; | |
223 | my $config = 0; | |
224 | ||
225 | my $stack = [$pool]; | |
226 | my $curlvl = 0; | |
227 | ||
228 | run_command($cmd, outfunc => sub { | |
229 | my ($line) = @_; | |
230 | ||
231 | if ($line =~ m/^\s*(\S+): (\S+.*)$/) { | |
232 | $curfield = $1; | |
233 | $pool->{$curfield} = $2; | |
234 | ||
235 | $config = 0 if $curfield eq 'errors'; | |
236 | } elsif (!$config && $line =~ m/^\s+(\S+.*)$/) { | |
237 | $pool->{$curfield} .= " " . $1; | |
238 | } elsif (!$config && $line =~ m/^\s*config:/) { | |
239 | $config = 1; | |
a49fc735 | 240 | } elsif ($config && $line =~ m/^(\s+)(\S+)\s*(\S+)?(?:\s+(\S+)\s+(\S+)\s+(\S+))?\s*(.*)$/) { |
c84106ed | 241 | my ($space, $name, $state, $read, $write, $cksum, $msg) = ($1, $2, $3, $4, $5, $6, $7); |
576e143a FE |
242 | if ($name ne "NAME") { |
243 | my $lvl = int(length($space) / 2) + 1; # two spaces per level | |
c84106ed DC |
244 | my $vdev = { |
245 | name => $name, | |
c84106ed DC |
246 | msg => $msg, |
247 | lvl => $lvl, | |
248 | }; | |
8b6b7102 | 249 | |
a49fc735 TM |
250 | $vdev->{state} = $state if defined($state); |
251 | $vdev->{read} = $read + 0 if defined($read); | |
252 | $vdev->{write} = $write + 0 if defined($write); | |
253 | $vdev->{cksum} = $cksum + 0 if defined($cksum); | |
8b6b7102 | 254 | |
c84106ed DC |
255 | my $cur = pop @$stack; |
256 | ||
257 | if ($lvl > $curlvl) { | |
258 | $cur->{children} = [ $vdev ]; | |
c84106ed DC |
259 | } elsif ($lvl == $curlvl) { |
260 | $cur = pop @$stack; | |
261 | push @{$cur->{children}}, $vdev; | |
c84106ed | 262 | } else { |
8b6b7102 | 263 | while ($lvl <= $cur->{lvl} && $cur->{lvl} != 0) { |
c84106ed DC |
264 | $cur = pop @$stack; |
265 | } | |
266 | push @{$cur->{children}}, $vdev; | |
c84106ed | 267 | } |
8b6b7102 | 268 | |
a49fc735 TM |
269 | push @$stack, $cur; |
270 | push @$stack, $vdev; | |
c84106ed DC |
271 | $curlvl = $lvl; |
272 | } | |
273 | } | |
274 | }); | |
275 | ||
276 | # change treenodes for extjs tree | |
277 | $pool->{name} = delete $pool->{pool}; | |
278 | preparetree($pool); | |
279 | ||
280 | return $pool; | |
281 | }}); | |
282 | ||
59db1208 SH |
283 | my $draid_config_format = { |
284 | spares => { | |
285 | type => 'integer', | |
286 | minimum => 0, | |
287 | description => 'Number of dRAID spares.', | |
288 | }, | |
289 | data => { | |
290 | type => 'integer', | |
291 | minimum => 1, | |
292 | description => 'The number of data devices per redundancy group. (dRAID)', | |
293 | }, | |
294 | }; | |
295 | ||
c84106ed DC |
296 | __PACKAGE__->register_method ({ |
297 | name => 'create', | |
298 | path => '', | |
299 | method => 'POST', | |
300 | proxyto => 'node', | |
301 | protected => 1, | |
302 | permissions => { | |
303 | check => ['perm', '/', ['Sys.Modify', 'Datastore.Allocate']], | |
304 | }, | |
fdc863c7 | 305 | description => "Create a ZFS pool.", |
c84106ed DC |
306 | parameters => { |
307 | additionalProperties => 0, | |
308 | properties => { | |
309 | node => get_standard_option('pve-node'), | |
310 | name => get_standard_option('pve-storage-id'), | |
311 | raidlevel => { | |
312 | type => 'string', | |
7058abe2 | 313 | description => 'The RAID level to use.', |
59db1208 SH |
314 | enum => [ |
315 | 'single', 'mirror', | |
316 | 'raid10', 'raidz', 'raidz2', 'raidz3', | |
317 | 'draid', 'draid2', 'draid3', | |
318 | ], | |
c84106ed DC |
319 | }, |
320 | devices => { | |
5be1a092 | 321 | type => 'string', format => 'string-list', |
fdc863c7 | 322 | description => 'The block devices you want to create the zpool on.', |
c84106ed | 323 | }, |
59db1208 SH |
324 | 'draid-config' => { |
325 | type => 'string', | |
326 | format => $draid_config_format, | |
327 | optional => 1, | |
328 | }, | |
c84106ed DC |
329 | ashift => { |
330 | type => 'integer', | |
331 | minimum => 9, | |
332 | maximum => 16, | |
333 | optional => 1, | |
334 | default => 12, | |
7d597888 | 335 | description => 'Pool sector size exponent.', |
c84106ed DC |
336 | }, |
337 | compression => { | |
338 | type => 'string', | |
339 | description => 'The compression algorithm to use.', | |
ae098a19 | 340 | enum => ['on', 'off', 'gzip', 'lz4', 'lzjb', 'zle', 'zstd'], |
c84106ed DC |
341 | optional => 1, |
342 | default => 'on', | |
343 | }, | |
344 | add_storage => { | |
fdc863c7 | 345 | description => "Configure storage using the zpool.", |
c84106ed DC |
346 | type => 'boolean', |
347 | optional => 1, | |
348 | default => 0, | |
349 | }, | |
350 | }, | |
351 | }, | |
352 | returns => { type => 'string' }, | |
353 | code => sub { | |
354 | my ($param) = @_; | |
355 | ||
356 | my $rpcenv = PVE::RPCEnvironment::get(); | |
357 | my $user = $rpcenv->get_user(); | |
358 | ||
359 | my $name = $param->{name}; | |
55553bd4 | 360 | my $node = $param->{node}; |
c84106ed | 361 | my $devs = [PVE::Tools::split_list($param->{devices})]; |
38572a8f | 362 | my $raidlevel = $param->{raidlevel}; |
c84106ed | 363 | my $compression = $param->{compression} // 'on'; |
e698cbb9 TL |
364 | |
365 | my $draid_config; | |
59db1208 | 366 | if (exists $param->{'draid-config'}) { |
8a5ffcd9 | 367 | die "draid-config set without using dRAID level\n" if $raidlevel !~ m/^draid/; |
e698cbb9 | 368 | $draid_config = parse_property_string($draid_config_format, $param->{'draid-config'}); |
59db1208 | 369 | } |
c84106ed | 370 | |
107208bd | 371 | for my $dev (@$devs) { |
c84106ed | 372 | $dev = PVE::Diskmanage::verify_blockdev_path($dev); |
0370861c | 373 | PVE::Diskmanage::assert_disk_unused($dev); |
bd485fd4 AL |
374 | |
375 | } | |
376 | my $storage_params = { | |
377 | type => 'zfspool', | |
378 | pool => $name, | |
379 | storage => $name, | |
380 | content => 'rootdir,images', | |
381 | nodes => $node, | |
382 | }; | |
383 | my $verify_params = [qw(pool)]; | |
384 | ||
385 | if ($param->{add_storage}) { | |
386 | PVE::API2::Storage::Config->create_or_update( | |
387 | $name, | |
388 | $node, | |
389 | $storage_params, | |
390 | $verify_params, | |
391 | 1, | |
392 | ); | |
c84106ed | 393 | } |
c84106ed | 394 | |
55553bd4 AL |
395 | my $pools = get_pool_data(); |
396 | die "pool '${name}' already exists on node '${node}'\n" | |
397 | if grep { $_->{name} eq $name } @{$pools}; | |
398 | ||
c84106ed DC |
399 | my $numdisks = scalar(@$devs); |
400 | my $mindisks = { | |
7058abe2 DC |
401 | single => 1, |
402 | mirror => 2, | |
c84106ed DC |
403 | raid10 => 4, |
404 | raidz => 3, | |
405 | raidz2 => 4, | |
406 | raidz3 => 5, | |
59db1208 SH |
407 | draid => 3, |
408 | draid2 => 4, | |
409 | draid3 => 5, | |
c84106ed DC |
410 | }; |
411 | ||
412 | # sanity checks | |
413 | die "raid10 needs an even number of disks\n" | |
38572a8f | 414 | if $raidlevel eq 'raid10' && $numdisks % 2 != 0; |
c84106ed | 415 | |
7058abe2 DC |
416 | die "please give only one disk for single disk mode\n" |
417 | if $raidlevel eq 'single' && $numdisks > 1; | |
418 | ||
38572a8f DC |
419 | die "$raidlevel needs at least $mindisks->{$raidlevel} disks\n" |
420 | if $numdisks < $mindisks->{$raidlevel}; | |
c84106ed | 421 | |
59db1208 SH |
422 | # draid checks |
423 | if ($raidlevel =~ m/^draid/) { | |
e698cbb9 TL |
424 | # bare minimum would be two drives: one for parity & one for data, but forbid that |
425 | # because it makes no sense in practice, at least one spare disk should be used | |
426 | my $draid_min = $mindisks->{$raidlevel} - 2; | |
427 | if ($draid_config) { | |
428 | $draid_min += $draid_config->{data} || 0; | |
429 | $draid_min += $draid_config->{spares} || 0; | |
430 | } | |
431 | die "At least $draid_min disks needed for current dRAID config\n" | |
432 | if $numdisks < $draid_min; | |
59db1208 SH |
433 | } |
434 | ||
107208bd TL |
435 | my $code = sub { |
436 | for my $dev (@$devs) { | |
437 | PVE::Diskmanage::assert_disk_unused($dev); | |
05d91712 | 438 | |
107208bd | 439 | my $is_partition = PVE::Diskmanage::is_partition($dev); |
a2c34371 | 440 | |
107208bd TL |
441 | if ($is_partition) { |
442 | eval { | |
443 | PVE::Diskmanage::change_parttype($dev, '6a898cc3-1dd2-11b2-99a6-080020736631'); | |
444 | }; | |
445 | warn $@ if $@; | |
446 | } | |
a2c34371 | 447 | |
107208bd TL |
448 | my $sysfsdev = $is_partition ? PVE::Diskmanage::get_blockdev($dev) : $dev; |
449 | ||
450 | $sysfsdev =~ s!^/dev/!/sys/block/!; | |
451 | if ($is_partition) { | |
452 | my $part = $dev =~ s!^/dev/!!r; | |
453 | $sysfsdev .= "/${part}"; | |
e99bc248 FE |
454 | } |
455 | ||
107208bd TL |
456 | my $udevinfo = PVE::Diskmanage::get_udev_info($sysfsdev); |
457 | $dev = $udevinfo->{by_id_link} if defined($udevinfo->{by_id_link}); | |
458 | } | |
c84106ed | 459 | |
107208bd TL |
460 | # create zpool with desired raidlevel |
461 | my $ashift = $param->{ashift} // 12; | |
c84106ed | 462 | |
107208bd TL |
463 | my $cmd = [$ZPOOL, 'create', '-o', "ashift=$ashift", $name]; |
464 | ||
465 | if ($raidlevel eq 'raid10') { | |
466 | for (my $i = 0; $i < @$devs; $i+=2) { | |
467 | push @$cmd, 'mirror', $devs->[$i], $devs->[$i+1]; | |
c84106ed | 468 | } |
107208bd TL |
469 | } elsif ($raidlevel eq 'single') { |
470 | push @$cmd, $devs->[0]; | |
59db1208 SH |
471 | } elsif ($raidlevel =~ m/^draid/) { |
472 | my $draid_cmd = $raidlevel; | |
e698cbb9 TL |
473 | $draid_cmd .= ":$$draid_config->{data}d" if $$draid_config->{data}; |
474 | $draid_cmd .= ":$$draid_config->{spares}s" if $draid_config->{spares}; | |
59db1208 | 475 | push @$cmd, $draid_cmd, @$devs; |
107208bd TL |
476 | } else { |
477 | push @$cmd, $raidlevel, @$devs; | |
478 | } | |
c84106ed | 479 | |
107208bd TL |
480 | print "# ", join(' ', @$cmd), "\n"; |
481 | run_command($cmd); | |
482 | ||
483 | $cmd = [$ZFS, 'set', "compression=$compression", $name]; | |
484 | print "# ", join(' ', @$cmd), "\n"; | |
485 | run_command($cmd); | |
c84106ed | 486 | |
107208bd TL |
487 | if (-e '/lib/systemd/system/zfs-import@.service') { |
488 | my $importunit = 'zfs-import@'. PVE::Systemd::escape_unit($name, undef) . '.service'; | |
489 | $cmd = ['systemctl', 'enable', $importunit]; | |
c84106ed DC |
490 | print "# ", join(' ', @$cmd), "\n"; |
491 | run_command($cmd); | |
107208bd | 492 | } |
c84106ed | 493 | |
107208bd | 494 | PVE::Diskmanage::udevadm_trigger($devs->@*); |
21a75847 | 495 | |
107208bd | 496 | if ($param->{add_storage}) { |
bd485fd4 AL |
497 | PVE::API2::Storage::Config->create_or_update( |
498 | $name, | |
499 | $node, | |
500 | $storage_params, | |
501 | $verify_params, | |
502 | ); | |
107208bd | 503 | } |
c84106ed DC |
504 | }; |
505 | ||
107208bd TL |
506 | return $rpcenv->fork_worker('zfscreate', $name, $user, sub { |
507 | PVE::Diskmanage::locked_disk_action($code); | |
508 | }); | |
c84106ed DC |
509 | }}); |
510 | ||
a83d8eb1 FE |
511 | __PACKAGE__->register_method ({ |
512 | name => 'delete', | |
513 | path => '{name}', | |
514 | method => 'DELETE', | |
515 | proxyto => 'node', | |
516 | protected => 1, | |
517 | permissions => { | |
518 | check => ['perm', '/', ['Sys.Modify', 'Datastore.Allocate']], | |
519 | }, | |
520 | description => "Destroy a ZFS pool.", | |
521 | parameters => { | |
522 | additionalProperties => 0, | |
523 | properties => { | |
524 | node => get_standard_option('pve-node'), | |
525 | name => get_standard_option('pve-storage-id'), | |
cde43c48 FE |
526 | 'cleanup-config' => { |
527 | description => "Marks associated storage(s) as not available on this node anymore ". | |
528 | "or removes them from the configuration (if configured for this node only).", | |
529 | type => 'boolean', | |
530 | optional => 1, | |
531 | default => 0, | |
532 | }, | |
f81908eb FE |
533 | 'cleanup-disks' => { |
534 | description => "Also wipe disks so they can be repurposed afterwards.", | |
535 | type => 'boolean', | |
536 | optional => 1, | |
537 | default => 0, | |
538 | }, | |
a83d8eb1 FE |
539 | }, |
540 | }, | |
541 | returns => { type => 'string' }, | |
542 | code => sub { | |
543 | my ($param) = @_; | |
544 | ||
545 | my $rpcenv = PVE::RPCEnvironment::get(); | |
546 | my $user = $rpcenv->get_user(); | |
547 | ||
548 | my $name = $param->{name}; | |
cde43c48 | 549 | my $node = $param->{node}; |
a83d8eb1 FE |
550 | |
551 | my $worker = sub { | |
552 | PVE::Diskmanage::locked_disk_action(sub { | |
f81908eb FE |
553 | my $to_wipe = []; |
554 | if ($param->{'cleanup-disks'}) { | |
555 | # Using -o name does not only output the name in combination with -v. | |
556 | run_command(['zpool', 'list', '-vHPL', $name], outfunc => sub { | |
557 | my ($line) = @_; | |
558 | ||
559 | my ($name) = PVE::Tools::split_list($line); | |
560 | return if $name !~ m|^/dev/.+|; | |
561 | ||
562 | my $dev = PVE::Diskmanage::verify_blockdev_path($name); | |
563 | my $wipe = $dev; | |
564 | ||
565 | $dev =~ s|^/dev/||; | |
566 | my $info = PVE::Diskmanage::get_disks($dev, 1, 1); | |
567 | die "unable to obtain information for disk '$dev'\n" if !$info->{$dev}; | |
568 | ||
569 | # Wipe whole disk if usual ZFS layout with partition 9 as ZFS reserved. | |
570 | my $parent = $info->{$dev}->{parent}; | |
571 | if ($parent && scalar(keys $info->%*) == 3) { | |
572 | $parent =~ s|^/dev/||; | |
573 | my $info9 = $info->{"${parent}9"}; | |
574 | ||
575 | $wipe = $info->{$dev}->{parent} # need leading /dev/ | |
576 | if $info9 && $info9->{used} && $info9->{used} =~ m/^ZFS reserved/; | |
577 | } | |
578 | ||
579 | push $to_wipe->@*, $wipe; | |
580 | }); | |
581 | } | |
582 | ||
a83d8eb1 FE |
583 | if (-e '/lib/systemd/system/zfs-import@.service') { |
584 | my $importunit = 'zfs-import@' . PVE::Systemd::escape_unit($name) . '.service'; | |
585 | run_command(['systemctl', 'disable', $importunit]); | |
586 | } | |
587 | ||
588 | run_command(['zpool', 'destroy', $name]); | |
f81908eb | 589 | |
cde43c48 FE |
590 | my $config_err; |
591 | if ($param->{'cleanup-config'}) { | |
592 | my $match = sub { | |
593 | my ($scfg) = @_; | |
594 | return $scfg->{type} eq 'zfspool' && $scfg->{pool} eq $name; | |
595 | }; | |
596 | eval { PVE::API2::Storage::Config->cleanup_storages_for_node($match, $node); }; | |
597 | warn $config_err = $@ if $@; | |
598 | } | |
599 | ||
f81908eb FE |
600 | eval { PVE::Diskmanage::wipe_blockdev($_) for $to_wipe->@*; }; |
601 | my $err = $@; | |
602 | PVE::Diskmanage::udevadm_trigger($to_wipe->@*); | |
603 | die "cleanup failed - $err" if $err; | |
cde43c48 FE |
604 | |
605 | die "config cleanup failed - $config_err" if $config_err; | |
a83d8eb1 FE |
606 | }); |
607 | }; | |
608 | ||
609 | return $rpcenv->fork_worker('zfsremove', $name, $user, $worker); | |
610 | }}); | |
611 | ||
c84106ed | 612 | 1; |