From 7814e05f6f6deab2186dc2ca1b31dd85deb6180e Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 3 Nov 2011 09:22:53 +0100 Subject: [PATCH] implement file upload API --- PVE/API2/Storage/Status.pm | 136 ++++++++++++++++++++++++++++++++++++- PVE/Storage.pm | 44 ------------ 2 files changed, 135 insertions(+), 45 deletions(-) diff --git a/PVE/API2/Storage/Status.pm b/PVE/API2/Storage/Status.pm index 509253d..717a937 100644 --- a/PVE/API2/Storage/Status.pm +++ b/PVE/API2/Storage/Status.pm @@ -3,6 +3,10 @@ package PVE::API2::Storage::Status; use strict; use warnings; +use File::Path; +use File::Basename; +use PVE::Tools; +use PVE::INotify; use PVE::Cluster qw(cfs_read_file); use PVE::Storage; use PVE::API2::Storage::Content; @@ -13,7 +17,6 @@ use PVE::Exception qw(raise_param_exc); use base qw(PVE::RESTHandler); - __PACKAGE__->register_method ({ subclass => "PVE::API2::Storage::Content", # set fragment delimiter (no subdirs) - we need that, because volume @@ -101,6 +104,7 @@ __PACKAGE__->register_method ({ my $res = [ { subdir => 'status' }, { subdir => 'content' }, + { subdir => 'upload' }, { subdir => 'rrd' }, { subdir => 'rrddata' }, ]; @@ -224,5 +228,135 @@ __PACKAGE__->register_method ({ "pve2-storage/$param->{node}/$param->{storage}", $param->{timeframe}, $param->{cf}); }}); + +__PACKAGE__->register_method ({ + name => 'upload', + path => '{storage}/upload', + method => 'POST', + description => "Upload file.", + protected => 1, + parameters => { + additionalProperties => 0, + properties => { + node => get_standard_option('pve-node'), + storage => get_standard_option('pve-storage-id'), + content => { + description => "Content type.", + type => 'string', format => 'pve-storage-content', + }, + 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 $user = $rpcenv->get_user(); + + my $cfg = cfs_read_file("storage.cfg"); + + my $node = $param->{node}; + my $scfg = PVE::Storage::storage_check_enabled($cfg, $param->{storage}, $node); + + die "cant upload to storage type '$scfg->{type}'" + if !($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs'); + + my $content = $param->{content}; + + my $tmpfilename = $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 = $param->{filename}; + + chomp $filename; + $filename =~ s/^.*[\/\\]//; + $filename =~ s/\s/_/g; + + my $path; + + if ($content eq 'iso') { + if ($filename !~ m![^/]+\.[Ii][Ss][Oo]$!) { + raise_param_exc({ filename => "missing '.iso' extension" }); + } + $path = PVE::Storage::get_iso_dir($cfg, $param->{storage}); + } elsif ($content eq 'vztmpl') { + if ($filename !~ m![^/]+\.tar\.gz$!) { + raise_param_exc({ filename => "missing '.tar.gz' extension" }); + } + $path = get_vztmpl_dir ($cfg, $param->{storage}); + } elsif ($content eq 'backup') { + if ($filename !~ m!/([^/]+\.(tar|tgz))$!) { + raise_param_exc({ filename => "missing '.(tar|tgz)' extension" }); + } + $path = get_backup_dir($cfg, $param->{storage}); + } else { + raise_param_exc({ content => "upload content type '$content' not implemented" }); + } + + die "storage '$param->{storage}' does not support '$content' content\n" + if !$scfg->{content}->{$content}; + + my $dest = "$path/$filename"; + my $dirname = dirname($dest); + + # we simply overwrite when destination when file already exists + + my $cmd; + if ($node ne 'localhost' && $node ne PVE::INotify::nodename()) { + my $remip = PVE::Cluster::remote_node_ip($node); + + my @ssh_options = ('-o', 'BatchMode=yes', '-c', 'blowfish-cbc'); + + my @remcmd = ('/usr/bin/ssh', @ssh_options, $remip); + + eval { + # activate remote storage + PVE::Tools::run_command([@remcmd, '/usr/sbin/pvesm', 'status', + '--storage', $param->{storage}]); + }; + die "can't activate storage '$param->{storage}' on node '$node'\n" if $@; + + PVE::Tools::run_command([@remcmd, '/bin/mkdir', '-p', $dirname], + errmsg => "mkdir failed"); + + $cmd = ['/usr/bin/scp', @ssh_options, $tmpfilename, "$remip:$dest"]; + } else { + PVE::Storage::activate_storage($cfg, $param->{storage}); + make_path($dirname); + $cmd = ['cp', $tmpfilename, $dest]; + } + + my $worker = sub { + my $upid = shift; + + print "starting file import from: $tmpfilename\n"; + print "target node: $node\n"; + print "target file: $dest\n"; + print "file size is: $size\n"; + print "command: " . join(' ', @$cmd) . "\n"; + + eval { PVE::Tools::run_command($cmd, errmsg => 'import failed'); }; + if (my $err = $@) { + unlink $dest; + die $err; + } + print "finished file import successfully\n"; + }; + + return $rpcenv->fork_worker('imgcopy', undef, $user, $worker); + }}); 1; diff --git a/PVE/Storage.pm b/PVE/Storage.pm index 6f7e265..386945a 100755 --- a/PVE/Storage.pm +++ b/PVE/Storage.pm @@ -1482,50 +1482,6 @@ sub lvm_lvs { return $lvs; } -#install iso or openvz template ($tt = ) -# we simply overwrite when file already exists -sub install_template { - my ($cfg, $storeid, $tt, $srcfile, $destfile) = @_; - - my $scfg = storage_config ($cfg, $storeid); - - my $type = $scfg->{type}; - - die "invalid storage type '$type'" if !($type eq 'dir' || $type eq 'nfs'); - - my $path; - - if ($tt eq 'iso') { - die "file '$destfile' has no '.iso' extension\n" - if $destfile !~ m![^/]+\.[Ii][Ss][Oo]$!; - die "storage '$storeid' does not support 'iso' content\n" - if !$scfg->{content}->{iso}; - $path = get_iso_dir ($cfg, $storeid); - } elsif ($tt eq 'vztmpl') { - die "file '$destfile' has no '.tar.gz' extension\n" - if $destfile !~ m![^/]+\.tar\.gz$!; - die "storage '$storeid' does not support 'vztmpl' content\n" - if !$scfg->{content}->{vztmpl}; - $path = get_vztmpl_dir ($cfg, $storeid); - } else { - die "unknown template type '$tt'"; - } - - activate_storage ($cfg, $storeid); - - my $dest = "$path/$destfile"; - - my $cmd = ['cp', $srcfile, $dest]; - - eval { run_command ($cmd); }; - my $err = $@; - - if ($err) { - unlink $dest; - die $err; - } -} - #list iso or openvz template ($tt = ) sub template_list { my ($cfg, $storeid, $tt) = @_; -- 2.39.2