]> git.proxmox.com Git - pve-manager.git/blame - PVE/API2/ReplicationConfig.pm
update shipped appliance info index
[pve-manager.git] / PVE / API2 / ReplicationConfig.pm
CommitLineData
892821fd
DM
1package PVE::API2::ReplicationConfig;
2
3use warnings;
4use strict;
5
6use PVE::Tools qw(extract_param);
f9d38c54 7use PVE::Exception qw(raise_perm_exc raise_param_exc);
892821fd
DM
8use PVE::JSONSchema qw(get_standard_option);
9use PVE::RPCEnvironment;
10use PVE::ReplicationConfig;
4542a42a 11use PVE::Cluster;
892821fd
DM
12
13use PVE::RESTHandler;
14
15use base qw(PVE::RESTHandler);
16
17__PACKAGE__->register_method ({
18 name => 'index',
19 path => '',
20 method => 'GET',
21 description => "List replication jobs.",
22 permissions => {
4f0d5839
LW
23 description => "Will only return replication jobs for which the calling user has"
24 . " VM.Audit permission on /vms/<vmid>.",
892821fd
DM
25 user => 'all',
26 },
27 parameters => {
28 additionalProperties => 0,
29 properties => {},
30 },
31 returns => {
32 type => 'array',
33 items => {
34 type => "object",
35 properties => {},
36 },
4b48563a 37 links => [ { rel => 'child', href => "{id}" } ],
892821fd
DM
38 },
39 code => sub {
40 my ($param) = @_;
41
42 my $rpcenv = PVE::RPCEnvironment::get();
43 my $authuser = $rpcenv->get_user();
44
45 my $cfg = PVE::ReplicationConfig->new();
46
47 my $res = [];
48 foreach my $id (sort keys %{$cfg->{ids}}) {
49 my $d = $cfg->{ids}->{$id};
50 my $vmid = $d->{guest};
4f0d5839 51 next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ], 1);
892821fd
DM
52 $d->{id} = $id;
53 push @$res, $d;
54 }
55
56 return $res;
57 }});
58
59__PACKAGE__->register_method ({
60 name => 'read',
61 path => '{id}',
62 method => 'GET',
63 description => "Read replication job configuration.",
64 permissions => {
65 description => "Requires the VM.Audit permission on /vms/<vmid>.",
66 user => 'all',
67 },
68 parameters => {
69 additionalProperties => 0,
70 properties => {
71 id => get_standard_option('pve-replication-id'),
72 },
73 },
74 returns => { type => 'object' },
75 code => sub {
76 my ($param) = @_;
77
78 my $rpcenv = PVE::RPCEnvironment::get();
79 my $authuser = $rpcenv->get_user();
80
81 my $cfg = PVE::ReplicationConfig->new();
82
83 my $data = $cfg->{ids}->{$param->{id}};
84
85 die "no such replication job '$param->{id}'\n" if !defined($data);
86
87 my $vmid = $data->{guest};
88
89 raise_perm_exc() if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ]);
90
91 $data->{id} = $param->{id};
92
a4dc8611
DC
93 $data->{digest} = $cfg->{digest};
94
892821fd
DM
95 return $data;
96 }});
97
98__PACKAGE__->register_method ({
99 name => 'create',
100 path => '',
101 protected => 1,
102 method => 'POST',
103 description => "Create a new replication job",
104 permissions => {
105 check => ['perm', '/storage', ['Datastore.Allocate']],
106 },
107 parameters => PVE::ReplicationConfig->createSchema(),
108 returns => { type => 'null' },
109 code => sub {
110 my ($param) = @_;
111
112 my $type = extract_param($param, 'type');
113 my $plugin = PVE::ReplicationConfig->lookup($type);
114 my $id = extract_param($param, 'id');
115
a9da300d
DM
116 # extract guest ID from job ID
117 my ($guest) = PVE::ReplicationConfig::parse_replication_job_id($id);
118
4542a42a
DM
119 my $nodelist = PVE::Cluster::get_members();
120 my $vmlist = PVE::Cluster::get_vmlist();
121
25420507 122 my $guest_info = $vmlist->{ids}->{$guest};
ef3fde16 123
a7f04758 124 die "Guest '$guest' does not exist.\n"
25420507 125 if !defined($guest_info);
a7f04758 126 die "Target '$param->{target}' does not exist.\n"
10257794 127 if !defined($nodelist->{$param->{target}});
4542a42a 128
ef3fde16 129 my $source = $guest_info->{node};
09575ae8 130 die "Source '$param->{source}' does not match current node of guest '$guest' ($source)\n"
ef3fde16
FG
131 if defined($param->{source}) && $param->{source} ne $source;
132
133 $param->{source} //= $source;
134
b88b0100
FG
135 die "Source and target must not be identical\n"
136 if $param->{target} eq $source;
137
25420507 138 my $guest_class = $PVE::API2::Replication::lookup_guest_class->($guest_info->{type});
ef3fde16 139 my $guest_conf = $guest_class->load_config($guest, $source);
1adc6f7a
WB
140 my $rep_volumes = $guest_class->get_replicatable_volumes(PVE::Storage::config(), $guest, $guest_conf, 0, 0);
141 die "No replicatable volumes found\n" if !%$rep_volumes;
25420507 142
892821fd
DM
143 my $code = sub {
144 my $cfg = PVE::ReplicationConfig->new();
145
892821fd
DM
146 die "replication job '$id' already exists\n"
147 if $cfg->{ids}->{$id};
148
149 my $opts = $plugin->check_config($id, $param, 1, 1);
150
a9da300d
DM
151 $opts->{guest} = $guest;
152
892821fd
DM
153 $cfg->{ids}->{$id} = $opts;
154
155 $cfg->write();
156 };
157
158 PVE::ReplicationConfig::lock($code);
159
160 return undef;
161 }});
162
163
164__PACKAGE__->register_method ({
165 name => 'update',
166 protected => 1,
167 path => '{id}',
168 method => 'PUT',
169 description => "Update replication job configuration.",
170 permissions => {
171 check => ['perm', '/storage', ['Datastore.Allocate']],
172 },
173 parameters => PVE::ReplicationConfig->updateSchema(),
174 returns => { type => 'null' },
175 code => sub {
176 my ($param) = @_;
177
178 my $id = extract_param($param, 'id');
a4dc8611 179 my $digest = extract_param($param, 'digest');
dc9bc768 180 my $delete = extract_param($param, 'delete');
892821fd
DM
181
182 my $code = sub {
183 my $cfg = PVE::ReplicationConfig->new();
184
a4dc8611
DC
185 PVE::SectionConfig::assert_if_modified($cfg, $digest);
186
892821fd
DM
187 my $data = $cfg->{ids}->{$id};
188 die "no such job '$id'\n" if !$data;
189
190 my $plugin = PVE::ReplicationConfig->lookup($data->{type});
191 my $opts = $plugin->check_config($id, $param, 0, 1);
192
33b45548 193 foreach my $k (keys %$opts) {
892821fd
DM
194 $data->{$k} = $opts->{$k};
195 }
196
dc9bc768
DC
197 if ($delete) {
198 my $options = $plugin->private()->{options}->{$data->{type}};
199 foreach my $k (PVE::Tools::split_list($delete)) {
200 my $d = $options->{$k} ||
201 die "no such option '$k'\n";
202 die "unable to delete required option '$k'\n"
203 if !$d->{optional};
204 die "unable to delete fixed option '$k'\n"
205 if $d->{fixed};
206 delete $data->{$k};
207 }
208 }
209
892821fd
DM
210 $cfg->write();
211 };
212
213 PVE::ReplicationConfig::lock($code);
214
215 return undef;
216 }});
217
218__PACKAGE__->register_method ({
219 name => 'delete',
220 protected => 1,
221 path => '{id}',
222 method => 'DELETE',
f9d38c54 223 description => "Mark replication job for removal.",
892821fd
DM
224 permissions => {
225 check => ['perm', '/storage', ['Datastore.Allocate']],
226 },
227 parameters => {
228 additionalProperties => 0,
229 properties => {
230 id => get_standard_option('pve-replication-id'),
231 keep => {
232 description => "Keep replicated data at target (do not remove).",
233 type => 'boolean',
234 optional => 1,
235 default => 0,
236 },
948136a4
WL
237 force => {
238 description => "Will remove the jobconfig entry, but will not cleanup.",
239 type => 'boolean',
240 optional => 1,
241 default => 0,
242 },
892821fd
DM
243 }
244 },
245 returns => { type => 'null' },
246 code => sub {
247 my ($param) = @_;
248
bc1ec7bc
DM
249 my $rpcenv = PVE::RPCEnvironment::get();
250
892821fd
DM
251 my $code = sub {
252 my $cfg = PVE::ReplicationConfig->new();
253
f9d38c54 254 my $id = $param->{id};
948136a4 255 if ($param->{force}) {
9a427c6c 256 raise_param_exc({ 'keep' => "conflicts with parameter 'force'" }) if $param->{keep};
948136a4 257 delete $cfg->{ids}->{$id};
f9d38c54 258 } else {
948136a4
WL
259 my $jobcfg = $cfg->{ids}->{$id};
260 die "no such job '$id'\n" if !$jobcfg;
261
262 if (!$param->{keep} && $jobcfg->{type} eq 'local') {
263 # remove local snapshots and remote volumes
264 $jobcfg->{remove_job} = 'full';
265 } else {
266 # only remove local snapshots
267 $jobcfg->{remove_job} = 'local';
268 }
269
270 warn "Replication job removal is a background task and will take some time.\n"
271 if $rpcenv->{type} eq 'cli';
892821fd 272 }
892821fd
DM
273 $cfg->write();
274 };
275
276 PVE::ReplicationConfig::lock($code);
277
278 return undef;
279 }});
f9d38c54 280
892821fd 2811;