mirror of
https://git.proxmox.com/git/pve-guest-common
synced 2025-08-06 05:42:01 +00:00

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>
118 lines
2.7 KiB
Perl
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;
|