Hi everyone,
I wanted to create some graphs showing the current power consumption of my OMV server, so that I can monitor it over time.
I could not find many hints on how to approach this matter, so I decided to use a plugin-like approach. I also could not find many best practices for adding custom graphs to the OMV web UI. Have I overlooked an existing plugin? I am fairly new to creating custom plugin-like extensions in OMV, so I am looking for advice and want to share my current work in progress.
Perhaps some of the more experienced members of this forum could advise me on whether this is the best way to tackle my requirement.
I should also mention that I measure the power consumption of my HP ProLiant server via hpasmcli (from hp-health), which gives me the current power consumption in watts for each running PSU. It might also be possible with iLo, but it is currently disabled on my server and I don't know how to configure it.
This is my current approach:
I created a small bash script that extracts the watt values from the hpasmcli -s show powersupply output as a collectd compatible string:
#!/bin/bash
#HOSTNAME=$(hostname)
HOSTNAME="localhost"
PLUGIN="hpasmcli"
PLUGIN_INSTANCE="powersupply"
#timestamp=$(date +%s)
timestamp="N"
interval=60
output=$(sudo hpasmcli -s "show powersupply")
current_id=""
sum=0
watts=0
while IFS= read -r line; do
if [[ $line =~ Power\ supply\ \#([0-9]+) ]]; then
if [[ -n "$current_id" ]]; then
sum=$((sum + watts))
echo "PUTVAL \"$HOSTNAME/$PLUGIN-$PLUGIN_INSTANCE/gauge-power_supply_$current_id\" interval=$interval $timestamp:$watts"
fi
current_id="${BASH_REMATCH[1]}"
watts=0
fi
if [[ $line =~ Power[[:space:]]*:[[:space:]]*([0-9]+)\ Watts ]]; then
watts="${BASH_REMATCH[1]}"
fi
done <<< "$output"
if [[ -n "$current_id" ]]; then
sum=$((sum + watts))
echo "PUTVAL \"$HOSTNAME/$PLUGIN-$PLUGIN_INSTANCE/gauge-power_supply_$current_id\" interval=$interval $timestamp:$watts"
fi
echo "PUTVAL \"$HOSTNAME/$PLUGIN-$PLUGIN_INSTANCE/gauge-power_supply_total\" interval=$interval $timestamp:$sum"
Display More
After that, I added a custom collectd configuration file:
LoadPlugin exec
<Plugin exec>
Exec "adminUser:adminGroup" "/usr/local/bin/hp_powersupply.sh"
#Exec "root" "/usr/local/bin/hp_powersupply.sh"
</Plugin>
In order to run my hp_powersupply.sh script (especially hpasmcli) through collectd, I had to allow adminUser to run hpasmcli without a password prompt. Therefore, I had to create a custom sudoers configuration:
After all this collectd was collecting my current power consumption for each PSU (and for all power supplies together) every minute. The already configured rrdcached daemon created the corresponding RRD files in /var/lib/rrdcached/db/localhost/hpasmcli-powersupply/:
Quote from bash$ ls /var/lib/rrdcached/db/localhost/hpasmcli-powersupply/
gauge-power_supply_1.rrd gauge-power_supply_2.rrd gauge-power_supply_total.rrd
It took quite a while, until the first values were flushed to disk.
I was now ready to create a Python script to render my graphs:
# -*- coding: utf-8 -*-
import openmediavault.mkrrdgraph
class Plugin(openmediavault.mkrrdgraph.IPlugin):
def parse_rrd_start_generic(self, start_str: str) -> int:
units = {
's': 1,
'M': 60,
'h': 3600,
'd': 86400,
'w': 7 * 86400,
'm': 30 * 86400,
'y': 365 * 86400,
}
# Example: '-1d', '+5h', '10m'
num_part = start_str[:-1]
unit = start_str[-1]
num = int(num_part)
if unit not in units:
raise ValueError(f"Unknown time unit: {unit}")
return num * units[unit]
def create_graph(self, config):
# Color codes like in load.py
config.update({
'title_psu': 'Power Supply (Watts)',
'color_psu_1m': '#FFD700', # yellow
'color_psu_5m': '#3399FF', # blue
'color_psu_15m': '#FF3333', # red
})
windows = [
('1m', 60, config['color_psu_1m']),
('5m', 300, config['color_psu_5m']),
('15m', 900, config['color_psu_15m'])
]
longest_window = max(win[1] for win in windows)
def_start_int = self.parse_rrd_start_generic(config['start']) - longest_window
datasets = [
('psu1', 'Power Supply 1', '/var/lib/rrdcached/db/localhost/hpasmcli-powersupply/gauge-power_supply_1.rrd'),
('psu2', 'Power Supply 2', '/var/lib/rrdcached/db/localhost/hpasmcli-powersupply/gauge-power_supply_2.rrd'),
('total', 'Total Power', '/var/lib/rrdcached/db/localhost/hpasmcli-powersupply/gauge-power_supply_total.rrd')
]
for name, label, rrd_file in datasets:
args = []
args.append(f"{config['image_dir']}/powersupply-{name}-{config['period']}.png")
args.extend(config['defaults'])
args.extend(['--start', config['start']])
args.extend(['--title', f'"{label}{config["title_by_period"]}"'])
args.extend(['--vertical-label', 'Watts'])
args.append('--slope-mode')
# Load data starting earlier for TREND calculation
args.append(f'DEF:val={rrd_file}:value:AVERAGE:start={def_start_int}s')
for short, win_seconds, color in windows:
cdef_name = f'sm_{short}'
args.append(f'CDEF:{cdef_name}=val,{win_seconds},TREND')
args.append(f'VDEF:{cdef_name}_min={cdef_name},MINIMUM')
args.append(f'VDEF:{cdef_name}_avg={cdef_name},AVERAGE')
args.append(f'VDEF:{cdef_name}_max={cdef_name},MAXIMUM')
args.append(f'VDEF:{cdef_name}_last={cdef_name},LAST')
for short, _, color in windows:
cdef_name = f'sm_{short}'
args.append(f'LINE1:{cdef_name}{color}:" {short}"')
args.append(f'GPRINT:{cdef_name}_min:"%6.2lf Min"')
args.append(f'GPRINT:{cdef_name}_avg:"%6.2lf Avg"')
args.append(f'GPRINT:{cdef_name}_max:"%6.2lf Max"')
args.append(f'GPRINT:{cdef_name}_last:"%6.2lf Last\\l"')
args.append(f'COMMENT:"{config["last_update"]}"')
openmediavault.mkrrdgraph.call_rrdtool_graph(args)
return 0
Display More
After that, I created my graph page. I decided to use the same location as all the other graphs: Diagnostics/Performance Statistics. I also decided to put each PSU and the total consumption on a separate tab. I therefore created the following YAML files:
version: "1.0"
type: component
data:
name: omv-diagnostics-performance-statistics-powersupply-rrd-page
type: rrdPage
config:
graphs:
- name: "powersupply-total"
label: _("PSU Total")
- name: "powersupply-psu1"
label: _("PSU 1")
- name: "powersupply-psu2"
label: _("PSU 2")
Display More
version: "1.0"
type: navigation-item
data:
path: "diagnostics.performance-statistics.powersupply"
text: _("Powersupply")
icon: "mdi:lightning-bolt"
url: "/diagnostics/performance-statistics/powersupply"
version: "1.0"
type: route
data:
url: "/diagnostics/performance-statistics/powersupply"
title: _("Powersupply")
component: omv-diagnostics-performance-statistics-powersupply-rrd-page
I could see myself developing these power consumption graphs further if someone thinks they might be useful (e.g. currently, they only run on HP servers; I would like to be able to dynamically create tabs for every PSU; create a real plugin and configuration; etc.). However, I would need help with this, as I am new to OMV plugin and Debian package creation.
I would be very grateful for any feedback. Maybe my approach is too over-engineered?
Regards