Add shared_names config and port uptime tracking
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,3 +5,4 @@ log
|
|||||||
*~
|
*~
|
||||||
cert.pem
|
cert.pem
|
||||||
key.pem
|
key.pem
|
||||||
|
status
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Locations []*Location `yaml:"locations" json:"locations"`
|
Locations []*Location `yaml:"locations" json:"locations"`
|
||||||
|
SharedNames []string `yaml:"shared_names,omitempty" json:"shared_names,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Location struct {
|
type Location struct {
|
||||||
|
|||||||
15
nodes.go
15
nodes.go
@@ -113,6 +113,9 @@ func (n *Nodes) findOrMergeByName(target *Node, nodeName string) *Node {
|
|||||||
if nodeName == "" {
|
if nodeName == "" {
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
if n.isSharedName(nodeName) {
|
||||||
|
return target
|
||||||
|
}
|
||||||
found := n.nameIndex[nodeName]
|
found := n.nameIndex[nodeName]
|
||||||
if found == nil {
|
if found == nil {
|
||||||
return target
|
return target
|
||||||
@@ -126,6 +129,18 @@ func (n *Nodes) findOrMergeByName(target *Node, nodeName string) *Node {
|
|||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *Nodes) isSharedName(name string) bool {
|
||||||
|
if n.t.config == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, shared := range n.t.config.SharedNames {
|
||||||
|
if shared == name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (n *Nodes) createNode() *Node {
|
func (n *Nodes) createNode() *Node {
|
||||||
node := &Node{
|
node := &Node{
|
||||||
ID: newID("node"),
|
ID: newID("node"),
|
||||||
|
|||||||
38
snmp.go
38
snmp.go
@@ -73,10 +73,14 @@ func snmpToInt(val interface{}) (int, bool) {
|
|||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
case int:
|
case int:
|
||||||
return v, true
|
return v, true
|
||||||
case uint:
|
case int32:
|
||||||
return int(v), true
|
return int(v), true
|
||||||
case int64:
|
case int64:
|
||||||
return int(v), true
|
return int(v), true
|
||||||
|
case uint:
|
||||||
|
return int(v), true
|
||||||
|
case uint32:
|
||||||
|
return int(v), true
|
||||||
case uint64:
|
case uint64:
|
||||||
return int(v), true
|
return int(v), true
|
||||||
default:
|
default:
|
||||||
@@ -126,12 +130,33 @@ func (t *Tendrils) querySNMPDevice(node *Node, ip net.IP) {
|
|||||||
|
|
||||||
t.querySysName(snmp, node)
|
t.querySysName(snmp, node)
|
||||||
t.queryInterfaceMACs(snmp, node, ifNames)
|
t.queryInterfaceMACs(snmp, node, ifNames)
|
||||||
t.queryInterfaceStats(snmp, node, ifNames)
|
sysUpTime := t.getSysUpTime(snmp)
|
||||||
|
t.queryInterfaceStats(snmp, node, ifNames, sysUpTime)
|
||||||
t.queryPoEBudget(snmp, node)
|
t.queryPoEBudget(snmp, node)
|
||||||
t.queryBridgeMIB(snmp, node, ifNames)
|
t.queryBridgeMIB(snmp, node, ifNames)
|
||||||
t.queryDHCPBindings(snmp)
|
t.queryDHCPBindings(snmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tendrils) getSysUpTime(snmp *gosnmp.GoSNMP) uint64 {
|
||||||
|
oid := "1.3.6.1.2.1.1.3.0"
|
||||||
|
|
||||||
|
result, err := snmp.Get([]string{oid})
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(result.Variables) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
v, ok := snmpToInt(result.Variables[0].Value)
|
||||||
|
if !ok {
|
||||||
|
log.Printf("[ERROR] failed to parse sysUpTime: type=%T value=%v", result.Variables[0].Value, result.Variables[0].Value)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uint64(v)
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tendrils) querySysName(snmp *gosnmp.GoSNMP, node *Node) {
|
func (t *Tendrils) querySysName(snmp *gosnmp.GoSNMP, node *Node) {
|
||||||
oid := "1.3.6.1.2.1.1.5.0"
|
oid := "1.3.6.1.2.1.1.5.0"
|
||||||
|
|
||||||
@@ -195,8 +220,9 @@ func (t *Tendrils) queryInterfaceMACs(snmp *gosnmp.GoSNMP, node *Node, ifNames m
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) queryInterfaceStats(snmp *gosnmp.GoSNMP, node *Node, ifNames map[int]string) {
|
func (t *Tendrils) queryInterfaceStats(snmp *gosnmp.GoSNMP, node *Node, ifNames map[int]string, sysUpTime uint64) {
|
||||||
ifOperStatus := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.8")
|
ifOperStatus := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.8")
|
||||||
|
ifLastChange := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.9")
|
||||||
ifHighSpeed := t.getInterfaceTable(snmp, "1.3.6.1.2.1.31.1.1.1.15")
|
ifHighSpeed := t.getInterfaceTable(snmp, "1.3.6.1.2.1.31.1.1.1.15")
|
||||||
ifInErrors := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.14")
|
ifInErrors := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.14")
|
||||||
ifOutErrors := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.20")
|
ifOutErrors := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.20")
|
||||||
@@ -236,6 +262,12 @@ func (t *Tendrils) queryInterfaceStats(snmp *gosnmp.GoSNMP, node *Node, ifNames
|
|||||||
stats.Speed = uint64(speed) * 1000000
|
stats.Speed = uint64(speed) * 1000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if lastChange, ok := ifLastChange[ifIndex]; ok && sysUpTime > 0 {
|
||||||
|
if uint64(lastChange) <= sysUpTime {
|
||||||
|
stats.Uptime = (sysUpTime - uint64(lastChange)) / 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if inErr, ok := ifInErrors[ifIndex]; ok {
|
if inErr, ok := ifInErrors[ifIndex]; ok {
|
||||||
stats.InErrors = uint64(inErr)
|
stats.InErrors = uint64(inErr)
|
||||||
}
|
}
|
||||||
|
|||||||
3
types.go
3
types.go
@@ -384,6 +384,7 @@ func (i *Interface) MarshalJSON() ([]byte, error) {
|
|||||||
|
|
||||||
type InterfaceStats struct {
|
type InterfaceStats struct {
|
||||||
Speed uint64 `json:"speed,omitempty"`
|
Speed uint64 `json:"speed,omitempty"`
|
||||||
|
Uptime uint64 `json:"uptime,omitempty"`
|
||||||
InErrors uint64 `json:"in_errors,omitempty"`
|
InErrors uint64 `json:"in_errors,omitempty"`
|
||||||
OutErrors uint64 `json:"out_errors,omitempty"`
|
OutErrors uint64 `json:"out_errors,omitempty"`
|
||||||
InPktsRate float64 `json:"in_pkts_rate,omitempty"`
|
InPktsRate float64 `json:"in_pkts_rate,omitempty"`
|
||||||
@@ -400,6 +401,7 @@ func round2(v float64) float64 {
|
|||||||
func (s *InterfaceStats) MarshalJSON() ([]byte, error) {
|
func (s *InterfaceStats) MarshalJSON() ([]byte, error) {
|
||||||
type statsJSON struct {
|
type statsJSON struct {
|
||||||
Speed uint64 `json:"speed,omitempty"`
|
Speed uint64 `json:"speed,omitempty"`
|
||||||
|
Uptime uint64 `json:"uptime,omitempty"`
|
||||||
InErrors uint64 `json:"in_errors,omitempty"`
|
InErrors uint64 `json:"in_errors,omitempty"`
|
||||||
OutErrors uint64 `json:"out_errors,omitempty"`
|
OutErrors uint64 `json:"out_errors,omitempty"`
|
||||||
InPktsRate float64 `json:"in_pkts_rate,omitempty"`
|
InPktsRate float64 `json:"in_pkts_rate,omitempty"`
|
||||||
@@ -410,6 +412,7 @@ func (s *InterfaceStats) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return json.Marshal(statsJSON{
|
return json.Marshal(statsJSON{
|
||||||
Speed: s.Speed,
|
Speed: s.Speed,
|
||||||
|
Uptime: s.Uptime,
|
||||||
InErrors: s.InErrors,
|
InErrors: s.InErrors,
|
||||||
OutErrors: s.OutErrors,
|
OutErrors: s.OutErrors,
|
||||||
InPktsRate: round2(s.InPktsRate),
|
InPktsRate: round2(s.InPktsRate),
|
||||||
|
|||||||
Reference in New Issue
Block a user