[pve-devel] [PATCH qemu-server 4/4] add API2 handler for uploading disk images
Wolfgang Bumiller
w.bumiller at proxmox.com
Wed Feb 17 15:18:32 CET 2016
So you moved this from pve-storage (in your previous [WIP] patch) to the
qemu package. But I'm still wondering if the common parts can be
factored out into public functions in the pve-storage package.
I also see you didn't copy over the ssh code, so you won't be able to
upload disks to VMs on different hosts when in a cluster?
On Mon, Feb 15, 2016 at 02:33:49PM +0100, Timo Grodzinski wrote:
> Signed-off-by: Timo Grodzinski <t.grodzinski at profihost.ag>
> ---
> PVE/API2/Qemu.pm | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 123 insertions(+)
>
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index 226e597..47a0a56 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -3,6 +3,7 @@ package PVE::API2::Qemu;
> use strict;
> use warnings;
> use Cwd 'abs_path';
> +use File::Basename;
> use Net::SSLeay;
> use UUID;
>
> @@ -2492,6 +2493,128 @@ __PACKAGE__->register_method({
> }});
>
> __PACKAGE__->register_method({
> + name => 'upload_image',
> + path => '{vmid}/upload_image',
> + method => 'POST',
> + proxyto => 'node',
> + description => "Upload vm disk images.",
> + permissions => { user => 'all' },
This is a tricky one. We have VM.Config.Disk on VMs which should
probably be used here.
> + protected => 1,
> + parameters => {
> + additionalProperties => 0,
> + properties => {
> + node => get_standard_option( 'pve-node' ),
> + vmid => get_standard_option( 'pve-vmid' ),
> + disk => {
> + type => 'string',
> + description => "The target disk where you want to upload.",
> + enum => [ PVE::QemuServer::disknames() ],
> + },
> + filename => {
> + description => "The name of the file to create.",
> + type => 'string',
> + },
> + tmpfilename => {
> + description =>
> +"The source file name. This parameter is usually set by the REST handler. You can only overwrite it when connecting to the trustet port on localhost.",
> + type => 'string',
> + optional => 1,
> + },
> + },
> + },
> + returns => { type => "string" },
> + code => sub {
> + my ( $param ) = @_;
> +
> + my $rpcenv = PVE::RPCEnvironment::get();
> +
> + my $authuser = $rpcenv->get_user();
> +
> + my $node = extract_param( $param, 'node' );
> +
> + my $vmid = extract_param( $param, 'vmid' );
> + die "vm $vmid is running\n" if PVE::QemuServer::check_running( $vmid );
> +
> + my $digest = extract_param( $param, 'digest' );
> +
> + my $conf = PVE::QemuServer::load_config( $vmid );
> + die "checksum missmatch (file change by other user?)\n" if $digest && $digest ne $conf->{digest};
> +
> + my $disk = extract_param( $param, 'disk' );
> + die "disk '$disk' does not exist\n" if !$conf->{$disk};
> +
> + my $tmpfilename = extract_param( $param, 'tmpfilename' );
> + die "missing temporary file name\n" if !$tmpfilename;
> +
> + my $size = -s $tmpfilename;
> + die "temporary file '$tmpfilename' does not exists\n" if !defined( $size );
> +
> + my $filename = extract_param( $param, 'filename' );
> +
> + chomp $filename;
> + $filename =~ s/^.*[\/\\]//;
> + $filename =~ s/[;:,=\s\x80-\xff]/_/g;
> +
> + my @allowed_extensions = map { ( $_, "$_.gz" ) } qw(raw qcow qcow2 cow vdi vmdk vpc cloop);
> + raise_param_exc( { filename => "extension must be one of " . join ', ', map ".$_", @allowed_extensions } )
> + if !grep { $filename =~ m![^/]+\.$_$! } @allowed_extensions;
> +
> + my $storecfg = PVE::Storage::config();
> +
> + my $drive = PVE::QemuServer::parse_drive( $disk, $conf->{$disk} );
> +
> + my $worker = sub {
> + my ( $upid ) = @_;
> +
> + my $dirname = dirname( $tmpfilename );
> + my $file = "$dirname/$filename";
> + my $new_filename;
> +
> + eval {
> +
> + # rename file (pigz wont work without .gz extension)
> + rename( $tmpfilename, $file );
> +
> + # parallel gunzip if file has .gz extension
> + if ( $filename =~ /(.*?)\.gz$/i ) {
> +
> + print "\nextracting file...\n";
> +
> + $new_filename = $1;
> +
> + my @unzip_cmd = ( 'unpigz', $file );
In vzdump the use of pigz is optional as pigz might not be available
it should probably be optional here, too.
> + print "running '" . PVE::Tools::cmd2string( \@unzip_cmd ) . "'\n";
> + eval { PVE::Tools::run_command( \@unzip_cmd, errmsg => 'Extract failed' ); };
> + die "extracting file failed: $@\n" if $@;
> +
> + print "extracted file successfully\n";
> + $filename = $new_filename;
> + $file = "$dirname/$new_filename";
> + }
> +
> + my $img_volid = PVE::Storage::path_to_volume_id( $storecfg, $file );
> + die "cannot get volume id for file '$file'\n" if !$img_volid;
> +
> + my $err;
> + my $newdrive = eval { PVE::QemuServer::import_disk( $storecfg, $vmid, $img_volid, $drive ) };
> + die "error with disk import: $@\n" if $@;
> +
> + };
> +
> + unlink $file;
> + unlink $new_filename if defined $new_filename;
> +
> + print "\nimport successfull\n";
> +
> + };
> +
> + my $upid = $rpcenv->fork_worker( 'imgupload', undef, $authuser, $worker );
> +
> + return $upid;
> +
> + }});
> +
> +__PACKAGE__->register_method({
> name => 'migrate_vm',
> path => '{vmid}/migrate',
> method => 'POST',
> --
> 2.1.4
>
> _______________________________________________
> pve-devel mailing list
> pve-devel at pve.proxmox.com
> http://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
More information about the pve-devel
mailing list