]> git.proxmox.com Git - pve-storage.git/blame - PVE/API2/Disks.pm
fix #3610: properly build ZFS detail tree
[pve-storage.git] / PVE / API2 / Disks.pm
CommitLineData
409f8203
DC
1package PVE::API2::Disks;
2
3use strict;
4use warnings;
5
2829e6a8 6use File::Basename;
409f8203 7use HTTP::Status qw(:constants);
d5c80a5b
TL
8
9use PVE::Diskmanage;
409f8203 10use PVE::JSONSchema qw(get_standard_option);
d5c80a5b 11use PVE::SafeSyslog;
409f8203 12
d5c80a5b 13use PVE::API2::Disks::Directory;
8b6842ca 14use PVE::API2::Disks::LVM;
0ea9f384 15use PVE::API2::Disks::LVMThin;
c84106ed 16use PVE::API2::Disks::ZFS;
8b6842ca 17
409f8203 18use PVE::RESTHandler;
409f8203
DC
19use base qw(PVE::RESTHandler);
20
8b6842ca
DC
21__PACKAGE__->register_method ({
22 subclass => "PVE::API2::Disks::LVM",
23 path => 'lvm',
24});
409f8203 25
0ea9f384
DC
26__PACKAGE__->register_method ({
27 subclass => "PVE::API2::Disks::LVMThin",
28 path => 'lvmthin',
29});
30
793d720c
DC
31__PACKAGE__->register_method ({
32 subclass => "PVE::API2::Disks::Directory",
33 path => 'directory',
34});
35
c84106ed
DC
36__PACKAGE__->register_method ({
37 subclass => "PVE::API2::Disks::ZFS",
38 path => 'zfs',
39});
40
409f8203
DC
41__PACKAGE__->register_method ({
42 name => 'index',
43 path => '',
44 method => 'GET',
45 proxyto => 'node',
46 permissions => { user => 'all' },
47 description => "Node index.",
48 parameters => {
49 additionalProperties => 0,
50 properties => {
51 node => get_standard_option('pve-node'),
52 },
53 },
54 returns => {
55 type => 'array',
56 items => {
57 type => "object",
58 properties => {},
59 },
60 links => [ { rel => 'child', href => "{name}" } ],
61 },
62 code => sub {
63 my ($param) = @_;
64
65 my $result = [
66 { name => 'list' },
67 { name => 'initgpt' },
68 { name => 'smart' },
8b6842ca 69 { name => 'lvm' },
0ea9f384 70 { name => 'lvmthin' },
793d720c 71 { name => 'directory' },
2829e6a8 72 { name => 'wipedisk' },
c84106ed 73 { name => 'zfs' },
d5c80a5b 74 ];
409f8203
DC
75
76 return $result;
77 }});
78
79__PACKAGE__->register_method ({
80 name => 'list',
81 path => 'list',
82 method => 'GET',
83 description => "List local disks.",
84 protected => 1,
85 proxyto => 'node',
86 permissions => {
1d6c5488
FE
87 check => ['or',
88 ['perm', '/', ['Sys.Audit', 'Datastore.Audit'], any => 1],
89 ['perm', '/nodes/{node}', ['Sys.Audit', 'Datastore.Audit'], any => 1],
90 ],
409f8203
DC
91 },
92 parameters => {
93 additionalProperties => 0,
94 properties => {
95 node => get_standard_option('pve-node'),
2949c537
FE
96 'include-partitions' => {
97 description => "Also include partitions.",
98 type => 'boolean',
99 optional => 1,
100 default => 0,
101 },
83bbd6f5
DC
102 skipsmart => {
103 description => "Skip smart checks.",
104 type => 'boolean',
105 optional => 1,
106 default => 0,
107 },
108 type => {
109 description => "Only list specific types of disks.",
110 type => 'string',
111 enum => ['unused', 'journal_disks'],
112 optional => 1,
113 },
409f8203
DC
114 },
115 },
116 returns => {
117 type => 'array',
118 items => {
119 type => 'object',
120 properties => {
121 devpath => {
122 type => 'string',
123 description => 'The device path',
124 },
125 used => { type => 'string', optional => 1 },
126 gpt => { type => 'boolean' },
127 size => { type => 'integer'},
128 osdid => { type => 'integer'},
129 vendor => { type => 'string', optional => 1 },
130 model => { type => 'string', optional => 1 },
131 serial => { type => 'string', optional => 1 },
132 wwn => { type => 'string', optional => 1},
133 health => { type => 'string', optional => 1},
2949c537
FE
134 parent => {
135 type => 'string',
136 description => 'For partitions only. The device path of ' .
137 'the disk the partition resides on.',
138 optional => 1
139 },
409f8203
DC
140 },
141 },
142 },
143 code => sub {
144 my ($param) = @_;
145
83bbd6f5 146 my $skipsmart = $param->{skipsmart} // 0;
2949c537 147 my $include_partitions = $param->{'include-partitions'} // 0;
83bbd6f5 148
2949c537
FE
149 my $disks = PVE::Diskmanage::get_disks(
150 undef,
151 $skipsmart,
152 $include_partitions
153 );
409f8203 154
83bbd6f5 155 my $type = $param->{type} // '';
409f8203
DC
156 my $result = [];
157
158 foreach my $disk (sort keys %$disks) {
159 my $entry = $disks->{$disk};
83bbd6f5
DC
160 if ($type eq 'journal_disks') {
161 next if $entry->{osdid} >= 0;
b2843044
FE
162 if (my $usage = $entry->{used}) {
163 next if !($usage eq 'partitions' && $entry->{gpt}
164 || $usage eq 'LVM');
165 }
83bbd6f5
DC
166 } elsif ($type eq 'unused') {
167 next if $entry->{used};
168 } elsif ($type ne '') {
169 die "internal error"; # should not happen
170 }
409f8203
DC
171 push @$result, $entry;
172 }
173 return $result;
174 }});
175
176__PACKAGE__->register_method ({
177 name => 'smart',
178 path => 'smart',
179 method => 'GET',
180 description => "Get SMART Health of a disk.",
181 protected => 1,
182 proxyto => "node",
183 permissions => {
184 check => ['perm', '/', ['Sys.Audit', 'Datastore.Audit'], any => 1],
185 },
186 parameters => {
187 additionalProperties => 0,
188 properties => {
189 node => get_standard_option('pve-node'),
190 disk => {
191 type => 'string',
192 pattern => '^/dev/[a-zA-Z0-9\/]+$',
193 description => "Block device name",
194 },
195 healthonly => {
196 type => 'boolean',
197 description => "If true returns only the health status",
198 optional => 1,
199 },
200 },
201 },
16bf963b
FG
202 returns => {
203 type => 'object',
204 properties => {
205 health => { type => 'string' },
206 type => { type => 'string', optional => 1 },
207 attributes => { type => 'array', optional => 1},
208 text => { type => 'string', optional => 1 },
209 },
210 },
409f8203
DC
211 code => sub {
212 my ($param) = @_;
213
214 my $disk = PVE::Diskmanage::verify_blockdev_path($param->{disk});
215
dd902da7 216 my $result = PVE::Diskmanage::get_smart_data($disk, $param->{healthonly});
409f8203 217
e3b02ffe 218 $result->{health} = 'UNKNOWN' if !defined $result->{health};
dd902da7 219 $result = { health => $result->{health} } if $param->{healthonly};
acd3d916 220
409f8203
DC
221 return $result;
222 }});
223
224__PACKAGE__->register_method ({
225 name => 'initgpt',
226 path => 'initgpt',
227 method => 'POST',
228 description => "Initialize Disk with GPT",
229 protected => 1,
230 proxyto => "node",
231 permissions => {
232 check => ['perm', '/', ['Sys.Modify']],
233 },
234 parameters => {
235 additionalProperties => 0,
236 properties => {
237 node => get_standard_option('pve-node'),
238 disk => {
239 type => 'string',
240 description => "Block device name",
241 pattern => '^/dev/[a-zA-Z0-9\/]+$',
242 },
243 uuid => {
244 type => 'string',
245 description => 'UUID for the GPT table',
246 pattern => '[a-fA-F0-9\-]+',
247 maxLength => 36,
248 optional => 1,
249 },
250 },
251 },
252 returns => { type => 'string' },
253 code => sub {
254 my ($param) = @_;
255
256 my $disk = PVE::Diskmanage::verify_blockdev_path($param->{disk});
257
258 my $rpcenv = PVE::RPCEnvironment::get();
259
260 my $authuser = $rpcenv->get_user();
261
262 die "disk $disk already in use\n" if PVE::Diskmanage::disk_is_used($disk);
263 my $worker = sub {
264 PVE::Diskmanage::init_disk($disk, $param->{uuid});
265 };
266
267 my $diskid = $disk;
268 $diskid =~ s|^.*/||; # remove all up to the last slash
269 return $rpcenv->fork_worker('diskinit', $diskid, $authuser, $worker);
270 }});
271
2829e6a8
FE
272__PACKAGE__->register_method ({
273 name => 'wipe_disk',
274 path => 'wipedisk',
275 method => 'PUT',
276 description => "Wipe a disk or partition.",
277 proxyto => 'node',
278 protected => 1,
279 parameters => {
280 additionalProperties => 0,
281 properties => {
282 node => get_standard_option('pve-node'),
283 disk => {
284 type => 'string',
285 description => "Block device name",
286 pattern => '^/dev/[a-zA-Z0-9\/]+$',
287 },
288 },
289 },
290 returns => { type => 'string' },
291 code => sub {
292 my ($param) = @_;
293
294 my $disk = PVE::Diskmanage::verify_blockdev_path($param->{disk});
295
296 my $mounted = PVE::Diskmanage::is_mounted($disk);
297 die "disk/partition '${mounted}' is mounted\n" if $mounted;
298
299 my $held = PVE::Diskmanage::has_holder($disk);
300 die "disk/partition '${held}' has a holder\n" if $held;
301
302 my $rpcenv = PVE::RPCEnvironment::get();
303 my $authuser = $rpcenv->get_user();
304
305 my $worker = sub { PVE::Diskmanage::wipe_blockdev($disk); };
306
307 my $basename = basename($disk); # avoid '/' in the ID
308
309 return $rpcenv->fork_worker('wipedisk', $basename, $authuser, $worker);
310 }});
311
409f8203 3121;