]>
git.proxmox.com Git - pve-storage.git/blob - PVE/API2/Storage/Content.pm
1 package PVE
:: API2
:: Storage
:: Content
;
8 use PVE
:: Cluster
qw(cfs_read_file) ;
11 use PVE
:: Exception
qw(raise_param_exc) ;
12 use PVE
:: RPCEnvironment
;
14 use PVE
:: JSONSchema
qw(get_standard_option) ;
16 use base
qw(PVE::RESTHandler) ;
18 my @ctypes = qw(images vztmpl iso backup) ;
20 __PACKAGE__-
> register_method ({
24 description
=> "List storage content." ,
26 check
=> [ 'perm' , '/storage/{storage}' , [ 'Datastore.Audit' , 'Datastore.AllocateSpace' ], any
=> 1 ],
31 additionalProperties
=> 0 ,
33 node
=> get_standard_option
( 'pve-node' ),
34 storage
=> get_standard_option
( 'pve-storage-id' ),
36 description
=> "Only list content of this type." ,
37 type
=> 'string' , format
=> 'pve-storage-content' ,
40 vmid
=> get_standard_option
42 description
=> "Only list images for this VM" ,
57 links
=> [ { rel
=> 'child' , href
=> "{volid}" } ],
62 my $rpcenv = PVE
:: RPCEnvironment
:: get
();
64 my $authuser = $rpcenv -> get_user ();
66 my $cts = $param ->{ content
} ?
[ $param ->{ content
} ] : [ @ctypes ];
68 my $storeid = $param ->{ storage
};
70 my $cfg = cfs_read_file
( "storage.cfg" );
72 my $scfg = PVE
:: Storage
:: storage_config
( $cfg, $storeid );
75 foreach my $ct ( @$cts ) {
77 if ( $ct eq 'images' || defined ( $param ->{ vmid
})) {
78 $data = PVE
:: Storage
:: vdisk_list
( $cfg, $storeid, $param ->{ vmid
});
79 } elsif ( $ct eq 'iso' ) {
80 $data = PVE
:: Storage
:: template_list
( $cfg, $storeid, 'iso' );
81 } elsif ( $ct eq 'vztmpl' ) {
82 $data = PVE
:: Storage
:: template_list
( $cfg, $storeid, 'vztmpl' );
83 } elsif ( $ct eq 'backup' ) {
84 $data = PVE
:: Storage
:: template_list
( $cfg, $storeid, 'backup' );
87 next if ! $data || ! $data ->{ $storeid };
89 foreach my $item (@{ $data ->{ $storeid }}) {
90 eval { $rpcenv -> check_volume_access ( $authuser, $cfg, undef , $item ->{ volid
}); };
92 $item ->{ content
} = $ct ;
100 __PACKAGE__-
> register_method ({
104 description
=> "Allocate disk images." ,
106 check
=> [ 'perm' , '/storage/{storage}' , [ 'Datastore.AllocateSpace' ]],
111 additionalProperties
=> 0 ,
113 node
=> get_standard_option
( 'pve-node' ),
114 storage
=> get_standard_option
( 'pve-storage-id' ),
116 description
=> "The name of the file to create." ,
119 vmid
=> get_standard_option
( 'pve-vmid' , { description
=> "Specify owner VM" } ),
121 description
=> "Size in kilobyte (1024 bytes). Optional suffixes 'M' (megabyte, 1024K) and 'G' (gigabyte, 1024M)" ,
123 pattern
=> '\d+[MG]?' ,
127 enum
=> [ 'raw' , 'qcow2' , 'subvol' ],
134 description
=> "Volume identifier" ,
140 my $storeid = $param ->{ storage
};
141 my $name = $param ->{ filename
};
142 my $sizestr = $param ->{ size
};
145 if ( $sizestr =~ m/^\d+$/ ) {
147 } elsif ( $sizestr =~ m/^(\d+)M$/ ) {
149 } elsif ( $sizestr =~ m/^(\d+)G$/ ) {
150 $size = $1 * 1024 * 1024 ;
152 raise_param_exc
({ size
=> "unable to parse size ' $sizestr '" });
155 # extract FORMAT from name
156 if ( $name =~ m/\.(raw|qcow2|vmdk)$/ ) {
159 raise_param_exc
({ format
=> "different storage formats ( $param ->{format} != $fmt )" })
160 if $param ->{ format
} && $param ->{ format
} ne $fmt ;
162 $param ->{ format
} = $fmt ;
165 my $cfg = cfs_read_file
( 'storage.cfg' );
167 my $volid = PVE
:: Storage
:: vdisk_alloc
( $cfg, $storeid, $param ->{ vmid
},
174 # we allow to pass volume names (without storage prefix) if the storage
175 # is specified as separate parameter.
176 my $real_volume_id = sub {
177 my ( $storeid, $volume ) = @_ ;
181 if ( $volume =~ m/:/ ) {
183 my ( $sid, $volname ) = PVE
:: Storage
:: parse_volume_id
( $volume );
184 die "storage ID missmatch ( $sid != $storeid ) \n "
185 if $storeid && $sid ne $storeid ;
189 raise_param_exc
({ volume
=> $@ }) if $@ ;
192 raise_param_exc
({ volume
=> "no storage speficied - incomplete volume ID" })
195 $volid = " $storeid : $volume " ;
198 return wantarray ?
( $volid, $storeid ) : $volid ;
201 __PACKAGE__-
> register_method ({
205 description
=> "Get volume attributes" ,
207 description
=> "You need read access for the volume." ,
213 additionalProperties
=> 0 ,
215 node
=> get_standard_option
( 'pve-node' ),
216 storage
=> get_standard_option
( 'pve-storage-id' , { optional
=> 1 }),
218 description
=> "Volume identifier" ,
223 returns
=> { type
=> 'object' },
227 my $rpcenv = PVE
:: RPCEnvironment
:: get
();
228 my $authuser = $rpcenv -> get_user ();
230 my ( $volid, $storeid ) = & $real_volume_id ( $param ->{ storage
}, $param ->{ volume
});
232 my $cfg = cfs_read_file
( 'storage.cfg' );
234 $rpcenv -> check_volume_access ( $authuser, $cfg, undef , $volid );
236 my $path = PVE
:: Storage
:: path
( $cfg, $volid );
237 my ( $size, $format, $used, $parent ) = PVE
:: Storage
:: file_size_info
( $path );
238 die "file_size_info on ' $volid ' failed \n " if !( $format && $size );
240 # fixme: return more attributes?
249 __PACKAGE__-
> register_method ({
253 description
=> "Delete volume" ,
255 description
=> "You need 'Datastore.Allocate' privilege on the storage (or 'Datastore.AllocateSpace' for backup volumes if you have VM.Backup privilege on the VM)." ,
261 additionalProperties
=> 0 ,
263 node
=> get_standard_option
( 'pve-node' ),
264 storage
=> get_standard_option
( 'pve-storage-id' , { optional
=> 1 }),
266 description
=> "Volume identifier" ,
271 returns
=> { type
=> 'null' },
275 my $rpcenv = PVE
:: RPCEnvironment
:: get
();
276 my $authuser = $rpcenv -> get_user ();
278 my $cfg = cfs_read_file
( 'storage.cfg' );
280 my ( $volid, $storeid ) = & $real_volume_id ( $param ->{ storage
}, $param ->{ volume
});
282 my ( $path, $ownervm, $vtype ) = PVE
:: Storage
:: path
( $cfg, $volid );
283 if ( $vtype eq 'backup' && $ownervm ) {
284 $rpcenv -> check ( $authuser, "/storage/ $storeid " , [ 'Datastore.AllocateSpace' ]);
285 $rpcenv -> check ( $authuser, "/vms/ $ownervm " , [ 'VM.Backup' ]);
287 $rpcenv -> check ( $authuser, "/storage/ $storeid " , [ 'Datastore.Allocate' ]);
290 PVE
:: Storage
:: vdisk_free
( $cfg, $volid );
295 __PACKAGE__-
> register_method ({
299 description
=> "Copy a volume. This is experimental code - do not use." ,
303 additionalProperties
=> 0 ,
305 node
=> get_standard_option
( 'pve-node' ),
306 storage
=> get_standard_option
( 'pve-storage-id' , { optional
=> 1 }),
308 description
=> "Source volume identifier" ,
312 description
=> "Target volume identifier" ,
315 target_node
=> get_standard_option
( 'pve-node' , {
316 description
=> "Target node. Default is local node." ,
327 my $rpcenv = PVE
:: RPCEnvironment
:: get
();
329 my $user = $rpcenv -> get_user ();
331 my $target_node = $param ->{ target_node
} || PVE
:: INotify
:: nodename
();
333 # cd /nodes/localhost/storage/local/content
334 # pve:/> create local:103/vm-103-disk-1.raw -target local:103/vm-103-disk-2.raw
335 # pve:/> create 103/vm-103-disk-1.raw -target 103/vm-103-disk-3.raw
337 my $src_volid = & $real_volume_id ( $param ->{ storage
}, $param ->{ volume
});
338 my $dst_volid = & $real_volume_id ( $param ->{ storage
}, $param ->{ target
});
340 print "DEBUG: COPY $src_volid TO $dst_volid\n " ;
342 my $cfg = cfs_read_file
( 'storage.cfg' );
344 # do all parameter checks first
346 # then do all short running task (to raise errors befor we go to background)
348 # then start the worker task
352 print "DEBUG: starting worker $upid\n " ;
354 my ( $target_sid, $target_volname ) = PVE
:: Storage
:: parse_volume_id
( $dst_volid );
355 #my $target_ip = PVE::Cluster::remote_node_ip($target_node);
357 # you need to get this working (fails currently, because storage_migrate() uses
358 # ssh to connect to local host (which is not needed
359 PVE
:: Storage
:: storage_migrate
( $cfg, $src_volid, $target_node, $target_sid, $target_volname );
361 print "DEBUG: end worker $upid\n " ;
365 return $rpcenv -> fork_worker ( 'imgcopy' , undef , $user, $worker );