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