222 lines
4.7 KiB
Perl
222 lines
4.7 KiB
Perl
package PVE::CLI::pvesr;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use POSIX qw(strftime);
|
|
|
|
use PVE::JSONSchema qw(get_standard_option);
|
|
use PVE::INotify;
|
|
use PVE::RPCEnvironment;
|
|
use PVE::Tools qw(extract_param);
|
|
use PVE::SafeSyslog;
|
|
use PVE::CLIHandler;
|
|
|
|
use PVE::API2::Storage::Replication;
|
|
|
|
use base qw(PVE::CLIHandler);
|
|
|
|
my $nodename = PVE::INotify::nodename();
|
|
|
|
sub setup_environment {
|
|
PVE::RPCEnvironment->setup_default_cli_env();
|
|
}
|
|
|
|
my $print_list = sub {
|
|
my ($conf, $json) = @_;
|
|
|
|
if (defined($json)) {
|
|
print JSON::encode_json($conf);
|
|
} else {
|
|
printf("%-10s%-20s%-20s%-5s%-10s%-5s\n",
|
|
"VMID", "DEST", "LAST SYNC","IVAL", "STATE", "FAIL");
|
|
|
|
foreach my $vmid (sort keys %$conf) {
|
|
my $job = $conf->{$vmid};
|
|
my $timestr = strftime("%Y-%m-%d_%H:%M:%S", localtime($job->{lastsync}));
|
|
|
|
printf("%-9s ", $vmid);
|
|
printf("%-19s ", $job->{tnode});
|
|
printf("%-19s ", $timestr);
|
|
printf("%-4s ", $job->{interval});
|
|
printf("%-9s ", $job->{state});
|
|
printf("%-9s\n", $job->{fail});
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
sub set_list {
|
|
my ($list, $synctime, $vmid) = @_;
|
|
|
|
if (defined($list->{$synctime})) {
|
|
$list = set_list($list,$synctime+1, $vmid);
|
|
} else {
|
|
$list->{$synctime} = $vmid;
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
my $get_replica_list = sub {
|
|
|
|
my $jobs = PVE::ReplicationTools::read_state();
|
|
my $list = {};
|
|
|
|
foreach my $vmid (keys %$jobs) {
|
|
my $job = $jobs->{$vmid};
|
|
my $lastsync = $job->{lastsync};
|
|
|
|
# interval in min
|
|
my $interval = $job->{interval};
|
|
my $now = time();
|
|
my $fail = $job->{fail};
|
|
|
|
my $synctime = $lastsync + $interval * 60;
|
|
|
|
if ($now >= $synctime && $job->{state} eq 'ok') {
|
|
$list = set_list($list, $synctime, $vmid);
|
|
} elsif ($job->{state} eq 'sync') {
|
|
|
|
my $synctime += $interval * ($job->{fail}+1);
|
|
$list = set_list($list, $synctime, $vmid)
|
|
if ($now >= $synctime);
|
|
|
|
}
|
|
}
|
|
|
|
return $list;
|
|
};
|
|
|
|
my $replicate_vms = sub {
|
|
my ($list) = @_;
|
|
|
|
my @sorted_times = reverse sort keys %$list;
|
|
|
|
foreach my $synctime (@sorted_times) {
|
|
eval {
|
|
PVE::ReplicationTools::sync_guest($list->{$synctime});
|
|
};
|
|
if (my $err = $@) {
|
|
syslog ('err', $err );
|
|
}
|
|
}
|
|
};
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'run',
|
|
path => 'run',
|
|
method => 'POST',
|
|
description => "This method will run by the systemd-timer and sync all jobs",
|
|
permissions => {
|
|
description => {
|
|
check => ['perm', '/', [ 'Sys.Console' ]],
|
|
},
|
|
},
|
|
protected => 1,
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
},
|
|
},
|
|
returns => { type => 'null' },
|
|
code => sub {
|
|
|
|
my $list = &$get_replica_list();
|
|
&$replicate_vms($list);
|
|
|
|
return undef;
|
|
}});
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'destroyjob',
|
|
path => 'destroyjob',
|
|
method => 'DELETE',
|
|
description => "Destroy an async replication job",
|
|
permissions => {
|
|
description => {
|
|
check => ['perm', '/storage', ['Datastore.Allocate']],
|
|
},
|
|
},
|
|
protected => 1,
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
vmid => {
|
|
type => 'string', format => 'pve-vmid',
|
|
description => "The VMID of the guest.",
|
|
completion => \&PVE::Cluster::complete_local_vmid,
|
|
},
|
|
},
|
|
},
|
|
returns => { type => 'null' },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
my $vmid = extract_param($param, 'vmid');
|
|
|
|
PVE::ReplicationTools::destroy_replica($vmid);
|
|
|
|
}});
|
|
|
|
__PACKAGE__->register_method ({
|
|
name => 'list',
|
|
path => 'list',
|
|
method => 'GET',
|
|
description => "List of all replication jobs.",
|
|
permissions => {
|
|
user => 'all'
|
|
},
|
|
protected => 1,
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
vmid => {
|
|
type => 'string', format => 'pve-vmid',
|
|
description => "The VMID of the guest.",
|
|
completion => \&PVE::Cluster::complete_local_vmid,
|
|
},
|
|
},
|
|
},
|
|
protected => 1,
|
|
proxyto => 'node',
|
|
parameters => {
|
|
additionalProperties => 0,
|
|
properties => {
|
|
node => get_standard_option('pve-node'),
|
|
nodes => get_standard_option('pve-node-list' ,
|
|
{description => "Notes where the jobs is located.",
|
|
optional => 1}),
|
|
json => {
|
|
optional => 1,
|
|
type => 'boolean',
|
|
description => "Output in JSON format.",
|
|
},
|
|
},
|
|
},
|
|
returns => { type => 'string' },
|
|
code => sub {
|
|
my ($param) = @_;
|
|
|
|
if ($param->{nodes}) {
|
|
foreach my $node (PVE::Tools::split_list($param->{nodes})) {
|
|
die "Node: $node does not exists.\n" if
|
|
!PVE::Cluster::check_node_exists($node);
|
|
}
|
|
}
|
|
|
|
my $nodes = $param->{nodes} ?
|
|
$param->{nodes} : $param->{node};
|
|
|
|
my $list = PVE::ReplicationTools::get_all_jobs($nodes);
|
|
|
|
&$print_list($list, $param->{json});
|
|
}});
|
|
|
|
|
|
our $cmddef = {
|
|
list => [ __PACKAGE__ , 'list' , [], {node => $nodename}],
|
|
run => [ __PACKAGE__ , 'run'],
|
|
destroyjob => [ __PACKAGE__ , 'destroyjob', ['vmid']],
|
|
};
|
|
|
|
1;
|