BusinessService
Describe a Business Service Monitoring (BSM) hierarchy declaratively: a service, its per-service reduce function, optional attributes, and four kinds of edge (to child services, monitored IP services, applications, and raw alarm reduction keys), each with a weight and optional per-edge map function.
Maps to the v2 /api/v2/business-services surface; named and multi-instance (one document per service).
There is no version gate: the API is present in every supported Horizon/Meridian.
YAML
apiVersion: bsm.opennms.org/v1
kind: BusinessService
metadata: { name: web-frontend }
spec:
attributes: { owner: platform-team }
reduceFunction:
type: Threshold # HighestSeverity | Threshold | HighestSeverityAbove | ExponentialPropagation
properties: { threshold: "0.75" }
childServices: # → another BusinessService, by name
- { name: database-tier, weight: 2, mapFunction: { type: Increase } }
ipServices: # → a monitored service; node by label+location
- node: { label: webhost01, location: Default }
ipAddress: 10.0.0.10
service: HTTP
applications: # → an OpenNMS Application, by name
- { name: Webservers }
reductionKeys: # → a raw alarm reduction key (escape hatch)
- reductionKey: "uei.opennms.org/threshold/highThresholdExceeded::{{nodeId}}:10.0.0.10:ifHCInOctets:90.0:3:75.0:Gi1/0/1"
node: { label: webhost01 } # resolves {{nodeId}} at apply
mapFunction: { type: SetTo, properties: { status: Major } }
References are by name (BSM's REST API is ID-centric; onmsctl resolves names to ids at apply, so the same YAML is portable across instances).
Node references. A node is {label, location} (the default location is Default) or {foreignSource, foreignId}.
Labels are not unique in OpenNMS; an ambiguous label fails the apply and tells you to use the foreignSource/foreignId form.
Prefer ipServices over hand-written reduction keys. An ipServices edge auto-covers the service's standard alarms (nodeLostService/interfaceDown/nodeDown), so you never type a node id.
Reach for reductionKeys only for custom alarms (thresholds, custom UEIs, situations); the literal key must match a resolved alarm reduction key (copy it from a real alarm, not the event-def formula), and {{nodeId}} (plus {{foreignSource}}/{{foreignId}}/{{nodeLabel}}) is expanded from the edge's node.
Apply
onmsctl apply -f examples/business-service.yaml --dry-run --diff
Whole-object reconcile. A service is created then fully PUT (a destructive full replace). Edges omitted from a document are pruned; an unchanged service (order-insensitive) is a no-op. Child references are resolved by a two-pass apply (create, then PUT with resolved ids), so two new services can reference each other in one file regardless of order; a child cycle fails at plan time.
Across-apply non-deletion. A service present on the server but absent from your apply is not deleted; use business-service delete <name>.
Daemon reload. Changes are inert until bsmd reloads; a mutating apply (and delete) issues exactly one daemon/reload automatically.
Inspect and delete
onmsctl business-service list # or: onmsctl bs list
onmsctl business-service get web-frontend
onmsctl business-service delete web-frontend # explicit removal
list/get are Read; apply/delete are Write.
Example
# A Business Service exercising all four edge types. References are by name and
# resolved to numeric ids at apply time (BSM's REST API is ID-centric). See
# README "Business services (kind: BusinessService)".
apiVersion: bsm.opennms.org/v1
kind: BusinessService
metadata:
name: web-frontend
spec:
attributes:
owner: platform-team
tier: "1"
# Per-service reduce function: how edge severities aggregate into the
# service's operational status. Exactly one.
reduceFunction:
type: Threshold # HighestSeverity | Threshold | HighestSeverityAbove | ExponentialPropagation
properties:
threshold: "0.75" # fraction in (0,1]
# → another Business Service, by name.
childServices:
- name: database-tier
weight: 2
mapFunction:
type: Increase # Identity | Increase | Decrease | Ignore | SetTo
# → a monitored IP service. The node is resolved by label + location; this
# auto-covers the service's standard alarms (nodeLostService/interfaceDown/
# nodeDown) — no hand-written reduction key needed.
ipServices:
- node:
label: webhost01
location: Default # optional; defaults to "Default"
ipAddress: 10.0.0.10
service: HTTP
friendlyName: web-http
weight: 1
mapFunction:
type: Identity
# → an OpenNMS Application, by name.
applications:
- name: Webservers
weight: 1
# → a raw alarm reduction key (escape hatch for custom alarms). Only {{nodeId}}
# is templated from the node reference; the rest is the threshold's own
# reduction-key signature, typed verbatim.
reductionKeys:
- node:
foreignSource: networking
foreignId: dist-sw-01
reductionKey: "uei.opennms.org/threshold/highThresholdExceeded::{{nodeId}}:10.42.0.130:ifHCInOctets * 8 / 1000000 / ifHighSpeed * 100:90.0:3:75.0:Gi1/0/47"
friendlyName: uplink-saturation
weight: 1
mapFunction:
type: SetTo
properties:
status: Major