]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/LXC.pm
Refactor has_feature
[pve-container.git] / src / PVE / LXC.pm
index 4ba91257958858ca5f5ce83968c40333b44b0fd7..503a57fb872ada093e83b101349afe851950baf3 100644 (file)
@@ -1199,7 +1199,7 @@ sub verify_searchdomain_list {
 }
 
 sub is_volume_in_use {
-    my ($config, $volid) = @_;
+    my ($config, $volid, $include_snapshots) = @_;
     my $used = 0;
 
     foreach_mountpoint($config, sub {
@@ -1210,6 +1210,13 @@ sub is_volume_in_use {
        }
     });
 
+    my $snapshots = $config->{snapshots};
+    if ($include_snapshots && $snapshots) {
+       foreach my $snap (keys %$snapshots) {
+           $used ||= is_volume_in_use($snapshots->{$snap}, $volid);
+       }
+    }
+
     return $used;
 }
 
@@ -1425,6 +1432,8 @@ sub update_pct_config {
        my $storage_cfg = PVE::Storage::config();
        foreach my $volume (@deleted_volumes) {
            next if $used_volids->{$volume}; # could have been re-added, too
+           # also check for references in snapshots
+           next if is_volume_in_use($conf, $volume, 1);
            delete_mountpoint_volume($storage_cfg, $vmid, $volume);
        }
     }
@@ -1791,9 +1800,9 @@ my $snapshot_apply_config = sub {
     return $newconf;
 };
 
-my $snapshot_save_vmstate = sub {
+sub snapshot_save_vmstate {
     die "implement me - snapshot_save_vmstate\n";
-};
+}
 
 sub snapshot_prepare {
     my ($vmid, $snapname, $save_vmstate, $comment) = @_;
@@ -1815,15 +1824,13 @@ sub snapshot_prepare {
            if defined($conf->{snapshots}->{$snapname});
 
        my $storecfg = PVE::Storage::config();
-
-       # workaround until mp snapshots are implemented
-       my $feature = $snapname eq 'vzdump' ? 'vzdump' : 'snapshot';
-       die "snapshot feature is not available\n" if !has_feature($feature, $conf, $storecfg);
+       die "snapshot feature is not available\n"
+           if !has_feature('snapshot', $conf, $storecfg, undef, undef, $snapname eq 'vzdump');
 
        $snap = $conf->{snapshots}->{$snapname} = {};
 
        if ($save_vmstate && check_running($vmid)) {
-           &$snapshot_save_vmstate($vmid, $conf, $snapname, $storecfg);
+           snapshot_save_vmstate($vmid, $conf, $snapname, $storecfg);
        }
 
        &$snapshot_copy_config($conf, $snap);
@@ -1870,23 +1877,17 @@ sub snapshot_commit {
 }
 
 sub has_feature {
-    my ($feature, $conf, $storecfg, $snapname) = @_;
+    my ($feature, $conf, $storecfg, $snapname, $running, $backup_only) = @_;
     
     my $err;
-    my $vzdump = $feature eq 'vzdump';
-    $feature = 'snapshot' if $vzdump;
 
     foreach_mountpoint($conf, sub {
        my ($ms, $mountpoint) = @_;
 
        return if $err; # skip further test
-       return if $vzdump && $ms ne 'rootfs' && !$mountpoint->{backup};
+       return if $backup_only && $ms ne 'rootfs' && !$mountpoint->{backup};
        
-       $err = 1 if !PVE::Storage::volume_has_feature($storecfg, $feature, $mountpoint->{volume}, $snapname);
-
-       # TODO: implement support for mountpoints
-       die "unable to handle mountpoint '$ms' - feature not implemented\n"
-           if $ms ne 'rootfs';
+       $err = 1 if !PVE::Storage::volume_has_feature($storecfg, $feature, $mountpoint->{volume}, $snapname, $running);
     });
 
     return $err ? 0 : 1;
@@ -1961,43 +1962,54 @@ sub sync_container_namespace {
     die "failed to sync container namespace\n" if $? != 0;
 }
 
+sub check_freeze_needed {
+    my ($vmid, $config, $save_vmstate) = @_;
+
+    my $ret = check_running($vmid);
+    return ($ret, $ret);
+}
+
 sub snapshot_create {
     my ($vmid, $snapname, $save_vmstate, $comment) = @_;
 
     my $snap = snapshot_prepare($vmid, $snapname, $save_vmstate, $comment);
 
+    $save_vmstate = 0 if !$snap->{vmstate};
+
     my $conf = load_config($vmid);
 
-    my $running = check_running($vmid);
-    
-    my $unfreeze = 0;
+    my ($running, $freezefs) = check_freeze_needed($vmid, $conf, $snap->{vmstate});
 
     my $drivehash = {};
 
     eval {
-       if ($running) {
-           $unfreeze = 1;
+       if ($freezefs) {
            PVE::Tools::run_command(['/usr/bin/lxc-freeze', '-n', $vmid]);
            sync_container_namespace($vmid);
-       };
+       }
 
        my $storecfg = PVE::Storage::config();
-       my $rootinfo = parse_ct_rootfs($conf->{rootfs});
-       my $volid = $rootinfo->{volume};
+       foreach_mountpoint($conf, sub {
+           my ($ms, $mountpoint) = @_;
 
-       PVE::Storage::volume_snapshot($storecfg, $volid, $snapname);
-       $drivehash->{rootfs} = 1;
+           return if $snapname eq 'vzdump' && $ms ne 'rootfs' && !$mountpoint->{backup};
+           PVE::Storage::volume_snapshot($storecfg, $mountpoint->{volume}, $snapname);
+           $drivehash->{$ms} = 1;
+       });
     };
     my $err = $@;
     
-    if ($unfreeze) {
-       eval { PVE::Tools::run_command(['/usr/bin/lxc-unfreeze', '-n', $vmid]); };
-       warn $@ if $@;
+    if ($running) {
+       if ($freezefs) {
+           eval { PVE::Tools::run_command(['/usr/bin/lxc-unfreeze', '-n', $vmid]); };
+           warn $@ if $@;
+       }
     }
     
     if ($err) {
+       warn "snapshot create failed: starting cleanup\n";
        eval { snapshot_delete($vmid, $snapname, 1, $drivehash); };
-       warn "$@\n" if $@;
+       warn "$@" if $@;
        die "$err\n";
     }
 
@@ -2011,6 +2023,7 @@ sub snapshot_delete {
     my $prepare = 1;
 
     my $snap;
+    my $unused = [];
 
     my $unlink_parent = sub {
        my ($confref, $new_parent) = @_;
@@ -2052,7 +2065,11 @@ sub snapshot_delete {
            if ($remove_drive eq 'vmstate') {
                die "implement me - saving vmstate\n";
            } else {
-               die "implement me - remove drive\n";
+               my $value = $snap->{$remove_drive};
+               my $mountpoint = $remove_drive eq 'rootfs' ? parse_ct_rootfs($value, 1) : parse_ct_mountpoint($value, 1);
+               delete $snap->{$remove_drive};
+               add_unused_volume($snap, $mountpoint->{volume})
+                   if (!is_volume_in_use($snap, $mountpoint->{volume}));
            }
        }
 
@@ -2061,6 +2078,10 @@ sub snapshot_delete {
        } else {
            delete $conf->{snapshots}->{$snapname};
            delete $conf->{lock} if $drivehash;
+           foreach my $volid (@$unused) {
+               add_unused_volume($conf, $volid)
+                   if (!is_volume_in_use($conf, $volid));
+           }
        }
 
        write_config($vmid, $conf);
@@ -2077,17 +2098,22 @@ sub snapshot_delete {
     };
 
     # now remove all volume snapshots
-    # only rootfs for now!
-    eval {
-       my $rootfs = $snap->{rootfs};
-       my $rootinfo = parse_ct_rootfs($rootfs);
-       my $volid = $rootinfo->{volume};
-       PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snapname);
-    };
-    if (my $err = $@) {
-       die $err if !$force;
-       warn $err;
-    }
+    foreach_mountpoint($snap, sub {
+       my ($ms, $mountpoint) = @_;
+
+       return if $snapname eq 'vzdump' && $ms ne 'rootfs' && !$mountpoint->{backup};
+       if (!$drivehash || $drivehash->{$ms}) {
+           eval { PVE::Storage::volume_snapshot_delete($storecfg, $mountpoint->{volume}, $snapname); };
+           if (my $err = $@) {
+               die $err if !$force;
+               warn $err;
+           }
+       }
+
+       # save changes (remove mp from snapshot)
+       lock_config($vmid, $updatefn, $ms) if !$force;
+       push @$unused, $mountpoint->{volume};
+    });
 
     # now cleanup config
     $prepare = 0;
@@ -2116,12 +2142,11 @@ sub snapshot_rollback {
 
     my $snap = &$get_snapshot_config();
 
-    # only for rootfs for now!
-    my $rootfs = $snap->{rootfs};
-    my $rootinfo = parse_ct_rootfs($rootfs);
-    my $volid = $rootinfo->{volume};
+    foreach_mountpoint($snap, sub {
+       my ($ms, $mountpoint) = @_;
 
-    PVE::Storage::volume_rollback_is_possible($storecfg, $volid, $snapname);
+       PVE::Storage::volume_rollback_is_possible($storecfg, $mountpoint->{volume}, $snapname);
+    });
 
     my $updatefn = sub {
 
@@ -2165,8 +2190,11 @@ sub snapshot_rollback {
 
     lock_config($vmid, $updatefn);
 
-    # only rootfs for now!
-    PVE::Storage::volume_snapshot_rollback($storecfg, $volid, $snapname);
+    foreach_mountpoint($snap, sub {
+       my ($ms, $mountpoint) = @_;
+
+       PVE::Storage::volume_snapshot_rollback($storecfg, $mountpoint->{volume}, $snapname);
+    });
 
     $prepare = 0;
     lock_config($vmid, $updatefn);