Commit d7c6257f authored by Dietmar Maurer's avatar Dietmar Maurer

adopt vzdump to pve 2

parent 46e1d3ca
...@@ -383,7 +383,7 @@ sub json_config_properties { ...@@ -383,7 +383,7 @@ sub json_config_properties {
} }
# read global vz.conf # read global vz.conf
my $read_global_vz_config = sub { sub read_global_vz_config {
my $res = { my $res = {
rootdir => '/var/lib/vz/root/$VEID', # note '$VEID' is a place holder rootdir => '/var/lib/vz/root/$VEID', # note '$VEID' is a place holder
...@@ -431,7 +431,7 @@ my $read_global_vz_config = sub { ...@@ -431,7 +431,7 @@ my $read_global_vz_config = sub {
return $res; return $res;
}; };
my $global_vzconf = &$read_global_vz_config(); my $global_vzconf = read_global_vz_config();
my $res_unlimited = LONG_MAX; my $res_unlimited = LONG_MAX;
sub parse_netif { sub parse_netif {
...@@ -1065,6 +1065,15 @@ sub generate_raw_config { ...@@ -1065,6 +1065,15 @@ sub generate_raw_config {
return $text; return $text;
} }
sub create_lock_manager {
return LockFile::Simple->make(-format => '%f',
-autoclean => 1,
-max => 30,
-delay => 2,
-stale => 1,
-nfs => 0);
}
sub lock_container { sub lock_container {
my ($vmid, $code, @param) = @_; my ($vmid, $code, @param) = @_;
...@@ -1074,12 +1083,7 @@ sub lock_container { ...@@ -1074,12 +1083,7 @@ sub lock_container {
eval { eval {
my $lockmgr = LockFile::Simple->make(-format => '%f', my $lockmgr = create_lock_manager();
-autoclean => 1,
-max => 30,
-delay => 2,
-stale => 1,
-nfs => 0);
$lock = $lockmgr->lock($filename) || die "can't lock container $vmid\n"; $lock = $lockmgr->lock($filename) || die "can't lock container $vmid\n";
......
package PVE::VZDump; package PVE::VZDump;
# Copyright (C) 2007-2009 Proxmox Server Solutions GmbH
#
# Copyright: vzdump is under GNU GPL, the GNU General Public License.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 dated June, 1991.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
# Author: Dietmar Maurer <dietmar@proxmox.com>
use strict; use strict;
use warnings; use warnings;
use Fcntl ':flock'; use Fcntl ':flock';
use Sys::Hostname; use PVE::SafeSyslog;
use Sys::Syslog;
use IO::File; use IO::File;
use IO::Select; use IO::Select;
use IPC::Open3; use IPC::Open3;
use POSIX qw(strftime); use POSIX qw(strftime);
use File::Path; use File::Path;
use PVE::Storage;
use PVE::Cluster qw(cfs_read_file);
use PVE::VZDump::OpenVZ; use PVE::VZDump::OpenVZ;
use Time::localtime; use Time::localtime;
use Time::Local; use Time::Local;
...@@ -84,112 +65,32 @@ sub debugmsg { ...@@ -84,112 +65,32 @@ sub debugmsg {
sub run_command { sub run_command {
my ($logfd, $cmdstr, %param) = @_; my ($logfd, $cmdstr, %param) = @_;
my $timeout; my $returnstdout = $param{returnstdout};
my $input; delete $param{returnstdout};
my $output;
foreach my $p (keys %param) {
if ($p eq 'timeout') {
$timeout = $param{$p};
} elsif ($p eq 'input') {
$input = $param{$p};
} elsif ($p eq 'output') {
$output = $param{$p};
} else {
die "got unknown parameter '$p' for run_command\n";
}
}
my $reader = $output && $output =~ m/^>&/ ? $output : IO::File->new();
my $writer = $input && $input =~ m/^<&/ ? $input : IO::File->new();
my $error = IO::File->new();
my $orig_pid = $$; my $ostream = 0;
my $pid; my $outfunc = sub {
eval { my $line = shift;
# suppress LVM warnings like: "File descriptor 3 left open"; $ostream .= "$line\n" if $returnstdout;
local $ENV{LVM_SUPPRESS_FD_WARNINGS} = "1"; debugmsg ('info', $line, $logfd);
$pid = open3 ($writer, $reader, $error, ($cmdstr)) || die $!;
}; };
my $err = $@; my $errfunc = sub {
my $line = shift;
# catch exec errors
if ($orig_pid != $$) {
debugmsg ('err', "command '$cmdstr' failed - fork failed: $!", $logfd);
POSIX::_exit (1);
kill ('KILL', $$);
}
die $err if $err;
if (ref($writer)) {
print $writer $input if defined $input;
close $writer;
}
my $select = new IO::Select;
$select->add ($reader) if ref($reader);
$select->add ($error);
my ($ostream, $estream, $logout, $logerr) = ('', '', '', '');
while ($select->count) {
my @handles = $select->can_read ($timeout);
if (defined ($timeout) && (scalar (@handles) == 0)) {
die "command '$cmdstr' failed: timeout\n";
}
foreach my $h (@handles) {
my $buf = '';
my $count = sysread ($h, $buf, 4096);
if (!defined ($count)) {
waitpid ($pid, 0);
die "command '$cmdstr' failed: $!\n";
}
$select->remove ($h) if !$count;
if ($h eq $reader) {
$ostream .= $buf;
$logout .= $buf;
while ($logout =~ s/^([^\n]*\n)//s) {
my $line = $1;
debugmsg ('info', $line, $logfd); debugmsg ('info', $line, $logfd);
} };
} elsif ($h eq $error) {
$estream .= $buf;
$logerr .= $buf;
while ($logerr =~ s/^([^\n]*\n)//s) {
my $line = $1;
debugmsg ('info', $line, $logfd);
}
}
}
}
debugmsg ('info', $logout, $logfd);
debugmsg ('info', $logerr, $logfd);
waitpid ($pid, 0);
my $ec = ($? >> 8);
return $ostream if $ec == 24 && ($cmdstr =~ m|^(\S+/)?rsync\s|);
die "command '$cmdstr' failed with exit code $ec\n" if $ec; PVE::Tools::run_command($cmdstr, %param, outfunc => $outfunc, errfunc => $errfunc);
return $ostream; return $returnstdout ? $ostream : undef;
} }
sub storage_info { sub storage_info {
my $storage = shift; my $storage = shift;
eval { require PVE::Storage; }; my $cfg = cfs_read_file('storage.cfg');
die "unable to query storage info for '$storage' - $@\n" if $@; my $scfg = PVE::Storage::storage_config($cfg, $storage);
my $cfg = PVE::Storage::load_config();
my $scfg = PVE::Storage::storage_config ($cfg, $storage);
my $type = $scfg->{type}; my $type = $scfg->{type};
die "can't use storage type '$type' for backup\n" die "can't use storage type '$type' for backup\n"
...@@ -197,7 +98,7 @@ sub storage_info { ...@@ -197,7 +98,7 @@ sub storage_info {
die "can't use storage for backups - wrong content type\n" die "can't use storage for backups - wrong content type\n"
if (!$scfg->{content}->{backup}); if (!$scfg->{content}->{backup});
PVE::Storage::activate_storage ($cfg, $storage); PVE::Storage::activate_storage($cfg, $storage);
return { return {
dumpdir => $scfg->{path}, dumpdir => $scfg->{path},
...@@ -272,7 +173,7 @@ sub check_vmids { ...@@ -272,7 +173,7 @@ sub check_vmids {
foreach my $vmid (@vmids) { foreach my $vmid (@vmids) {
die "ERROR: strange VM ID '${vmid}'\n" if $vmid !~ m/^\d+$/; die "ERROR: strange VM ID '${vmid}'\n" if $vmid !~ m/^\d+$/;
$vmid = int ($vmid); # remove leading zeros $vmid = int ($vmid); # remove leading zeros
die "ERROR: got reserved VM ID '${vmid}'\n" if $vmid < 100; next if !$vmid;
push @$res, $vmid; push @$res, $vmid;
} }
...@@ -374,7 +275,7 @@ my $sendmail = sub { ...@@ -374,7 +275,7 @@ my $sendmail = sub {
my $mailto = $opts->{mailto}; my $mailto = $opts->{mailto};
return if !$mailto; return if !($mailto && scalar(@$mailto));
my $cmdline = $self->{cmdline}; my $cmdline = $self->{cmdline};
...@@ -394,10 +295,9 @@ my $sendmail = sub { ...@@ -394,10 +295,9 @@ my $sendmail = sub {
my $stat = $ecount ? 'backup failed' : 'backup successful'; my $stat = $ecount ? 'backup failed' : 'backup successful';
my $hostname = `hostname -f` || hostname(); my $hostname = `hostname -f` || PVE::INotify::nodename();
chomp $hostname; chomp $hostname;
my $boundary = "----_=_NextPart_001_".int(time).$$; my $boundary = "----_=_NextPart_001_".int(time).$$;
my $rcvrarg = ''; my $rcvrarg = '';
...@@ -539,6 +439,7 @@ my $sendmail = sub { ...@@ -539,6 +439,7 @@ my $sendmail = sub {
# end html part # end html part
print MAIL "\n--$boundary--\n"; print MAIL "\n--$boundary--\n";
close(MAIL);
}; };
sub new { sub new {
...@@ -1136,6 +1037,10 @@ sub exec_backup { ...@@ -1136,6 +1037,10 @@ sub exec_backup {
eval { $self->$sendmail ($tasklist, $totaltime); }; eval { $self->$sendmail ($tasklist, $totaltime); };
debugmsg ('err', $@) if $@; debugmsg ('err', $@) if $@;
die $err if $err;
die "job errors\n" if $errcount;
} }
1; 1;
...@@ -24,117 +24,33 @@ use strict; ...@@ -24,117 +24,33 @@ use strict;
use warnings; use warnings;
use File::Path; use File::Path;
use File::Basename; use File::Basename;
use PVE::INotify;
use PVE::VZDump; use PVE::VZDump;
use Sys::Hostname; use PVE::OpenVZ;
use LockFile::Simple;
use base qw (PVE::VZDump::Plugin); use base qw (PVE::VZDump::Plugin);
use constant SCRIPT_EXT => qw (start stop mount umount); use constant SCRIPT_EXT => qw (start stop mount umount);
use constant VZDIR => '/etc/vz';
my $remove_quotes = sub {
my $str = shift;
$str =~ s/^\s*\"?//;
$str =~ s/\"?\s*$//;
return $str;
};
# read global vz.conf
sub read_global_vz_config {
local $/;
my $res = {
rootdir => '/vz/root/$VEID', # note '$VEID' is a place holder
privatedir => '/vz/private/$VEID', # note '$VEID' is a place holder
dumpdir => '/vz/dump',
lockdir => '/var/lib/vz/lock',
};
my $filename = VZDIR . "/vz.conf";
my $fh = IO::File->new ($filename, "r");
return $res if !$fh;
my $data = <$fh> || '';
$fh->close();
if ($data =~ m/^\s*VE_PRIVATE=(.*)$/m) {
my $dir = &$remove_quotes ($1);
if ($dir !~ m/\$VEID/) {
warn "VE_PRIVATE does not contain '\$VEID' ('$dir')\n";
} else {
$res->{privatedir} = $dir;
}
}
if ($data =~ m/^\s*VE_ROOT=(.*)$/m) {
my $dir = &$remove_quotes ($1);
if ($dir !~ m/\$VEID/) {
warn "VE_ROOT does not contain '\$VEID' ('$dir')\n";
} else {
$res->{rootdir} = $dir;
}
}
if ($data =~ m/^\s*DUMPDIR=(.*)$/m) {
my $dir = &$remove_quotes ($1);
$dir =~ s|/\$VEID$||;
$res->{dumpdir} = $dir;
}
if ($data =~ m/^\s*LOCKDIR=(.*)$/m) {
my $dir = &$remove_quotes ($1);
$res->{lockdir} = $dir;
}
return $res;
}
my $load_vz_conf = sub { my $load_vz_conf = sub {
my ($self, $vmid) = @_; my ($self, $vmid) = @_;
local $/; my $conf = PVE::OpenVZ::load_config($vmid);
my $conf = $self->{vmlist}->{$vmid}->{conffile};
my $fh = IO::File->new ($conf, "r") ||
die "unable to open config file '$conf'\n";
my $data = <$fh>;
$fh->close();
my $dir; my $dir = $self->{privatedir};
if ($data =~ m/^\s*VE_PRIVATE=(.*)$/m) { if ($conf->{ve_private} && $conf->{ve_private}->{value}) {
$dir = &$remove_quotes ($1); $dir = $conf->{ve_private}->{value};
} else {
$dir = $self->{privatedir};
} }
$dir =~ s/\$VEID/$vmid/; $dir =~ s/\$VEID/$vmid/;
$self->{vmlist}->{$vmid}->{dir} = $dir; $self->{vmlist}->{$vmid}->{dir} = $dir;
if ($data =~ m/^\s*HOSTNAME=(.*)/m) { my $hostname = "CT $vmid";
$self->{vmlist}->{$vmid}->{hostname} = &$remove_quotes ($1); if ($conf->{hostname} && $conf->{hostname}->{value}) {
} else { $hostname = $conf->{hostname}->{value};
$self->{vmlist}->{$vmid}->{hostname} = "VM $vmid";
} }
$self->{vmlist}->{$vmid}->{hostname} = $hostname;
}; };
sub read_vz_list {
my $vmlist = {};
my $dir = VZDIR . "/conf";
foreach my $conf (<$dir/*.conf>) {
next if $conf !~ m|/(\d\d\d+)\.conf$|;
my $vmid = $1;
$vmlist->{$vmid}->{conffile} = $conf;
}
return $vmlist;
}
my $rsync_vm = sub { my $rsync_vm = sub {
my ($self, $task, $from, $to, $text) = @_; my ($self, $task, $from, $to, $text) = @_;
...@@ -160,11 +76,11 @@ sub new { ...@@ -160,11 +76,11 @@ sub new {
PVE::VZDump::check_bin ('vzctl'); PVE::VZDump::check_bin ('vzctl');
my $self = bless read_global_vz_config (); my $self = bless PVE::OpenVZ::read_global_vz_config ();
$self->{vzdump} = $vzdump; $self->{vzdump} = $vzdump;
$self->{vmlist} = read_vz_list (); $self->{vmlist} = PVE::OpenVZ::config_list();
return $self; return $self;
}; };
...@@ -176,12 +92,12 @@ sub type { ...@@ -176,12 +92,12 @@ sub type {
sub vm_status { sub vm_status {
my ($self, $vmid) = @_; my ($self, $vmid) = @_;
my $status_text = $self->cmd ("vzctl status $vmid"); my $status_text = $self->cmd ("vzctl status $vmid", returnstdout => 1);
chomp $status_text; chomp $status_text;
my $running = $status_text =~ m/running/ ? 1 : 0; my $running = $status_text =~ m/running/ ? 1 : 0;
return wantarray ? ($running, $status_text) : $running; return wantarray ? ($running, $running ? 'running' : 'stopped') : $running;
} }
sub prepare { sub prepare {
...@@ -197,7 +113,7 @@ sub prepare { ...@@ -197,7 +113,7 @@ sub prepare {
$task->{diskinfo} = $diskinfo; $task->{diskinfo} = $diskinfo;
my $hostname = hostname(); my $hostname = PVE::INotify::nodename();
if ($mode eq 'snapshot') { if ($mode eq 'snapshot') {
...@@ -236,12 +152,7 @@ sub lock_vm { ...@@ -236,12 +152,7 @@ sub lock_vm {
my $filename = "$self->{lockdir}/103.lck"; my $filename = "$self->{lockdir}/103.lck";
my $lockmgr = LockFile::Simple->make(-format => '%f', my $lockmgr = PVE::OpenVZ::create_lock_manager();
-autoclean => 1,
-max => 30,
-delay => 2,
-stale => 1,
-nfs => 0);
$self->{lock} = $lockmgr->lock($filename) || die "can't lock VM $vmid\n"; $self->{lock} = $lockmgr->lock($filename) || die "can't lock VM $vmid\n";
} }
...@@ -325,7 +236,7 @@ sub resume_vm { ...@@ -325,7 +236,7 @@ sub resume_vm {
sub assemble { sub assemble {
my ($self, $task, $vmid) = @_; my ($self, $task, $vmid) = @_;
my $conffile = $self->{vmlist}->{$vmid}->{conffile}; my $conffile = PVE::OpenVZ::config_file($vmid);
my $dir = $task->{snapdir}; my $dir = $task->{snapdir};
...@@ -354,9 +265,13 @@ sub archive { ...@@ -354,9 +265,13 @@ sub archive {
my $taropts = "--totals --sparse --numeric-owner --no-recursion --ignore-failed-read --one-file-system"; my $taropts = "--totals --sparse --numeric-owner --no-recursion --ignore-failed-read --one-file-system";
if ($snapdir eq $task->{tmpdir} && $snapdir =~ m|^$opts->{dumpdir}/|) { # note: --remove-files does not work because we do not
$taropts .= " --remove-files"; # try to save space # backup all files (filters). tar complains:
} # Cannot rmdir: Directory not empty
# we we disable this optimization for now
#if ($snapdir eq $task->{tmpdir} && $snapdir =~ m|^$opts->{dumpdir}/|) {
# $taropts .= " --remove-files"; # try to save space
#}
my $cmd = "("; my $cmd = "(";
$cmd .= "cd $snapdir;find . $findargs|sed 's/\\\\/\\\\\\\\/g'|"; $cmd .= "cd $snapdir;find . $findargs|sed 's/\\\\/\\\\\\\\/g'|";
......
package PVE::VZDump::Plugin; package PVE::VZDump::Plugin;
# Copyright (C) 2007-2009 Proxmox Server Solutions GmbH
#
# Copyright: vzdump is under GNU GPL, the GNU General Public License.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 dated June, 1991.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
# Author: Dietmar Maurer <dietmar@proxmox.com>
use strict; use strict;
use warnings; use warnings;
use PVE::VZDump;
sub set_logfd { sub set_logfd {
my ($self, $logfd) = @_; my ($self, $logfd) = @_;
...@@ -47,13 +28,13 @@ sub cmd_noerr { ...@@ -47,13 +28,13 @@ sub cmd_noerr {
sub loginfo { sub loginfo {
my ($self, $msg) = @_; my ($self, $msg) = @_;
PVE::VZDump::debugmsg ('info', $msg, $self->{logfd}, 0); PVE::VZDump::debugmsg('info', $msg, $self->{logfd}, 0);
} }
sub logerr { sub logerr {
my ($self, $msg) = @_; my ($self, $msg) = @_;
PVE::VZDump::debugmsg ('err', $msg, $self->{logfd}, 0); PVE::VZDump::debugmsg('err', $msg, $self->{logfd}, 0);
} }
sub type { sub type {
......
...@@ -16,6 +16,7 @@ SCRIPTS = \ ...@@ -16,6 +16,7 @@ SCRIPTS = \
MANS = \ MANS = \
pvectl.1 \ pvectl.1 \
vzdump.1 \
pvestatd.1 \ pvestatd.1 \
pvedaemon.1 \ pvedaemon.1 \
pveversion.1 \ pveversion.1 \
...@@ -33,6 +34,9 @@ all: ${MANS} ...@@ -33,6 +34,9 @@ all: ${MANS}
pvectl.1.pod: pvectl pvectl.1.pod: pvectl
perl -I.. ./pvectl printmanpod >$@ perl -I.. ./pvectl printmanpod >$@
vzdump.1.pod: vzdump
perl -I.. ./vzdump printmanpod >$@
.PHONY: install .PHONY: install
install: ${SCRIPTS} ${MANS} install: ${SCRIPTS} ${MANS}
perl -I.. ./pvesh verifyapi perl -I.. ./pvesh verifyapi
......
This diff is collapsed.
...@@ -383,7 +383,8 @@ Ext.define('PVE.Utils', { statics: { ...@@ -383,7 +383,8 @@ Ext.define('PVE.Utils', { statics: {
srvstart: 'Start service {0}', srvstart: 'Start service {0}',
srvstop: 'Stop service {0}', srvstop: 'Stop service {0}',
srvrestart: 'Restart service {0}', srvrestart: 'Restart service {0}',
srvreload: 'Reload service {0}' srvreload: 'Reload service {0}',
vzdump: 'Backup'
}, },
format_task_description: function(type, id) { format_task_description: function(type, id) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment