]>
Commit | Line | Data |
---|---|---|
b6cf0a66 DM |
1 | package PVE::API2::Storage::Scan; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use PVE::SafeSyslog; | |
7 | use PVE::Storage; | |
6d64e9e0 | 8 | use PVE::Storage::LVMPlugin; |
b6cf0a66 DM |
9 | use HTTP::Status qw(:constants); |
10 | use PVE::JSONSchema qw(get_standard_option); | |
11 | ||
12 | use PVE::RESTHandler; | |
13 | ||
14 | use base qw(PVE::RESTHandler); | |
15 | ||
16 | __PACKAGE__->register_method ({ | |
17 | name => 'index', | |
18 | path => '', | |
19 | method => 'GET', | |
20 | description => "Index of available scan methods", | |
5f642f73 DM |
21 | permissions => { |
22 | user => 'all', | |
23 | }, | |
b6cf0a66 DM |
24 | parameters => { |
25 | additionalProperties => 0, | |
26 | properties => { | |
27 | node => get_standard_option('pve-node'), | |
28 | }, | |
29 | }, | |
30 | returns => { | |
31 | type => 'array', | |
32 | items => { | |
33 | type => "object", | |
34 | properties => { method => { type => 'string'} }, | |
35 | }, | |
36 | links => [ { rel => 'child', href => "{method}" } ], | |
37 | }, | |
38 | code => sub { | |
39 | my ($param) = @_; | |
40 | ||
41 | my $res = [ | |
42 | { method => 'lvm' }, | |
43 | { method => 'iscsi' }, | |
44 | { method => 'nfs' }, | |
3cf5e19e | 45 | { method => 'glusterfs' }, |
b6cf0a66 | 46 | { method => 'usb' }, |
584d97f6 | 47 | { method => 'zfs' }, |
b9cfb8ca | 48 | { method => 'cifs' }, |
b6cf0a66 DM |
49 | ]; |
50 | ||
51 | return $res; | |
52 | }}); | |
53 | ||
584d97f6 DM |
54 | __PACKAGE__->register_method ({ |
55 | name => 'zfsscan', | |
56 | path => 'zfs', | |
57 | method => 'GET', | |
58 | description => "Scan zfs pool list on local node.", | |
59 | protected => 1, | |
60 | proxyto => "node", | |
61 | permissions => { | |
62 | check => ['perm', '/storage', ['Datastore.Allocate']], | |
63 | }, | |
64 | parameters => { | |
65 | additionalProperties => 0, | |
66 | properties => { | |
67 | node => get_standard_option('pve-node'), | |
68 | }, | |
69 | }, | |
70 | returns => { | |
71 | type => 'array', | |
72 | items => { | |
73 | type => "object", | |
74 | properties => { | |
48dccd2f DM |
75 | pool => { |
76 | description => "ZFS pool name.", | |
77 | type => 'string', | |
78 | }, | |
584d97f6 DM |
79 | }, |
80 | }, | |
81 | }, | |
82 | code => sub { | |
83 | my ($param) = @_; | |
84 | ||
85 | return PVE::Storage::scan_zfs(); | |
86 | }}); | |
87 | ||
b6cf0a66 DM |
88 | __PACKAGE__->register_method ({ |
89 | name => 'nfsscan', | |
90 | path => 'nfs', | |
91 | method => 'GET', | |
92 | description => "Scan remote NFS server.", | |
93 | protected => 1, | |
94 | proxyto => "node", | |
5f642f73 DM |
95 | permissions => { |
96 | check => ['perm', '/storage', ['Datastore.Allocate']], | |
97 | }, | |
b6cf0a66 DM |
98 | parameters => { |
99 | additionalProperties => 0, | |
100 | properties => { | |
101 | node => get_standard_option('pve-node'), | |
102 | server => { type => 'string', format => 'pve-storage-server' }, | |
103 | }, | |
104 | }, | |
105 | returns => { | |
106 | type => 'array', | |
107 | items => { | |
108 | type => "object", | |
109 | properties => { | |
48dccd2f DM |
110 | path => { |
111 | description => "The exported path.", | |
112 | type => 'string', | |
113 | }, | |
114 | options => { | |
115 | description => "NFS export options.", | |
116 | type => 'string', | |
117 | }, | |
b6cf0a66 DM |
118 | }, |
119 | }, | |
120 | }, | |
121 | code => sub { | |
122 | my ($param) = @_; | |
123 | ||
124 | my $server = $param->{server}; | |
125 | my $res = PVE::Storage::scan_nfs($server); | |
126 | ||
127 | my $data = []; | |
128 | foreach my $k (keys %$res) { | |
129 | push @$data, { path => $k, options => $res->{$k} }; | |
130 | } | |
131 | return $data; | |
132 | }}); | |
133 | ||
b9cfb8ca WL |
134 | __PACKAGE__->register_method ({ |
135 | name => 'cifsscan', | |
136 | path => 'cifs', | |
137 | method => 'GET', | |
138 | description => "Scan remote CIFS server.", | |
139 | protected => 1, | |
140 | proxyto => "node", | |
141 | permissions => { | |
142 | check => ['perm', '/storage', ['Datastore.Allocate']], | |
143 | }, | |
144 | parameters => { | |
145 | additionalProperties => 0, | |
146 | properties => { | |
147 | node => get_standard_option('pve-node'), | |
148 | server => { type => 'string', format => 'pve-storage-server' }, | |
149 | username => { type => 'string', optional => 1 }, | |
150 | password => { type => 'string', optional => 1 }, | |
151 | domain => { type => 'string', optional => 1 }, | |
152 | }, | |
153 | }, | |
154 | returns => { | |
155 | type => 'array', | |
156 | items => { | |
157 | type => "object", | |
158 | properties => { | |
48dccd2f DM |
159 | share => { |
160 | description => "The cifs share name.", | |
161 | type => 'string', | |
162 | }, | |
163 | description => { | |
164 | description => "Descriptive text from server.", | |
165 | type => 'string', | |
166 | }, | |
b9cfb8ca WL |
167 | }, |
168 | }, | |
169 | }, | |
170 | code => sub { | |
171 | my ($param) = @_; | |
172 | ||
173 | my $server = $param->{server}; | |
174 | ||
175 | my $username = $param->{username}; | |
176 | my $password = $param->{password}; | |
177 | my $domain = $param->{domain}; | |
178 | ||
179 | my $res = PVE::Storage::scan_cifs($server, $username, $password, $domain); | |
180 | ||
181 | my $data = []; | |
182 | foreach my $k (keys %$res) { | |
183 | next if $k =~ m/NT_STATUS_/; | |
184 | push @$data, { share => $k, description => $res->{$k} }; | |
185 | } | |
186 | ||
187 | return $data; | |
188 | }}); | |
189 | ||
3cf5e19e DM |
190 | # Note: GlusterFS currently does not have an equivalent of showmount. |
191 | # As workaround, we simply use nfs showmount. | |
192 | # see http://www.gluster.org/category/volumes/ | |
193 | ||
194 | __PACKAGE__->register_method ({ | |
195 | name => 'glusterfsscan', | |
196 | path => 'glusterfs', | |
197 | method => 'GET', | |
198 | description => "Scan remote GlusterFS server.", | |
199 | protected => 1, | |
200 | proxyto => "node", | |
201 | permissions => { | |
202 | check => ['perm', '/storage', ['Datastore.Allocate']], | |
203 | }, | |
204 | parameters => { | |
205 | additionalProperties => 0, | |
206 | properties => { | |
207 | node => get_standard_option('pve-node'), | |
208 | server => { type => 'string', format => 'pve-storage-server' }, | |
209 | }, | |
210 | }, | |
211 | returns => { | |
212 | type => 'array', | |
213 | items => { | |
214 | type => "object", | |
215 | properties => { | |
48dccd2f DM |
216 | volname => { |
217 | description => "The volume name.", | |
218 | type => 'string', | |
219 | }, | |
3cf5e19e DM |
220 | }, |
221 | }, | |
222 | }, | |
223 | code => sub { | |
224 | my ($param) = @_; | |
225 | ||
226 | my $server = $param->{server}; | |
227 | my $res = PVE::Storage::scan_nfs($server); | |
228 | ||
229 | my $data = []; | |
230 | foreach my $path (keys %$res) { | |
231 | if ($path =~ m!^/([^\s/]+)$!) { | |
232 | push @$data, { volname => $1 }; | |
233 | } | |
234 | } | |
235 | return $data; | |
236 | }}); | |
237 | ||
b6cf0a66 DM |
238 | __PACKAGE__->register_method ({ |
239 | name => 'iscsiscan', | |
240 | path => 'iscsi', | |
241 | method => 'GET', | |
242 | description => "Scan remote iSCSI server.", | |
243 | protected => 1, | |
244 | proxyto => "node", | |
5f642f73 DM |
245 | permissions => { |
246 | check => ['perm', '/storage', ['Datastore.Allocate']], | |
247 | }, | |
b6cf0a66 DM |
248 | parameters => { |
249 | additionalProperties => 0, | |
250 | properties => { | |
251 | node => get_standard_option('pve-node'), | |
252 | portal => { type => 'string', format => 'pve-storage-portal-dns' }, | |
253 | }, | |
254 | }, | |
255 | returns => { | |
256 | type => 'array', | |
257 | items => { | |
258 | type => "object", | |
259 | properties => { | |
48dccd2f DM |
260 | target => { |
261 | description => "The iSCSI target name.", | |
262 | type => 'string', | |
263 | }, | |
264 | portal => { | |
265 | description => "The iSCSI portal name.", | |
266 | type => 'string', | |
267 | }, | |
b6cf0a66 DM |
268 | }, |
269 | }, | |
270 | }, | |
271 | code => sub { | |
272 | my ($param) = @_; | |
273 | ||
274 | my $res = PVE::Storage::scan_iscsi($param->{portal}); | |
275 | ||
276 | my $data = []; | |
277 | foreach my $k (keys %$res) { | |
278 | push @$data, { target => $k, portal => join(',', @{$res->{$k}}) }; | |
279 | } | |
280 | ||
281 | return $data; | |
282 | }}); | |
283 | ||
284 | __PACKAGE__->register_method ({ | |
285 | name => 'lvmscan', | |
286 | path => 'lvm', | |
287 | method => 'GET', | |
288 | description => "List local LVM volume groups.", | |
289 | protected => 1, | |
290 | proxyto => "node", | |
5f642f73 DM |
291 | permissions => { |
292 | check => ['perm', '/storage', ['Datastore.Allocate']], | |
293 | }, | |
b6cf0a66 DM |
294 | parameters => { |
295 | additionalProperties => 0, | |
296 | properties => { | |
297 | node => get_standard_option('pve-node'), | |
298 | }, | |
299 | }, | |
300 | returns => { | |
301 | type => 'array', | |
302 | items => { | |
303 | type => "object", | |
48dccd2f DM |
304 | properties => { |
305 | vg => { | |
306 | description => "The LVM logical volume group name.", | |
307 | type => 'string', | |
308 | }, | |
b6cf0a66 DM |
309 | }, |
310 | }, | |
311 | }, | |
312 | code => sub { | |
313 | my ($param) = @_; | |
314 | ||
6d64e9e0 | 315 | my $res = PVE::Storage::LVMPlugin::lvm_vgs(); |
b6cf0a66 DM |
316 | return PVE::RESTHandler::hash_to_array($res, 'vg'); |
317 | }}); | |
318 | ||
d0ea89e5 | 319 | __PACKAGE__->register_method ({ |
668f6d9f | 320 | name => 'lvmthinscan', |
d0ea89e5 DC |
321 | path => 'lvmthin', |
322 | method => 'GET', | |
323 | description => "List local LVM Thin Pools.", | |
324 | protected => 1, | |
325 | proxyto => "node", | |
326 | permissions => { | |
327 | check => ['perm', '/storage', ['Datastore.Allocate']], | |
328 | }, | |
329 | parameters => { | |
330 | additionalProperties => 0, | |
331 | properties => { | |
332 | node => get_standard_option('pve-node'), | |
333 | vg => { | |
334 | type => 'string', | |
335 | pattern => '[a-zA-Z0-9\.\+\_][a-zA-Z0-9\.\+\_\-]+', # see lvm(8) manpage | |
336 | maxLength => 100, | |
337 | }, | |
338 | }, | |
339 | }, | |
340 | returns => { | |
341 | type => 'array', | |
342 | items => { | |
343 | type => "object", | |
344 | properties => { | |
48dccd2f DM |
345 | lv => { |
346 | description => "The LVM Thin Pool name (LVM logical volume).", | |
347 | type => 'string', | |
348 | }, | |
d0ea89e5 DC |
349 | }, |
350 | }, | |
351 | }, | |
352 | code => sub { | |
353 | my ($param) = @_; | |
668f6d9f | 354 | |
d0ea89e5 DC |
355 | return PVE::Storage::LvmThinPlugin::list_thinpools($param->{vg}); |
356 | }}); | |
357 | ||
b6cf0a66 DM |
358 | __PACKAGE__->register_method ({ |
359 | name => 'usbscan', | |
360 | path => 'usb', | |
361 | method => 'GET', | |
362 | description => "List local USB devices.", | |
363 | protected => 1, | |
364 | proxyto => "node", | |
5f642f73 DM |
365 | permissions => { |
366 | check => ['perm', '/', ['Sys.Modify']], | |
367 | }, | |
b6cf0a66 DM |
368 | parameters => { |
369 | additionalProperties => 0, | |
370 | properties => { | |
371 | node => get_standard_option('pve-node'), | |
372 | }, | |
373 | }, | |
374 | returns => { | |
375 | type => 'array', | |
376 | items => { | |
377 | type => "object", | |
378 | properties => { | |
379 | busnum => { type => 'integer'}, | |
380 | devnum => { type => 'integer'}, | |
381 | port => { type => 'integer'}, | |
382 | usbpath => { type => 'string', optional => 1}, | |
383 | level => { type => 'integer'}, | |
384 | class => { type => 'integer'}, | |
385 | vendid => { type => 'string'}, | |
386 | prodid => { type => 'string'}, | |
387 | speed => { type => 'string'}, | |
388 | ||
389 | product => { type => 'string', optional => 1 }, | |
390 | serial => { type => 'string', optional => 1 }, | |
391 | manufacturer => { type => 'string', optional => 1 }, | |
392 | }, | |
393 | }, | |
394 | }, | |
395 | code => sub { | |
396 | my ($param) = @_; | |
397 | ||
398 | return PVE::Storage::scan_usb(); | |
399 | }}); | |
400 | ||
401 | 1; |