]>
git.proxmox.com Git - pve-manager.git/blob - PVE/VZDump/OpenVZ.pm
1 package PVE
::VZDump
::OpenVZ
;
3 # Copyright (C) 2007-2009 Proxmox Server Solutions GmbH
5 # Copyright: vzdump is under GNU GPL, the GNU General Public License.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; version 2 dated June, 1991.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the
18 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 # Author: Dietmar Maurer <dietmar@proxmox.com>
31 use base qw
(PVE
::VZDump
::Plugin
);
33 use constant SCRIPT_EXT
=> qw
(start stop mount umount
);
35 my $load_vz_conf = sub {
36 my ($self, $vmid) = @_;
38 my $conf = PVE
::OpenVZ
::load_config
($vmid);
40 my $dir = $self->{privatedir
};
41 if ($conf->{ve_private
} && $conf->{ve_private
}->{value
}) {
42 $dir = $conf->{ve_private
}->{value
};
44 $dir =~ s/\$VEID/$vmid/;
45 $self->{vmlist
}->{$vmid}->{dir
} = $dir;
47 my $hostname = "CT $vmid";
48 if ($conf->{hostname
} && $conf->{hostname
}->{value
}) {
49 $hostname = $conf->{hostname
}->{value
};
51 $self->{vmlist
}->{$vmid}->{hostname
} = $hostname;
55 my ($self, $task, $from, $to, $text) = @_;
57 $self->loginfo ("starting $text sync $from to $to");
59 my $starttime = time();
61 my $opts = $self->{vzdump
}->{opts
};
63 my $rsyncopts = "--stats -x --numeric-ids";
65 $rsyncopts .= " --bwlimit=$opts->{bwlimit}" if $opts->{bwlimit
};
67 $self->cmd ("rsync $rsyncopts -aH --delete --no-whole-file --inplace '$from' '$to'");
69 my $delay = time () - $starttime;
71 $self->loginfo ("$text sync finished ($delay seconds)");
75 my ($class, $vzdump) = @_;
77 PVE
::VZDump
::check_bin
('vzctl');
79 my $self = bless PVE
::OpenVZ
::read_global_vz_config
();
81 $self->{vzdump
} = $vzdump;
83 $self->{vmlist
} = PVE
::OpenVZ
::config_list
();
93 my ($self, $vmid) = @_;
95 my $status_text = $self->cmd ("vzctl status $vmid", returnstdout
=> 1);
98 my $running = $status_text =~ m/running/ ?
1 : 0;
100 return wantarray ?
($running, $running ?
'running' : 'stopped') : $running;
104 my ($self, $task, $vmid, $mode) = @_;
106 $self->$load_vz_conf ($vmid);
108 my $dir = $self->{vmlist
}->{$vmid}->{dir
};
110 my $diskinfo = { dir
=> $dir };
112 $task->{hostname
} = $self->{vmlist
}->{$vmid}->{hostname
};
114 $task->{diskinfo
} = $diskinfo;
116 my $hostname = PVE
::INotify
::nodename
();
118 if ($mode eq 'snapshot') {
120 my $lvmmap = PVE
::VZDump
::get_lvm_mapping
();
121 my ($srcdev, $lvmpath, $lvmvg, $lvmlv, $fstype) =
122 PVE
::VZDump
::get_lvm_device
($dir, $lvmmap);
124 my $targetdev = PVE
::VZDump
::get_lvm_device
($task->{dumpdir
}, $lvmmap);
126 die ("mode failure - unable to detect lvm volume group\n") if !$lvmvg;
127 die ("mode failure - wrong lvm mount point '$lvmpath'\n") if $dir !~ m
|/?$lvmpath/?
|;
128 die ("mode failure - unable to dump into snapshot (use option --dumpdir)\n")
129 if $targetdev eq $srcdev;
131 $diskinfo->{snapname
} = "vzsnap-$hostname-0";
132 $diskinfo->{snapdev
} = "/dev/$lvmvg/$diskinfo->{snapname}";
133 $diskinfo->{srcdev
} = $srcdev;
134 $diskinfo->{lvmvg
} = $lvmvg;
135 $diskinfo->{lvmlv
} = $lvmlv;
136 $diskinfo->{fstype
} = $fstype;
137 $diskinfo->{lvmpath
} = $lvmpath;
138 $diskinfo->{mountpoint
} = "/mnt/vzsnap0";
140 $task->{snapdir
} = $dir;
141 $task->{snapdir
} =~ s
|/?$lvmpath/?
|$diskinfo->{mountpoint
}/|;
143 } elsif ($mode eq 'suspend') {
144 $task->{snapdir
} = $task->{tmpdir
};
146 $task->{snapdir
} = $dir;
151 my ($self, $vmid) = @_;
153 my $filename = "$self->{lockdir}/103.lck";
155 my $lockmgr = PVE
::OpenVZ
::create_lock_manager
();
157 $self->{lock} = $lockmgr->lock($filename) || die "can't lock VM $vmid\n";
161 my ($self, $vmid) = @_;
163 $self->{lock}->release();
166 sub copy_data_phase1
{
167 my ($self, $task) = @_;
169 $self->$rsync_vm ($task, "$task->{diskinfo}->{dir}/", $task->{snapdir
}, "first");
172 # we use --skiplock for vzctl because we have already locked the VM
173 # by calling lock_vm()
176 my ($self, $task, $vmid) = @_;
178 $self->cmd ("vzctl --skiplock stop $vmid");
182 my ($self, $task, $vmid) = @_;
184 $self->cmd ("vzctl --skiplock start $vmid");
188 my ($self, $task, $vmid) = @_;
190 $self->cmd ("vzctl --skiplock chkpnt $vmid --suspend");
194 my ($self, $task) = @_;
196 my $opts = $self->{vzdump
}->{opts
};
198 my $di = $task->{diskinfo
};
200 mkpath
$di->{mountpoint
}; # create mount point for lvm snapshot
202 if (-b
$di->{snapdev
}) {
203 $self->loginfo ("trying to remove stale snapshot '$di->{snapdev}'");
205 $self->cmd_noerr ("umount $di->{mountpoint}");
207 $self->cmd_noerr ("lvremove -f $di->{snapdev}");
210 $self->loginfo ("creating lvm snapshot of $di->{srcdev} ('$di->{snapdev}')");
212 $task->{cleanup
}->{lvm_snapshot
} = 1;
214 $self->cmd ("lvcreate --size $opts->{size}M --snapshot" .
215 " --name $di->{snapname} /dev/$di->{lvmvg}/$di->{lvmlv}");
217 my $mopts = $di->{fstype
} eq 'xfs' ?
"-o nouuid" : '';
219 $task->{cleanup
}->{snapshot_mount
} = 1;
221 $self->cmd ("mount -t $di->{fstype} $mopts $di->{snapdev} $di->{mountpoint}");
224 sub copy_data_phase2
{
225 my ($self, $task) = @_;
227 $self->$rsync_vm ($task, "$task->{diskinfo}->{dir}/", $task->{snapdir
}, "final");
231 my ($self, $task, $vmid) = @_;
233 $self->cmd ("vzctl --skiplock chkpnt $vmid --resume");
237 my ($self, $task, $vmid) = @_;
239 my $conffile = PVE
::OpenVZ
::config_file
($vmid);
241 my $dir = $task->{snapdir
};
243 $task->{cleanup
}->{etc_vzdump
} = 1;
245 mkpath
"$dir/etc/vzdump/";
246 $self->cmd ("cp '$conffile' '$dir/etc/vzdump/vps.conf'");
247 my $cfgdir = dirname
($conffile);
248 foreach my $s (SCRIPT_EXT
) {
249 my $fn = "$cfgdir/$vmid.$s";
250 $self->cmd ("cp '$fn' '$dir/etc/vzdump/vps.$s'") if -f
$fn;
255 my ($self, $task, $vmid, $filename) = @_;
257 my $findexcl = $self->{vzdump
}->{findexcl
};
258 my $findargs = join (' ', @$findexcl) . ' -print0';
259 my $opts = $self->{vzdump
}->{opts
};
261 my $srcdir = $self->{vmlist
}->{$vmid}->{dir
};
262 my $snapdir = $task->{snapdir
};
264 my $zflag = $opts->{compress
} ?
'z' : '';
266 my $taropts = "--totals --sparse --numeric-owner --no-recursion --ignore-failed-read --one-file-system";
268 # note: --remove-files does not work because we do not
269 # backup all files (filters). tar complains:
270 # Cannot rmdir: Directory not empty
271 # we we disable this optimization for now
272 #if ($snapdir eq $task->{tmpdir} && $snapdir =~ m|^$opts->{dumpdir}/|) {
273 # $taropts .= " --remove-files"; # try to save space
277 $cmd .= "cd $snapdir;find . $findargs|sed 's/\\\\/\\\\\\\\/g'|";
278 $cmd .= "tar c${zflag}pf - $taropts --null -T -";
280 if ($opts->{bwlimit
}) {
281 my $bwl = $opts->{bwlimit
}*1024; # bandwidth limit for cstream
282 $cmd .= "|cstream -t $bwl";
287 if ($opts->{stdout
}) {
288 $self->cmd ($cmd, output
=> ">&=" . fileno($opts->{stdout
}));
290 $self->cmd ("$cmd >$filename");
295 my ($self, $task, $vmid) = @_;
297 my $di = $task->{diskinfo
};
299 if ($task->{cleanup
}->{snapshot_mount
}) {
300 $self->cmd_noerr ("umount $di->{mountpoint}");
303 if ($task->{cleanup
}->{lvm_snapshot
}) {
304 $self->cmd_noerr ("lvremove -f $di->{snapdev}") if -b
$di->{snapdev
};
307 if ($task->{cleanup
}->{etc_vzdump
}) {
308 my $dir = "$task->{snapdir}/etc/vzdump";
309 eval { rmtree
$dir if -d
$dir; };
310 $self->logerr ($@) if $@;