]>
Commit | Line | Data |
---|---|---|
aff192e6 DM |
1 | package PVE::API2::Cluster; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use PVE::SafeSyslog; | |
7 | use PVE::Tools qw(extract_param); | |
a06a3eac | 8 | use PVE::INotify; |
7cdf443c | 9 | use PVE::Cluster qw(cfs_register_file cfs_lock_file cfs_read_file cfs_write_file); |
aff192e6 | 10 | use PVE::Storage; |
ac27b58d | 11 | use PVE::API2::Backup; |
a06a3eac | 12 | use PVE::API2::HAConfig; |
aff192e6 | 13 | use JSON; |
aff192e6 DM |
14 | use PVE::RESTHandler; |
15 | use PVE::RPCEnvironment; | |
16 | ||
17 | use base qw(PVE::RESTHandler); | |
18 | ||
ac27b58d DM |
19 | __PACKAGE__->register_method ({ |
20 | subclass => "PVE::API2::Backup", | |
21 | path => 'backup', | |
22 | }); | |
23 | ||
a06a3eac DM |
24 | __PACKAGE__->register_method ({ |
25 | subclass => "PVE::API2::HAConfig", | |
26 | path => 'ha', | |
27 | }); | |
28 | ||
aff192e6 DM |
29 | my $dc_schema = PVE::Cluster::get_datacenter_schema(); |
30 | my $dc_properties = { | |
31 | delete => { | |
32 | type => 'string', format => 'pve-configid-list', | |
33 | description => "A list of settings you want to delete.", | |
34 | optional => 1, | |
35 | } | |
36 | }; | |
37 | foreach my $opt (keys %{$dc_schema->{properties}}) { | |
38 | $dc_properties->{$opt} = $dc_schema->{properties}->{$opt}; | |
39 | } | |
40 | ||
41 | __PACKAGE__->register_method ({ | |
42 | name => 'index', | |
43 | path => '', | |
44 | method => 'GET', | |
45 | description => "Cluster index.", | |
46 | permissions => { user => 'all' }, | |
47 | parameters => { | |
48 | additionalProperties => 0, | |
49 | properties => {}, | |
50 | }, | |
51 | returns => { | |
52 | type => 'array', | |
53 | items => { | |
54 | type => "object", | |
55 | properties => {}, | |
56 | }, | |
57 | links => [ { rel => 'child', href => "{name}" } ], | |
58 | }, | |
59 | code => sub { | |
60 | my ($param) = @_; | |
61 | ||
62 | my $result = [ | |
63 | { name => 'log' }, | |
64 | { name => 'options' }, | |
65 | { name => 'resources' }, | |
66 | { name => 'tasks' }, | |
ac27b58d | 67 | { name => 'backup' }, |
a06a3eac | 68 | { name => 'ha' }, |
aff192e6 DM |
69 | ]; |
70 | ||
71 | return $result; | |
72 | }}); | |
73 | ||
74 | __PACKAGE__->register_method({ | |
75 | name => 'log', | |
76 | path => 'log', | |
77 | method => 'GET', | |
78 | description => "Read cluster log", | |
79 | permissions => { user => 'all' }, | |
80 | parameters => { | |
81 | additionalProperties => 0, | |
82 | properties => { | |
83 | max => { | |
84 | type => 'integer', | |
85 | description => "Maximum number of entries.", | |
86 | optional => 1, | |
87 | minimum => 1, | |
88 | } | |
89 | }, | |
90 | }, | |
91 | returns => { | |
92 | type => 'array', | |
93 | items => { | |
94 | type => "object", | |
95 | properties => {}, | |
96 | }, | |
97 | }, | |
98 | code => sub { | |
99 | my ($param) = @_; | |
100 | ||
101 | my $rpcenv = PVE::RPCEnvironment::get(); | |
102 | ||
103 | my $max = $param->{max} || 0; | |
104 | my $user = $rpcenv->get_user(); | |
105 | ||
106 | my $admin = $rpcenv->check($user, "/", [ 'Sys.Syslog' ]); | |
107 | ||
108 | my $loguser = $admin ? '' : $user; | |
109 | ||
110 | my $res = decode_json(PVE::Cluster::get_cluster_log($loguser, $max)); | |
111 | ||
112 | return $res->{data}; | |
113 | }}); | |
114 | ||
115 | __PACKAGE__->register_method({ | |
116 | name => 'resources', | |
117 | path => 'resources', | |
118 | method => 'GET', | |
119 | description => "Resources index (cluster wide).", | |
120 | permissions => { user => 'all' }, | |
121 | parameters => { | |
122 | additionalProperties => 0, | |
badcb8d1 DM |
123 | properties => { |
124 | type => { | |
125 | type => 'string', | |
126 | optional => 1, | |
127 | enum => ['vm', 'storage', 'node'], | |
128 | }, | |
129 | }, | |
aff192e6 DM |
130 | }, |
131 | returns => { | |
132 | type => 'array', | |
133 | items => { | |
134 | type => "object", | |
135 | properties => { | |
136 | }, | |
137 | }, | |
138 | }, | |
139 | code => sub { | |
140 | my ($param) = @_; | |
141 | ||
142 | my $rpcenv = PVE::RPCEnvironment::get(); | |
143 | my $user = $rpcenv->get_user(); | |
144 | ||
145 | my $res = []; | |
146 | ||
bc7bff8e DM |
147 | my $nodelist = PVE::Cluster::get_nodelist(); |
148 | my $members = PVE::Cluster::get_members(); | |
aff192e6 DM |
149 | |
150 | my $rrd = PVE::Cluster::rrd_dump(); | |
151 | ||
152 | my $vmlist = PVE::Cluster::get_vmlist() || {}; | |
153 | my $idlist = $vmlist->{ids} || {}; | |
154 | ||
155 | ||
156 | # we try to generate 'numbers' by using "$X + 0" | |
badcb8d1 DM |
157 | if (!$param->{type} || $param->{type} eq 'vm') { |
158 | foreach my $vmid (keys %$idlist) { | |
159 | my $data = $idlist->{$vmid}; | |
aff192e6 | 160 | |
aff192e6 | 161 | |
badcb8d1 | 162 | next if !$rpcenv->check($user, "/vms/$vmid", [ 'VM.Audit' ]); |
aff192e6 | 163 | |
badcb8d1 DM |
164 | my $entry = { |
165 | id => "$data->{type}/$vmid", | |
166 | vmid => $vmid + 0, | |
167 | node => $data->{node}, | |
168 | type => $data->{type}, | |
169 | }; | |
aff192e6 | 170 | |
badcb8d1 | 171 | if (my $d = $rrd->{"pve2-vm/$vmid"}) { |
aff192e6 | 172 | |
bc7bff8e | 173 | $entry->{uptime} = ($d->[0] || 0) + 0; |
badcb8d1 DM |
174 | $entry->{name} = $d->[1]; |
175 | ||
176 | $entry->{maxcpu} = ($d->[3] || 0) + 0; | |
bc7bff8e | 177 | $entry->{cpu} = ($d->[4] || 0) + 0; |
badcb8d1 DM |
178 | $entry->{maxmem} = ($d->[5] || 0) + 0; |
179 | $entry->{mem} = ($d->[6] || 0) + 0; | |
180 | $entry->{maxdisk} = ($d->[7] || 0) + 0; | |
181 | $entry->{disk} = ($d->[8] || 0) + 0; | |
bc7bff8e | 182 | } |
badcb8d1 DM |
183 | |
184 | push @$res, $entry; | |
aff192e6 | 185 | } |
aff192e6 DM |
186 | } |
187 | ||
badcb8d1 | 188 | if (!$param->{type} || $param->{type} eq 'node') { |
bc7bff8e | 189 | foreach my $node (@$nodelist) { |
aff192e6 | 190 | my $entry = { |
badcb8d1 DM |
191 | id => "node/$node", |
192 | node => $node, | |
193 | type => "node", | |
194 | }; | |
195 | if (my $d = $rrd->{"pve2-node/$node"}) { | |
196 | ||
197 | if (!$members || # no cluster | |
198 | ($members->{$node} && $members->{$node}->{online})) { | |
199 | $entry->{uptime} = ($d->[0] || 0) + 0; | |
200 | $entry->{cpu} = ($d->[4] || 0) + 0; | |
201 | $entry->{mem} = ($d->[7] || 0) + 0; | |
202 | $entry->{disk} = ($d->[11] || 0) + 0; | |
203 | } | |
204 | ||
205 | $entry->{maxcpu} = ($d->[3] || 0) + 0; | |
206 | $entry->{maxmem} = ($d->[6] || 0) + 0; | |
207 | $entry->{maxdisk} = ($d->[10] || 0) + 0; | |
aff192e6 DM |
208 | } |
209 | ||
210 | push @$res, $entry; | |
badcb8d1 DM |
211 | } |
212 | } | |
aff192e6 | 213 | |
badcb8d1 DM |
214 | if (!$param->{type} || $param->{type} eq 'storage') { |
215 | ||
216 | my $cfg = PVE::Storage::config(); | |
217 | my @sids = PVE::Storage::storage_ids ($cfg); | |
218 | ||
219 | foreach my $storeid (@sids) { | |
220 | my $scfg = PVE::Storage::storage_config($cfg, $storeid); | |
221 | next if !$rpcenv->check($user, "/storage/$storeid", [ 'Datastore.Audit' ]); | |
222 | # we create a entry for each node | |
223 | foreach my $node (@$nodelist) { | |
224 | next if !PVE::Storage::storage_check_enabled($cfg, $storeid, $node, 1); | |
225 | my $entry = { | |
226 | id => "storage/$node/$storeid", | |
227 | storage => $storeid, | |
228 | node => $node, | |
229 | type => 'storage', | |
230 | }; | |
231 | ||
232 | if (my $d = $rrd->{"pve2-storage/$node/$storeid"}) { | |
233 | $entry->{maxdisk} = ($d->[1] || 0) + 0; | |
234 | $entry->{disk} = ($d->[2] || 0) + 0; | |
235 | } | |
236 | ||
237 | push @$res, $entry; | |
238 | } | |
aff192e6 DM |
239 | } |
240 | } | |
241 | ||
242 | return $res; | |
243 | }}); | |
244 | ||
245 | __PACKAGE__->register_method({ | |
246 | name => 'tasks', | |
247 | path => 'tasks', | |
248 | method => 'GET', | |
249 | description => "List recent tasks (cluster wide).", | |
250 | permissions => { user => 'all' }, | |
251 | parameters => { | |
252 | additionalProperties => 0, | |
253 | properties => {}, | |
254 | }, | |
255 | returns => { | |
256 | type => 'array', | |
257 | items => { | |
258 | type => "object", | |
259 | properties => { | |
260 | upid => { type => 'string' }, | |
261 | }, | |
262 | }, | |
263 | }, | |
264 | code => sub { | |
265 | my ($param) = @_; | |
266 | ||
267 | my $rpcenv = PVE::RPCEnvironment::get(); | |
268 | my $user = $rpcenv->get_user(); | |
269 | ||
270 | my $tlist = PVE::Cluster::get_tasklist(); | |
271 | ||
272 | my $res = []; | |
273 | ||
274 | return $res if !$tlist; | |
275 | ||
276 | my $all = $rpcenv->check($user, "/", [ 'Sys.Audit' ]); | |
277 | ||
278 | foreach my $task (@$tlist) { | |
279 | push @$res, $task if $all || ($task->{user} eq $user); | |
280 | } | |
281 | ||
282 | return $res; | |
283 | }}); | |
284 | ||
285 | __PACKAGE__->register_method({ | |
286 | name => 'get_options', | |
287 | path => 'options', | |
288 | method => 'GET', | |
289 | description => "Get datacenter options.", | |
290 | permissions => { | |
291 | path => '/', | |
292 | privs => [ 'Sys.Audit' ], | |
293 | }, | |
294 | parameters => { | |
295 | additionalProperties => 0, | |
296 | properties => {}, | |
297 | }, | |
298 | returns => { | |
299 | type => "object", | |
300 | properties => {}, | |
301 | }, | |
302 | code => sub { | |
303 | my ($param) = @_; | |
304 | return PVE::Cluster::cfs_read_file('datacenter.cfg'); | |
305 | }}); | |
306 | ||
307 | __PACKAGE__->register_method({ | |
308 | name => 'set_options', | |
309 | path => 'options', | |
310 | method => 'PUT', | |
311 | description => "Set datacenter options.", | |
312 | permissions => { | |
313 | path => '/', | |
314 | privs => [ 'Sys.Modify' ], | |
315 | }, | |
316 | protected => 1, | |
317 | parameters => { | |
318 | additionalProperties => 0, | |
319 | properties => $dc_properties, | |
320 | }, | |
321 | returns => { type => "null" }, | |
322 | code => sub { | |
323 | my ($param) = @_; | |
324 | ||
325 | my $filename = 'datacenter.cfg'; | |
326 | ||
327 | my $delete = extract_param($param, 'delete'); | |
328 | ||
329 | my $code = sub { | |
330 | ||
331 | my $conf = cfs_read_file($filename); | |
332 | ||
333 | foreach my $opt (keys %$param) { | |
334 | $conf->{$opt} = $param->{$opt}; | |
335 | } | |
336 | ||
337 | foreach my $opt (PVE::Tools::split_list($delete)) { | |
338 | delete $conf->{$opt}; | |
339 | }; | |
340 | ||
341 | cfs_write_file($filename, $conf); | |
342 | }; | |
343 | ||
344 | cfs_lock_file($filename, undef, $code); | |
345 | die $@ if $@; | |
346 | ||
347 | return undef; | |
348 | }}); | |
349 | ||
350 | 1; |