]>
git.proxmox.com Git - pve-manager.git/blob - PVE/API2/Cluster.pm
1 package PVE
::API2
::Cluster
;
9 use PVE
::Tools
qw(extract_param);
10 use PVE
::Exception
qw(raise_param_exc);
12 use PVE
::Cluster
qw(cfs_register_file cfs_lock_file cfs_read_file cfs_write_file);
15 use PVE
::API2
::Backup
;
16 use PVE
::API2
::HAConfig
;
19 use PVE
::RPCEnvironment
;
20 use PVE
::JSONSchema
qw(get_standard_option);
22 use PVE
::API2
::Firewall
::Cluster
;
24 use base
qw(PVE::RESTHandler);
26 __PACKAGE__-
>register_method ({
27 subclass
=> "PVE::API2::Firewall::Cluster",
31 __PACKAGE__-
>register_method ({
32 subclass
=> "PVE::API2::Backup",
36 __PACKAGE__-
>register_method ({
37 subclass
=> "PVE::API2::HAConfig",
41 my $dc_schema = PVE
::Cluster
::get_datacenter_schema
();
44 type
=> 'string', format
=> 'pve-configid-list',
45 description
=> "A list of settings you want to delete.",
49 foreach my $opt (keys %{$dc_schema->{properties
}}) {
50 $dc_properties->{$opt} = $dc_schema->{properties
}->{$opt};
53 __PACKAGE__-
>register_method ({
57 description
=> "Cluster index.",
58 permissions
=> { user
=> 'all' },
60 additionalProperties
=> 0,
69 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
76 { name
=> 'options' },
77 { name
=> 'resources' },
83 { name
=> 'firewall' },
89 __PACKAGE__-
>register_method({
93 description
=> "Read cluster log",
94 permissions
=> { user
=> 'all' },
96 additionalProperties
=> 0,
100 description
=> "Maximum number of entries.",
116 my $rpcenv = PVE
::RPCEnvironment
::get
();
118 my $max = $param->{max
} || 0;
119 my $user = $rpcenv->get_user();
121 my $admin = $rpcenv->check($user, "/", [ 'Sys.Syslog' ], 1);
123 my $loguser = $admin ?
'' : $user;
125 my $res = decode_json
(PVE
::Cluster
::get_cluster_log
($loguser, $max));
130 __PACKAGE__-
>register_method({
134 description
=> "Resources index (cluster wide).",
135 permissions
=> { user
=> 'all' },
137 additionalProperties
=> 0,
142 enum
=> ['vm', 'storage', 'node'],
157 my $rpcenv = PVE
::RPCEnvironment
::get
();
158 my $authuser = $rpcenv->get_user();
159 my $usercfg = $rpcenv->{user_cfg
};
163 my $nodelist = PVE
::Cluster
::get_nodelist
();
164 my $members = PVE
::Cluster
::get_members
();
166 my $rrd = PVE
::Cluster
::rrd_dump
();
168 my $vmlist = PVE
::Cluster
::get_vmlist
() || {};
169 my $idlist = $vmlist->{ids
} || {};
172 if (!$param->{type
} || $param->{type
} eq 'pool') {
173 foreach my $pool (keys %{$usercfg->{pools
}}) {
174 my $d = $usercfg->{pools
}->{$pool};
176 next if !$rpcenv->check($authuser, "/pool/$pool", [ 'Pool.Allocate' ], 1);
184 $pooldata->{$pool} = $entry;
190 # we try to generate 'numbers' by using "$X + 0"
191 if (!$param->{type
} || $param->{type
} eq 'vm') {
192 foreach my $vmid (keys %$idlist) {
194 my $data = $idlist->{$vmid};
195 my $entry = PVE
::API2Tools
::extract_vm_stats
($vmid, $data, $rrd);
196 if ($entry->{uptime
}) {
197 if (my $pool = $usercfg->{vms
}->{$vmid}) {
198 if (my $pe = $pooldata->{$pool}) {
199 $pe->{uptime
} = $entry->{uptime
} if !$pe->{uptime
} || $entry->{uptime
} > $pe->{uptime
};
200 $pe->{mem
} = 0 if !$pe->{mem
};
201 $pe->{mem
} += $entry->{mem
};
202 $pe->{maxmem
} = 0 if !$pe->{maxmem
};
203 $pe->{maxmem
} += $entry->{maxmem
};
204 $pe->{cpu
} = 0 if !$pe->{cpu
};
205 $pe->{cpu
} += $entry->{cpu
};
206 $pe->{maxcpu
} = 0 if !$pe->{maxcpu
};
207 $pe->{maxcpu
} += $entry->{maxcpu
};
212 next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ], 1);
218 if (!$param->{type
} || $param->{type
} eq 'node') {
219 foreach my $node (@$nodelist) {
220 my $entry = PVE
::API2Tools
::extract_node_stats
($node, $members, $rrd);
225 if (!$param->{type
} || $param->{type
} eq 'storage') {
227 my $cfg = PVE
::Storage
::config
();
228 my @sids = PVE
::Storage
::storage_ids
($cfg);
230 foreach my $storeid (@sids) {
231 next if !$rpcenv->check($authuser, "/storage/$storeid", [ 'Datastore.Audit' ], 1);
233 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
234 # we create a entry for each node
235 foreach my $node (@$nodelist) {
236 next if !PVE
::Storage
::storage_check_enabled
($cfg, $storeid, $node, 1);
238 my $entry = PVE
::API2Tools
::extract_storage_stats
($storeid, $scfg, $node, $rrd);
247 __PACKAGE__-
>register_method({
251 description
=> "List recent tasks (cluster wide).",
252 permissions
=> { user
=> 'all' },
254 additionalProperties
=> 0,
262 upid
=> { type
=> 'string' },
269 my $rpcenv = PVE
::RPCEnvironment
::get
();
270 my $authuser = $rpcenv->get_user();
272 my $tlist = PVE
::Cluster
::get_tasklist
();
276 return $res if !$tlist;
278 my $all = $rpcenv->check($authuser, "/", [ 'Sys.Audit' ], 1);
280 foreach my $task (@$tlist) {
281 push @$res, $task if $all || ($task->{user
} eq $authuser);
287 __PACKAGE__-
>register_method({
288 name
=> 'get_options',
291 description
=> "Get datacenter options.",
293 check
=> ['perm', '/', [ 'Sys.Audit' ]],
296 additionalProperties
=> 0,
306 return PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
309 __PACKAGE__-
>register_method({
310 name
=> 'set_options',
313 description
=> "Set datacenter options.",
315 check
=> ['perm', '/', [ 'Sys.Modify' ]],
319 additionalProperties
=> 0,
320 properties
=> $dc_properties,
322 returns
=> { type
=> "null" },
326 my $filename = 'datacenter.cfg';
328 my $delete = extract_param
($param, 'delete');
332 my $conf = cfs_read_file
($filename);
334 foreach my $opt (keys %$param) {
335 $conf->{$opt} = $param->{$opt};
338 foreach my $opt (PVE
::Tools
::split_list
($delete)) {
339 delete $conf->{$opt};
342 cfs_write_file
($filename, $conf);
345 cfs_lock_file
($filename, undef, $code);
351 my $parse_clustat = sub {
352 my ($clinfo, $members, $rrd, $nodename, $raw) = @_;
354 my $createNode = sub {
355 my ($expat, $tag, %attrib) = @_;
356 my $node = { type
=> $tag, %attrib };
358 if ($tag eq 'node') {
359 my $name = $node->{name
};
360 return if !$name; # just to be sure
362 foreach my $key (qw(estranged local qdisk rgmanager rgmanager_master state)) {
363 $node->{$key} = int($node->{$key}) if defined($node->{$key});
365 $node->{nodeid
} = hex($node->{nodeid
}) if defined($node->{nodeid
});
368 $node->{id
} = "node/$node->{name}";
371 if (!$members) { # no cluster
372 if ($name eq $nodename) {
373 $pmxcfs = ($clinfo && $clinfo->{version
}) ?
1 : 0; # pmxcfs online ?
375 } elsif ($members->{$name}) {
376 $pmxcfs = $members->{$name}->{online
} ?
1 : 0
378 $node->{pmxcfs
} = $pmxcfs;
380 if ($members && $members->{$name}) {
381 if (my $ip = $members->{$name}->{ip
}) {
386 if (my $entry = PVE
::API2Tools
::extract_node_stats
($name, $members, $rrd)) {
387 $node->{level
} = $entry->{level
} || '';
390 } elsif ($tag eq 'group') {
391 my $name = $node->{name
};
392 return if !$name; # just to be sure
394 $node->{id
} = "group/$node->{name}";
412 $expat->{NodeList
} = [];
421 if ($extract_tags->{$tag}) {
422 my $node = &$createNode($expat, $tag, @_);
423 push @{$expat->{NodeList
}}, $node;
430 my $parser = new XML
::Parser
(Handlers
=> $handlers);
431 $data = $parser->parse($raw);
436 __PACKAGE__-
>register_method({
437 name
=> 'get_status',
440 description
=> "Get cluster status informations.",
442 check
=> ['perm', '/', [ 'Sys.Audit' ]],
446 additionalProperties
=> 0,
463 # we also add info from pmxcfs
464 my $clinfo = PVE
::Cluster
::get_clinfo
();
465 my $members = PVE
::Cluster
::get_members
();
466 my $nodename = PVE
::INotify
::nodename
();
467 my $rrd = PVE
::Cluster
::rrd_dump
();
470 my $cmd = ['clustat', '-x'];
472 PVE
::Tools
::run_command
($cmd, outfunc
=> sub { $out .= shift; });
473 return &$parse_clustat($clinfo, $members, $rrd, $nodename, $out);
475 # fake entry for local node if no cluster defined
476 my $pmxcfs = ($clinfo && $clinfo->{version
}) ?
1 : 0; # pmxcfs online ?
478 my $subinfo = PVE
::INotify
::read_file
('subscription');
479 my $sublevel = $subinfo->{level
} || '';
483 id
=> "node/$nodename",
494 __PACKAGE__-
>register_method({
498 description
=> "Get next free VMID. If you pass an VMID it will raise an error if the ID is already used.",
499 permissions
=> { user
=> 'all' },
501 additionalProperties
=> 0,
503 vmid
=> get_standard_option
('pve-vmid', {optional
=> 1}),
508 description
=> "The next free VMID.",
513 my $vmlist = PVE
::Cluster
::get_vmlist
() || {};
514 my $idlist = $vmlist->{ids
} || {};
516 if (my $vmid = $param->{vmid
}) {
517 return $vmid if !defined($idlist->{$vmid});
518 raise_param_exc
({ vmid
=> "VM $vmid already exists" });
521 for (my $i = 100; $i < 10000; $i++) {
522 return $i if !defined($idlist->{$i});
525 die "unable to get any free VMID\n";