[pve-devel] [PATCH 3/9] Add snapshot functionality on zfs to lxc

Wolfgang Link w.link at proxmox.com
Fri Jul 17 09:26:45 CEST 2015


Signed-off-by: Wolfgang Link <w.link at proxmox.com>
---
 src/PVE/LXC.pm | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 123 insertions(+), 3 deletions(-)

diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm
index 3bb69ca..dc351c6 100644
--- a/src/PVE/LXC.pm
+++ b/src/PVE/LXC.pm
@@ -240,7 +240,7 @@ sub write_lxc_config {
 	foreach my $k (sort keys %$elem) {
 	    next if $k eq 'snapshots';
 	    next if $done_hash->{$k};
-	    die "found un-written value in config - implement this!";
+	    die "found un-written value \"$k\" in config - implement this!";
 	}
 
     };
@@ -1203,7 +1203,7 @@ sub update_lxc_config {
 		update_net($vmid, $conf, $opt, $net, $netid, $rootdir);
 	    }
 	} else {
-	    die "implement me"
+	    die "implement me: $opt";
 	}
 	PVE::LXC::write_config($vmid, $conf) if $running;
     }
@@ -1428,11 +1428,131 @@ sub update_ipconfig {
 
 }
 
+# Internal snapshots
+
+# NOTE: Snapshot create/delete involves several non-atomic
+# action, and can take a long time.
+# So we try to avoid locking the file and use 'lock' variable
+# inside the config file instead.
+
+my $snapshot_copy_config = sub {
+    my ($source, $dest) = @_;
+
+    foreach my $k (keys %$source) {
+	next if $k eq 'snapshots';
+	next if $k eq 'pve.snapstate';
+	next if $k eq 'pve.snaptime';
+	next if $k eq 'pve.lock';
+	next if $k eq 'digest';
+	next if $k eq 'pve.comment';
+
+	$dest->{$k} = $source->{$k};
+    }
+};
+
+my $snapshot_prepare = sub {
+    my ($vmid, $snapname, $comment) = @_;
+
+    my $snap;
+
+    my $updatefn =  sub {
+
+	my $conf = load_config($vmid);
+
+	check_lock($conf);
+
+	$conf->{'pve.lock'} = 'snapshot';
+
+	die "snapshot name '$snapname' already used\n"
+	    if defined($conf->{snapshots}->{$snapname});
+
+	my $storecfg = PVE::Storage::config();
+	die "snapshot feature is not available\n" if !has_feature('snapshot', $conf, $storecfg);
+
+	$snap = $conf->{snapshots}->{$snapname} = {};
+
+	&$snapshot_copy_config($conf, $snap);
+
+	$snap->{'pve.snapstate'} = "prepare";
+	$snap->{'pve.snaptime'} = time();
+	$snap->{'pve.snapname'} = $snapname;
+	$snap->{'pve.snapcomment'} = $comment if $comment;
+	$conf->{snapshots}->{$snapname} = $snap;
+
+	PVE::LXC::write_config($vmid, $conf);
+    };
+
+    lock_container($vmid, 10, $updatefn);
+
+    return $snap;
+};
+
+my $snapshot_commit = sub {
+    my ($vmid, $snapname) = @_;
+
+    my $updatefn = sub {
+
+	my $conf = load_config($vmid);
+
+	die "missing snapshot lock\n"
+	    if !($conf->{'pve.lock'} && $conf->{'pve.lock'} eq 'snapshot');
+
+	die "snapshot '$snapname' does not exist\n" 
+	    if !defined($conf->{snapshots}->{$snapname});
+
+	die "wrong snapshot state\n"
+	    if !($conf->{snapshots}->{$snapname}->{'pve.snapstate'} && $conf->{snapshots}->{$snapname}->{'pve.snapstate'} eq "prepare");
+
+	delete $conf->{snapshots}->{$snapname}->{'pve.snapstate'};
+	delete $conf->{'pve.lock'};
+	$conf->{'pve.parent'} = $snapname;
+
+	PVE::LXC::write_config($vmid, $conf);
+
+    };
+
+    lock_container($vmid, 10 ,$updatefn);
+};
+
+sub has_feature {
+    my ($feature, $conf, $storecfg, $snapname) = @_;
+    #Fixme add other drives if necessary.
+    my $err;
+    my $volid = $conf->{'pve.volid'};
+    $err = 1 if !PVE::Storage::volume_has_feature($storecfg, $feature, $volid, $snapname);
+
+    return $err ? 0 : 1;
+}
+
 sub snapshot_create {
     my ($vmid, $snapname, $comment) = @_;
 
-    print "Not implemented\n";
+    my $snap = &$snapshot_prepare($vmid, $snapname, $comment);
+
+    my $config = load_config($vmid);
+
+    my $cmd = "/usr/bin/lxc-freeze -n $vmid";
+    my $running = check_running($vmid);
+    eval {
+	if ($running) {
+	    PVE::Tools::run_command($cmd);
+	};
+
+	my $storecfg = PVE::Storage::config();
+	my $volid = $config->{'pve.volid'};
+
+	$cmd = "/usr/bin/lxc-freeze -n $vmid";
+	if ($running) {
+	    PVE::Tools::run_command($cmd);
+	};
 
+	PVE::Storage::volume_snapshot($storecfg, $volid, $snapname);
+	&$snapshot_commit($vmid, $snapname);
+    };
+    if(my $err = $@) {
+	#ToDo implement delete snapshot
+	die "$err\n";
+    }
 }
 
 1;
-- 
2.1.4





More information about the pve-devel mailing list