]>
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'),
150 die "zfsutils-linux not installed\n";
153 my $cmd = [$ZPOOL, 'status', '-P', $param->{name
}];
166 run_command
($cmd, outfunc
=> sub {
169 if ($line =~ m/^\s*(\S+): (\S+.*)$/) {
171 $pool->{$curfield} = $2;
173 $config = 0 if $curfield eq 'errors';
174 } elsif (!$config && $line =~ m/^\s+(\S+.*)$/) {
175 $pool->{$curfield} .= " " . $1;
176 } elsif (!$config && $line =~ m/^\s*config:/) {
178 } elsif ($config && $line =~ m/^(\s+)(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*(.*)$/) {
179 my ($space, $name, $state, $read, $write, $cksum, $msg) = ($1, $2, $3, $4, $5, $6, $7);
180 if ($space =~ m/^\t(\s+)$/) {
181 my $lvl= length($1)/2; # two spaces per level
192 my $cur = pop @$stack;
194 if ($lvl > $curlvl) {
195 $cur->{children
} = [ $vdev ];
198 } elsif ($lvl == $curlvl) {
200 push @{$cur->{children
}}, $vdev;
204 while ($lvl <= $cur->{lvl
}) {
207 push @{$cur->{children
}}, $vdev;
216 # change treenodes for extjs tree
217 $pool->{name
} = delete $pool->{pool
};
223 __PACKAGE__-
>register_method ({
230 check
=> ['perm', '/', ['Sys.Modify', 'Datastore.Allocate']],
232 description
=> "Create a ZFS pool.",
234 additionalProperties
=> 0,
236 node
=> get_standard_option
('pve-node'),
237 name
=> get_standard_option
('pve-storage-id'),
240 description
=> 'The RAID level to use, for single disk, use mirror.',
241 enum
=> ['mirror', 'raid10', 'raidz', 'raidz2', 'raidz3'],
244 type
=> 'string', format
=> 'string-list',
245 description
=> 'The block devices you want to create the zpool on.',
253 description
=> 'Pool sector size exponent.',
257 description
=> 'The compression algorithm to use.',
258 enum
=> ['on', 'off', 'gzip', 'lz4', 'lzjb', 'zle'],
263 description
=> "Configure storage using the zpool.",
270 returns
=> { type
=> 'string' },
274 my $rpcenv = PVE
::RPCEnvironment
::get
();
275 my $user = $rpcenv->get_user();
277 my $name = $param->{name
};
278 my $devs = [PVE
::Tools
::split_list
($param->{devices
})];
279 my $raidlvl = $param->{raidlevel
};
280 my $node = $param->{node
};
281 my $ashift = $param->{ashift
} // 12;
282 my $compression = $param->{compression
} // 'on';
284 foreach my $dev (@$devs) {
285 $dev = PVE
::Diskmanage
::verify_blockdev_path
($dev);
286 die "device $dev is already in use\n" if PVE
::Diskmanage
::disk_is_used
($dev);
289 my $cfg = PVE
::Storage
::config
();
291 if (my $scfg = PVE
::Storage
::storage_config
($cfg, $name, 1)) {
292 die "storage ID '$name' already defined\n";
295 my $numdisks = scalar(@$devs);
305 die "raid10 needs an even number of disks\n"
306 if $raidlvl eq 'raid10' && $numdisks % 2 != 0;
308 die "$raidlvl needs at least $mindisks->{$raidlvl} disks\n"
309 if $numdisks < $mindisks->{$raidlvl};
312 lock_file
('/run/lock/pve-diskmanage.lck', 10, sub {
313 # create zpool with desired raidlevel
315 my $cmd = [$ZPOOL, 'create', '-o', "ashift=$ashift", $name];
317 if ($raidlvl eq 'raid10') {
318 for (my $i = 0; $i < @$devs; $i+=2) {
319 push @$cmd, 'mirror', $devs->[$i], $devs->[$i+1];
322 push @$cmd, $raidlvl, @$devs;
325 print "# ", join(' ', @$cmd), "\n";
328 $cmd = [$ZFS, 'set', "compression=$compression", $name];
329 print "# ", join(' ', @$cmd), "\n";
332 if ($param->{add_storage
}) {
333 my $storage_params = {
337 content
=> 'rootdir,images',
341 PVE
::API2
::Storage
::Config-
>create($storage_params);
348 return $rpcenv->fork_worker('zfscreate', $name, $user, $worker);