]> git.proxmox.com Git - pve-storage.git/blob - PVE/API2/Storage/Scan.pm
15b39b50eb76a284797a73750fd7adf343dd8514
[pve-storage.git] / PVE / API2 / Storage / Scan.pm
1 package PVE::API2::Storage::Scan;
2
3 use strict;
4 use warnings;
5
6 # NOTE: This API endpoints are mounted by pve-manager's API2::Node module and pvesm CLI
7
8 use PVE::JSONSchema qw(get_standard_option);
9 use PVE::RESTHandler;
10 use PVE::SafeSyslog;
11 use PVE::Storage::LVMPlugin;
12 use PVE::Storage;
13 use PVE::SysFSTools;
14
15 use base qw(PVE::RESTHandler);
16
17 __PACKAGE__->register_method({
18 name => 'index',
19 path => '',
20 method => 'GET',
21 description => "Index of available scan methods",
22 permissions => {
23 user => 'all',
24 },
25 parameters => {
26 additionalProperties => 0,
27 properties => {
28 node => get_standard_option('pve-node'),
29 },
30 },
31 returns => {
32 type => 'array',
33 items => {
34 type => "object",
35 properties => {
36 method => { type => 'string'},
37 },
38 },
39 links => [ { rel => 'child', href => "{method}" } ],
40 },
41 code => sub {
42 my ($param) = @_;
43
44 my $res = [
45 { method => 'cifs' },
46 { method => 'glusterfs' },
47 { method => 'iscsi' },
48 { method => 'lvm' },
49 { method => 'nfs' },
50 { method => 'pbs' },
51 # FIXME: remove with 7.0 (replaced by /nodes/<node>/hardware/usb)
52 { method => 'usb' },
53 { method => 'zfs' },
54 ];
55
56 return $res;
57 }});
58
59 __PACKAGE__->register_method({
60 name => 'nfsscan',
61 path => 'nfs',
62 method => 'GET',
63 description => "Scan remote NFS server.",
64 protected => 1,
65 proxyto => "node",
66 permissions => {
67 check => ['perm', '/storage', ['Datastore.Allocate']],
68 },
69 parameters => {
70 additionalProperties => 0,
71 properties => {
72 node => get_standard_option('pve-node'),
73 server => {
74 description => "The server address (name or IP).",
75 type => 'string', format => 'pve-storage-server',
76 },
77 },
78 },
79 returns => {
80 type => 'array',
81 items => {
82 type => "object",
83 properties => {
84 path => {
85 description => "The exported path.",
86 type => 'string',
87 },
88 options => {
89 description => "NFS export options.",
90 type => 'string',
91 },
92 },
93 },
94 },
95 code => sub {
96 my ($param) = @_;
97
98 my $server = $param->{server};
99 my $res = PVE::Storage::scan_nfs($server);
100
101 my $data = [];
102 foreach my $k (sort keys %$res) {
103 push @$data, { path => $k, options => $res->{$k} };
104 }
105 return $data;
106 }});
107
108 __PACKAGE__->register_method({
109 name => 'cifsscan',
110 path => 'cifs',
111 method => 'GET',
112 description => "Scan remote CIFS server.",
113 protected => 1,
114 proxyto => "node",
115 permissions => {
116 check => ['perm', '/storage', ['Datastore.Allocate']],
117 },
118 parameters => {
119 additionalProperties => 0,
120 properties => {
121 node => get_standard_option('pve-node'),
122 server => {
123 description => "The server address (name or IP).",
124 type => 'string', format => 'pve-storage-server',
125 },
126 username => {
127 description => "User name.",
128 type => 'string',
129 optional => 1,
130 },
131 password => {
132 description => "User password.",
133 type => 'string',
134 optional => 1,
135 },
136 domain => {
137 description => "SMB domain (Workgroup).",
138 type => 'string',
139 optional => 1,
140 },
141 },
142 },
143 returns => {
144 type => 'array',
145 items => {
146 type => "object",
147 properties => {
148 share => {
149 description => "The cifs share name.",
150 type => 'string',
151 },
152 description => {
153 description => "Descriptive text from server.",
154 type => 'string',
155 },
156 },
157 },
158 },
159 code => sub {
160 my ($param) = @_;
161
162 my $server = $param->{server};
163
164 my $username = $param->{username};
165 my $password = $param->{password};
166 my $domain = $param->{domain};
167
168 my $res = PVE::Storage::scan_cifs($server, $username, $password, $domain);
169
170 my $data = [];
171 foreach my $k (sort keys %$res) {
172 next if $k =~ m/NT_STATUS_/;
173 push @$data, { share => $k, description => $res->{$k} };
174 }
175
176 return $data;
177 }});
178
179 __PACKAGE__->register_method({
180 name => 'pbsscan',
181 path => 'pbs',
182 method => 'GET',
183 description => "Scan remote Proxmox Backup Server.",
184 protected => 1,
185 proxyto => "node",
186 permissions => {
187 check => ['perm', '/storage', ['Datastore.Allocate']],
188 },
189 parameters => {
190 additionalProperties => 0,
191 properties => {
192 node => get_standard_option('pve-node'),
193 server => {
194 description => "The server address (name or IP).",
195 type => 'string', format => 'pve-storage-server',
196 },
197 username => {
198 description => "User-name or API token-ID.",
199 type => 'string',
200 },
201 password => {
202 description => "User password or API token secret.",
203 type => 'string',
204 },
205 fingerprint => get_standard_option('fingerprint-sha256', {
206 optional => 1,
207 }),
208 port => {
209 description => "Optional port.",
210 type => 'integer',
211 minimum => 1,
212 maximum => 65535,
213 default => 8007,
214 optional => 1,
215 },
216 },
217 },
218 returns => {
219 type => 'array',
220 items => {
221 type => "object",
222 properties => {
223 store => {
224 description => "The datastore name.",
225 type => 'string',
226 },
227 comment => {
228 description => "Comment from server.",
229 type => 'string',
230 optional => 1,
231 },
232 },
233 },
234 },
235 code => sub {
236 my ($param) = @_;
237
238 my $password = delete $param->{password};
239
240 return PVE::Storage::PBSPlugin::scan_datastores($param, $password);
241 }
242 });
243
244 # Note: GlusterFS currently does not have an equivalent of showmount.
245 # As workaround, we simply use nfs showmount.
246 # see http://www.gluster.org/category/volumes/
247 __PACKAGE__->register_method({
248 name => 'glusterfsscan',
249 path => 'glusterfs',
250 method => 'GET',
251 description => "Scan remote GlusterFS server.",
252 protected => 1,
253 proxyto => "node",
254 permissions => {
255 check => ['perm', '/storage', ['Datastore.Allocate']],
256 },
257 parameters => {
258 additionalProperties => 0,
259 properties => {
260 node => get_standard_option('pve-node'),
261 server => {
262 description => "The server address (name or IP).",
263 type => 'string', format => 'pve-storage-server',
264 },
265 },
266 },
267 returns => {
268 type => 'array',
269 items => {
270 type => "object",
271 properties => {
272 volname => {
273 description => "The volume name.",
274 type => 'string',
275 },
276 },
277 },
278 },
279 code => sub {
280 my ($param) = @_;
281
282 my $server = $param->{server};
283 my $res = PVE::Storage::scan_nfs($server);
284
285 my $data = [];
286 foreach my $path (sort keys %$res) {
287 if ($path =~ m!^/([^\s/]+)$!) {
288 push @$data, { volname => $1 };
289 }
290 }
291 return $data;
292 }});
293
294 __PACKAGE__->register_method({
295 name => 'iscsiscan',
296 path => 'iscsi',
297 method => 'GET',
298 description => "Scan remote iSCSI server.",
299 protected => 1,
300 proxyto => "node",
301 permissions => {
302 check => ['perm', '/storage', ['Datastore.Allocate']],
303 },
304 parameters => {
305 additionalProperties => 0,
306 properties => {
307 node => get_standard_option('pve-node'),
308 portal => {
309 description => "The iSCSI portal (IP or DNS name with optional port).",
310 type => 'string', format => 'pve-storage-portal-dns',
311 },
312 },
313 },
314 returns => {
315 type => 'array',
316 items => {
317 type => "object",
318 properties => {
319 target => {
320 description => "The iSCSI target name.",
321 type => 'string',
322 },
323 portal => {
324 description => "The iSCSI portal name.",
325 type => 'string',
326 },
327 },
328 },
329 },
330 code => sub {
331 my ($param) = @_;
332
333 my $res = PVE::Storage::scan_iscsi($param->{portal});
334
335 my $data = [];
336 foreach my $k (sort keys %$res) {
337 push @$data, { target => $k, portal => join(',', @{$res->{$k}}) };
338 }
339
340 return $data;
341 }});
342
343 __PACKAGE__->register_method({
344 name => 'lvmscan',
345 path => 'lvm',
346 method => 'GET',
347 description => "List local LVM volume groups.",
348 protected => 1,
349 proxyto => "node",
350 permissions => {
351 check => ['perm', '/storage', ['Datastore.Allocate']],
352 },
353 parameters => {
354 additionalProperties => 0,
355 properties => {
356 node => get_standard_option('pve-node'),
357 },
358 },
359 returns => {
360 type => 'array',
361 items => {
362 type => "object",
363 properties => {
364 vg => {
365 description => "The LVM logical volume group name.",
366 type => 'string',
367 },
368 },
369 },
370 },
371 code => sub {
372 my ($param) = @_;
373
374 my $res = PVE::Storage::LVMPlugin::lvm_vgs();
375 return PVE::RESTHandler::hash_to_array($res, 'vg');
376 }});
377
378 __PACKAGE__->register_method({
379 name => 'lvmthinscan',
380 path => 'lvmthin',
381 method => 'GET',
382 description => "List local LVM Thin Pools.",
383 protected => 1,
384 proxyto => "node",
385 permissions => {
386 check => ['perm', '/storage', ['Datastore.Allocate']],
387 },
388 parameters => {
389 additionalProperties => 0,
390 properties => {
391 node => get_standard_option('pve-node'),
392 vg => {
393 type => 'string',
394 pattern => '[a-zA-Z0-9\.\+\_][a-zA-Z0-9\.\+\_\-]+', # see lvm(8) manpage
395 maxLength => 100,
396 },
397 },
398 },
399 returns => {
400 type => 'array',
401 items => {
402 type => "object",
403 properties => {
404 lv => {
405 description => "The LVM Thin Pool name (LVM logical volume).",
406 type => 'string',
407 },
408 },
409 },
410 },
411 code => sub {
412 my ($param) = @_;
413
414 return PVE::Storage::LvmThinPlugin::list_thinpools($param->{vg});
415 }});
416
417 __PACKAGE__->register_method({
418 name => 'zfsscan',
419 path => 'zfs',
420 method => 'GET',
421 description => "Scan zfs pool list on local node.",
422 protected => 1,
423 proxyto => "node",
424 permissions => {
425 check => ['perm', '/storage', ['Datastore.Allocate']],
426 },
427 parameters => {
428 additionalProperties => 0,
429 properties => {
430 node => get_standard_option('pve-node'),
431 },
432 },
433 returns => {
434 type => 'array',
435 items => {
436 type => "object",
437 properties => {
438 pool => {
439 description => "ZFS pool name.",
440 type => 'string',
441 },
442 },
443 },
444 },
445 code => sub {
446 my ($param) = @_;
447
448 return PVE::Storage::scan_zfs();
449 }});
450
451 # FIXME: remove with 7.0 (replaced by /nodes/<node>/hardware/usb)
452 __PACKAGE__->register_method({
453 name => 'usbscan',
454 path => 'usb',
455 method => 'GET',
456 description => "List local USB devices.",
457 protected => 1,
458 proxyto => "node",
459 permissions => {
460 check => ['perm', '/', ['Sys.Modify']],
461 },
462 parameters => {
463 additionalProperties => 0,
464 properties => {
465 node => get_standard_option('pve-node'),
466 },
467 },
468 returns => {
469 type => 'array',
470 items => {
471 type => "object",
472 properties => {
473 busnum => { type => 'integer'},
474 class => { type => 'integer'},
475 devnum => { type => 'integer'},
476 level => { type => 'integer'},
477 manufacturer => { type => 'string', optional => 1 },
478 port => { type => 'integer'},
479 prodid => { type => 'string'},
480 product => { type => 'string', optional => 1 },
481 serial => { type => 'string', optional => 1 },
482 speed => { type => 'string'},
483 usbpath => { type => 'string', optional => 1},
484 vendid => { type => 'string'},
485 },
486 },
487 },
488 code => sub {
489 my ($param) = @_;
490
491 return PVE::SysFSTools::scan_usb();
492 }});
493
494 1;