Skip to content

Instantly share code, notes, and snippets.

@marshallmassengill
Last active June 24, 2026 15:34
Show Gist options
  • Select an option

  • Save marshallmassengill/6b4c6dcbac33afb63159c00afb0b9600 to your computer and use it in GitHub Desktop.

Select an option

Save marshallmassengill/6b4c6dcbac33afb63159c00afb0b9600 to your computer and use it in GitHub Desktop.
OpenNMS + Prometheus: VMware CPU Readiness (% per vCPU) Grafana dashboard. CpuRdinessAvg is in hundredths of a percent, so queries divide by 100.

VMware CPU Readiness — OpenNMS / Meridian threshold + graph package

Companion to the Grafana dashboard in this gist. Collects and alerts on VMware CPU Readiness (the percentage form of CPU Ready) per vCPU.

The one thing that bites everyone: units

CpuRdinessAvg is collected in hundredths of a percent (VMware's convention for percentage perf counters, same as cpu.usage). Validated on a live lab against the summation counter: CpuRdinessAvg / 100 == CpuRdySum / 20000 * 100.

You want Raw value to use
5% per vCPU 500
10% per vCPU 1000

So thresholds use 500 / 1000, and any graph divides by 100.

Reference thresholds (per vCPU)

  • < 5% healthy · 5–10% investigate (warning) · > 10% contention (critical)
  • Tiers are per vCPU. A 4-vCPU VM at "10% aggregate" is only 2.5% per vCPU.

Files

File Goes in Purpose
vmware-cpu-readiness-thresholds.xml merge <group> into etc/thresholds.xml the two high thresholds (5% / 10%)
vmware-cpu-readiness-thresd-configuration.xml merge <package> into etc/thresd-configuration.xml wires the group to the VMware-VirtualMachine service
vmware-cpu-readiness.events.xml etc/events/ + reference in etc/eventconf.xml gives the custom UEIs proper severity + auto-clearing alarms
vmware-readiness-percent.properties etc/snmp-graph.properties.d/ OpenNMS resource graph in true % (CDEF /100)

ds-type is vmware7Cpu (this lab's vCenter API generation). Change to vmware6Cpu / vmware8Cpu to match the resource type your environment actually produces — check a VM's resource IDs first.

Apply (pristine default assumed)

  1. Merge the <group> and <package> snippets into the respective files.
  2. Copy vmware-cpu-readiness.events.xml to etc/events/ and add <event-file>events/vmware-cpu-readiness.events.xml</event-file> to eventconf.xml.
  3. Drop vmware-readiness-percent.properties into etc/snmp-graph.properties.d/.
  4. Reload the daemons (no restart needed):
/opt/opennms/bin/send-event.pl uei.opennms.org/internal/reloadDaemonConfig --parm 'daemonName Eventd'
/opt/opennms/bin/send-event.pl uei.opennms.org/internal/reloadDaemonConfig --parm 'daemonName Threshd'
/opt/opennms/bin/send-event.pl uei.opennms.org/internal/reloadDaemonConfig --parm 'daemonName Collectd'

thresholding-enabled=true is already set on the VMware services in collectd-configuration.xml, so no change is needed there.

Tuning notes

  • trigger="3" at the 300s collection interval = the value must stay high for ~15 minutes before firing. Lower to 1 for immediate alerts (noisier), raise for longer sustain.
  • rearm sits one tier below value (4% / 8%) to avoid flapping.
  • Each sample is a single 20-second realtime window sampled every 5 minutes, so very brief sub-minute spikes between samples won't be seen — fine for sustained contention, not for catching micro-bursts.

Assisted by Anthropic Claude Opus 4.8

<!--
Merge this <package> into /opt/opennms/etc/thresd-configuration.xml,
inside the root <thresd-configuration> element (a pristine default ships this file).
A DEDICATED package is used on purpose: threshold groups are additive across
matching packages, so this applies the new group to VMware VMs without touching
or conflicting with the default package's existing service->group mappings.
The service name + interval must match the collectd-configuration.xml service
(VMware-VirtualMachine @ 300000ms in this lab).
-->
<package name="vmware-cpu-readiness">
<filter>IPADDR != '0.0.0.0'</filter>
<service name="VMware-VirtualMachine" interval="300000" user-defined="false" status="on">
<parameter key="thresholding-group" value="vmware-cpu-readiness"/>
</service>
</package>
<!--
Merge this <group> into /opt/opennms/etc/thresholds.xml, inside <thresholding-config>.
UNIT GOTCHA: CpuRdinessAvg is collected in HUNDREDTHS OF A PERCENT.
raw 500 = 5% (investigate / warning)
raw 1000 = 10% (contention / critical)
Do NOT use 5 / 10 here.
ds-type "vmware7Cpu" => evaluated PER vCPU instance, which matches the
per-vCPU guideline. Change to vmware6Cpu / vmware8Cpu to match the resource
type produced by your vCenter's API version (this lab is vmware7Cpu).
trigger="3" at a 300s (5 min) collection interval = sustained ~15 min before
it fires, so brief one-sample spikes are ignored.
-->
<group name="vmware-cpu-readiness" rrdRepository="/opt/opennms/share/rrd/snmp/">
<threshold type="high" ds-type="vmware7Cpu" ds-name="CpuRdinessAvg"
ds-label="vmware7CpuName"
value="1000.0" rearm="800.0" trigger="3"
triggeredUEI="uei.opennms.org/threshold/vmwareCpuReadinessCritExceeded"
rearmedUEI="uei.opennms.org/threshold/vmwareCpuReadinessCritRearmed"
description="VMware CPU Readiness >= 10% per vCPU sustained ~15m (critical)"/>
<threshold type="high" ds-type="vmware7Cpu" ds-name="CpuRdinessAvg"
ds-label="vmware7CpuName"
value="500.0" rearm="400.0" trigger="3"
triggeredUEI="uei.opennms.org/threshold/vmwareCpuReadinessWarnExceeded"
rearmedUEI="uei.opennms.org/threshold/vmwareCpuReadinessWarnRearmed"
description="VMware CPU Readiness >= 5% per vCPU sustained ~15m (warning)"/>
</group>
<!--
Event definitions for the custom threshold UEIs referenced by
vmware-cpu-readiness-thresholds.xml. Without these, the custom UEIs still fire
but render with default/Indeterminate styling and won't carry sensible severity.
Install: place at /opt/opennms/etc/events/vmware-cpu-readiness.events.xml and add
<event-file>events/vmware-cpu-readiness.events.xml</event-file>
to /opt/opennms/etc/eventconf.xml (near the other custom/threshold entries),
then reload Eventd (see README).
The rearmed events clear their matching exceeded alarm via clear-key (alarm-type 2).
Threshold events expose parms: label (instance), value, threshold, trigger, rearm, ds.
-->
<events xmlns="http://xmlns.opennms.org/xsd/eventconf">
<event>
<uei>uei.opennms.org/threshold/vmwareCpuReadinessWarnExceeded</uei>
<event-label>VMware CPU Readiness high (warning, &gt;= 5% per vCPU)</event-label>
<descr>VMware CPU Readiness on vCPU instance %parm[label]% reached raw value
%parm[value]% (&gt;= 500 = 5% per vCPU) on node %nodelabel%.</descr>
<logmsg dest="logndisplay">VMware CPU Readiness WARNING on %nodelabel% vCPU %parm[label]% (raw %parm[value]%)</logmsg>
<severity>Warning</severity>
<alarm-data reduction-key="%uei%:%nodeid%:%parm[label]%" alarm-type="1" auto-clean="false"/>
</event>
<event>
<uei>uei.opennms.org/threshold/vmwareCpuReadinessWarnRearmed</uei>
<event-label>VMware CPU Readiness warning rearmed</event-label>
<descr>VMware CPU Readiness on vCPU instance %parm[label]% on node %nodelabel%
dropped back below the 5% per-vCPU warning level.</descr>
<logmsg dest="logndisplay">VMware CPU Readiness warning REARMED on %nodelabel% vCPU %parm[label]%</logmsg>
<severity>Normal</severity>
<alarm-data reduction-key="%uei%:%nodeid%:%parm[label]%" alarm-type="2"
clear-key="uei.opennms.org/threshold/vmwareCpuReadinessWarnExceeded:%nodeid%:%parm[label]%"
auto-clean="false"/>
</event>
<event>
<uei>uei.opennms.org/threshold/vmwareCpuReadinessCritExceeded</uei>
<event-label>VMware CPU Readiness high (critical, &gt;= 10% per vCPU)</event-label>
<descr>VMware CPU Readiness on vCPU instance %parm[label]% reached raw value
%parm[value]% (&gt;= 1000 = 10% per vCPU) on node %nodelabel%.</descr>
<logmsg dest="logndisplay">VMware CPU Readiness CRITICAL on %nodelabel% vCPU %parm[label]% (raw %parm[value]%)</logmsg>
<severity>Major</severity>
<alarm-data reduction-key="%uei%:%nodeid%:%parm[label]%" alarm-type="1" auto-clean="false"/>
</event>
<event>
<uei>uei.opennms.org/threshold/vmwareCpuReadinessCritRearmed</uei>
<event-label>VMware CPU Readiness critical rearmed</event-label>
<descr>VMware CPU Readiness on vCPU instance %parm[label]% on node %nodelabel%
dropped back below the 10% per-vCPU critical level.</descr>
<logmsg dest="logndisplay">VMware CPU Readiness critical REARMED on %nodelabel% vCPU %parm[label]%</logmsg>
<severity>Normal</severity>
<alarm-data reduction-key="%uei%:%nodeid%:%parm[label]%" alarm-type="2"
clear-key="uei.opennms.org/threshold/vmwareCpuReadinessCritExceeded:%nodeid%:%parm[label]%"
auto-clean="false"/>
</event>
</events>
{
"title": "VMware CPU Readiness (% per vCPU)",
"uid": "vmware-cpu-readiness",
"tags": ["vmware", "cpu-ready", "opennms"],
"timezone": "browser",
"schemaVersion": 39,
"__comment": "CpuRdinessAvg is in hundredths of a percent -> divide by 100 for true %. Prometheus datasource via OpenNMS Cortex plugin. Adjust datasource uid on import.",
"templating": {
"list": [
{
"name": "ds",
"type": "datasource",
"query": "prometheus",
"label": "Datasource"
}
]
},
"panels": [
{
"title": "Per-VM readiness % (worst vCPU) — top 10",
"type": "timeseries",
"datasource": { "type": "prometheus", "uid": "${ds}" },
"gridPos": { "h": 10, "w": 24, "x": 0, "y": 0 },
"fieldConfig": { "defaults": { "unit": "percent", "custom": { "drawStyle": "line", "fillOpacity": 10 } } },
"options": { "legend": { "displayMode": "list", "placement": "bottom" } },
"targets": [
{
"expr": "topk(10, max by (node) (CpuRdinessAvg{resourceId=~\".+/vmware7Cpu/.+\"} / 100))",
"legendFormat": "{{node}}"
}
]
},
{
"title": "Per-VM worst vCPU (current)",
"type": "bargauge",
"datasource": { "type": "prometheus", "uid": "${ds}" },
"gridPos": { "h": 12, "w": 12, "x": 0, "y": 10 },
"fieldConfig": {
"defaults": {
"unit": "percent",
"thresholds": { "mode": "absolute", "steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 5 },
{ "color": "red", "value": 10 }
] }
}
},
"options": { "orientation": "horizontal", "displayMode": "gradient" },
"targets": [
{
"expr": "max by (node, foreignSource) (CpuRdinessAvg{resourceId=~\".+/vmware7Cpu/.+\"} / 100)",
"legendFormat": "{{node}}",
"instant": true
}
]
},
{
"title": "Per-VM 24h peak vCPU readiness %",
"type": "bargauge",
"datasource": { "type": "prometheus", "uid": "${ds}" },
"gridPos": { "h": 12, "w": 12, "x": 12, "y": 10 },
"fieldConfig": {
"defaults": {
"unit": "percent",
"thresholds": { "mode": "absolute", "steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 5 },
{ "color": "red", "value": 10 }
] }
}
},
"options": { "orientation": "horizontal", "displayMode": "gradient" },
"targets": [
{
"expr": "max by (node, foreignSource) (max_over_time(CpuRdinessAvg{resourceId=~\".+/vmware7Cpu/.+\"}[24h])) / 100",
"legendFormat": "{{node}}",
"instant": true
}
]
},
{
"title": "Per-VM CPU co-stop % (worst vCPU) — top 10",
"description": "Time a VM's vCPUs were stopped to let lagging siblings catch up. High co-stop = too many vCPUs for how the host can schedule the VM. CpuCostopSum is ms over a 20s window -> /20000*100. (Distinct from CpuRdinessAvg, which is /100.)",
"type": "timeseries",
"datasource": { "type": "prometheus", "uid": "${ds}" },
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 22 },
"fieldConfig": {
"defaults": {
"unit": "percent",
"custom": { "drawStyle": "line", "fillOpacity": 10 },
"thresholds": { "mode": "absolute", "steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 3 },
{ "color": "red", "value": 10 }
] }
}
},
"options": { "legend": { "displayMode": "list", "placement": "bottom" } },
"targets": [
{
"expr": "topk(10, max by (node) (CpuCostopSum{resourceId=~\".+/vmware7Cpu/.+\"} / 20000 * 100))",
"legendFormat": "{{node}}"
}
]
},
{
"title": "ESXi host readiness % (node aggregate)",
"description": "Host-level CPU readiness. Uses CpuRdinessAvg (already normalized per-pCPU) / 100. Host CpuRdySum is summed across all pCPUs, so it is intentionally NOT used here.",
"type": "timeseries",
"datasource": { "type": "prometheus", "uid": "${ds}" },
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 30 },
"fieldConfig": {
"defaults": {
"unit": "percent",
"custom": { "drawStyle": "line", "fillOpacity": 10 },
"thresholds": { "mode": "absolute", "steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 5 },
{ "color": "red", "value": 10 }
] }
}
},
"options": { "legend": { "displayMode": "list", "placement": "bottom" } },
"targets": [
{
"expr": "CpuRdinessAvg{resourceId=~\".+/host-.+/vmware7Node\"} / 100",
"legendFormat": "{{node}}"
}
]
},
{
"title": "Host 24h peak readiness %",
"type": "bargauge",
"datasource": { "type": "prometheus", "uid": "${ds}" },
"gridPos": { "h": 6, "w": 24, "x": 0, "y": 38 },
"fieldConfig": {
"defaults": {
"unit": "percent",
"thresholds": { "mode": "absolute", "steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 5 },
{ "color": "red", "value": 10 }
] }
}
},
"options": { "orientation": "horizontal", "displayMode": "gradient" },
"targets": [
{
"expr": "max by (node, foreignSource) (max_over_time(CpuRdinessAvg{resourceId=~\".+/host-.+/vmware7Node\"}[24h])) / 100",
"legendFormat": "{{node}}",
"instant": true
}
]
}
]
}
##
## Custom: VMware CPU Readiness expressed as a true percentage (per vCPU).
## CpuRdinessAvg is collected in hundredths of a percent (raw 13 = 0.13%),
## so this report divides by 100 via CDEF. Validated against CpuRdySum/20000*100.
##
reports=vmware7.CpuReadinessPct
report.vmware7.CpuReadinessPct.name=VMware7 CPU Readiness (% per vCPU)
report.vmware7.CpuReadinessPct.columns=CpuRdinessAvg
report.vmware7.CpuReadinessPct.propertiesValues=vmware7CpuName
report.vmware7.CpuReadinessPct.type=vmware7Cpu
report.vmware7.CpuReadinessPct.command=--title="VMware7 CPU Readiness (%% per vCPU) {vmware7CpuName}" \
--vertical-label="readiness %%" \
--lower-limit=0 \
DEF:raw={rrd1}:CpuRdinessAvg:AVERAGE \
CDEF:pct=raw,100,/ \
AREA:pct#3a7bd5:"Readiness %% (per vCPU)" \
LINE1:pct#1f4e9c \
GPRINT:pct:AVERAGE:"Avg \\: %6.3lf%%" \
GPRINT:pct:MIN:"Min \\: %6.3lf%%" \
GPRINT:pct:MAX:"Max \\: %6.3lf%%\\n" \
HRULE:5#ff0000:"5%% per-vCPU investigate guideline"
@marshallmassengill

Copy link
Copy Markdown
Author
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment