]>
git.proxmox.com Git - pve-manager.git/blob - PVE/API2/Replication.pm
1 package PVE
::API2
::Replication
;
6 use PVE
::JSONSchema
qw(get_standard_option);
7 use PVE
::RPCEnvironment
;
9 use PVE
::ReplicationConfig
;
10 use PVE
::ReplicationState
;
19 use base
qw(PVE::RESTHandler);
21 our $pvesr_lock_path = "/var/lock/pvesr.lck";
23 our $lookup_guest_class = sub {
26 if ($vmtype eq 'qemu') {
27 return 'PVE::QemuConfig';
28 } elsif ($vmtype eq 'lxc') {
29 return 'PVE::LXC::Config';
31 die "unknown guest type '$vmtype' - internal error";
35 # passing $now is useful for regression testing
37 my ($jobid, $now, $logfunc) = @_;
39 my $local_node = PVE
::INotify
::nodename
();
44 my $cfg = PVE
::ReplicationConfig-
>new();
46 my $jobcfg = $cfg->{ids
}->{$jobid};
47 die "no such job '$jobid'\n" if !$jobcfg;
49 die "internal error - not implemented" if $jobcfg->{type
} ne 'local';
51 die "job '$jobid' is disabled\n" if $jobcfg->{disable
};
53 my $vms = PVE
::Cluster
::get_vmlist
();
54 my $vmid = $jobcfg->{guest
};
56 die "no such guest '$vmid'\n" if !$vms->{ids
}->{$vmid};
58 die "guest '$vmid' is not on local node\n"
59 if $vms->{ids
}->{$vmid}->{node
} ne $local_node;
61 die "unable to sync to local node\n" if $jobcfg->{target
} eq $local_node;
63 my $vmtype = $vms->{ids
}->{$vmid}->{type
};
65 my $guest_class = $lookup_guest_class->($vmtype);
66 PVE
::Replication
::run_replication
($guest_class, $jobcfg, $now, $now, $logfunc);
69 my $res = PVE
::Tools
::lock_file
($pvesr_lock_path, 60, $code);
73 # passing $now and $verbose is useful for regression testing
75 my ($now, $logfunc, $verbose, $mail) = @_;
77 my $iteration = $now // time();
80 my $start_time = $now // time();
82 PVE
::ReplicationState
::purge_old_states
();
84 while (my $jobcfg = PVE
::ReplicationState
::get_next_job
($iteration, $start_time)) {
85 my $guest_class = $lookup_guest_class->($jobcfg->{vmtype
});
88 PVE
::Replication
::run_replication
($guest_class, $jobcfg, $iteration, $start_time, $logfunc, $verbose);
91 warn "$jobcfg->{id}: got unexpected replication job error - $err";
92 my $state = PVE
::ReplicationState
::read_state
();
93 my $jobstate = PVE
::ReplicationState
::extract_job_state
($state, $jobcfg);
95 PVE
::Tools
::sendmail
('root', "Replication Job: $jobcfg->{id} failed", $err)
96 if $jobstate->{fail_count
} == 1 && $mail;
101 $start_time = $now // time();
105 my $res = PVE
::Tools
::lock_file
($pvesr_lock_path, 60, $code);
109 my $extract_job_status = sub {
110 my ($jobcfg, $jobid) = @_;
112 # Note: we modify $jobcfg
113 my $state = delete $jobcfg->{state};
116 $data->{id
} = $jobid;
118 foreach my $k (qw(last_sync last_try fail_count error duration)) {
119 $data->{$k} = $state->{$k} if defined($state->{$k});
122 if ($state->{pid
} && $state->{ptime
}) {
123 if (PVE
::ProcFSTools
::check_process_running
($state->{pid
}, $state->{ptime
})) {
124 $data->{pid
} = $state->{pid
};
131 __PACKAGE__-
>register_method ({
135 description
=> "List status of all replication jobs on this node.",
137 description
=> "Requires the VM.Audit permission on /vms/<vmid>.",
143 additionalProperties
=> 0,
145 node
=> get_standard_option
('pve-node'),
146 guest
=> get_standard_option
('pve-vmid', {
148 description
=> "Only list replication jobs for this guest.",
157 id
=> { type
=> 'string' },
160 links
=> [ { rel
=> 'child', href
=> "{id}" } ],
165 my $rpcenv = PVE
::RPCEnvironment
::get
();
166 my $authuser = $rpcenv->get_user();
168 my $jobs = PVE
::ReplicationState
::job_status
(1);
171 foreach my $id (sort keys %$jobs) {
172 my $data = $extract_job_status->($jobs->{$id}, $id);
173 my $guest = $data->{guest
};
174 next if defined($param->{guest
}) && $guest != $param->{guest
};
175 next if !$rpcenv->check($authuser, "/vms/$guest", [ 'VM.Audit' ]);
182 __PACKAGE__-
>register_method ({
186 permissions
=> { user
=> 'all' },
187 description
=> "Directory index.",
189 additionalProperties
=> 0,
191 id
=> get_standard_option
('pve-replication-id'),
192 node
=> get_standard_option
('pve-node'),
201 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
207 { name
=> 'schedule_now' },
209 { name
=> 'status' },
214 __PACKAGE__-
>register_method ({
215 name
=> 'job_status',
216 path
=> '{id}/status',
218 description
=> "Get replication job status.",
220 description
=> "Requires the VM.Audit permission on /vms/<vmid>.",
226 additionalProperties
=> 0,
228 id
=> get_standard_option
('pve-replication-id'),
229 node
=> get_standard_option
('pve-node'),
239 my $rpcenv = PVE
::RPCEnvironment
::get
();
240 my $authuser = $rpcenv->get_user();
242 my $jobs = PVE
::ReplicationState
::job_status
();
243 my $jobid = $param->{id
};
244 my $jobcfg = $jobs->{$jobid};
246 die "no such replication job '$jobid'\n" if !defined($jobcfg);
248 my $data = $extract_job_status->($jobcfg, $jobid);
249 my $guest = $data->{guest
};
251 raise_perm_exc
() if !$rpcenv->check($authuser, "/vms/$guest", [ 'VM.Audit' ]);
256 __PACKAGE__-
>register_method({
257 name
=> 'read_job_log',
261 description
=> "Requires the VM.Audit permission on /vms/<vmid>, or 'Sys.Audit' on '/nodes/<node>'",
265 description
=> "Read replication job log.",
268 additionalProperties
=> 0,
270 id
=> get_standard_option
('pve-replication-id'),
271 node
=> get_standard_option
('pve-node'),
290 description
=> "Line number",
294 description
=> "Line text",
303 my $rpcenv = PVE
::RPCEnvironment
::get
();
304 my $authuser = $rpcenv->get_user();
306 my $jobid = $param->{id
};
307 my $filename = PVE
::ReplicationState
::job_logfile_name
($jobid);
309 my $cfg = PVE
::ReplicationConfig-
>new();
310 my $data = $cfg->{ids
}->{$jobid};
312 die "no such replication job '$jobid'\n" if !defined($data);
314 my $node = $param->{node
};
316 my $vmid = $data->{guest
};
317 raise_perm_exc
() if (!($rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ]) ||
318 $rpcenv->check($authuser, "/nodes/$node", [ 'Sys.Audit' ])));
320 my ($count, $lines) = PVE
::Tools
::dump_logfile
($filename, $param->{start
}, $param->{limit
});
322 $rpcenv->set_result_attrib('total', $count);
327 __PACKAGE__-
>register_method ({
328 name
=> 'schedule_now',
329 path
=> '{id}/schedule_now',
331 description
=> "Schedule replication job to start as soon as possible.",
335 check
=> ['perm', '/storage', ['Datastore.Allocate']],
338 additionalProperties
=> 0,
340 id
=> get_standard_option
('pve-replication-id'),
341 node
=> get_standard_option
('pve-node'),
350 my $jobid = $param->{id
};
352 my $cfg = PVE
::ReplicationConfig-
>new();
353 my $jobcfg = $cfg->{ids
}->{$jobid};
355 die "no such replication job '$jobid'\n" if !defined($jobcfg);
357 PVE
::ReplicationState
::schedule_job_now
($jobcfg);