]> git.proxmox.com Git - pve-storage.git/blame - PVE/API2/Storage/Content.pm
API: add scan method for glusterfs
[pve-storage.git] / PVE / API2 / Storage / Content.pm
CommitLineData
b6cf0a66
DM
1package PVE::API2::Storage::Content;
2
3use strict;
4use warnings;
5
6use PVE::SafeSyslog;
7use PVE::Cluster qw(cfs_read_file);
8use PVE::Storage;
9use PVE::INotify;
10use PVE::Exception qw(raise_param_exc);
11use PVE::RPCEnvironment;
12use PVE::RESTHandler;
13use PVE::JSONSchema qw(get_standard_option);
14
15use base qw(PVE::RESTHandler);
16
17my @ctypes = qw(images vztmpl iso backup);
18
19__PACKAGE__->register_method ({
20 name => 'index',
21 path => '',
22 method => 'GET',
23 description => "List storage content.",
5f642f73
DM
24 permissions => {
25 check => ['perm', '/storage/{storage}', ['Datastore.Audit', 'Datastore.AllocateSpace'], any => 1],
26 },
b6cf0a66
DM
27 protected => 1,
28 proxyto => 'node',
29 parameters => {
30 additionalProperties => 0,
31 properties => {
32 node => get_standard_option('pve-node'),
33 storage => get_standard_option('pve-storage-id'),
34 content => {
35 description => "Only list content of this type.",
36 type => 'string', format => 'pve-storage-content',
37 optional => 1,
38 },
39 vmid => get_standard_option
40 ('pve-vmid', {
41 description => "Only list images for this VM",
42 optional => 1,
43 }),
44 },
45 },
46 returns => {
47 type => 'array',
48 items => {
49 type => "object",
50 properties => {
51 volid => {
52 type => 'string'
53 }
54 },
55 },
56 links => [ { rel => 'child', href => "{volid}" } ],
57 },
58 code => sub {
59 my ($param) = @_;
60
b8744249
DM
61 my $rpcenv = PVE::RPCEnvironment::get();
62
63 my $authuser = $rpcenv->get_user();
64
b6cf0a66
DM
65 my $cts = $param->{content} ? [ $param->{content} ] : [ @ctypes ];
66
67 my $storeid = $param->{storage};
68
69 my $cfg = cfs_read_file("storage.cfg");
70
b8744249 71 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
b6cf0a66
DM
72
73 my $res = [];
74 foreach my $ct (@$cts) {
75 my $data;
568de3d1 76 if ($ct eq 'images' || defined($param->{vmid})) {
b6cf0a66
DM
77 $data = PVE::Storage::vdisk_list ($cfg, $storeid, $param->{vmid});
78 } elsif ($ct eq 'iso') {
568de3d1 79 $data = PVE::Storage::template_list ($cfg, $storeid, 'iso');
b6cf0a66 80 } elsif ($ct eq 'vztmpl') {
568de3d1 81 $data = PVE::Storage::template_list ($cfg, $storeid, 'vztmpl');
b6cf0a66 82 } elsif ($ct eq 'backup') {
568de3d1 83 $data = PVE::Storage::template_list ($cfg, $storeid, 'backup');
b6cf0a66
DM
84 }
85
86 next if !$data || !$data->{$storeid};
87
88 foreach my $item (@{$data->{$storeid}}) {
b8744249
DM
89 eval { $rpcenv->check_volume_access($authuser, $cfg, undef, $item->{volid}); };
90 next if $@;
87191fbe 91 $item->{content} = $ct;
b6cf0a66
DM
92 push @$res, $item;
93 }
94 }
95
96 return $res;
97 }});
98
99__PACKAGE__->register_method ({
100 name => 'create',
101 path => '',
102 method => 'POST',
103 description => "Allocate disk images.",
5f642f73
DM
104 permissions => {
105 check => ['perm', '/storage/{storage}', ['Datastore.AllocateSpace']],
106 },
b6cf0a66
DM
107 protected => 1,
108 proxyto => 'node',
109 parameters => {
110 additionalProperties => 0,
111 properties => {
112 node => get_standard_option('pve-node'),
113 storage => get_standard_option('pve-storage-id'),
114 filename => {
03f03009 115 description => "The name of the file to create.",
b6cf0a66
DM
116 type => 'string',
117 },
118 vmid => get_standard_option('pve-vmid', { description => "Specify owner VM" } ),
119 size => {
120 description => "Size in kilobyte (1024 bytes). Optional suffixes 'M' (megabyte, 1024K) and 'G' (gigabyte, 1024M)",
121 type => 'string',
122 pattern => '\d+[MG]?',
123 },
124 'format' => {
125 type => 'string',
126 enum => ['raw', 'qcow2'],
127 requires => 'size',
128 optional => 1,
129 },
130 },
131 },
132 returns => {
133 description => "Volume identifier",
134 type => 'string',
135 },
136 code => sub {
137 my ($param) = @_;
138
139 my $storeid = $param->{storage};
140 my $name = $param->{filename};
141 my $sizestr = $param->{size};
142
143 my $size;
144 if ($sizestr =~ m/^\d+$/) {
145 $size = $sizestr;
146 } elsif ($sizestr =~ m/^(\d+)M$/) {
147 $size = $1 * 1024;
148 } elsif ($sizestr =~ m/^(\d+)G$/) {
149 $size = $1 * 1024 * 1024;
150 } else {
151 raise_param_exc({ size => "unable to parse size '$sizestr'" });
152 }
153
154 # extract FORMAT from name
155 if ($name =~ m/\.(raw|qcow2)$/) {
156 my $fmt = $1;
157
158 raise_param_exc({ format => "different storage formats ($param->{format} != $fmt)" })
159 if $param->{format} && $param->{format} ne $fmt;
160
161 $param->{format} = $fmt;
162 }
163
164 my $cfg = cfs_read_file('storage.cfg');
165
166 my $volid = PVE::Storage::vdisk_alloc ($cfg, $storeid, $param->{vmid},
167 $param->{format},
168 $name, $size);
169
170 return $volid;
171 }});
172
173# we allow to pass volume names (without storage prefix) if the storage
174# is specified as separate parameter.
175my $real_volume_id = sub {
176 my ($storeid, $volume) = @_;
177
178 my $volid;
179
180 if ($volume =~ m/:/) {
181 eval {
182 my ($sid, $volname) = PVE::Storage::parse_volume_id ($volume);
183 raise_param_exc({ storage => "storage ID missmatch" })
184 if $storeid && $sid ne $storeid;
185 $volid = $volume;
b755bdb0 186 $storeid = $sid;
b6cf0a66
DM
187 };
188 raise_param_exc({ volume => $@}) if $@;
189
190 } else {
191 raise_param_exc({ volume => "no storage speficied - incomplete volume ID" })
192 if !$storeid;
193
194 $volid = "$storeid:$volume";
195 }
196
b755bdb0 197 return wantarray ? ($volid, $storeid) : $volid;
b6cf0a66
DM
198};
199
200__PACKAGE__->register_method ({
201 name => 'info',
202 path => '{volume}',
203 method => 'GET',
204 description => "Get volume attributes",
5f642f73 205 permissions => {
b8744249 206 description => "You need read access for the volume.",
b755bdb0 207 user => 'all',
5f642f73 208 },
b6cf0a66
DM
209 protected => 1,
210 proxyto => 'node',
211 parameters => {
212 additionalProperties => 0,
213 properties => {
214 node => get_standard_option('pve-node'),
215 storage => get_standard_option('pve-storage-id', { optional => 1 }),
216 volume => {
217 description => "Volume identifier",
218 type => 'string',
219 },
220 },
221 },
222 returns => { type => 'object' },
223 code => sub {
224 my ($param) = @_;
225
b755bdb0
DM
226 my $rpcenv = PVE::RPCEnvironment::get();
227 my $authuser = $rpcenv->get_user();
228
229 my ($volid, $storeid) = &$real_volume_id($param->{storage}, $param->{volume});
230
b6cf0a66
DM
231 my $cfg = cfs_read_file('storage.cfg');
232
b8744249
DM
233 $rpcenv->check_volume_access($authuser, $cfg, undef, $volid);
234
b6cf0a66
DM
235 my $path = PVE::Storage::path($cfg, $volid);
236 my ($size, $format, $used) = PVE::Storage::file_size_info ($path);
237
238 # fixme: return more attributes?
239 return {
240 path => $path,
241 size => $size,
242 used => $used,
243 };
244 }});
245
246__PACKAGE__->register_method ({
247 name => 'delete',
248 path => '{volume}',
249 method => 'DELETE',
250 description => "Delete volume",
5f642f73 251 permissions => {
df6b79c8 252 description => "You need 'Datastore.Allocate' privilege on the storage (or 'Datastore.AllocateSpace' for backup volumes if you have VM.Backup privilege on the VM).",
b755bdb0 253 user => 'all',
5f642f73 254 },
b6cf0a66
DM
255 protected => 1,
256 proxyto => 'node',
257 parameters => {
258 additionalProperties => 0,
259 properties => {
260 node => get_standard_option('pve-node'),
261 storage => get_standard_option('pve-storage-id', { optional => 1}),
262 volume => {
263 description => "Volume identifier",
264 type => 'string',
265 },
266 },
267 },
268 returns => { type => 'null' },
269 code => sub {
270 my ($param) = @_;
271
b755bdb0
DM
272 my $rpcenv = PVE::RPCEnvironment::get();
273 my $authuser = $rpcenv->get_user();
274
df6b79c8
DM
275 my $cfg = cfs_read_file('storage.cfg');
276
b755bdb0 277 my ($volid, $storeid) = &$real_volume_id($param->{storage}, $param->{volume});
b755bdb0 278
df6b79c8
DM
279 my ($path, $ownervm, $vtype) = PVE::Storage::path($cfg, $volid);
280 if ($vtype eq 'backup' && $ownervm) {
281 $rpcenv->check($authuser, "/storage/$storeid", ['Datastore.AllocateSpace']);
282 $rpcenv->check($authuser, "/vms/$ownervm", ['VM.Backup']);
283 } else {
284 $rpcenv->check($authuser, "/storage/$storeid", ['Datastore.Allocate']);
285 }
b6cf0a66
DM
286
287 PVE::Storage::vdisk_free ($cfg, $volid);
288
289 return undef;
290 }});
291
883eeea6
DM
292__PACKAGE__->register_method ({
293 name => 'copy',
294 path => '{volume}',
295 method => 'POST',
5f642f73 296 description => "Copy a volume. This is experimental code - do not use.",
883eeea6
DM
297 protected => 1,
298 proxyto => 'node',
299 parameters => {
300 additionalProperties => 0,
301 properties => {
302 node => get_standard_option('pve-node'),
303 storage => get_standard_option('pve-storage-id', { optional => 1}),
304 volume => {
305 description => "Source volume identifier",
306 type => 'string',
307 },
308 target => {
309 description => "Target volume identifier",
310 type => 'string',
311 },
312 target_node => get_standard_option('pve-node', {
313 description => "Target node. Default is local node.",
314 optional => 1,
315 }),
316 },
317 },
318 returns => {
319 type => 'string',
320 },
321 code => sub {
322 my ($param) = @_;
323
324 my $rpcenv = PVE::RPCEnvironment::get();
325
326 my $user = $rpcenv->get_user();
327
328 my $target_node = $param->{target_node} || PVE::INotify::nodename();
329 # pvesh examples
330 # cd /nodes/localhost/storage/local/content
331 # pve:/> create local:103/vm-103-disk-1.raw -target local:103/vm-103-disk-2.raw
332 # pve:/> create 103/vm-103-disk-1.raw -target 103/vm-103-disk-3.raw
333
334 my $src_volid = &$real_volume_id($param->{storage}, $param->{volume});
335 my $dst_volid = &$real_volume_id($param->{storage}, $param->{target});
336
337 print "DEBUG: COPY $src_volid TO $dst_volid\n";
338
339 my $cfg = cfs_read_file('storage.cfg');
340
341 # do all parameter checks first
342
343 # then do all short running task (to raise errors befor we go to background)
344
345 # then start the worker task
346 my $worker = sub {
347 my $upid = shift;
348
349 print "DEBUG: starting worker $upid\n";
350
351 my ($target_sid, $target_volname) = PVE::Storage::parse_volume_id($dst_volid);
352 #my $target_ip = PVE::Cluster::remote_node_ip($target_node);
353
354 # you need to get this working (fails currently, because storage_migrate() uses
355 # ssh to connect to local host (which is not needed
356 PVE::Storage::storage_migrate($cfg, $src_volid, $target_node, $target_sid, $target_volname);
357
358 print "DEBUG: end worker $upid\n";
359
360 };
361
362 return $rpcenv->fork_worker('imgcopy', undef, $user, $worker);
363 }});
364
b6cf0a66 3651;