Files
nmon/internal/librenms/render.go
jleung 287fbb98bd Maintainability cleanup (core libraries): 223 lint findings to 0, oversized files split; fix apc-ups label columns and never poll text metrics
Migration files restructured with shared helpers; verified byte-identical SQLite schema vs previous commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lx9FNLG2CqeBbVGGd9bFsP
2026-10-22 19:11:15 +00:00

101 lines
2.9 KiB
Go

package librenms
import (
"bytes"
"fmt"
"strconv"
"strings"
)
// render writes the draft profile YAML: header comments, match, then one block per metric.
func (im *Importer) render(d *Draft, m match, metrics []*metric) []byte {
var b bytes.Buffer
w := func(format string, a ...any) { fmt.Fprintf(&b, format, a...) }
im.renderHeader(w, d)
renderMatch(w, m)
if len(d.Skipped) > 0 {
w("# Skipped LibreNMS entries:\n")
for _, s := range d.Skipped {
w("# %s: %s\n", s.Where, oneLine(s.Reason))
}
}
if len(metrics) == 0 {
w("metrics: []\n")
return b.Bytes()
}
w("metrics:\n")
for _, mt := range metrics {
renderMetric(w, mt)
}
return b.Bytes()
}
type writeFunc func(format string, a ...any)
func (im *Importer) renderHeader(w writeFunc, d *Draft) {
w("# DRAFT imported by nmon-librenms-import from the LibreNMS %q definitions. Review before use.\n", d.OS)
w("# Every metric is type: unverified, so the poller never collects it. `nmon profile test` confirms the SNMP type\n")
w("# against a device or fixture; then set the real type (and enum for status) and drop imported: librenms.\n")
w("# interval is a placeholder (5m). Names, OIDs and units come from LibreNMS's published OS definitions; no LibreNMS code is used.\n")
if d.Name != d.OS {
w("# Named %s because a shipped profile is already called %s.\n", d.Name, d.OS)
}
w("# %d metrics mapped (+%d label columns), %d definition entries skipped.\n", d.Mapped, d.Helpers, len(d.Skipped))
w("name: %s\nextends: generic\nprovenance: %s\n", d.Name, strconv.Quote(im.provenance(d.OS)))
}
func renderMatch(w writeFunc, m match) {
if len(m.sysObjectID)+len(m.sysDescr) > 0 {
w("match:\n")
renderList(w, "sysObjectID", m.sysObjectID)
renderList(w, "sysDescr", m.sysDescr)
} else {
w("# no usable match: section could be derived; add one before use.\n")
}
for _, n := range m.notes {
w("# match: %s\n", oneLine(n))
}
}
func renderList(w writeFunc, key string, items []string) {
if len(items) == 0 {
return
}
w(" %s:\n", key)
for _, o := range items {
w(" - %s\n", strconv.Quote(o))
}
}
func renderMetric(w writeFunc, mt *metric) {
w(" # from %s\n", mt.src)
for _, n := range mt.notes {
w(" # %s\n", oneLine(n))
}
w(" - name: %s\n oid: %s\n type: unverified\n unit: %s\n interval: 5m\n", mt.name, mt.oid, mt.unit)
if mt.scale != 0 {
w(" scale: %s\n", fmtNum(mt.scale))
}
if mt.label != nil {
w(" index_label: { column: %s, as: %s }\n", mt.label.column, mt.label.as)
}
if len(mt.notAvail) > 0 {
var xs []string
for _, f := range mt.notAvail {
xs = append(xs, fmtNum(f))
}
w(" not_available: [%s]\n", strings.Join(xs, ", "))
}
if len(mt.states) > 0 {
w(" enum:\n")
seen := map[int]bool{}
for _, s := range mt.states {
if !seen[s.value] {
seen[s.value] = true
w(" %d: %s\n", s.value, strconv.Quote(s.descr))
}
}
}
w(" imported: librenms\n")
}