]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/API2/HA/Resources.pm
clean up 'Data::Dumper' usage tree wide
[pve-ha-manager.git] / src / PVE / API2 / HA / Resources.pm
CommitLineData
239a687f
DM
1package PVE::API2::HA::Resources;
2
3use strict;
4use warnings;
5
6use PVE::SafeSyslog;
7use PVE::Tools qw(extract_param);
23944168 8use PVE::Cluster;
239a687f
DM
9use PVE::HA::Config;
10use PVE::HA::Resources;
11use HTTP::Status qw(:constants);
12use Storable qw(dclone);
13use PVE::JSONSchema qw(get_standard_option);
14use PVE::RPCEnvironment;
15
16use PVE::RESTHandler;
17
18use base qw(PVE::RESTHandler);
19
20# fixme: use cfs_read_file
21
239a687f
DM
22my $resource_type_enum = PVE::HA::Resources->lookup_types();
23
239a687f
DM
24my $api_copy_config = sub {
25 my ($cfg, $sid) = @_;
26
95ea5d67
DM
27 die "no such resource '$sid'\n" if !$cfg->{ids}->{$sid};
28
239a687f
DM
29 my $scfg = dclone($cfg->{ids}->{$sid});
30 $scfg->{sid} = $sid;
31 $scfg->{digest} = $cfg->{digest};
32
33 return $scfg;
34};
35
2732fccf
TL
36sub check_service_state {
37 my ($sid, $req_state) = @_;
38
39 my $service_status = PVE::HA::Config::get_service_status($sid);
40 if ($service_status->{managed} && $service_status->{state} eq 'error') {
41 # service in error state, must get disabled before new state request
42 # can be executed
43 return if defined($req_state) && $req_state eq 'disabled';
44 die "service '$sid' in error state, must be disabled and fixed first\n";
45 }
46}
47
239a687f 48__PACKAGE__->register_method ({
95ea5d67 49 name => 'index',
239a687f
DM
50 path => '',
51 method => 'GET',
95ea5d67 52 description => "List HA resources.",
0fcba7ab
TL
53 permissions => {
54 check => ['perm', '/', [ 'Sys.Audit' ]],
55 },
239a687f
DM
56 parameters => {
57 additionalProperties => 0,
58 properties => {
95ea5d67 59 type => {
239a687f 60 description => "Only list resources of specific type",
95ea5d67 61 type => 'string',
239a687f
DM
62 enum => $resource_type_enum,
63 optional => 1,
64 },
65 },
66 },
67 returns => {
68 type => 'array',
69 items => {
70 type => "object",
71 properties => { sid => { type => 'string'} },
72 },
73 links => [ { rel => 'child', href => "{sid}" } ],
74 },
75 code => sub {
76 my ($param) = @_;
77
139a9b90 78 my $cfg = PVE::HA::Config::read_resources_config();
6cdf1da6 79 my $groups = PVE::HA::Config::read_group_config();
239a687f
DM
80
81 my $res = [];
82 foreach my $sid (keys %{$cfg->{ids}}) {
83 my $scfg = &$api_copy_config($cfg, $sid);
84 next if $param->{type} && $param->{type} ne $scfg->{type};
6cdf1da6
DM
85 if ($scfg->{group} && !$groups->{ids}->{$scfg->{group}}) {
86 $scfg->{errors}->{group} = "group '$scfg->{group}' does not exist";
87 }
239a687f
DM
88 push @$res, $scfg;
89 }
90
91 return $res;
92 }});
93
95ea5d67
DM
94__PACKAGE__->register_method ({
95 name => 'read',
96 path => '{sid}',
97 method => 'GET',
0fcba7ab
TL
98 permissions => {
99 check => ['perm', '/', [ 'Sys.Audit' ]],
100 },
95ea5d67
DM
101 description => "Read resource configuration.",
102 parameters => {
103 additionalProperties => 0,
104 properties => {
73bede9b
TL
105 sid => get_standard_option('pve-ha-resource-or-vm-id',
106 { completion => \&PVE::HA::Tools::complete_sid }),
95ea5d67
DM
107 },
108 },
109 returns => {},
110 code => sub {
111 my ($param) = @_;
112
139a9b90 113 my $cfg = PVE::HA::Config::read_resources_config();
95ea5d67 114
6ca2edcd
DM
115 my $sid = PVE::HA::Tools::parse_sid($param->{sid});
116
117 return &$api_copy_config($cfg, $sid);
95ea5d67
DM
118 }});
119
120__PACKAGE__->register_method ({
121 name => 'create',
122 protected => 1,
123 path => '',
124 method => 'POST',
0fcba7ab
TL
125 permissions => {
126 check => ['perm', '/', [ 'Sys.Console' ]],
127 },
95ea5d67
DM
128 description => "Create a new HA resource.",
129 parameters => PVE::HA::Resources->createSchema(),
130 returns => { type => 'null' },
131 code => sub {
132 my ($param) = @_;
133
23944168
DM
134 # create /etc/pve/ha directory
135 PVE::Cluster::check_cfs_quorum();
136 mkdir("/etc/pve/ha");
137
6ca2edcd 138 my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid'));
95ea5d67
DM
139
140 if (my $param_type = extract_param($param, 'type')) {
141 # useless, but do it anyway
142 die "types does not match\n" if $param_type ne $type;
143 }
144
145 my $plugin = PVE::HA::Resources->lookup($type);
146 $plugin->verify_name($name);
147
a8b14c78
TL
148 $plugin->exists($name);
149
95ea5d67
DM
150 my $opts = $plugin->check_config($sid, $param, 1, 1);
151
66c7e7ef 152 PVE::HA::Config::lock_ha_domain(
95ea5d67
DM
153 sub {
154
139a9b90 155 my $cfg = PVE::HA::Config::read_resources_config();
95ea5d67
DM
156
157 if ($cfg->{ids}->{$sid}) {
158 die "resource ID '$sid' already defined\n";
159 }
160
161 $cfg->{ids}->{$sid} = $opts;
162
e3235f56 163 PVE::HA::Config::write_resources_config($cfg)
95ea5d67
DM
164
165 }, "create resource failed");
166
167 return undef;
168 }});
169
170__PACKAGE__->register_method ({
171 name => 'update',
172 protected => 1,
173 path => '{sid}',
174 method => 'PUT',
175 description => "Update resource configuration.",
0fcba7ab
TL
176 permissions => {
177 check => ['perm', '/', [ 'Sys.Console' ]],
178 },
95ea5d67
DM
179 parameters => PVE::HA::Resources->updateSchema(),
180 returns => { type => 'null' },
181 code => sub {
182 my ($param) = @_;
183
184 my $digest = extract_param($param, 'digest');
185 my $delete = extract_param($param, 'delete');
186
6ca2edcd 187 my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid'));
95ea5d67
DM
188
189 if (my $param_type = extract_param($param, 'type')) {
190 # useless, but do it anyway
191 die "types does not match\n" if $param_type ne $type;
192 }
193
a93c65d9
TL
194 if (my $group = $param->{group}) {
195 my $group_cfg = PVE::HA::Config::read_group_config();
196
197 die "HA group '$group' does not exist\n"
198 if !$group_cfg->{ids}->{$group};
199 }
200
2732fccf
TL
201 check_service_state($sid, $param->{state});
202
66c7e7ef 203 PVE::HA::Config::lock_ha_domain(
95ea5d67
DM
204 sub {
205
139a9b90 206 my $cfg = PVE::HA::Config::read_resources_config();
95ea5d67
DM
207
208 PVE::SectionConfig::assert_if_modified($cfg, $digest);
209
210 my $scfg = $cfg->{ids}->{$sid} ||
211 die "no such resource '$sid'\n";
212
213 my $plugin = PVE::HA::Resources->lookup($scfg->{type});
214 my $opts = $plugin->check_config($sid, $param, 0, 1);
215
216 foreach my $k (%$opts) {
217 $scfg->{$k} = $opts->{$k};
218 }
219
220 if ($delete) {
221 my $options = $plugin->private()->{options}->{$type};
222 foreach my $k (PVE::Tools::split_list($delete)) {
223 my $d = $options->{$k} ||
224 die "no such option '$k'\n";
225 die "unable to delete required option '$k'\n"
226 if !$d->{optional};
227 die "unable to delete fixed option '$k'\n"
228 if $d->{fixed};
229 delete $scfg->{$k};
230 }
231 }
232
139a9b90 233 PVE::HA::Config::write_resources_config($cfg)
95ea5d67
DM
234
235 }, "update resource failed");
236
237 return undef;
238 }});
239
240__PACKAGE__->register_method ({
241 name => 'delete',
242 protected => 1,
243 path => '{sid}',
244 method => 'DELETE',
245 description => "Delete resource configuration.",
0fcba7ab
TL
246 permissions => {
247 check => ['perm', '/', [ 'Sys.Console' ]],
248 },
95ea5d67
DM
249 parameters => {
250 additionalProperties => 0,
251 properties => {
73bede9b
TL
252 sid => get_standard_option('pve-ha-resource-or-vm-id',
253 { completion => \&PVE::HA::Tools::complete_sid }),
95ea5d67
DM
254 },
255 },
256 returns => { type => 'null' },
257 code => sub {
258 my ($param) = @_;
259
6ca2edcd 260 my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid'));
95ea5d67 261
a8b14c78
TL
262 PVE::HA::Config::service_is_ha_managed($sid);
263
66c7e7ef 264 PVE::HA::Config::lock_ha_domain(
95ea5d67
DM
265 sub {
266
139a9b90 267 my $cfg = PVE::HA::Config::read_resources_config();
95ea5d67
DM
268
269 delete $cfg->{ids}->{$sid};
270
139a9b90 271 PVE::HA::Config::write_resources_config($cfg)
95ea5d67 272
a77fc389 273 }, "delete resource failed");
95ea5d67
DM
274
275 return undef;
276 }});
239a687f 277
50a87f1f
DM
278__PACKAGE__->register_method ({
279 name => 'migrate',
280 protected => 1,
281 path => '{sid}/migrate',
282 method => 'POST',
283 description => "Request resource migration (online) to another node.",
0fcba7ab
TL
284 permissions => {
285 check => ['perm', '/', [ 'Sys.Console' ]],
286 },
50a87f1f
DM
287 parameters => {
288 additionalProperties => 0,
289 properties => {
73bede9b
TL
290 sid => get_standard_option('pve-ha-resource-or-vm-id',
291 { completion => \&PVE::HA::Tools::complete_sid }),
292 node => get_standard_option('pve-node',
293 { completion => \&PVE::Cluster::get_nodelist }),
50a87f1f
DM
294 },
295 },
296 returns => { type => 'null' },
297 code => sub {
298 my ($param) = @_;
299
6ca2edcd
DM
300 my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid'));
301
a8b14c78
TL
302 PVE::HA::Config::service_is_ha_managed($sid);
303
2732fccf
TL
304 check_service_state($sid);
305
6ca2edcd 306 PVE::HA::Config::queue_crm_commands("migrate $sid $param->{node}");
50a87f1f
DM
307
308 return undef;
309 }});
310
311__PACKAGE__->register_method ({
312 name => 'relocate',
313 protected => 1,
314 path => '{sid}/relocate',
315 method => 'POST',
316 description => "Request resource relocatzion to another node. This stops the service on the old node, and restarts it on the target node.",
0fcba7ab
TL
317 permissions => {
318 check => ['perm', '/', [ 'Sys.Console' ]],
319 },
50a87f1f
DM
320 parameters => {
321 additionalProperties => 0,
322 properties => {
73bede9b
TL
323 sid => get_standard_option('pve-ha-resource-or-vm-id',
324 { completion => \&PVE::HA::Tools::complete_sid }),
325 node => get_standard_option('pve-node',
326 { completion => \&PVE::Cluster::get_nodelist }),
50a87f1f
DM
327 },
328 },
329 returns => { type => 'null' },
330 code => sub {
331 my ($param) = @_;
332
6ca2edcd
DM
333 my ($sid, $type, $name) = PVE::HA::Tools::parse_sid(extract_param($param, 'sid'));
334
a8b14c78
TL
335 PVE::HA::Config::service_is_ha_managed($sid);
336
2732fccf
TL
337 check_service_state($sid);
338
6ca2edcd 339 PVE::HA::Config::queue_crm_commands("relocate $sid $param->{node}");
50a87f1f
DM
340
341 return undef;
342 }});
343
239a687f 3441;