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