pve-guest-common/PVE/GuestHelpers.pm
Oguz Bektas 725dcadba3 reformat code for snapshot tree into GuestHelpers
qm/pct listsnapshot lack feature parity w.r.t. showing snapshots in a
tree ordered by the date. by moving this code into GuestHelpers, it can
be shared.

Signed-off-by: Oguz Bektas <o.bektas@proxmox.com>
2019-10-01 17:15:04 +02:00

118 lines
2.7 KiB
Perl

package PVE::GuestHelpers;
use strict;
use warnings;
use PVE::Tools;
use PVE::Storage;
use POSIX qw(strftime);
# We use a separate lock to block migration while a replication job
# is running.
our $lockdir = '/var/lock/pve-manager';
sub guest_migration_lock {
my ($vmid, $timeout, $func, @param) = @_;
my $lockid = "pve-migrate-$vmid";
mkdir $lockdir;
my $res = PVE::Tools::lock_file("$lockdir/$lockid", $timeout, $func, @param);
die $@ if $@;
return $res;
}
sub check_hookscript {
my ($volid, $storecfg) = @_;
$storecfg = PVE::Storage::config() if !defined($storecfg);
my ($path, undef, $type) = PVE::Storage::path($storecfg, $volid);
die "'$volid' is not in the snippets directory\n"
if $type ne 'snippets';
die "script '$volid' does not exists\n"
if ! -f $path;
die "script '$volid' is not executable\n"
if ! -x $path;
return $path;
}
sub exec_hookscript {
my ($conf, $vmid, $phase, $stop_on_error) = @_;
return if !$conf->{hookscript};
eval {
my $hookscript = check_hookscript($conf->{hookscript});
die $@ if $@;
PVE::Tools::run_command([$hookscript, $vmid, $phase]);
};
if (my $err = $@) {
my $errmsg = "hookscript error for $vmid on $phase: $err\n";
die $errmsg if ($stop_on_error);
warn $errmsg;
}
}
sub snapshot_tree {
my ($res) = @_;
my $snapshots = { map { $_->{name} => $_ } @$res };
my @roots;
foreach my $e (@$res) {
my $parent;
if (($parent = $e->{parent}) && defined $snapshots->{$parent}) {
push @{$snapshots->{$parent}->{children}}, $e->{name};
} else {
push @roots, $e->{name};
}
}
# sort the elements by snaptime - with "current" (no snaptime) highest
my $snaptimesort = sub {
return +1 if !defined $snapshots->{$a}->{snaptime};
return -1 if !defined $snapshots->{$b}->{snaptime};
return $snapshots->{$a}->{snaptime} <=> $snapshots->{$b}->{snaptime};
};
# recursion function for displaying the tree
my $snapshottree;
$snapshottree = sub {
my ($prefix, $root, $snapshots) = @_;
my $e = $snapshots->{$root};
my $description = $e->{description} || 'no-description';
($description) = $description =~ m/(.*)$/m;
my $timestring = "";
if (defined $e->{snaptime}) {
$timestring = strftime("%F %H:%M:%S", localtime($e->{snaptime}));
}
my $len = 30 - length($prefix); # for aligning the description
printf("%s %-${len}s %-23s %s\n", $prefix, $root, $timestring, $description);
if ($e->{children}) {
$prefix = " $prefix";
foreach my $child (sort $snaptimesort @{$e->{children}}) {
$snapshottree->($prefix, $child, $snapshots);
}
}
};
foreach my $root (sort $snaptimesort @roots) {
$snapshottree->('`->', $root, $snapshots);
}
}
1;