]> git.proxmox.com Git - pve-manager.git/blobdiff - PVE/API2/Cluster.pm
fixup /cluster/resources schema
[pve-manager.git] / PVE / API2 / Cluster.pm
index 0020d2ea681fd795e1b1a6cce20a7a5413807496..49e319a5c624b356e7d8b8fb8692b9e6bed3f3e6 100644 (file)
@@ -21,8 +21,12 @@ use PVE::Storage;
 use PVE::Tools qw(extract_param);
 
 use PVE::API2::ACMEAccount;
+use PVE::API2::ACMEPlugin;
 use PVE::API2::Backup;
+use PVE::API2::Cluster::BackupInfo;
 use PVE::API2::Cluster::Ceph;
+use PVE::API2::Cluster::Jobs;
+use PVE::API2::Cluster::MetricServer;
 use PVE::API2::ClusterConfig;
 use PVE::API2::Firewall::Cluster;
 use PVE::API2::HAConfig;
@@ -41,6 +45,11 @@ __PACKAGE__->register_method ({
     path => 'replication',
 });
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Cluster::MetricServer",
+    path => 'metrics',
+});
+
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::ClusterConfig",
     path => 'config',
@@ -56,6 +65,11 @@ __PACKAGE__->register_method ({
     path => 'backup',
 });
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Cluster::BackupInfo",
+    path => 'backup-info',
+});
+
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::HAConfig",
     path => 'ha',
@@ -71,6 +85,10 @@ __PACKAGE__->register_method ({
     path => 'ceph',
 });
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Cluster::Jobs",
+    path => 'jobs',
+});
 if ($have_sdn) {
     __PACKAGE__->register_method ({
        subclass => "PVE::API2::Network::SDN",
@@ -112,20 +130,23 @@ __PACKAGE__->register_method ({
        my ($param) = @_;
 
        my $result = [
+           { name => 'acme' },
+           { name => 'backup' },
+           { name => 'backup-info' },
+           { name => 'ceph' },
+           { name => 'config' },
+           { name => 'firewall' },
+           { name => 'ha' },
+           { name => 'jobs' },
            { name => 'log' },
+           { name => 'metrics' },
+           { name => 'nextid' },
            { name => 'options' },
-           { name => 'resources' },
            { name => 'replication' },
-           { name => 'tasks' },
-           { name => 'backup' },
-           { name => 'ha' },
+           { name => 'resources' },
            { name => 'status' },
-           { name => 'nextid' },
-           { name => 'firewall' },
-           { name => 'config' },
-           { name => 'acme' },
-           { name => 'ceph' },
-           ];
+           { name => 'tasks' },
+       ];
 
        if ($have_sdn) {
            push(@{$result}, { name => 'sdn' });
@@ -211,6 +232,11 @@ __PACKAGE__->register_method({
                    type => 'string',
                    optional => 1,
                },
+               name => {
+                   description => "Name of the resource.",
+                   type => 'string',
+                   optional => 1,
+               },
                node => get_standard_option('pve-node', {
                    description => "The cluster node name (when type in node,storage,qemu,lxc).",
                    optional => 1,
@@ -228,18 +254,21 @@ __PACKAGE__->register_method({
                    description => "CPU utilization (when type in node,qemu,lxc).",
                    type => 'number',
                    optional => 1,
+                   minimum => 0,
                    renderer => 'fraction_as_percentage',
                },
                maxcpu => {
                    description => "Number of available CPUs (when type in node,qemu,lxc).",
                    type => 'number',
                    optional => 1,
+                   minimum => 0,
                },
                mem => {
                    description => "Used memory in bytes (when type in node,qemu,lxc).",
-                   type => 'string',
+                   type => 'integer',
                    optional => 1,
                    renderer => 'bytes',
+                   minimum => 0,
                },
                maxmem => {
                    description => "Number of available memory in bytes (when type in node,qemu,lxc).",
@@ -265,15 +294,34 @@ __PACKAGE__->register_method({
                },
                disk => {
                    description => "Used disk space in bytes (when type in storage), used root image spave for VMs (type in qemu,lxc).",
-                   type => 'string',
+                   type => 'integer',
                    optional => 1,
                    renderer => 'bytes',
+                   minimum => 0,
                },
                maxdisk => {
                    description => "Storage size in bytes (when type in storage), root image size for VMs (type in qemu,lxc).",
                    type => 'integer',
                    optional => 1,
                    renderer => 'bytes',
+                   minimum => 0,
+               },
+               content => {
+                   description => "Allowed storage content types (when type == storage).",
+                   type => 'string',
+                   format => 'pve-storage-content-list',
+                   optional => 1,
+               },
+               plugintype => {
+                   description => "More specific type, if available.",
+                   type => 'string',
+                   optional => 1,
+               },
+               vmid => {
+                   description => "The numerical vmid (when type in qemu,lxc).",
+                   type => 'integer',
+                   optional => 1,
+                   minimum => 1,
                },
            },
        },
@@ -304,10 +352,10 @@ __PACKAGE__->register_method({
 
        my $pooldata = {};
        if (!$param->{type} || $param->{type} eq 'pool') {
-           foreach my $pool (keys %{$usercfg->{pools}}) {
+           for my $pool (sort keys %{$usercfg->{pools}}) {
                my $d = $usercfg->{pools}->{$pool};
 
-               next if !$rpcenv->check($authuser, "/pool/$pool", [ 'Pool.Allocate' ], 1);
+               next if !$rpcenv->check($authuser, "/pool/$pool", [ 'Pool.Audit' ], 1);
 
                my $entry = {
                    id => "/pool/$pool",
@@ -325,15 +373,11 @@ __PACKAGE__->register_method({
        if (!$param->{type} || $param->{type} eq 'vm') {
            my $locked_vms = PVE::Cluster::get_guest_config_property('lock');
 
-           foreach my $vmid (keys %$idlist) {
+           for my $vmid (sort keys %$idlist) {
 
                my $data = $idlist->{$vmid};
                my $entry = PVE::API2Tools::extract_vm_stats($vmid, $data, $rrd);
 
-               if (defined(my $lock = $locked_vms->{$vmid}->{lock})) {
-                   $entry->{lock} = $lock;
-               }
-
                if (my $pool = $usercfg->{vms}->{$vmid}) {
                    $entry->{pool} = $pool;
                    if (my $pe = $pooldata->{$pool}) {
@@ -356,8 +400,18 @@ __PACKAGE__->register_method({
                    }
                }
 
+               # only skip now to next to ensure that the pool stats above are filled, if eligible
                next if !$rpcenv->check($authuser, "/vms/$vmid", [ 'VM.Audit' ], 1);
 
+               if (defined(my $lock = $locked_vms->{$vmid}->{lock})) {
+                   $entry->{lock} = $lock;
+               }
+
+               if (defined($entry->{pool}) &&
+                   !$rpcenv->check($authuser, "/pool/$entry->{pool}", ['Pool.Audit'], 1)) {
+                   delete $entry->{pool};
+               }
+
                # get ha status
                if (my $hatype = $hatypemap->{$entry->{type}}) {
                    my $sid = "$hatype:$vmid";
@@ -405,12 +459,12 @@ __PACKAGE__->register_method({
 
                my $nodes = PVE::Cluster::get_node_kv("sdn");
 
-               foreach my $node (keys %{$nodes}) {
+               for my $node (sort keys %{$nodes}) {
                    my $sdns = decode_json($nodes->{$node});
 
-                   foreach my $id (keys %{$sdns}) {
+                   for my $id (sort keys %{$sdns}) {
+                       next if !$rpcenv->check($authuser, "/sdn/zones/$id", [ 'SDN.Audit' ], 1);
                        my $sdn = $sdns->{$id};
-                       #next if !$rpcenv->check($authuser, "/sdn/$id", [ 'SDN.Audit' ], 1);
                        my $entry = {
                            id => "sdn/$node/$id",
                            sdn => $id,
@@ -453,14 +507,15 @@ __PACKAGE__->register_method({
        my $authuser = $rpcenv->get_user();
 
        my $tlist = PVE::Cluster::get_tasklist();
-
-       my $res = [];
-
-       return $res if !$tlist;
+       return [] if !$tlist;
 
        my $all = $rpcenv->check($authuser, "/", [ 'Sys.Audit' ], 1);
 
+       my $res = [];
        foreach my $task (@$tlist) {
+           if (PVE::AccessControl::pve_verify_tokenid($task->{user}, 1)) {
+               ($task->{user}, $task->{tokenid}) = PVE::AccessControl::split_tokenid($task->{user});
+           }
            push @$res, $task if $all || ($task->{user} eq $authuser);
        }
 
@@ -506,26 +561,17 @@ __PACKAGE__->register_method({
     code => sub {
        my ($param) = @_;
 
-       my $filename = 'datacenter.cfg';
-
        my $delete = extract_param($param, 'delete');
 
-       my $code = sub {
+       cfs_lock_file('datacenter.cfg', undef, sub {
+           my $conf = cfs_read_file('datacenter.cfg');
 
-           my $conf = cfs_read_file($filename);
+           $conf->{$_} = $param->{$_} for keys $param->%*;
 
-           foreach my $opt (keys %$param) {
-               $conf->{$opt} = $param->{$opt};
-           }
+           delete $conf->{$_} for PVE::Tools::split_list($delete);
 
-           foreach my $opt (PVE::Tools::split_list($delete)) {
-               delete $conf->{$opt};
-           };
-
-           cfs_write_file($filename, $conf);
-       };
-
-       cfs_lock_file($filename, undef, $code);
+           cfs_write_file('datacenter.cfg', $conf);
+       });
        die $@ if $@;
 
        return undef;
@@ -583,7 +629,7 @@ __PACKAGE__->register_method({
                ip => {
                    type => 'string',
                    optional => 1,
-                   description => '[node] Ip of the node.',
+                   description => '[node] IP of the resolved nodename.',
                },
                'local' => {
                    type => 'boolean',
@@ -636,13 +682,16 @@ __PACKAGE__->register_method({
                    id => "node/$node",
                    name => $node,
                    nodeid => $d->{id},
-                   ip => $d->{ip},
                    'local' => ($node eq $nodename) ? 1 : 0,
                    online => $d->{online},
                };
 
+               if (defined($d->{ip})) {
+                   $entry->{ip} = $d->{ip};
+               }
+
                if (my $d = PVE::API2Tools::extract_node_stats($node, $members, $rrd)) {
-                   $entry->{level} = $d->{level};
+                   $entry->{level} = $d->{level} || '';
                }
 
                push @$res, $entry;
@@ -652,7 +701,7 @@ __PACKAGE__->register_method({
            # fake entry for local node if no cluster defined
            my $pmxcfs = ($clinfo && $clinfo->{version}) ? 1 : 0; # pmxcfs online ?
 
-           my $subinfo = PVE::INotify::read_file('subscription');
+           my $subinfo = PVE::API2::Subscription::read_etc_subscription();
            my $sublevel = $subinfo->{level} || '';
 
            return [{
@@ -672,12 +721,14 @@ __PACKAGE__->register_method({
     name => 'nextid',
     path => 'nextid',
     method => 'GET',
-    description => "Get next free VMID. If you pass an VMID it will raise an error if the ID is already used.",
+    description => "Get next free VMID. Pass a VMID to assert that its free (at time of check).",
     permissions => { user => 'all' },
     parameters => {
        additionalProperties => 0,
        properties => {
-           vmid => get_standard_option('pve-vmid', {optional => 1}),
+           vmid => get_standard_option('pve-vmid', {
+                   optional => 1,
+           }),
        },
     },
     returns => {
@@ -695,11 +746,17 @@ __PACKAGE__->register_method({
            raise_param_exc({ vmid => "VM $vmid already exists" });
        }
 
-       for (my $i = 100; $i < 10000; $i++) {
+       my $dc_conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
+       my $next_id = $dc_conf->{'next-id'} // {};
+
+       my $lower = $next_id->{lower} // 100;
+       my $upper = $next_id->{upper} // (1000 * 1000); # note, lower than the schema-maximum
+
+       for (my $i = $lower; $i < $upper; $i++) {
            return $i if !defined($idlist->{$i});
        }
 
-       die "unable to get any free VMID\n";
+       die "unable to get any free VMID in range [$lower, $upper]\n";
     }});
 
 1;