[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