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