mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
Add application powermon (#12500)
* adding powermon application * working consumption graph * updating powermon application * powermon app style fixes * added powermon app test data * debug code * revert * fix tests * fix tests Co-authored-by: Tony Murray <murraytony@gmail.com> Co-authored-by: Jellyfrog <Jellyfrog@users.noreply.github.com>
This commit is contained in:
@@ -69,6 +69,7 @@ class StringHelpers
|
||||
'powerdns' => 'PowerDNS',
|
||||
'powerdns-dnsdist' => 'PowerDNS dnsdist',
|
||||
'powerdns-recursor' => 'PowerDNS Recursor',
|
||||
'powermon' => 'PowerMon',
|
||||
'pureftpd' => 'PureFTPd',
|
||||
'rrdcached' => 'RRDCached',
|
||||
'sdfsinfo' => 'SDFS info',
|
||||
|
||||
@@ -124,6 +124,7 @@ by following the steps under the `SNMP Extend` heading.
|
||||
1. [PowerDNS](#powerdns) - Agent
|
||||
1. [PowerDNS Recursor](#powerdns-recursor) - Direct, SNMP extend, Agent
|
||||
1. [PowerDNS dnsdist](#powerdns-dnsdist) - SNMP extend
|
||||
1. [PowerMon](#powermon) - SNMP extend
|
||||
1. [Proxmox](#proxmox) - SNMP extend
|
||||
1. [Puppet Agent](#puppet_agent) - SNMP extend
|
||||
1. [PureFTPd](#pureftpd) - SNMP extend
|
||||
@@ -819,7 +820,7 @@ Verify it is working by running `/usr/lib/check_mk_agent/local/gpsd`
|
||||
Shell script that reports load average/memory/open-files stats of Icecast
|
||||
## SNMP Extend
|
||||
|
||||
1. Copy the shell script, icecast-stats.sh, to the desired host (the host must be added to LibreNMS devices)
|
||||
1. Copy the shell script, icecast-stats.sh, to the desired host (the host must be added to LibreNMS devices)
|
||||
```
|
||||
wget https://github.com/librenms/librenms-agent/raw/master/snmp/icecast-stats.sh -O /etc/snmp/icecast-stats.sh
|
||||
```
|
||||
@@ -845,7 +846,7 @@ wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/mailc
|
||||
|
||||
2: Run `chmod +x /etc/snmp/mailcow-dockerized-postfix`
|
||||
|
||||
> Maybe you will be neeed to install `pflogsumm` on debian based OS. Please check if you have package installed.
|
||||
> Maybe you will be neeed to install `pflogsumm` on debian based OS. Please check if you have package installed.
|
||||
|
||||
3: Edit your snmpd.conf file (usually /etc/snmp/snmpd.conf) and add:
|
||||
|
||||
@@ -1531,6 +1532,151 @@ The application should be auto-discovered as described at the top of
|
||||
the page. If it is not, please follow the steps set out under `SNMP
|
||||
Extend` heading top of page.
|
||||
|
||||
# PowerMon
|
||||
|
||||
PowerMon tracks the power usage on your host and can report on both consumption
|
||||
and cost, using a python script installed on the host.
|
||||
|
||||
[PowerMon consumption graph](../img/example-app-powermon-consumption-02.png)
|
||||
|
||||
Currently the script uses one of two methods to determine current power usage:
|
||||
|
||||
* ACPI via libsensors
|
||||
|
||||
* HP-Health (HP Proliant servers only)
|
||||
|
||||
The ACPI method is quite unreliable as it is usually only implemented by
|
||||
battery-powered devices, e.g. laptops. YMMV. However, it's possible to support
|
||||
any method as long as it can return a power value, usually in Watts.
|
||||
|
||||
> TIP: You can achieve this by adding a method and a function for that method to
|
||||
> the script. It should be called by getData() and return a dictionary.
|
||||
|
||||
Because the methods are unreliable for all hardware, you need to declare to the
|
||||
script which method to use. The are several options to assist with testing, see
|
||||
`--help`.
|
||||
|
||||
## SNMP Extend
|
||||
|
||||
### Initial setup
|
||||
|
||||
1. Download the python script onto the host:
|
||||
```
|
||||
wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/powermon-snmp.py -O /usr/local/bin/powermon-snmp.py
|
||||
```
|
||||
|
||||
2. Make the script executable:
|
||||
```
|
||||
chmod +x /usr/local/bin/powermon-snmp.py
|
||||
```
|
||||
|
||||
3. Edit the script and set the cost per kWh for your supply. You must uncomment
|
||||
this line for the script to work:
|
||||
```
|
||||
vi /usr/local/bin/powermon-snmp.py
|
||||
#costPerkWh = 0.15
|
||||
```
|
||||
|
||||
4. Choose you method below:
|
||||
|
||||
=== "Method 1: sensors"
|
||||
|
||||
* Install dependencies:
|
||||
```
|
||||
dnf install lm_sensors
|
||||
pip install PySensors
|
||||
```
|
||||
|
||||
* Test the script from the command-line. For example:
|
||||
```
|
||||
$ /usr/local/bin/powermon-snmp.py -m sensors -n -p
|
||||
{
|
||||
"meter": {
|
||||
"0": {
|
||||
"reading": 0.0
|
||||
}
|
||||
},
|
||||
"psu": {},
|
||||
"supply": {
|
||||
"rate": 0.15
|
||||
},
|
||||
"reading": "0.0"
|
||||
}
|
||||
```
|
||||
|
||||
If you see a reading of `0.0` it is likely this method is not supported for
|
||||
your system. If not, continue.
|
||||
|
||||
=== "Method 2: hpasmcli"
|
||||
|
||||
* Obtain the hp-health package for your system. Generally there are
|
||||
three options:
|
||||
* Standalone package from [HPE Support](https://support.hpe.com/hpsc/swd/public/detail?swItemId=MTX-c0104db95f574ae6be873e2064#tab2)
|
||||
* From the HP Management Component Pack (MCP).
|
||||
* Included in the [HP Service Pack for Proliant (SPP)](https://support.hpe.com/hpesc/public/docDisplay?docId=emr_na-a00026884en_us)
|
||||
|
||||
* If you've downloaded the standalone package, install it. For example:
|
||||
```
|
||||
rpm -ivh hp-health-10.91-1878.11.rhel8.x86_64.rpm
|
||||
```
|
||||
|
||||
* Check the service is running:
|
||||
```
|
||||
systemctl status hp-health
|
||||
```
|
||||
|
||||
* Test the script from the command-line. For example:
|
||||
```
|
||||
$ /usr/local/bin/powermon-snmp.py -m hpasmcli -n -p
|
||||
{
|
||||
"meter": {
|
||||
"1": {
|
||||
"reading": 338.0
|
||||
}
|
||||
},
|
||||
"psu": {
|
||||
"1": {
|
||||
"present": "Yes",
|
||||
"redundant": "No",
|
||||
"condition": "Ok",
|
||||
"hotplug": "Supported",
|
||||
"reading": 315.0
|
||||
},
|
||||
"2": {
|
||||
"present": "Yes",
|
||||
"redundant": "No",
|
||||
"condition": "FAILED",
|
||||
"hotplug": "Supported"
|
||||
}
|
||||
},
|
||||
"supply": {
|
||||
"rate": 0.224931
|
||||
},
|
||||
"reading": 338.0
|
||||
}
|
||||
```
|
||||
|
||||
If you see a reading of `0.0` it is likely this method is not supported for
|
||||
your system. If not, continue.
|
||||
|
||||
### Finishing Up
|
||||
|
||||
5. Edit your snmpd.conf file (usually `/etc/snmp/snmpd.conf`) and add the following:
|
||||
```
|
||||
extend powermon /usr/local/bin/powermon-snmp.py -m hpasmcli
|
||||
```
|
||||
|
||||
> NOTE: Avoid using other script options in the snmpd config as the results may not be
|
||||
> interpreted correctly by LibreNMS.
|
||||
|
||||
6. Reload your snmpd service:
|
||||
```
|
||||
systemctl reload snmpd
|
||||
```
|
||||
|
||||
7. You're now ready to enable the application in LibreNMS.
|
||||
|
||||
|
||||
# Proxmox
|
||||
|
||||
1: For Proxmox 4.4+ install the libpve-apiclient-perl package `apt
|
||||
|
||||
BIN
doc/img/example-app-powermon-consumption-02.png
Executable file
BIN
doc/img/example-app-powermon-consumption-02.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
176
includes/html/graphs/application/powermon_consumption.inc.php
Normal file
176
includes/html/graphs/application/powermon_consumption.inc.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
LibreNMS Application for monitoring power consumption
|
||||
|
||||
@link https://www.upaya.net.au/
|
||||
@copyright 2021 Ben Carbery
|
||||
@author Ben Carbery <yrebrac@upaya.net.au>
|
||||
|
||||
LICENSE - GPLv3
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 3. See https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
Displays the crrent watts being consumed by a host and uses that data series
|
||||
to estimate total power consumption in kWh over the graph. Finally, displays
|
||||
the cost of the kWh consumed based on the cost defined below.
|
||||
|
||||
Watts (power) is an instantaneous value. Hence this graph will be more accurate
|
||||
when these is a fairly consistent load on the server between polling cycles.
|
||||
|
||||
Watts is easily converted to kilowatt hours which most electricity providers
|
||||
will charge in terms of. The graph will display the total kWh hours consumed at
|
||||
the bottom. You can update the default cost_per_kWh below and currency symbol
|
||||
below under LOCAL OPTIONS
|
||||
|
||||
*/
|
||||
|
||||
$name = 'powermon';
|
||||
$app_id = $app['app_id'];
|
||||
|
||||
$rrd_filename = rrd_name($device['hostname'], ['app', $name, $app_id]);
|
||||
|
||||
$ds_list[0]['vname'] = 'watts';
|
||||
$ds_list[0]['ds'] = 'watts-gauge';
|
||||
$ds_list[0]['filename'] = $rrd_filename;
|
||||
$ds_list[0]['descr'] = 'Average Power';
|
||||
$ds_list[0]['units_text'] = ' W';
|
||||
$ds_list[0]['colour'] = 'FF6600'; // orange
|
||||
$ds_list[0]['colour'] = 'F9F900'; // yellow
|
||||
$ds_list[0]['areacolour'] = 'FAFAB2'; // yellow
|
||||
|
||||
$ds_list[1]['vname'] = 'rate';
|
||||
$ds_list[1]['ds'] = 'rate';
|
||||
$ds_list[1]['filename'] = $rrd_filename;
|
||||
$ds_list[1]['descr'] = ' Total Cost';
|
||||
$ds_list[1]['units_text'] = '$';
|
||||
$ds_list[1]['colour'] = '006600'; // money green
|
||||
|
||||
if ($_GET['debug']) {
|
||||
print_r($ds_list);
|
||||
}
|
||||
|
||||
// COMMON OPTIONS
|
||||
|
||||
//$from = ;
|
||||
//$to = ;
|
||||
//$width = 200;
|
||||
//$height = 100;
|
||||
//$inverse = false;
|
||||
//$nototal = true;
|
||||
//$nodetails = false;
|
||||
//$noagg = true;
|
||||
//$title = '';
|
||||
$scale_min = 0;
|
||||
//$scale_max = 0;
|
||||
//$scale_rigid = anything;
|
||||
//$norigid = false;
|
||||
$float_precision = 0;
|
||||
|
||||
// LOCAL OPTIONS
|
||||
|
||||
$line_width = 2.5;
|
||||
$pad_to = 18; // padding for left-hand column in legend
|
||||
$currency_symbol = '$'; // update this if required
|
||||
|
||||
require 'includes/html/graphs/common.inc.php';
|
||||
|
||||
//if ($nototal) {
|
||||
// $pad_to += '2';
|
||||
//}
|
||||
|
||||
$rrd_options .= ' COMMENT:\s'; // spacer in legend
|
||||
|
||||
$i = 0;
|
||||
foreach ($ds_list as $ds_item) {
|
||||
$vname = $ds_item['vname'];
|
||||
$ds = $ds_item['ds'];
|
||||
$filename = $ds_item['filename'];
|
||||
$descr = rrdtool_escape($ds_item['descr'], $pad_to);
|
||||
|
||||
// CF to use
|
||||
$use_cf_last = ['nothing', 'nothing'];
|
||||
|
||||
if (in_array($vname, $use_cf_last)) {
|
||||
$cf = 'LAST';
|
||||
} else {
|
||||
$cf = 'AVERAGE';
|
||||
}
|
||||
|
||||
$rrd_options .= ' DEF:' . "$vname=$filename:$ds:" . $cf;
|
||||
|
||||
// Units
|
||||
if (isset($ds_item['units_text'])) {
|
||||
$units_text = $ds_item['units_text'];
|
||||
} else {
|
||||
$units_text = '';
|
||||
}
|
||||
|
||||
// Line Width
|
||||
if (isset($ds_item['line_width'])) {
|
||||
$ds_line_width = $ds_item['line_width'];
|
||||
} else {
|
||||
$ds_line_wdith = $line_width;
|
||||
}
|
||||
|
||||
// Line Colour
|
||||
if (isset($ds_item['colour'])) {
|
||||
$colour = $ds_item['colour'];
|
||||
} else {
|
||||
if (! \LibreNMS\Config::get("graph_colours.$colours.$i")) {
|
||||
$i = 0;
|
||||
}
|
||||
$colour = \LibreNMS\Config::get("graph_colours.$colours.$i");
|
||||
$i++;
|
||||
}
|
||||
|
||||
// Area Colour
|
||||
if (isset($ds_item['areacolour'])) {
|
||||
$areacolour = $ds_item['areacolour'];
|
||||
} else {
|
||||
$areacolour = $colour . '20';
|
||||
}
|
||||
|
||||
// Graph command
|
||||
|
||||
if ($vname == 'watts') {
|
||||
$rrd_options .= ' AREA:' . $vname . '#' . $areacolour;
|
||||
$rrd_options .= " LINE{$ds_line_width}:{$vname}#{$colour}:'{$descr}'";
|
||||
$rrd_options .= " GPRINT:{$vname}:AVERAGE:%12.{$float_precision}lf'{$units_text}'\l";
|
||||
|
||||
$rrd_options .= ' COMMENT:\s'; // spacer in legend
|
||||
/*
|
||||
// Watt Seconds
|
||||
$descr = ' Total Consumed';
|
||||
$units_text = ' Ws';
|
||||
$descr = rrdtool_escape($descr, $pad_to + 2);
|
||||
$rrd_options .= " COMMENT:'{$descr}'";
|
||||
$rrd_options .= ' VDEF:wattsecs=watts,TOTAL';
|
||||
$rrd_options .= " GPRINT:wattsecs:%12.{$float_precision}lf'{$units_text}'\l";
|
||||
*/
|
||||
// Kilowatt Hours
|
||||
$units_text = ' kWh';
|
||||
$float_precision = 2;
|
||||
$descr = ' Total Consumed';
|
||||
$descr = rrdtool_escape($descr, $pad_to + 2);
|
||||
$rrd_options .= " COMMENT:'{$descr}'";
|
||||
$rrd_options .= ' CDEF:series_a=watts,3600000,/';
|
||||
$rrd_options .= ' VDEF:kilowatthours=series_a,TOTAL';
|
||||
$rrd_options .= " GPRINT:kilowatthours:%12.{$float_precision}lf'{$units_text}'\l";
|
||||
} elseif ($vname == 'rate') {
|
||||
// Consumption Charge
|
||||
$float_precision = 2;
|
||||
$descr = rrdtool_escape($descr, $pad_to + 7);
|
||||
$rrd_options .= " COMMENT:'{$descr}{$currency_symbol}'";
|
||||
$rrd_options .= " CDEF:series_b=watts,{$vname},*,3600000,/";
|
||||
$rrd_options .= ' VDEF:total_cost=series_b,TOTAL';
|
||||
$rrd_options .= " GPRINT:total_cost:%6.{$float_precision}lf' @ average rate of'";
|
||||
$rrd_options .= ' VDEF:average_rate=rate,AVERAGE';
|
||||
$rrd_options .= " GPRINT:average_rate:%0.6lf' per kWh\l'";
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,9 @@ $graphs['powerdns-recursor'] = [
|
||||
'cache_performance',
|
||||
'outqueries',
|
||||
];
|
||||
$graphs['powermon'] = [
|
||||
'consumption',
|
||||
];
|
||||
$graphs['pureftpd'] = [
|
||||
'bitrate',
|
||||
'connections',
|
||||
|
||||
41
includes/html/pages/device/apps/powermon.inc.php
Normal file
41
includes/html/pages/device/apps/powermon.inc.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
LibreNMS Application for monitoring power consumption and cost
|
||||
|
||||
@link https://www.upaya.net.au/
|
||||
@copyright 2021 Ben Carbery
|
||||
@author Ben Carbery <yrebrac@upaya.net.au>
|
||||
|
||||
LICENSE - GPLv3
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 3. See https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
|
||||
*/
|
||||
|
||||
$graphs = [
|
||||
'powermon_consumption' => 'PowerMon - Consumption',
|
||||
];
|
||||
|
||||
foreach ($graphs as $key => $text) {
|
||||
$graph_type = $key;
|
||||
$graph_array['height'] = '100';
|
||||
$graph_array['width'] = '215';
|
||||
$graph_array['to'] = \LibreNMS\Config::get('time.now');
|
||||
$graph_array['id'] = $app['app_id'];
|
||||
$graph_array['type'] = 'application_' . $key;
|
||||
|
||||
echo '<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">' . $text . '</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">';
|
||||
include 'includes/html/print-graphrow.inc.php';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
61
includes/polling/applications/powermon.inc.php
Normal file
61
includes/polling/applications/powermon.inc.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
|
||||
LibreNMS Application for monitoring power consumption and cost
|
||||
|
||||
@link https://www.upaya.net.au/
|
||||
@copyright 2021 Ben Carbery
|
||||
@author Ben Carbery <yrebrac@upaya.net.au>
|
||||
|
||||
LICENSE - GPLv3
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 3. See https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
|
||||
*/
|
||||
|
||||
use LibreNMS\Exceptions\JsonAppException;
|
||||
use LibreNMS\RRD\RrdDefinition;
|
||||
|
||||
$name = 'powermon';
|
||||
$app_id = $app['app_id'];
|
||||
|
||||
echo $name;
|
||||
|
||||
try {
|
||||
$result = json_app_get($device, $name);
|
||||
} catch (JsonAppException $e) {
|
||||
echo PHP_EOL . $name . ':' . $e->getCode() . ':' . $e->getMessage() . PHP_EOL;
|
||||
update_application($app, $e->getCode() . ':' . $e->getMessage(), []);
|
||||
// Set empty metrics and error message
|
||||
log_event('application ' . $name . ' caught JsonAppException');
|
||||
|
||||
return;
|
||||
}
|
||||
// should be doing something with error codes/messages returned in the snmp
|
||||
// result or will they be caught above?
|
||||
|
||||
$rrd_name = ['app', $name, $app_id];
|
||||
$rrd_def = RrdDefinition::make()
|
||||
->addDataset('watts-gauge', 'GAUGE', 0)
|
||||
->addDataset('watts-abs', 'ABSOLUTE', 0)
|
||||
->addDataset('rate', 'GAUGE', 0);
|
||||
|
||||
$fields = [
|
||||
'watts-gauge' => $result['data']['reading'],
|
||||
'watts-abs' => $result['data']['reading'],
|
||||
'rate' => $result['data']['supply']['rate'],
|
||||
];
|
||||
|
||||
/*
|
||||
log_event(
|
||||
"watts-gauage: " . $result['data']['reading']
|
||||
. ", watts-abs: " . $result['data']['reading']
|
||||
);
|
||||
*/
|
||||
|
||||
$tags = compact('name', 'app_id', 'rrd_name', 'rrd_def');
|
||||
data_update($device, 'app', $tags, $fields);
|
||||
update_application($app, 'OK', $fields);
|
||||
49
tests/data/linux_powermon.json
Normal file
49
tests/data/linux_powermon.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"applications": {
|
||||
"discovery": {
|
||||
"applications": [
|
||||
{
|
||||
"app_type": "powermon",
|
||||
"app_state": "UNKNOWN",
|
||||
"discovered": 1,
|
||||
"app_state_prev": null,
|
||||
"app_status": "",
|
||||
"app_instance": ""
|
||||
}
|
||||
],
|
||||
"application_metrics": []
|
||||
},
|
||||
"poller": {
|
||||
"applications": [
|
||||
{
|
||||
"app_type": "powermon",
|
||||
"app_state": "OK",
|
||||
"discovered": 1,
|
||||
"app_state_prev": "UNKNOWN",
|
||||
"app_status": "",
|
||||
"app_instance": ""
|
||||
}
|
||||
],
|
||||
"application_metrics": [
|
||||
{
|
||||
"metric": "rate",
|
||||
"value": 0.224931,
|
||||
"value_prev": null,
|
||||
"app_type": "powermon"
|
||||
},
|
||||
{
|
||||
"metric": "watts-abs",
|
||||
"value": 340,
|
||||
"value_prev": null,
|
||||
"app_type": "powermon"
|
||||
},
|
||||
{
|
||||
"metric": "watts-gauge",
|
||||
"value": 340,
|
||||
"value_prev": null,
|
||||
"app_type": "powermon"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
1527
tests/snmpsim/linux_powermon.snmprec
Normal file
1527
tests/snmpsim/linux_powermon.snmprec
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user