]> git.proxmox.com Git - pve-guest-common.git/blobdiff - PVE/GuestHelpers.pm
grammar fix: s/does not exists/does not exist/g
[pve-guest-common.git] / PVE / GuestHelpers.pm
index 64e26c96652f260d2adc76412e9c21792af299e6..07a62ce3a8ad960f61b3e05c27eec3c670e01b24 100644 (file)
@@ -7,6 +7,7 @@ use PVE::Tools;
 use PVE::Storage;
 
 use POSIX qw(strftime);
+use Scalar::Util qw(weaken);
 
 # We use a separate lock to block migration while a replication job
 # is running.
@@ -35,7 +36,7 @@ sub check_hookscript {
     die "'$volid' is not in the snippets directory\n"
        if $type ne 'snippets';
 
-    die "script '$volid' does not exists\n"
+    die "script '$volid' does not exist\n"
        if ! -f $path;
 
     die "script '$volid' is not executable\n"
@@ -62,13 +63,15 @@ sub exec_hookscript {
     }
 }
 
-sub snapshot_tree {
-    my ($res) = @_;
+# takes a snapshot list (e.g., qm/pct snapshot_list API call result) and
+# prints it out in a nice tree sorted by age. Can cope with multiple roots
+sub print_snapshot_tree {
+    my ($snapshot_list) = @_;
 
-    my $snapshots = { map { $_->{name} => $_ } @$res };
+    my $snapshots = { map { $_->{name} => $_ } @$snapshot_list };
 
     my @roots;
-    foreach my $e (@$res) {
+    foreach my $e (@$snapshot_list) {
        my $parent;
        if (($parent = $e->{parent}) && defined $snapshots->{$parent}) {
            push @{$snapshots->{$parent}->{children}}, $e->{name};
@@ -85,8 +88,8 @@ sub snapshot_tree {
     };
 
     # recursion function for displaying the tree
-    my $snapshottree;
-    $snapshottree = sub {
+    my $snapshottree_weak;
+    $snapshottree_weak = sub {
        my ($prefix, $root, $snapshots) = @_;
        my $e = $snapshots->{$root};
 
@@ -104,14 +107,82 @@ sub snapshot_tree {
        if ($e->{children}) {
            $prefix = "    $prefix";
            foreach my $child (sort $snaptimesort @{$e->{children}}) {
-               $snapshottree->($prefix, $child, $snapshots);
+               $snapshottree_weak->($prefix, $child, $snapshots);
            }
        }
     };
+    my $snapshottree = $snapshottree_weak;
+    weaken($snapshottree_weak);
 
     foreach my $root (sort $snaptimesort @roots) {
        $snapshottree->('`->', $root, $snapshots);
     }
 }
 
+sub format_pending {
+    my ($data) = @_;
+    foreach my $item (sort { $a->{key} cmp $b->{key}} @$data) {
+       my $k = $item->{key};
+       next if $k eq 'digest';
+       my $v = $item->{value};
+       my $p = $item->{pending};
+       if ($k eq 'description') {
+           $v = PVE::Tools::encode_text($v) if defined($v);
+           $p = PVE::Tools::encode_text($p) if defined($p);
+       }
+       if (defined($v)) {
+           if ($item->{delete}) {
+               print "del $k: $v\n";
+           } elsif (defined($p)) {
+               print "cur $k: $v\n";
+               print "new $k: $p\n";
+           } else {
+               print "cur $k: $v\n";
+           }
+       } elsif (defined($p)) {
+           print "new $k: $p\n";
+       }
+    }
+}
+
+# returns the config as an array of hashes, each hash can have the following keys:
+# key (the config property name, non-optional)
+# value (the current value in effect - if any)
+# pending (a new, still pending, value - if any)
+# delete (when deletions are pending, this is set to either 2 (force) or 1 (graceful))
+sub config_with_pending_array {
+    my ($conf, $pending_delete_hash) = @_;
+
+    my $res = [];
+
+    foreach my $opt (keys %$conf) {
+       next if ref($conf->{$opt});
+       my $item = { key => $opt };
+       $item->{value} = $conf->{$opt} if defined($conf->{$opt});
+       $item->{pending} = $conf->{pending}->{$opt} if defined($conf->{pending}->{$opt});
+       $item->{delete} = ($pending_delete_hash->{$opt}->{force} ? 2 : 1) if exists $pending_delete_hash->{$opt};
+
+       push @$res, $item;
+    }
+
+    foreach my $opt (keys %{$conf->{pending}}) {
+       next if $opt eq 'delete';
+       next if ref($conf->{pending}->{$opt}); # just to be sure
+       next if defined($conf->{$opt});
+       my $item = { key => $opt };
+       $item->{pending} = $conf->{pending}->{$opt};
+
+       push @$res, $item;
+    }
+
+    while (my ($opt, $force) = each %$pending_delete_hash) {
+       next if $conf->{pending}->{$opt}; # just to be sure
+       next if $conf->{$opt};
+       my $item = { key => $opt, delete => ($force ? 2 : 1)};
+       push @$res, $item;
+    }
+
+    return $res;
+}
+
 1;