From: Dietmar Maurer Date: Fri, 14 Oct 2011 11:43:06 +0000 (+0200) Subject: plug VZDump into our API X-Git-Url: https://git.proxmox.com/?p=pve-manager.git;a=commitdiff_plain;h=bf58f8dddae2bb6377e02693dd152e3781e7109c plug VZDump into our API --- diff --git a/PVE/API2/Makefile b/PVE/API2/Makefile index 624cba1a..c0d4a3ea 100644 --- a/PVE/API2/Makefile +++ b/PVE/API2/Makefile @@ -1,6 +1,7 @@ include ../../defines.mk PERLSOURCE = \ + VZDump.pm \ Cluster.pm \ Nodes.pm \ Tasks.pm \ diff --git a/PVE/API2/Nodes.pm b/PVE/API2/Nodes.pm index 3f7a7b76..a620e7c5 100644 --- a/PVE/API2/Nodes.pm +++ b/PVE/API2/Nodes.pm @@ -23,6 +23,7 @@ use PVE::API2::Storage::Scan; use PVE::API2::Storage::Status; use PVE::API2::Qemu; use PVE::API2::OpenVZ; +use PVE::API2::VZDump; use JSON; use base qw(PVE::RESTHandler); @@ -37,6 +38,11 @@ __PACKAGE__->register_method ({ path => 'openvz', }); +__PACKAGE__->register_method ({ + subclass => "PVE::API2::VZDump", + path => 'vzdump', +}); + __PACKAGE__->register_method ({ subclass => "PVE::API2::Services", path => 'services', @@ -100,6 +106,7 @@ __PACKAGE__->register_method ({ { name => 'upload' }, { name => 'qemu' }, { name => 'openvz' }, + { name => 'vzdump' }, { name => 'ubcfailcnt' }, { name => 'network' }, { name => 'network_changes' }, diff --git a/PVE/API2/VZDump.pm b/PVE/API2/VZDump.pm new file mode 100644 index 00000000..b4fefbd6 --- /dev/null +++ b/PVE/API2/VZDump.pm @@ -0,0 +1,245 @@ +package PVE::API2::VZDump; + +use strict; +use warnings; +use PVE::Exception qw(raise_param_exc);; +use PVE::Tools qw(extract_param); +use PVE::Cluster qw(cfs_register_file cfs_read_file); +use PVE::INotify; +use PVE::RPCEnvironment; +use PVE::AccessControl; +use PVE::JSONSchema qw(get_standard_option); +use PVE::Storage; +use PVE::VZDump; + +use Data::Dumper; # fixme: remove + + +use base qw(PVE::RESTHandler); + +__PACKAGE__->register_method ({ + name => 'vzdump', + path => '', + method => 'POST', + description => "Create backup.", + parameters => { + additionalProperties => 0, + properties => { + vmid => { + type => 'string', format => 'pve-vmid-list', + description => "The ID of the VM you want to backup.", + optional => 1, + }, + node => get_standard_option('pve-node', { + description => "Only run if executed on this node.", + optional => 1, + }), + all => { + type => 'boolean', + description => "Backup all known VMs on this host.", + optional => 1, + default => 0, + }, + stdexcludes => { + type => 'boolean', + description => "Exclude temorary files and logs.", + optional => 1, + default => 1, + }, + compress => { + type => 'boolean', + description => "Compress dump file (gzip).", + optional => 1, + default => 0, + }, + quiet => { + type => 'boolean', + description => "Be quiet.", + optional => 1, + default => 0, + }, + stop => { + type => 'boolean', + description => "Stop/Restart VM when running.", + optional => 1, + }, + snapshot => { + type => 'boolean', + description => "Try to use (LVM) snapshots when running.", + optional => 1, + }, + suspend => { + type => 'boolean', + description => "Suspend/resume VM when running", + optional => 1, + }, + stdout => { + type => 'boolean', + description => "Write tar to stdout, not to a file.", + optional => 1, + }, + exclude => { + type => 'string', format => 'pve-vmid-list', + description => "exclude specified VMs (assumes --all)", + optional => 1, + }, + 'exclude-path' => { + type => 'string', format => 'string-list', + description => "exclude certain files/directories (regex).", + optional => 1, + }, + mailto => { + type => 'string', format => 'string-list', + description => "", + optional => 1, + }, + tmpdir => { + type => 'string', + description => "Store temporary files to specified directory.", + optional => 1, + }, + dumpdir => { + type => 'string', + description => "Store resulting files to specified directory.", + optional => 1, + }, + script => { + type => 'string', + description => "Use specified hook script.", + optional => 1, + }, + storage => get_standard_option('pve-storage-id', { + description => "Store resulting file to this storage.", + optional => 1, + }), + size => { + type => 'integer', + description => "LVM snapshot size im MB.", + optional => 1, + minimum => 500, + }, + bwlimit => { + type => 'integer', + description => "Limit I/O bandwidth (KBytes per second).", + optional => 1, + minimum => 0, + }, + ionice => { + type => 'integer', + description => "Set CFQ ionice priority.", + optional => 1, + minimum => 0, + maximum => 8, + }, + lockwait => { + type => 'integer', + description => "Maximal time to wait for the global lock (minutes).", + optional => 1, + minimum => 0, + }, + stopwait => { + type => 'integer', + description => "Maximal time to wait until a VM is stopped (minutes).", + optional => 1, + minimum => 0, + }, + maxfiles => { + type => 'integer', + description => "Maximal number of backup files per VM.", + optional => 1, + minimum => 1, + }, + }, + }, + returns => { type => 'string' }, + code => sub { + my ($param) = @_; + + my $rpcenv = PVE::RPCEnvironment::get(); + + my $user = $rpcenv->get_user(); + + my $nodename = PVE::INotify::nodename(); + + if ($rpcenv->{type} ne 'cli') { + raise_param_exc({ node => "option is only allowed on the command line interface."}) + if $param->{node} && $param->{node} ne $nodename; + + raise_param_exc({ stdout => "option is only allowed on the command line interface."}) + if $param->{stdout}; + } + + # by default we set --rsyncable for gzip + local $ENV{GZIP} = "--rsyncable" if !$ENV{GZIP}; + + $param->{all} = 1 if defined($param->{exclude}); + + raise_param_exc({ all => "option conflicts with option 'vmid'"}) + if $param->{all} && $param->{vmid}; + + raise_param_exc({ vmid => "property is missing"}) + if !$param->{all} && !$param->{vmid}; + + # silent exit if we run on wrong node + exit(0) if $param->{node} && $param->{node} ne $nodename; + + # convert string lists to arrays + my @vmids = PVE::Tools::split_list(extract_param($param, 'vmid')); + + my $cmdline = 'vzdump'; + $cmdline .= ' ' . join(' ', @vmids) if scalar(@vmids); + foreach my $p (keys %$param) { + $cmdline .= " --$p $param->{$p}"; + } + + $param->{vmids} = PVE::VZDump::check_vmids(@vmids) if !$param->{all}; + my @exclude = PVE::Tools::split_list(extract_param($param, 'exclude')); + $param->{exclude} = PVE::VZDump::check_vmids(@exclude); + + # exclude-path list need to be 0 separated + my @expaths = split(/\0/, $param->{'exclude-path'} || ''); + $param->{'exclude-path'} = @expaths; + + my @mailto = PVE::Tools::split_list(extract_param($param, 'mailto')); + $param->{mailto} = [ @mailto ]; + + die "you can only backup a single VM with option --stdout\n" + if $param->{stdout} && scalar(@vmids) != 1; + + my $vzdump = PVE::VZDump->new($cmdline, $param); + + my $worker = sub { + $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub { + die "interrupted by signal\n"; + }; + + $vzdump->getlock (); # only one process allowed + + if (defined($param->{ionice})) { + if ($param->{ionice} > 7) { + PVE::VZDump::run_command(undef, "ionice -c3 -p $$"); + } else { + PVE::VZDump::run_command(undef, "ionice -c2 -n$param->{ionice} -p $$"); + } + } + $vzdump->exec_backup(); + }; + + open STDOUT, '>/dev/null' if $param->{quiet} && !$param->{stdout}; + open STDERR, '>/dev/null' if $param->{quiet}; + + if ($rpcenv->{type} eq 'cli') { + if ($param->{stdout}) { + + open my $saved_stdout, ">&STDOUT" + || die "can't dup STDOUT: $!\n"; + + open STDOUT, '>&STDERR' || + die "unable to redirect STDOUT: $!\n"; + + $param->{stdout} = $saved_stdout; + } + } + + return $rpcenv->fork_worker('vzdump', undef, $user, $worker); + }}); diff --git a/bin/vzdump b/bin/vzdump index 13f65ebe..01e4df76 100755 --- a/bin/vzdump +++ b/bin/vzdump @@ -1,17 +1,11 @@ #!/usr/bin/perl -w use strict; - -use PVE::Exception qw(raise_param_exc);; -use PVE::Tools qw(extract_param); -use PVE::Cluster qw(cfs_register_file cfs_read_file); use PVE::SafeSyslog; use PVE::INotify; use PVE::RPCEnvironment; use PVE::CLIHandler; -use PVE::JSONSchema qw(get_standard_option); -use PVE::Storage; -use PVE::VZDump; +use PVE::API2::VZDump; use Data::Dumper; # fixme: remove @@ -24,7 +18,6 @@ initlog('vzdump'); die "please run as root\n" if $> != 0; PVE::INotify::inotify_init(); -my $nodename = PVE::INotify::nodename(); my $rpcenv = PVE::RPCEnvironment->init('cli'); @@ -32,233 +25,8 @@ $rpcenv->init_request(); $rpcenv->set_language($ENV{LANG}); $rpcenv->set_user('root@pam'); -__PACKAGE__->register_method ({ - name => 'vzdump', - path => 'vzdump', - method => 'PUT', - description => "Create backup.", - parameters => { - additionalProperties => 0, - properties => { - vmid => { - type => 'string', format => 'pve-vmid-list', - description => "The ID of the VM you want to backup.", - optional => 1, - }, - node => get_standard_option('pve-node', { - description => "Only run if executed on this node.", - optional => 1, - }), - all => { - type => 'boolean', - description => "Backup all known VMs on this host.", - optional => 1, - default => 0, - }, - stdexcludes => { - type => 'boolean', - description => "Exclude temorary files and logs.", - optional => 1, - default => 1, - }, - compress => { - type => 'boolean', - description => "Compress dump file (gzip).", - optional => 1, - default => 0, - }, - quiet => { - type => 'boolean', - description => "Be quiet.", - optional => 1, - default => 0, - }, - stop => { - type => 'boolean', - description => "Stop/Restart VM when running.", - optional => 1, - }, - snapshot => { - type => 'boolean', - description => "Try to use (LVM) snapshots when running.", - optional => 1, - }, - suspend => { - type => 'boolean', - description => "Suspend/resume VM when running", - optional => 1, - }, - stdout => { - type => 'boolean', - description => "Write tar to stdout, not to a file.", - optional => 1, - }, - exclude => { - type => 'string', format => 'pve-vmid-list', - description => "exclude specified VMs (assumes --all)", - optional => 1, - }, - 'exclude-path' => { - type => 'string', format => 'string-list', - description => "exclude certain files/directories (regex).", - optional => 1, - }, - mailto => { - type => 'string', format => 'string-list', - description => "", - optional => 1, - }, - tmpdir => { - type => 'string', - description => "Store temporary files to specified directory.", - optional => 1, - }, - dumpdir => { - type => 'string', - description => "Store resulting files to specified directory.", - optional => 1, - }, - script => { - type => 'string', - description => "Use specified hook script.", - optional => 1, - }, - storage => get_standard_option('pve-storage-id', { - description => "Store resulting file to this storage.", - optional => 1, - }), - size => { - type => 'integer', - description => "LVM snapshot size im MB.", - optional => 1, - minimum => 500, - }, - bwlimit => { - type => 'integer', - description => "Limit I/O bandwidth (KBytes per second).", - optional => 1, - minimum => 0, - }, - ionice => { - type => 'integer', - description => "Set CFQ ionice priority.", - optional => 1, - minimum => 0, - maximum => 8, - }, - lockwait => { - type => 'integer', - description => "Maximal time to wait for the global lock (minutes).", - optional => 1, - minimum => 0, - }, - stopwait => { - type => 'integer', - description => "Maximal time to wait until a VM is stopped (minutes).", - optional => 1, - minimum => 0, - }, - maxfiles => { - type => 'integer', - description => "Maximal number of backup files per VM.", - optional => 1, - minimum => 1, - }, - }, - }, - returns => { type => 'string' }, - code => sub { - my ($param) = @_; - - my $rpcenv = PVE::RPCEnvironment::get(); - - my $user = $rpcenv->get_user(); - - if ($rpcenv->{type} ne 'cli') { - raise_param_exc({ node => "option is only allowed on the command line interface."}) - if $param->{node}; - - raise_param_exc({ stdout => "option is only allowed on the command line interface."}) - if $param->{stdout}; - } - - # by default we set --rsyncable for gzip - local $ENV{GZIP} = "--rsyncable" if !$ENV{GZIP}; - - $param->{all} = 1 if defined($param->{exclude}); - - raise_param_exc({ all => "option conflicts with option 'vmid'"}) - if $param->{all} && $param->{vmid}; - - raise_param_exc({ vmid => "property is missing"}) - if !$param->{all} && !$param->{vmid}; - - # silent exit if we run on wrong node - my $nodename = PVE::INotify::nodename(); - exit(0) if $param->{node} && $param->{node} ne $nodename; - - # convert string lists to arrays - my @vmids = PVE::Tools::split_list(extract_param($param, 'vmid')); - - my $cmdline = 'vzdump'; - $cmdline .= ' ' . join(' ', @vmids) if scalar(@vmids); - foreach my $p (keys %$param) { - $cmdline .= " --$p $param->{$p}"; - } - - $param->{vmids} = PVE::VZDump::check_vmids(@vmids) if !$param->{all}; - my @exclude = PVE::Tools::split_list(extract_param($param, 'exclude')); - $param->{exclude} = PVE::VZDump::check_vmids(@exclude); - - # exclude-path list need to be 0 separated - my @expaths = split(/\0/, $param->{'exclude-path'} || ''); - $param->{'exclude-path'} = @expaths; - - my @mailto = PVE::Tools::split_list(extract_param($param, 'mailto')); - $param->{mailto} = [ @mailto ]; - - die "you can only backup a single VM with option --stdout\n" - if $param->{stdout} && scalar(@vmids) != 1; - - my $vzdump = PVE::VZDump->new($cmdline, $param); - - my $worker = sub { - $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub { - die "interrupted by signal\n"; - }; - - $vzdump->getlock (); # only one process allowed - - if (defined($param->{ionice})) { - if ($param->{ionice} > 7) { - PVE::VZDump::run_command(undef, "ionice -c3 -p $$"); - } else { - PVE::VZDump::run_command(undef, "ionice -c2 -n$param->{ionice} -p $$"); - } - } - $vzdump->exec_backup(); - }; - - open STDOUT, '>/dev/null' if $param->{quiet} && !$param->{stdout}; - open STDERR, '>/dev/null' if $param->{quiet}; - - if ($rpcenv->{type} eq 'cli') { - if ($param->{stdout}) { - - open my $saved_stdout, ">&STDOUT" - || die "can't dup STDOUT: $!\n"; - - open STDOUT, '>&STDERR' || - die "unable to redirect STDOUT: $!\n"; - - $param->{stdout} = $saved_stdout; - } - } - - return $rpcenv->fork_worker('vzdump', undef, $user, $worker); - }}); -my $cmddef = [ __PACKAGE__, 'vzdump', 'vmid', undef, +my $cmddef = [ 'PVE::API2::VZDump', 'vzdump', 'vmid', undef, sub { my $upid = shift; my $status = PVE::Tools::upid_read_status($upid);