[pve-devel] [PATCH qemu-server 4/4] add API2 handler for uploading disk images

Timo Grodzinski t.grodzinski at profihost.ag
Mon Feb 15 14:33:49 CET 2016


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' },
+    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 );
+                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




More information about the pve-devel mailing list