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