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
101 lines
2.9 KiB
Go
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")
|
|
}
|