my $opts = $self->{vzdump}->{opts};
- my $rsync = ['rsync', '--stats', '-X', '--numeric-ids',
+ my @xattr = $task->{no_xattrs} ? () : ('-X', '-A');
+
+ my $rsync = ['rsync', '--stats', @xattr, '--numeric-ids',
'-aH', '--delete', '--no-whole-file', '--inplace',
'--one-file-system', '--relative'];
push @$rsync, "--bwlimit=$opts->{bwlimit}" if $opts->{bwlimit};
sub prepare {
my ($self, $task, $vmid, $mode) = @_;
- my $conf = $self->{vmlist}->{$vmid} = PVE::LXC::load_config($vmid);
+ my $conf = $self->{vmlist}->{$vmid} = PVE::LXC::Config->load_config($vmid);
my $storage_cfg = $self->{storecfg};
my $running = PVE::LXC::check_running($vmid);
$task->{hostname} = $conf->{'hostname'} || "CT$vmid";
- # fixme: when do we deactivate ??
- PVE::LXC::foreach_mountpoint($conf, sub {
+ my ($id_map, $rootuid, $rootgid) = PVE::LXC::parse_id_maps($conf);
+ $task->{userns_cmd} = PVE::LXC::userns_command($id_map);
+
+ my $volids = $task->{volids} = [];
+ PVE::LXC::Config->foreach_mountpoint($conf, sub {
my ($name, $data) = @_;
my $volid = $data->{volume};
my $mount = $data->{mp};
+ my $type = $data->{type};
- return if !$volid || !$mount || $volid =~ m|^/|;
+ return if !$volid || !$mount;
if ($name ne 'rootfs' && !$data->{backup}) {
push @$exclude_dirs, $mount;
}
push @$disks, $data;
+ push @$volids, $volid
+ if $type eq 'volume';
});
- my $volid_list = [map { $_->{volume} } @$disks];
- PVE::Storage::activate_volumes($storage_cfg, $volid_list);
if ($mode eq 'snapshot') {
- if (!PVE::LXC::has_feature('snapshot', $conf, $storage_cfg)) {
- die "mode failure - some volumes does not support snapshots\n";
+ if (!PVE::LXC::Config->has_feature('snapshot', $conf, $storage_cfg, undef, undef, 1)) {
+ die "mode failure - some volumes do not support snapshots\n";
}
+ unlock_vm($self, $vmid);
+
if ($conf->{snapshots} && $conf->{snapshots}->{vzdump}) {
$self->loginfo("found old vzdump snapshot (force removal)");
- PVE::LXC::snapshot_delete($vmid, 'vzdump', 0);
+ PVE::LXC::Config->snapshot_delete($vmid, 'vzdump', 1);
}
my $rootdir = $default_mount_point;
mkpath $rootdir;
&$check_mountpoint_empty($rootdir);
- # set snapshot_count (freezes CT it snapshot_count > 1)
- $task->{snapshot_count} = scalar(@$volid_list);
+ # set snapshot_count (freezes CT if snapshot_count > 1)
+ $task->{snapshot_count} = scalar(@$volids);
} elsif ($mode eq 'stop') {
my $rootdir = $default_mount_point;
mkpath $rootdir;
&$check_mountpoint_empty($rootdir);
+ PVE::Storage::activate_volumes($storage_cfg, $volids);
} elsif ($mode eq 'suspend') {
my $pid = PVE::LXC::find_lxc_pid($vmid);
foreach my $disk (@$disks) {
}
$task->{snapdir} = $task->{tmpdir};
} else {
+ unlock_vm($self, $vmid);
die "unknown mode '$mode'\n"; # should not happen
}
if ($mode ne 'suspend') {
- # If we preform mount operations, let's unshare the mount namespace
+ # If we perform mount operations, let's unshare the mount namespace
# to not influence the running host.
PVE::Tools::unshare(PVE::Tools::CLONE_NEWNS);
PVE::Tools::run_command(['mount', '--make-rprivate', '/']);
sub lock_vm {
my ($self, $vmid) = @_;
- PVE::LXC::lock_aquire($vmid);
+ my $lockconfig = sub {
+ my ($self, $vmid) = @_;
+
+ my $conf = PVE::LXC::Config->load_config($vmid);
+
+ PVE::LXC::Config->check_lock($conf);
+ $conf->{lock} = 'backup';
+
+ PVE::LXC::Config->write_config($vmid, $conf);
+ };
+
+ PVE::LXC::Config->lock_config($vmid, $lockconfig, ($self, $vmid));
}
sub unlock_vm {
my ($self, $vmid) = @_;
- PVE::LXC::lock_release($vmid);
+ my $unlockconfig = sub {
+ my ($self, $vmid) = @_;
+
+ my $conf = PVE::LXC::Config->load_config($vmid);
+
+ if ($conf->{lock} && $conf->{lock} eq 'backup') {
+ delete $conf->{lock};
+ PVE::LXC::Config->write_config($vmid, $conf);
+ }
+ };
+
+ PVE::LXC::Config->lock_config($vmid, $unlockconfig, ($self, $vmid));
}
sub snapshot {
my ($self, $task, $vmid) = @_;
- $self->loginfo("create storage snapshot snapshot");
+ $self->loginfo("create storage snapshot 'vzdump'");
# todo: freeze/unfreeze if we have more than one volid
- PVE::LXC::snapshot_create($vmid, 'vzdump', "vzdump backup snapshot");
+ PVE::LXC::Config->snapshot_create($vmid, 'vzdump', 0, "vzdump backup snapshot");
$task->{cleanup}->{remove_snapshot} = 1;
# reload config
- my $conf = $self->{vmlist}->{$vmid} = PVE::LXC::load_config($vmid);
- die "unable to read vzdump shanpshot config - internal error"
+ my $conf = $self->{vmlist}->{$vmid} = PVE::LXC::Config->load_config($vmid);
+ die "unable to read vzdump snapshot config - internal error"
if !($conf->{snapshots} && $conf->{snapshots}->{vzdump});
my $disks = $task->{disks};
- my $volid_list = [map { $_->{volume} } @$disks];
+ my $volids = $task->{volids};
my $rootdir = $default_mount_point;
my $storage_cfg = $self->{storecfg};
+ PVE::Storage::activate_volumes($storage_cfg, $volids, 'vzdump');
foreach my $disk (@$disks) {
$disk->{dir} = "${rootdir}$disk->{mp}";
PVE::LXC::mountpoint_mount($disk, $rootdir, $storage_cfg, 'vzdump');
sub copy_data_phase1 {
my ($self, $task) = @_;
+ if (my $mntinfo = PVE::VZDump::get_mount_info($task->{snapdir})) {
+ if ($mntinfo->{fstype} =~ /^nfs4?/) {
+ warn "temporary directory is on NFS, disabling xattr and acl support"
+ . ", consider configuring a local tmpdir via /etc/vzdump.conf\n";
+ $task->{no_xattrs} = 1;
+ }
+ }
+
$self->$rsync_vm($task, $task->{snapdir}, "first");
}
my ($self, $task, $vmid) = @_;
$self->cmd("lxc-stop -n $vmid");
+
+ # make sure container is stopped
+ $self->cmd("lxc-wait -n $vmid -s STOPPED");
}
sub start_vm {
mkpath "$tmpdir/etc/vzdump/";
- my $conf = PVE::LXC::load_config($vmid);
+ my $conf = PVE::LXC::Config->load_config($vmid);
+ delete $conf->{lock};
delete $conf->{snapshots};
delete $conf->{'pve.parent'};
PVE::Tools::file_set_contents("$tmpdir/etc/vzdump/pct.conf", PVE::LXC::write_pct_config("/lxc/$vmid.conf", $conf));
+
+ my $firewall ="/etc/pve/firewall/$vmid.fw";
+ if (-e $firewall) {
+ PVE::Tools::file_copy($firewall, "$tmpdir/etc/vzdump/pct.fw");
+ $task->{fw} = 1;
+ }
}
sub archive {
push @sources, ".$disk->{mp}";
}
$task->{snapdir} = $rootdir;
+ } elsif ($task->{mode} eq 'snapshot') {
+ # mounting the vzdump snapshots and setting $snapdir is already done,
+ # but we need to include all mountpoints here!
+ foreach my $disk (@$disks) {
+ push @sources, ".$disk->{mp}";
+ }
} else {
# the data was rsynced to a temporary location, only use '.' to avoid
# having mountpoints duplicated
my $snapdir = $task->{snapdir};
my $tmpdir = $task->{tmpdir};
- my $tar = ['tar', 'cpf', '-',
- '--totals', '--sparse', '--numeric-owner', '--xattrs',
- '--one-file-system'];
+ my $userns_cmd = $task->{userns_cmd};
+ my $tar = [@$userns_cmd, 'tar', 'cpf', '-', '--totals',
+ @$PVE::LXC::COMMON_TAR_FLAGS,
+ '--one-file-system', '--warning=no-file-ignored'];
# note: --remove-files does not work because we do not
# backup all files (filters). tar complains:
# Cannot rmdir: Directory not empty
- # we we disable this optimization for now
+ # we disable this optimization for now
#if ($snapdir eq $task->{tmpdir} && $snapdir =~ m|^$opts->{dumpdir}/|) {
# push @$tar, "--remove-files"; # try to save space
#}
- # The directory parameter can give a alternative directory as source.
+ # The directory parameter can give an alternative directory as source.
# the second parameter gives the structure in the tar.
push @$tar, "--directory=$tmpdir", './etc/vzdump/pct.conf';
+ push @$tar, "./etc/vzdump/pct.fw" if $task->{fw};
push @$tar, "--directory=$snapdir";
+ push @$tar, '--no-anchored', '--exclude=lost+found' if $userns_cmd;
+ push @$tar, '--anchored';
push @$tar, map { "--exclude=.$_" } @{$self->{vzdump}->{findexcl}};
push @$tar, @sources;
my $bwl = $opts->{bwlimit}*1024; # bandwidth limit for cstream
push @$cmd, [ 'cstream', '-t', $bwl ] if $opts->{bwlimit};
- push @$cmd, [ $comp ] if $comp;
+ push @$cmd, [ split(/\s+/, $comp) ] if $comp;
if ($opts->{stdout}) {
push @{$cmd->[-1]}, \(">&" . fileno($opts->{stdout}));
sub cleanup {
my ($self, $task, $vmid) = @_;
- my $conf = PVE::LXC::load_config($vmid);
+ my $conf = PVE::LXC::Config->load_config($vmid);
if ($task->{mode} ne 'suspend') {
my $rootdir = $default_mount_point;
if ($task->{cleanup}->{remove_snapshot}) {
$self->loginfo("remove vzdump snapshot");
- PVE::LXC::snapshot_delete($vmid, 'vzdump', 0);
+ PVE::LXC::Config->snapshot_delete($vmid, 'vzdump', 0);
}
}