#!/usr/bin/perl -w # # Copyright (C) 2007 Proxmox Server Solutions GmbH # Copyright (C) 2009 KAPPER NETWORK-COMMUNICATIONS 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., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Author: Dietmar Maurer # Co-Author: Harald Kapper # use strict; use Getopt::Long; use File::Path; use IO::File; use IO::Select; use IPC::Open3; use POSIX ":sys_wait_h"; use POSIX ':signal_h'; use POSIX qw(strftime); my $vzdir = '/etc/vz'; my $vpslist; my $opt_all; my $opt_exclude; my $opt_exclude_path; my $opt_debug = 1; my $opt_dumpdir; my $opt_compress = 0; my $opt_restore; my $opt_mailto; my $opt_xdelta; my $opt_stop; my $opt_suspend; my $opt_snap; my $vzctl = 'vzctl'; my $rsync = 'rsync'; my $xdelta = 'xdelta'; my $lvcreate = 'lvcreate'; my $lvscan = 'lvscan'; my $lvremove = 'lvremove'; my $sendmail = 'sendmail'; my @script_ext = qw (start stop mount umount); my @findexcl; sub find_add_exclude { my ($excltype, $value) = @_; if (($excltype eq '-regex') || ($excltype eq '-files')) { $value = "\.$value"; } if ($excltype eq '-files') { push @findexcl, "'('", '-not', '-type', 'd', '-regex' , "'$value'", "')'", '-o'; } else { push @findexcl, "'('", $excltype , "'$value'", '-prune', "')'", '-o'; } } find_add_exclude ('-type', 's'); # skip sockets my $debugstattxt = { err => 'ERROR:', info => 'INFO:', warn => 'WARN:', }; sub logmsg { my ($mtype, $msg, $logfd) = @_; chomp $msg; return if !$msg || !$logfd; my $pre = $debugstattxt->{$mtype}; foreach my $line (split (/\n/, $msg)) { print $logfd strftime ("%b %d %H:%M:%S", localtime) . " $pre $line\n"; } } sub debugmsg { my ($mtype, $msg, $logfd) = @_; chomp $msg; return if !$msg; my $pre = $debugstattxt->{$mtype}; print STDERR "$pre $msg\n" if $opt_debug; logmsg ($mtype, $msg, $logfd) if $logfd; } sub escape_html { my ($str) = @_; $str =~ s/&/&/g; $str =~ s//>/g; return $str; } sub encode8bit { my ($str) = @_; $str =~ s/^(.{990})/$1\n/mg; # reduce line length return $str; } # send nicely formated multipart/alternative mail sub send_mail { my ($mailto, $vpsid, $logfile, $backuptime, $size, $deltasize, $finalname, $err) = @_; my $stat = $err ? 'backup failed' : 'backup successful'; my $hostname = $vpslist->{$vpsid}->{hostname}; my $boundary = "----_=_NextPart_001_".int(time).$$; my $rcvrarg = ''; foreach my $r (@$mailto) { $rcvrarg .= " '$r'"; } open (MAIL,"|$sendmail -B 8BITMIME $rcvrarg") || die "unable to open $sendmail - $!"; my $rcvrtxt = join (', ', @$mailto); print MAIL "Content-Type: multipart/alternative;\n"; print MAIL "\tboundary=\"$boundary\"\n"; print MAIL "FROM: vzdump backup tool \n"; print MAIL "TO: $rcvrtxt\n"; print MAIL "SUBJECT: VPS Backup Status for $vpsid ($hostname) : $stat\n"; print MAIL "\n"; print MAIL "This is a multi-part message in MIME format.\n\n"; print MAIL "--$boundary\n"; print MAIL "Content-Type: text/plain;\n"; print MAIL "\tcharset=\"UTF8\"\n"; print MAIL "Content-Transfer-Encoding: 8bit\n"; print MAIL "\n"; # text part if ($err) { print MAIL "ERRORS during backup - backup FAILED!\n\n"; } else { print MAIL sprintf ("Backup successful - %.2f MB in %.2f minutes\n\n", $size / (1024*1024), $backuptime); } open (TMP, "$logfile"); while (my $line = ) { print MAIL encode8bit ($line); } close (TMP); print MAIL "\n--$boundary\n"; print MAIL "Content-Type: text/html;\n"; print MAIL "\tcharset=\"UTF8\"\n"; print MAIL "Content-Transfer-Encoding: 8bit\n"; print MAIL "\n"; # html part print MAIL "\n"; if ($err) { print MAIL "

ERRORS during backup - backup FAILED!

\n"; } else { print MAIL "

Backup successful!

\n"; print MAIL "\n"; print MAIL "\n"; print MAIL "\n"; print MAIL sprintf ("\n", $size / (1024*1024)); print MAIL sprintf ("\n", $deltasize / (1024*1024)) if $opt_xdelta; print MAIL sprintf ("\n", $backuptime); print MAIL "\n"; print MAIL "
VPSID$vpsid ($hostname)
Status$stat
Size%.2f MB
Delta%.2f MB
Time%.2f minutes
Path". escape_html ($finalname) . "

\n"; } print MAIL "Detailed backup log:\n"; print MAIL "
\n";
    open (TMP, "$logfile");
    while (my $line = ) { 

	if ($line =~ m/^\S+\s\d+\s+\d+:\d+:\d+\s+(ERROR|WARN):/) {
	    print MAIL encode8bit ("". 
				   escape_html ($line) . ""); 
	} else {
	    print MAIL encode8bit (escape_html ($line)); 
	}
    }
    close (TMP);
    print MAIL "
\n"; print MAIL "\n"; print MAIL "\n--$boundary--\n"; close (MAIL); } sub run_command { my ($logfd, $cmdstr, $input, $timeout) = @_; my $reader = IO::File->new(); my $writer = IO::File->new(); my $error = IO::File->new(); my $pid = open3 ($writer, $reader, $error, ($cmdstr)) || die $!; print $writer $input if defined $input; close $writer; my $select = new IO::Select; $select->add ($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"; } foreach my $h (@handles) { my $buf = ''; my $count = sysread ($h, $buf, 4096); if (!defined ($count)) { waitpid ($pid, 0); die "command '$cmdstr' failed: $!"; } $select->remove ($h) if !$count; if ($h eq $reader) { $ostream .= $buf; $logout .= $buf; while ($logout =~ s/^([^\n]*\n)//s) { my $line = $1; print STDOUT $line; logmsg ('info', $line, $logfd); } } elsif ($h eq $error) { $estream .= $buf; $logerr .= $buf; while ($logerr =~ s/^([^\n]*\n)//s) { my $line = $1; print STDERR $line; logmsg ('info', $line, $logfd); } } } } logmsg ('info', $logout, $logfd); logmsg ('info', $logerr, $logfd); waitpid ($pid, 0); my $ec = ($? >> 8); return $ostream if $ec == 24 && ($cmdstr =~ m/^$rsync/); return $ostream if $ec == 1 && ($cmdstr =~ m/^$xdelta/); die "command '$cmdstr' failed with exit code $ec" if $ec; return $ostream; } sub print_usage { my $msg = shift; print STDERR "ERROR: $msg\n\n" if $msg; print STDERR "usage: $0 OPTIONS [--all | VPSID]\n\n"; print STDERR "\t--exclude VPSID\t\texclude VPSID (assumes --all)\n"; print STDERR "\t--exclude-path REGEX\texclude certain files/directories\n"; print STDERR "\t--compress\t\tcompress dump file (gzip)\n"; print STDERR "\t--dumpdir DIR\t\tstore resulting files in DIR\n"; print STDERR "\t--xdelta\t\tcreate differential backup using xdelta\n"; print STDERR "\t--mailto EMAIL\t\tsend notification mail to EMAIL.\n"; print STDERR "\t--stop\t\t\tstop/start VPS if running\n"; print STDERR "\t--suspend\t\tsuspend/resume VPS when running\n"; print STDERR "\t--snapshot\t\tuse LVM snapshot when running\n"; print STDERR "\t--restore FILENAME\trestore FILENAME\n"; print STDERR "\n"; } my $devmapper; sub get_device { my $dir = shift; open (TMP, "df -P '$dir'|"); ; #skip first line my $out = ; close (TMP); my @res = split (/\s+/, $out); my $dev = $res[0]; my $mp = $res[5]; my ($vg, $lv); ($vg, $lv) = @{$devmapper->{$dev}} if defined $devmapper->{$dev}; return wantarray ? ($dev, $mp, $vg, $lv) : $dev; } sub check_vpsid { my $vpsid = shift; if ($vpsid !~ m/^\d\d\d+$/) { print_usage ("strange VPS ID '${vpsid}'"); exit (-1); } } if (!GetOptions ('all' => \$opt_all, 'exclude=s@' => \$opt_exclude, 'exclude-path=s@' => \$opt_exclude_path, 'compress' => \$opt_compress, 'restore=s' => \$opt_restore, 'mailto=s@' => \$opt_mailto, 'xdelta' => \$opt_xdelta, 'stop' =>\$opt_stop, 'suspend' =>\$opt_suspend, 'snapshot' =>\$opt_snap, 'dumpdir=s' => \$opt_dumpdir)) { print_usage (); exit (-1); } $opt_all = 1 if $opt_exclude; if ($opt_all && ($#ARGV >= 0 || $opt_restore)) { print_usage (); exit (-1); } if (!$opt_all && $#ARGV != 0) { print_usage (); exit (-1); } if ($opt_restore && ! -f $opt_restore) { print_usage ("unable to access file '${opt_restore}'"); exit (-1); } my $opt_vpsid; if (!$opt_all) { $opt_vpsid = $ARGV[0]; check_vpsid ($opt_vpsid); } if ($opt_exclude) { foreach my $vpsid (@$opt_exclude) { check_vpsid ($vpsid); } } if ($opt_exclude_path) { foreach my $path (@$opt_exclude_path) { find_add_exclude ('-regex', $path); } } sub check_bin { my ($bin, $msg) = @_; my $v = $$bin; my $path = "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"; foreach my $p (split (/:/, $path)) { my $fn = "$p/$v"; if (-x $fn) { $$bin = $fn; return; } } die "unable to find '$v' - $msg\n"; } check_bin (\$vzctl, "OpenVZ not installed?"); check_bin (\$rsync, "rsync not installed?") if $opt_suspend; check_bin (\$xdelta, "xdelta not installed?") if $opt_xdelta; check_bin (\$lvcreate, "lvm2 not installed?") if $opt_snap; check_bin (\$lvscan, "lvm2 not installed?") if $opt_snap; check_bin (\$lvremove, "lvm2 not installed?") if $opt_snap; check_bin (\$sendmail, "sendmail not installed?") if $opt_mailto; if ($opt_snap) { open (TMP, "$lvscan|") || die "unable to exec $lvscan\n"; while (my $line = ) { if ($line =~ m|^\s+ACTIVE\s+\'/dev/([^/]+)/([^\']+)\'\s|) { my $vg = $1; my $lv = $2; $devmapper->{"/dev/$vg/$lv"} = [$vg, $lv]; $devmapper->{"/dev/mapper/$vg-$lv"} = [$vg, $lv]; } } close (TMP); } my $stopve; $stopve = 'stop' if $opt_stop; $stopve = 'suspend' if $opt_suspend; my $vzconf = { vzdir => $vzdir, confdir => "$vzdir/conf", conffile => "$vzdir/vz.conf", rootdir => '/vz/root', privatedir => '/vz/private', dumpdir => $opt_dumpdir || '/vz/dump', }; $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub { die "interrupted by signal\n"; }; sub remove_quotes { my $str = shift; $str =~ s/^\s*\"?//; $str =~ s/\"?\s*$//; return $str; } # read global vz.conf sub read_global_config { local $/; my $filename = $vzconf->{conffile}; die "unable to open file '$filename' - $!\n" if ! -f $filename; open (TMP, "<$filename"); my $data = || ''; close (TMP); if ($data =~ m/^\s*VE_PRIVATE=(.*)$/m) { my $dir = remove_quotes ($1); $dir =~ s|/\$VEID$||; $vzconf->{privatedir} = $dir; } if ($data =~ m/^\s*VE_ROOT=(.*)$/m) { my $dir = remove_quotes ($1); $dir =~ s|/\$VEID$||; $vzconf->{rootdir} = $dir; } if ($data =~ m/^\s*DUMPDIR=(.*)$/m) { my $dir = remove_quotes ($1); $dir =~ s|/\$VEID$||; $vzconf->{dumpdir} = $opt_dumpdir || $dir; } } read_global_config (); my $cfgdir = $vzconf->{confdir}; foreach my $conf (<$cfgdir/*.conf>) { if ($conf =~ m|/(\d\d\d+)\.conf$|) { my $vpsid = $1; local $/; open (TMP, "<$conf"); my $data = ; close (TMP); $vpslist->{$vpsid}->{conffile} = $conf; $vpslist->{$vpsid}->{conf} = $data; if ($data =~ m/^\s*VE_PRIVATE=(.*)$/m) { my $dir = remove_quotes ($1); $dir =~ s/\$VEID/$vpsid/; $vpslist->{$vpsid}->{dir} = $dir; } else { $vpslist->{$vpsid}->{dir} = "$vzconf->{privatedir}/$vpsid"; } if ($data =~ m/^\s*VE_ROOT=(.*)$/m) { my $dir = remove_quotes ($1); $dir =~ s/\$VEID/$vpsid/; $vpslist->{$vpsid}->{root} = $dir; } else { $vpslist->{$vpsid}->{root} = "$vzconf->{rootdir}/$vpsid"; } if ($data =~ m/^\s*HOSTNAME=(.*)/m) { $vpslist->{$vpsid}->{hostname} = remove_quotes ($1); } } } if ($opt_restore) { my $conffile = "$vzconf->{confdir}/${opt_vpsid}.conf"; if (-f $conffile) { print_usage ("unable to restore VPS '${opt_vpsid}' - VPS already exists"); exit (-1); } my $private = "$vzconf->{privatedir}/${opt_vpsid}"; my $root = "$vzconf->{rootdir}/${opt_vpsid}"; if (-d $private) { print_usage ("unable to restore VPS '${opt_vpsid}' - directory '$private' already exists"); exit (-1); } if (-d $root) { print_usage ("unable to restore VPS '${opt_vpsid}' - directory '$root' already exists"); exit (-1); } eval { mkpath $private || die "unable to create private dir '$private'"; mkpath $root || die "unable to create private dir '$private'"; my $cmd = "zcat -f ${opt_restore}| tar xpf - --totals -C $private"; debugmsg ('info', "extracting archive '${opt_restore}'"); system ($cmd) == 0 || die "unable to extract archive"; debugmsg ('info', "extracting configuration to '$conffile'"); my $qroot = $root; $qroot =~ s|/|\\\/|g; $qroot =~ s|/${opt_vpsid}$|/\$VEID|; my $qprivate = $private; $qprivate =~ s|/|\\\/|g; $qprivate =~ s|/${opt_vpsid}$|/\$VEID|; my $scmd = "sed -e 's/VE_ROOT=.*/VE_ROOT=\\\"$qroot\\\"/' -e 's/VE_PRIVATE=.*/VE_PRIVATE=\\\"$qprivate\\\"/' <'$private/etc/vzdump/vps.conf' >'$conffile'"; run_command (undef, $scmd); foreach my $s (@script_ext) { my $cfgdir = $vzconf->{confdir}; my $tfn = "$cfgdir/${opt_vpsid}.$s"; my $sfn = "$private/etc/vzdump/vps.$s"; if (-f $sfn) { run_command (undef, "cp '$sfn' '$tfn'"); } } rmtree "$private/etc/vzdump"; debugmsg ('info', "restore successful"); }; my $err = $@; if ($err) { system ("rm -rf '$private' '$root' '$conffile'"); die $err; } exit (0); } if ($opt_vpsid && !exists ($vpslist->{$opt_vpsid})) { print_usage ("unable to find VPS '${opt_vpsid}'"); exit (-1); } foreach my $vpsid (keys %$vpslist) { next if $opt_vpsid && $vpsid ne $opt_vpsid; next if grep { $_ eq $vpsid } @$opt_exclude; my $backuptime = time (); my $targetdir = $vzconf->{dumpdir}; my $private = $vpslist->{$vpsid}->{dir}; my $root = $vpslist->{$vpsid}->{root}; my $basename = "vzdump-${vpsid}"; # war: my $tarfile = "$targetdir/$basename". ($opt_compress ? '.tar.gz' : '.tar'); my $tarfile = "$targetdir/$basename". ($opt_compress ? '.tar' : '.tar'); my $logfile = "$targetdir/$basename.log"; my $deltafile = "$targetdir/$basename.xdelta"; my $oldtarfile; if ($opt_xdelta) { if (! -f $tarfile) { $opt_xdelta = undef; } else { $oldtarfile = $tarfile; $tarfile = "$tarfile.$$"; } } unlink $tarfile; unlink $logfile; unlink $deltafile if !$opt_xdelta; my $dir = $private; my $tmpdir = "$targetdir/tmp$$"; open (LOG, ">$logfile"); my ($lvmpath, $lvmvg, $lvmlv); if ($opt_snap) { my ($dev, $mp, $vg, $lv) = get_device ($dir); $lvmpath = $mp; $lvmvg = $vg; $lvmlv = $lv; } my $snapdev; my $status = `$vzctl status $vpsid`; my $running = 0; $running = 1 if $status =~ m/running/; my $size = 0; my $deltasize = 0; my $finalname; eval { debugmsg ('info', "starting backup for VPS $vpsid ($dir)", \*LOG); if ($running) { if ($opt_snap) { my $targetdev = get_device ($targetdir); my $srcdev = get_device ($dir); die "unable to dump into snapshot (use option --dumpdir)" if ($targetdev eq $srcdev); mkdir "/vzsnap"; # create mount point for lvm snapshot $snapdev = "/dev/$lvmvg/vzsnap"; debugmsg ('info', "creating lvm snapshot of $srcdev ('$snapdev')", \*LOG); run_command (\*LOG, "$lvcreate --size 500m --snapshot --name vzsnap /dev/$lvmvg/$lvmlv"); debugmsg ('info', "mounting lvm snapshot", \*LOG); run_command (\*LOG, "mount $snapdev /vzsnap"); $dir =~ s|/?$lvmpath/?|/vzsnap/|; die "wrong lvm mount point '$lvmpath'" if ($dir !~ m|/vzsnap|) || (! -d $dir); } elsif ($stopve) { system ("rm -rf $tmpdir"); mkdir $tmpdir || die "unable to create tmpdir"; my $synccmd = "$rsync -aH --delete $dir $tmpdir"; debugmsg ('info', "starting first sync $dir to $tmpdir", \*LOG); run_command (\*LOG, $synccmd); my $starttime = time(); if ($stopve eq 'stop') { debugmsg ('info', "stopping vps", \*LOG); run_command (\*LOG, "$vzctl stop $vpsid"); } elsif ($stopve eq 'suspend') { debugmsg ('info', "suspend vps", \*LOG); run_command (\*LOG, "$vzctl chkpnt $vpsid --suspend"); } else { die "unknown mode '$stopve'"; } debugmsg ('info', "final sync $dir to $tmpdir", \*LOG); run_command (\*LOG, $synccmd); if ($stopve eq 'stop') { debugmsg ('info', "restarting vps", \*LOG); run_command (\*LOG, "$vzctl start $vpsid"); } elsif ($stopve eq 'suspend') { debugmsg ('info', "resume vps", \*LOG); run_command (\*LOG, "$vzctl chkpnt $vpsid --resume"); } my $delay = time () - $starttime; debugmsg ('info', "vps is online again after $delay seconds", \*LOG); $dir = "$tmpdir/$vpsid"; } else { debugmsg ('warn', "online backup without suspend/snapshot", \*LOG); debugmsg ('warn', "this can lead to inconsistent data", \*LOG); } } debugmsg ('info', "Creating archive '$tarfile' ($dir)", \*LOG); mkpath "$dir/etc/vzdump/"; my $srcconf = $vpslist->{$vpsid}->{conffile}; run_command (\*LOG, "cp $srcconf $dir/etc/vzdump/vps.conf"); foreach my $s (@script_ext) { my $cfgdir = $vzconf->{confdir}; my $fn = "$cfgdir/$vpsid.$s"; if (-f $fn) { run_command (\*LOG, "cp $fn $dir/etc/vzdump/vps.$s"); } } if (!$opt_exclude_path) { # excluded by hk 20071207 re-included 20090203 find_add_exclude ('-files', '/var/log/.+'); find_add_exclude ('-regex', '/tmp/.+'); find_add_exclude ('-regex', '/var/tmp/.+'); find_add_exclude ('-regex', '/var/run/.+pid'); } my $zflag = $opt_compress ? 'z' : ''; # backup all types except sockets my $findargs = join (' ', @findexcl) . ' -print0'; my $cmd = "(cd $dir; find . $findargs|tar cpf $tarfile --totals --numeric-owner --no-recursion --ignore-failed-read --null -T -)"; run_command (\*LOG, $cmd); rmtree "$dir/etc/vzdump"; system ("rm -rf $tmpdir"); # no longer needed if ($zflag eq 'z') { # gzip compress rsyncable debugmsg ('info', "Compressing gzip --rsyncable archive '$tarfile' ($dir)", \*LOG); $cmd = "(rm -f ${tarfile}.gz)"; run_command (\*LOG, $cmd); # sicherheitshalber oben mal das .gz wegraeumen das wir gleich machen $cmd = "(gzip --rsyncable $tarfile)"; run_command (\*LOG, $cmd); $tarfile = "${tarfile}.gz"; } $size = -s $tarfile; $finalname = $tarfile; if ($opt_xdelta) { debugmsg ('info', "creating delta", \*LOG); run_command (\*LOG, "$xdelta delta $oldtarfile $tarfile $deltafile"); unlink $tarfile; $deltasize = -s $deltafile; $finalname = $deltafile; } }; my $err = $@; system ("rm -rf $tmpdir"); if ($running && $opt_snap && $snapdev) { eval { run_command (\*LOG, "umount /vzsnap"); }; rmdir "/vzsnap"; eval { run_command (\*LOG, "$lvremove -f $snapdev"); }; } $backuptime = (time () - $backuptime) / 60.0; if ($err) { unlink $tarfile; unlink $deltafile; debugmsg ('err', sprintf ("creating backup for VPS %s failed (%.2f minutes): %s", $vpsid, $backuptime, $err), \*LOG); } else { debugmsg ('info', sprintf ("backup for VPS %s finished successful (%.2f minutes)", $vpsid, $backuptime), \*LOG); } close (LOG); eval { send_mail ($opt_mailto, $vpsid, $logfile, $backuptime, $size, $deltasize, $finalname, $err) if ($opt_mailto); }; debugmsg ('err', $@) if $@; last if $err =~ m/interrupted by signal/; } exit 0; __END__ =head1 NAME vzdump - openvz backup and restore utility =head1 SYNOPSIS vzdump OPTIONS [--all | ] --exclude VPSID exclude VPSID (assumes --all) --exclude-path REGEX exclude certain files/directories. Standard exclusions are disabled in this case. You can use this option more than once to specify multiple exclude paths --compress compress dump file (gzip) --dumpdir DIR store resulting files in DIR --xdelta create a differential backup using xdelta --mailto EMAIL send notification mail to EMAIL. You can use this option more than once to specify multiple receivers --stop stop/start VPS if running --suspend suspend/resume VPS when running --snapshot use LVM snapshot when running --restore FILENAME restore FILENAME =head1 DESCRIPTION vzdump is an utility to make consistent snapshots of running OpenVZ VEs. It basically creates a tar archive of the VE private area, which also includes the VE configuration files. There are several ways to provide consistency: - stop the VE during backup (very long downtime) - use rsync and suspend/resume (minimal downtime). - use LVM2 (no downtime, but needs LVM2 and 500m free space on the corresponding volume group to create the LVM snapshot) =head1 FILES vzdump skips the following files by default /var/log/.+ /tmp/.+ /var/tmp/.+ /var/run/.+pid You can overwrite those exclusions by manually specifying exclude paths, for example: > vzdump --exclude-path '/tmp/.+' --exclude-path '/var/tmp/.+' 777 (only excludes tmp directories) OpenVZ configuration files are also stored inside the backup archive (/etc/vzdump), and will be correctly restored with --restore =head1 EXAMPLES Simply dump VE 777 - no snapshot, just archive the VE private area and configuration files to the default dump directory (usually /vz/dump/). > vzdump 777 Use rsync and suspend/resume to create an snapshot (minimal downtime). > vzdump --suspend 777 Backup all VEs and send notification mails to root. > vzdump --suspend --all --mailto root Use LVM2 to create snapshots (no downtime). > vzdump --dumpdir /space/backup --snapshot 777 Restore above backup to VE 600 > vzdump --restore /space/backup/vzdump-777.tar 600 Backup all VESs excluding VE 101 and 102 > vzdump --suspend --exclude 101 --exclude 102 =head1 AUTHOR Dietmar Maurer Many thanks to Proxmox Server Solutions (www.proxmox.com) for sponsoring this work. =head1 COPYRIGHT AND DISCLAIMER Copyright (C) 2007 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.