package PVE::PullMetric; use strict; use warnings; use Proxmox::RS::SharedCache; use PVE::Network; use constant OLD_GENERATIONS => 180; use constant LOCK_TIMEOUT => 2; my $cache; my $get_cache = sub { if (!defined($cache)) { my $uid = getpwnam('root'); my $gid = getgrnam('www-data'); $cache = Proxmox::RS::SharedCache->new({ path => "/run/pve/metrics", owner => $uid, group => $gid, entry_mode => 0640, # Entry permissions keep_old => OLD_GENERATIONS, } ); } return $cache; }; # Return the number of generations stored by the metrics cache sub max_generations { # Number of old stats plus the most recent ones return OLD_GENERATIONS + 1; } sub transaction_start { return {}; } sub transaction_finish { my ($txn) = @_; $get_cache->()->set($txn, 2); } sub update { my ($txn, $subsystem, $data, $timestamp) = @_; $txn->{$subsystem}->{data} = $data; $txn->{$subsystem}->{timestamp} = $timestamp; } my sub gauge { my ($id, $timestamp, $metric, $value) = @_; return { metric => $metric, id => $id, value => $value + 0, timestamp => $timestamp + 0, type => 'gauge', } } my sub derive { my ($id, $timestamp, $metric, $value) = @_; return { metric => $metric, id => $id, value => $value + 0, timestamp => $timestamp + 0, type => 'derive', } } my $nodename = PVE::INotify::nodename(); my sub get_node_metrics { my ($stats) = @_; my $metrics = []; my $data = $stats->{data}; my $timestamp = $stats->{timestamp}; my $id = "node/$nodename"; push @$metrics, gauge($id, $timestamp, "uptime", $data->{uptime}); my ($netin, $netout) = (0, 0); for my $dev (grep { /^$PVE::Network::PHYSICAL_NIC_RE$/ } keys $data->{nics}->%*) { $netin += $data->{nics}->{$dev}->{receive}; $netout += $data->{nics}->{$dev}->{transmit}; } push @$metrics, derive($id, $timestamp, "net_in", $netin); push @$metrics, derive($id, $timestamp, "net_out", $netout); my $cpustat = $data->{cpustat}; push @$metrics, gauge($id, $timestamp, "cpu_avg1", $cpustat->{avg1}); push @$metrics, gauge($id, $timestamp, "cpu_avg5", $cpustat->{avg5}); push @$metrics, gauge($id, $timestamp, "cpu_avg15", $cpustat->{avg15}); push @$metrics, gauge($id, $timestamp, "cpu_max", $cpustat->{cpus}); push @$metrics, gauge($id, $timestamp, "cpu_current", $cpustat->{cpu}); push @$metrics, gauge($id, $timestamp, "cpu_iowait", $cpustat->{wait}); my $memory = $data->{memory}; push @$metrics, gauge($id, $timestamp, "mem_total", $memory->{memtotal}); push @$metrics, gauge($id, $timestamp, "mem_used", $memory->{memused}); push @$metrics, gauge($id, $timestamp, "swap_total", $memory->{swaptotal}); push @$metrics, gauge($id, $timestamp, "swap_used", $memory->{swapused}); my $blockstat = $data->{blockstat}; my $dused = $blockstat->{blocks} - $blockstat->{bfree}; push @$metrics, gauge($id, $timestamp, "disk_total", $blockstat->{blocks}); push @$metrics, gauge($id, $timestamp, "disk_used", $dused); return $metrics; } my sub get_qemu_metrics { my ($stats) = @_; my $metrics = []; my $timestamp = $stats->{timestamp}; for my $vmid (keys $stats->{data}->%*) { my $id = "qemu/$vmid"; my $guest_data = $stats->{data}->{$vmid}; if ($guest_data->{status} eq 'running') { push @$metrics, gauge($id, $timestamp, "cpu_current", $guest_data->{cpu}); push @$metrics, gauge($id, $timestamp, "mem_used", $guest_data->{mem}); push @$metrics, derive($id, $timestamp, "disk_read", $guest_data->{diskread}); push @$metrics, derive($id, $timestamp, "disk_write", $guest_data->{diskwrite}); push @$metrics, derive($id, $timestamp, "net_in", $guest_data->{netin}); push @$metrics, derive($id, $timestamp, "net_out", $guest_data->{netout}); } push @$metrics, gauge($id, $timestamp, "uptime", $guest_data->{uptime}); push @$metrics, gauge($id, $timestamp, "cpu_max", $guest_data->{cpus}); push @$metrics, gauge($id, $timestamp, "mem_total", $guest_data->{maxmem}); push @$metrics, gauge($id, $timestamp, "disk_total", $guest_data->{maxdisk}); # TODO: This one always seems to be 0? # push @$metrics, num_metric("disk_used", $id, $guest_data->{disk}, $timestamp); } return $metrics; } my sub get_lxc_metrics { my ($stats) = @_; my $metrics = []; my $timestamp = $stats->{timestamp}; for my $vmid (keys $stats->{data}->%*) { my $id = "lxc/$vmid"; my $guest_data = $stats->{data}->{$vmid}; if ($guest_data->{status} eq 'running') { push @$metrics, gauge($id, $timestamp, "cpu_current", $guest_data->{cpu}); push @$metrics, gauge($id, $timestamp, "mem_used", $guest_data->{mem}); push @$metrics, derive($id, $timestamp, "disk_read", $guest_data->{diskread}); push @$metrics, derive($id, $timestamp, "disk_write", $guest_data->{diskwrite}); push @$metrics, derive($id, $timestamp, "net_in", $guest_data->{netin}); push @$metrics, derive($id, $timestamp, "net_out", $guest_data->{netout}); push @$metrics, gauge($id, $timestamp, "disk_used", $guest_data->{disk}); } push @$metrics, gauge($id, $timestamp, "uptime", $guest_data->{uptime}); push @$metrics, gauge($id, $timestamp, "cpu_max", $guest_data->{cpus}); push @$metrics, gauge($id, $timestamp, "mem_total", $guest_data->{maxmem}); push @$metrics, gauge($id, $timestamp, "disk_total", $guest_data->{maxdisk}); } return $metrics; } my sub get_storage_metrics { my ($stats) = @_; my $metrics = []; my $timestamp = $stats->{timestamp}; for my $sid (keys $stats->{data}->%*) { my $id = "storage/$nodename/$sid"; my $data = $stats->{data}->{$sid}; push @$metrics, gauge($id, $timestamp, "disk_total", $data->{total}); push @$metrics, gauge($id, $timestamp, "disk_used", $data->{used}); } return $metrics; } # Return local metrics, including some recent history if needed. # sub get_local_metrics { my ($history) = @_; # If we do not provide the history parameter, set it to 0 -> only # query most recent metrics from the cache. $history = $history // 0; $history = int($history); my $metrics = []; my $data = $get_cache->()->get_last($history); for my $stat_gen ($data->@*) { push @$metrics, get_node_metrics($stat_gen->{node})->@*; push @$metrics, get_qemu_metrics($stat_gen->{qemu})->@*; push @$metrics, get_lxc_metrics($stat_gen->{lxc})->@*; push @$metrics, get_storage_metrics($stat_gen->{storage})->@*; } return $metrics; } 1;