]>
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 my $pvesr_lock_path = "/var/lock/pvesr.lck";
23 my $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 $jobcfg->{id
} = $jobid;
65 $jobcfg->{vmtype
} = $vms->{ids
}->{$vmid}->{type
};
67 my $guest_class = $lookup_guest_class->($jobcfg->{vmtype
});
68 PVE
::Replication
::run_replication
($guest_class, $jobcfg, $now, $now, $logfunc);
71 my $res = PVE
::Tools
::lock_file
($pvesr_lock_path, 60, $code);
75 # passing $now is useful for regression testing
77 my ($now, $logfunc) = @_;
79 my $iteration = $now // time();
82 my $start_time = $now // time();
84 while (my $jobcfg = PVE
::ReplicationState
::get_next_job
($iteration, $start_time)) {
85 my $guest_class = $lookup_guest_class->($jobcfg->{vmtype
});
86 PVE
::Replication
::run_replication
($guest_class, $jobcfg, $iteration, $start_time, $logfunc, 1);
87 $start_time = $now // time();
91 my $res = PVE
::Tools
::lock_file
($pvesr_lock_path, 60, $code);
95 my $extract_job_status = sub {
96 my ($jobcfg, $jobid) = @_;
98 # Note: we modify $jobcfg
99 my $state = delete $jobcfg->{state};
102 $data->{id
} = $jobid;
104 foreach my $k (qw(last_sync last_try fail_count error duration)) {
105 $data->{$k} = $state->{$k} if defined($state->{$k});
108 if ($state->{pid
} && $state->{ptime
}) {
109 if (PVE
::ProcFSTools
::check_process_running
($state->{pid
}, $state->{ptime
})) {
110 $data->{pid
} = $state->{pid
};
117 __PACKAGE__-
>register_method ({
121 description
=> "List status of all replication jobs on this node.",
123 description
=> "Requires the VM.Audit permission on /vms/<vmid>.",
129 additionalProperties
=> 0,
131 node
=> get_standard_option
('pve-node'),
132 guest
=> get_standard_option
('pve-vmid', {
134 description
=> "Only list replication jobs for this guest.",
143 id
=> { type
=> 'string' },
146 links
=> [ { rel
=> 'child', href
=> "{id}" } ],
151 my $rpcenv = PVE
::RPCEnvironment
::get
();
152 my $authuser = $rpcenv->get_user();
154 my $jobs = PVE
::ReplicationState
::job_status
();
157 foreach my $id (sort keys %$jobs) {
158 my $data = $extract_job_status->($jobs->{$id}, $id);
159 my $guest = $data->{guest
};
160 next if defined($param->{guest
}) && $guest != $param->{guest
};
161 next if !$rpcenv->check($authuser, "/vms/$guest", [ 'VM.Audit' ]);
168 __PACKAGE__-
>register_method ({
172 permissions
=> { user
=> 'all' },
173 description
=> "Directory index.",
175 additionalProperties
=> 0,
177 id
=> get_standard_option
('pve-replication-id'),
178 node
=> get_standard_option
('pve-node'),
187 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
194 { name
=> 'status' },
199 __PACKAGE__-
>register_method ({
200 name
=> 'job_status',
201 path
=> '{id}/status',
203 description
=> "Get replication job status.",
205 description
=> "Requires the VM.Audit permission on /vms/<vmid>.",
211 additionalProperties
=> 0,
213 id
=> get_standard_option
('pve-replication-id'),
214 node
=> get_standard_option
('pve-node'),
224 my $rpcenv = PVE
::RPCEnvironment
::get
();
225 my $authuser = $rpcenv->get_user();
227 my $jobs = PVE
::ReplicationState
::job_status
();
228 my $jobid = $param->{id
};
229 my $jobcfg = $jobs->{$jobid};
231 die "no such replication job '$jobid'\n" if !defined($jobcfg);
233 my $data = $extract_job_status->($jobcfg, $jobid);
234 my $guest = $data->{guest
};
236 raise_perm_exc
() if !$rpcenv->check($authuser, "/vms/$guest", [ 'VM.Audit' ]);
241 __PACKAGE__-
>register_method({
242 name
=> 'read_job_log',
246 description
=> "Requires the VM.Audit permission on /vms/<vmid>, or 'Sys.Audit' on '/nodes/<node>'",
250 description
=> "Read replication job log.",
253 additionalProperties
=> 0,
255 id
=> get_standard_option
('pve-replication-id'),
256 node
=> get_standard_option
('pve-node'),
275 description
=> "Line number",
279 description
=> "Line text",
288 my $rpcenv = PVE
::RPCEnvironment
::get
();
289 my $authuser = $rpcenv->get_user();
291 my $jobid = $param->{id
};
292 my $filename = PVE
::ReplicationState
::job_logfile_name
($jobid);
294 my $cfg = PVE
::ReplicationConfig-
>new();
295 my $data = $cfg->{ids
}->{$jobid};
297 die "no such replication job '$jobid'\n" if !defined($data);
299 my $node = $param->{node
};
301 my $vmid = $data->{guest
};
302 raise_perm_exc
() if (!($rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ]) ||
303 $rpcenv->check($authuser, "/nodes/$node", [ 'Sys.Audit' ])));
305 my ($count, $lines) = PVE
::Tools
::dump_logfile
($filename, $param->{start
}, $param->{limit
});
307 $rpcenv->set_result_attrib('total', $count);