]>
Commit | Line | Data |
---|---|---|
239a687f DM |
1 | package PVE::API2::HA::Resources; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use PVE::SafeSyslog; | |
7 | use PVE::Tools qw(extract_param); | |
23944168 | 8 | use PVE::Cluster; |
239a687f DM |
9 | use PVE::HA::Config; |
10 | use PVE::HA::Resources; | |
11 | use HTTP::Status qw(:constants); | |
12 | use Storable qw(dclone); | |
13 | use PVE::JSONSchema qw(get_standard_option); | |
14 | use PVE::RPCEnvironment; | |
95ea5d67 | 15 | use Data::Dumper; |
239a687f DM |
16 | |
17 | use PVE::RESTHandler; | |
18 | ||
19 | use base qw(PVE::RESTHandler); | |
20 | ||
21 | # fixme: use cfs_read_file | |
22 | ||
239a687f DM |
23 | my $resource_type_enum = PVE::HA::Resources->lookup_types(); |
24 | ||
25 | # fixme: fix permissions | |
26 | ||
27 | my $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 | 301 | 1; |