]>
git.proxmox.com Git - pve-storage.git/blob - PVE/API2/Disks/ZFS.pm
1 package PVE
::API2
::Disks
::ZFS
;
7 use PVE
::JSONSchema
qw(get_standard_option);
8 use PVE
::API2
::Storage
::Config
;
10 use PVE
::Tools
qw(run_command lock_file trim);
12 use PVE
::RPCEnvironment
;
15 use base
qw(PVE::RESTHandler);
17 my $ZPOOL = '/sbin/zpool';
18 my $ZFS = '/sbin/zfs';
20 __PACKAGE__-
>register_method ({
27 check
=> ['perm', '/', ['Sys.Audit', 'Datastore.Audit'], any
=> 1],
29 description
=> "List Zpools.",
31 additionalProperties
=> 0,
33 node
=> get_standard_option
('pve-node'),
71 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
77 die "zfsutils-linux not installed\n";
80 my $propnames = [qw(name size alloc free frag dedup health)];
89 my $cmd = [$ZPOOL,'list', '-HpPLo', join(',', @$propnames)];
93 run_command
($cmd, outfunc
=> sub {
96 my @props = split('\s+', trim
($line));
98 for (my $i = 0; $i < scalar(@$propnames); $i++) {
99 if ($numbers->{$propnames->[$i]}) {
100 $pool->{$propnames->[$i]} = $props[$i] + 0;
102 $pool->{$propnames->[$i]} = $props[$i];
115 if ($el->{children
} && scalar(@{$el->{children
}})) {
117 foreach my $child (@{$el->{children
}}) {
126 __PACKAGE__-
>register_method ({
133 check
=> ['perm', '/', ['Sys.Audit', 'Datastore.Audit'], any
=> 1],
135 description
=> "Get details about a zpool.",
137 additionalProperties
=> 0,
139 node
=> get_standard_option
('pve-node'),
140 name
=> get_standard_option
('pve-storage-id'),
148 description
=> 'The name of the zpool.',
152 description
=> 'The state of the zpool.',
157 description
=> 'Information about the state of the zpool.',
162 description
=> 'Information about the recommended action to fix the state.',
166 description
=> 'Information about the last/current scrub.',
170 description
=> 'Information about the errors on the zpool.',
174 description
=> "The tree of the vdevs. Depending on the configuration of the zpool, they can be nested.",
180 description
=> 'The name of the vdev.',
184 description
=> 'The state of the vdev.',
197 description
=> 'An optional message about the vdev.'
208 die "zfsutils-linux not installed\n";
211 my $cmd = [$ZPOOL, 'status', '-P', $param->{name
}];
224 run_command
($cmd, outfunc
=> sub {
227 if ($line =~ m/^\s*(\S+): (\S+.*)$/) {
229 $pool->{$curfield} = $2;
231 $config = 0 if $curfield eq 'errors';
232 } elsif (!$config && $line =~ m/^\s+(\S+.*)$/) {
233 $pool->{$curfield} .= " " . $1;
234 } elsif (!$config && $line =~ m/^\s*config:/) {
236 } elsif ($config && $line =~ m/^(\s+)(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/) {
237 my ($space, $name, $state, $read, $write, $cksum, $msg) = ($1, $2, $3, $4, $5, $6, $7);
238 if ($space =~ m/^\t(\s+)$/) {
239 my $lvl= length($1)/2; # two spaces per level
250 my $cur = pop @$stack;
252 if ($lvl > $curlvl) {
253 $cur->{children
} = [ $vdev ];
256 } elsif ($lvl == $curlvl) {
258 push @{$cur->{children
}}, $vdev;
262 while ($lvl <= $cur->{lvl
}) {
265 push @{$cur->{children
}}, $vdev;
274 # change treenodes for extjs tree
275 $pool->{name
} = delete $pool->{pool
};
281 __PACKAGE__-
>register_method ({
288 check
=> ['perm', '/', ['Sys.Modify', 'Datastore.Allocate']],
290 description
=> "Create a ZFS pool.",
292 additionalProperties
=> 0,
294 node
=> get_standard_option
('pve-node'),
295 name
=> get_standard_option
('pve-storage-id'),
298 description
=> 'The RAID level to use.',
299 enum
=> ['single', 'mirror', 'raid10', 'raidz', 'raidz2', 'raidz3'],
302 type
=> 'string', format
=> 'string-list',
303 description
=> 'The block devices you want to create the zpool on.',
311 description
=> 'Pool sector size exponent.',
315 description
=> 'The compression algorithm to use.',
316 enum
=> ['on', 'off', 'gzip', 'lz4', 'lzjb', 'zle'],
321 description
=> "Configure storage using the zpool.",
328 returns
=> { type
=> 'string' },
332 my $rpcenv = PVE
::RPCEnvironment
::get
();
333 my $user = $rpcenv->get_user();
335 my $name = $param->{name
};
336 my $devs = [PVE
::Tools
::split_list
($param->{devices
})];
337 my $raidlevel = $param->{raidlevel
};
338 my $node = $param->{node
};
339 my $ashift = $param->{ashift
} // 12;
340 my $compression = $param->{compression
} // 'on';
342 foreach my $dev (@$devs) {
343 $dev = PVE
::Diskmanage
::verify_blockdev_path
($dev);
344 PVE
::Diskmanage
::check_unused
($dev);
347 PVE
::Storage
::assert_sid_unused
($name) if $param->{add_storage
};
349 my $numdisks = scalar(@$devs);
360 die "raid10 needs an even number of disks\n"
361 if $raidlevel eq 'raid10' && $numdisks % 2 != 0;
363 die "please give only one disk for single disk mode\n"
364 if $raidlevel eq 'single' && $numdisks > 1;
366 die "$raidlevel needs at least $mindisks->{$raidlevel} disks\n"
367 if $numdisks < $mindisks->{$raidlevel};
370 PVE
::Diskmanage
::locked_disk_action
(sub {
371 # create zpool with desired raidlevel
373 my $cmd = [$ZPOOL, 'create', '-o', "ashift=$ashift", $name];
375 if ($raidlevel eq 'raid10') {
376 for (my $i = 0; $i < @$devs; $i+=2) {
377 push @$cmd, 'mirror', $devs->[$i], $devs->[$i+1];
379 } elsif ($raidlevel eq 'single') {
380 push @$cmd, $devs->[0];
382 push @$cmd, $raidlevel, @$devs;
385 print "# ", join(' ', @$cmd), "\n";
388 $cmd = [$ZFS, 'set', "compression=$compression", $name];
389 print "# ", join(' ', @$cmd), "\n";
392 if ($param->{add_storage
}) {
393 my $storage_params = {
397 content
=> 'rootdir,images',
401 PVE
::API2
::Storage
::Config-
>create($storage_params);
406 return $rpcenv->fork_worker('zfscreate', $name, $user, $worker);