Revert "Add missing node tracking for config-defined nodes"

This reverts commit 9ec193ef1d.
This commit is contained in:
Ian Gulliver
2026-01-28 08:42:12 -08:00
parent 9ec193ef1d
commit 85cfa6a9f4
7 changed files with 104 additions and 254 deletions

View File

@@ -2,7 +2,6 @@ package tendrils
import ( import (
"encoding/json" "encoding/json"
"net"
"os" "os"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
@@ -13,54 +12,10 @@ type Config struct {
} }
type Location struct { type Location struct {
Name string `yaml:"name" json:"name"` Name string `yaml:"name" json:"name"`
Direction string `yaml:"direction,omitempty" json:"direction,omitempty"` Direction string `yaml:"direction,omitempty" json:"direction,omitempty"`
Nodes []*NodeRef `yaml:"nodes,omitempty" json:"nodes,omitempty"` Nodes []string `yaml:"nodes,omitempty" json:"nodes,omitempty"`
Children []*Location `yaml:"children,omitempty" json:"children,omitempty"` Children []*Location `yaml:"children,omitempty" json:"children,omitempty"`
}
type NodeRef struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
MAC string `yaml:"mac,omitempty" json:"mac,omitempty"`
IP string `yaml:"ip,omitempty" json:"ip,omitempty"`
}
func (r *NodeRef) DisplayName() string {
if r.Name != "" {
return r.Name
}
if r.MAC != "" {
return r.MAC
}
return r.IP
}
func (r *NodeRef) ParseMAC() net.HardwareAddr {
if r.MAC == "" {
return nil
}
mac, _ := net.ParseMAC(r.MAC)
return mac
}
func (r *NodeRef) ParseIP() net.IP {
if r.IP == "" {
return nil
}
return net.ParseIP(r.IP)
}
func (c *Config) AllNodeRefs() []*NodeRef {
var refs []*NodeRef
var collect func([]*Location)
collect = func(locs []*Location) {
for _, loc := range locs {
refs = append(refs, loc.Nodes...)
collect(loc.Children)
}
}
collect(c.Locations)
return refs
} }
func LoadConfig(path string) (*Config, error) { func LoadConfig(path string) (*Config, error) {

View File

@@ -4,168 +4,168 @@ locations:
children: children:
- name: LIGHTING-2 Rack - name: LIGHTING-2 Rack
nodes: nodes:
- name: lighting-2 - lighting-2
- mac: "48:59:00:41:00:29" # Pixie Driver 8k Port 1 - "48:59:00:41:00:29" # Pixie Driver 8k Port 1
- mac: "48:59:00:28:00:27" # Pixie Driver 8k Port 2 - "48:59:00:28:00:27" # Pixie Driver 8k Port 2
- mac: "48:59:00:43:00:29" # Pixie Driver 8k Port 3 - "48:59:00:43:00:29" # Pixie Driver 8k Port 3
- mac: "48:59:00:42:00:29" # Pixie Driver 8k Port 4 - "48:59:00:42:00:29" # Pixie Driver 8k Port 4
- mac: "48:59:00:3c:00:3e" # Pixie Driver 8k Port 5 - "48:59:00:3c:00:3e" # Pixie Driver 8k Port 5
- mac: "48:59:00:3f:00:3e" # Pixie Driver 8k Port 6 - "48:59:00:3f:00:3e" # Pixie Driver 8k Port 6
- mac: "48:59:00:25:00:3e" # Pixie Driver 8k Port 7 - "48:59:00:25:00:3e" # Pixie Driver 8k Port 7
- mac: "48:59:00:41:00:3e" # Pixie Driver 8k Port 8 - "48:59:00:41:00:3e" # Pixie Driver 8k Port 8
- name: ART9 # Cyc - ART9 # Cyc
- name: ART10 # Cyc - ART10 # Cyc
- name: ART11 # Cyc - ART11 # Cyc
- name: ART12 # Cyc - ART12 # Cyc
- name: ART13 # Cyc - ART13 # Cyc
- name: ART14 # Cyc - ART14 # Cyc
- direction: horizontal - direction: horizontal
children: children:
- nodes: - nodes:
- name: ART16 # R2X1 - ART16 # R2X1
- nodes: - nodes:
- name: ART20 # R2X2 - ART20 # R2X2
- direction: horizontal - direction: horizontal
children: children:
- nodes: - nodes:
- name: MON1-A - "MON1-A"
- name: MON1-B - "MON1-B"
- name: Under Apron - name: Under Apron
direction: horizontal direction: horizontal
children: children:
- name: AUDIO Rack - name: AUDIO Rack
nodes: nodes:
- name: audio - audio
- name: MICS-A - "MICS-A"
- mac: "00:0e:dd:a7:29:93" # MICS-A bridge interface - "00:0e:dd:a7:29:93" # MICS-A bridge interface
- name: MICS-B - "MICS-B"
- mac: "00:0e:dd:a8:3e:b3" # MICS-B bridge interface - "00:0e:dd:a8:3e:b3" # MICS-B bridge interface
- name: MICS-C - "MICS-C"
- mac: "00:0e:dd:a7:6f:55" # MICS-C bridge interface - "00:0e:dd:a7:6f:55" # MICS-C bridge interface
- name: MICS-D - "MICS-D"
- mac: "00:0e:dd:64:3d:51" # MICS-D bridge interface - "00:0e:dd:64:3d:51" # MICS-D bridge interface
- name: MICS-E - "MICS-E"
- mac: "00:0e:dd:ac:fc:7d" # MICS-E bridge interface - "00:0e:dd:ac:fc:7d" # MICS-E bridge interface
- name: LIGHTING-1 Rack - name: LIGHTING-1 Rack
nodes: nodes:
- name: lighting-1 - lighting-1
- mac: "48:59:00:27:00:27" # Pixie Driver 8k Port 1 - "48:59:00:27:00:27" # Pixie Driver 8k Port 1
- mac: "48:59:00:37:00:27" # Pixie Driver 8k Port 2 - "48:59:00:37:00:27" # Pixie Driver 8k Port 2
- mac: "48:59:00:3e:00:27" # Pixie Driver 8k Port 3 - "48:59:00:3e:00:27" # Pixie Driver 8k Port 3
- mac: "48:59:00:3f:00:27" # Pixie Driver 8k Port 4 - "48:59:00:3f:00:27" # Pixie Driver 8k Port 4
- mac: "48:59:00:47:00:1a" # Pixie Driver 8k Port 5 - "48:59:00:47:00:1a" # Pixie Driver 8k Port 5
- mac: "48:59:00:44:00:1a" # Pixie Driver 8k Port 6 - "48:59:00:44:00:1a" # Pixie Driver 8k Port 6
- mac: "48:59:00:42:00:19" # Pixie Driver 8k Port 7 - "48:59:00:42:00:19" # Pixie Driver 8k Port 7
- mac: "48:59:00:44:00:19" # Pixie Driver 8k Port 8 - "48:59:00:44:00:19" # Pixie Driver 8k Port 8
- name: VIDEO Rack - name: VIDEO Rack
nodes: nodes:
- name: video - video
- name: "ATEM 2 M/E Constellation 4K" - "ATEM 2 M/E Constellation 4K"
- name: HyperDeck-Studio-4K-Pro - "HyperDeck-Studio-4K-Pro"
- name: RX-QLAB-1 - RX-QLAB-1
- name: RX-QLAB-2 - RX-QLAB-2
- name: TX-PROJ-1 - TX-PROJ-1
- name: TX-PROJ-2 - TX-PROJ-2
- name: TX-M4 - TX-M4
- name: TX-M16 - TX-M16
- name: TX-MISC - TX-MISC
- name: TX-PREVIEW - TX-PREVIEW
- direction: horizontal - direction: horizontal
children: children:
- nodes: - nodes:
- name: Y001-MAIN1-L-d1e155 - "Y001-MAIN1-L-d1e155"
- mac: "ac:44:f2:4e:84:d6" # MAIN1-L bridge interface - "ac:44:f2:4e:84:d6" # MAIN1-L bridge interface
- name: Stage 2 - name: Stage 2
nodes: nodes:
- name: MON2 - "MON2"
- name: Stage 3 - name: Stage 3
nodes: nodes:
- name: MON3 - "MON3"
- nodes: - nodes:
- name: Y001-MAIN1-R-d1e194 - "Y001-MAIN1-R-d1e194"
- mac: "ac:44:f2:4e:84:d4" # MAIN1-R bridge interface - "ac:44:f2:4e:84:d4" # MAIN1-R bridge interface
- direction: horizontal - direction: horizontal
children: children:
- nodes: - nodes:
- name: RX-PROJ-1 - "RX-PROJ-1"
- nodes: - nodes:
- name: RX-PROJ-2 - "RX-PROJ-2"
- direction: horizontal - direction: horizontal
children: children:
- nodes: - nodes:
- name: satellite-2 - satellite-2
- name: Y001-MAIN2-L-d1e298 - "Y001-MAIN2-L-d1e298"
- mac: "ac:44:f2:4e:87:2a" # MAIN2-L bridge interface - "ac:44:f2:4e:87:2a" # MAIN2-L bridge interface
- name: ART3 # Wash - ART3 # Wash
- name: ART4 # Wash - ART4 # Wash
- name: ART5 # Wash - ART5 # Wash
- name: ART17 # Focus - ART17 # Focus
- nodes: - nodes:
- name: ART15 # R3X - ART15 # R3X
- name: ART18 # Focus - ART18 # Focus
- nodes: - nodes:
- name: satellite-3 - satellite-3
- name: Y001-MAIN2-R-f0dd93 - "Y001-MAIN2-R-f0dd93"
- mac: "ac:44:f2:4e:87:27" # MAIN2-R bridge interface - "ac:44:f2:4e:87:27" # MAIN2-R bridge interface
- name: ART6 # Wash - ART6 # Wash
- name: ART7 # Wash - ART7 # Wash
- name: DMX32 # Wash - DMX8 # Wash
- name: ART19 # Focus - ART19 # Focus
- name: Booth - name: Booth
direction: vertical direction: vertical
children: children:
- nodes: - nodes:
- name: satellite-1 - satellite-1
- direction: horizontal - direction: horizontal
children: children:
- name: Lighting Control - name: Lighting Control
nodes: nodes:
- name: qlab - qlab
- name: TX-QLAB-1 - TX-QLAB-1
- name: TX-QLAB-2 - TX-QLAB-2
- name: "SK_PTZEXTREMEV2 [457081]" - "SK_PTZEXTREMEV2 [457081]"
- name: "SK_RACKPRO2 [452514]" - "SK_RACKPRO2 [452514]"
- name: pigeon - pigeon
- name: showpi1 - showpi1
- mac: "d8:3a:dd:e3:5b:db" # showpi2/artmap - d8:3a:dd:e3:5b:db # showpi2/artmap
- name: Sound Control - name: Sound Control
nodes: nodes:
- name: SQ-7 - SQ-7
- mac: "00:04:c4:15:07:a4" # SQ-7 bridge port - "00:04:c4:15:07:a4" # SQ-7 bridge port
- name: BT - BT
- name: Camera Control - name: Camera Control
nodes: nodes:
- name: RX-CC-PREVIEW - RX-CC-PREVIEW
- name: RX-CC-M16 - RX-CC-M16
- name: AtemPanel-7c2e0da86d22 - "AtemPanel-7c2e0da86d22"
- name: AtemPanel-7c2e0da86d4c - "AtemPanel-7c2e0da86d4c"
- name: Video Control - name: Video Control
nodes: nodes:
- name: RX-VC-M4 - RX-VC-M4
- name: RX-VC-M16 - RX-VC-M16
- name: ATEM-2-ME-Advanced-Panel-20 - "ATEM-2-ME-Advanced-Panel-20"
- name: Control - name: Control
nodes: nodes:
- name: sunset - sunset
- name: RX-CONTROL-1 - RX-CONTROL-1

View File

@@ -9,11 +9,10 @@ import (
type PortErrorType string type PortErrorType string
const ( const (
ErrorTypeStartup PortErrorType = "startup" ErrorTypeStartup PortErrorType = "startup"
ErrorTypeNew PortErrorType = "new" ErrorTypeNew PortErrorType = "new"
ErrorTypeUnreachable PortErrorType = "unreachable" ErrorTypeUnreachable PortErrorType = "unreachable"
ErrorTypeHighUtilization PortErrorType = "high_utilization" ErrorTypeHighUtilization PortErrorType = "high_utilization"
ErrorTypeMissing PortErrorType = "missing"
) )
type PortError struct { type PortError struct {
@@ -328,53 +327,3 @@ func (e *ErrorTracker) clearUnreachableLocked(node *Node) (changed bool, becameR
} }
return becameReachable, becameReachable return becameReachable, becameReachable
} }
func (e *ErrorTracker) SetMissing(node *Node) {
changed := e.setMissingLocked(node)
if changed {
e.t.NotifyUpdate()
}
}
func (e *ErrorTracker) setMissingLocked(node *Node) bool {
e.mu.Lock()
defer e.mu.Unlock()
key := "missing:" + node.TypeID
if _, exists := e.errors[key]; exists {
return false
}
now := time.Now()
e.nextID++
e.errors[key] = &PortError{
ID: fmt.Sprintf("err-%d", e.nextID),
NodeTypeID: node.TypeID,
NodeName: node.DisplayName(),
PortName: "",
ErrorType: ErrorTypeMissing,
FirstSeen: now,
LastUpdated: now,
}
return true
}
func (e *ErrorTracker) ClearMissing(node *Node) {
changed := e.clearMissingLocked(node)
if changed {
e.t.NotifyUpdate()
}
}
func (e *ErrorTracker) clearMissingLocked(node *Node) bool {
e.mu.Lock()
defer e.mu.Unlock()
key := "missing:" + node.TypeID
if _, exists := e.errors[key]; exists {
delete(e.errors, key)
return true
}
return false
}

View File

@@ -67,11 +67,6 @@ func (n *Nodes) updateLocked(target *Node, mac net.HardwareAddr, ips []net.IP, i
added := n.applyNodeUpdates(node, targetID, mac, ips, ifaceName, nodeName) added := n.applyNodeUpdates(node, targetID, mac, ips, ifaceName, nodeName)
if node.Missing && source != "config" {
node.Missing = false
n.t.errors.ClearMissing(node)
}
n.logUpdates(node, added, isNew, source) n.logUpdates(node, added, isNew, source)
if hasNewIP(added) { if hasNewIP(added) {

View File

@@ -991,9 +991,6 @@
if (node.interfaces) { if (node.interfaces) {
node.interfaces.forEach(iface => { node.interfaces.forEach(iface => {
if (iface.mac) ids.push(iface.mac.toLowerCase()); if (iface.mac) ids.push(iface.mac.toLowerCase());
if (iface.ips) {
iface.ips.forEach(ip => ids.push(ip.toLowerCase()));
}
}); });
} }
return ids; return ids;
@@ -1150,7 +1147,7 @@
name: loc.name || '', name: loc.name || '',
anonymous: anonymous, anonymous: anonymous,
direction: loc.direction || 'horizontal', direction: loc.direction || 'horizontal',
nodeRefs: (loc.nodes || []).map(n => (n.name || n.mac || n.ip || '').toLowerCase()), nodeRefs: (loc.nodes || []).map(n => n.toLowerCase()),
parent: parent, parent: parent,
children: [] children: []
}; };

View File

@@ -119,48 +119,6 @@ func (t *Tendrils) unsubscribeSSE(id int) {
} }
} }
func (t *Tendrils) syncConfigNodes() {
if t.config == nil {
return
}
for _, ref := range t.config.AllNodeRefs() {
var node *Node
var created bool
if ref.Name != "" {
node = t.nodes.GetByName(ref.Name)
if node == nil {
node = t.nodes.GetOrCreateByName(ref.Name)
created = true
}
} else if mac := ref.ParseMAC(); mac != nil {
node = t.nodes.GetByMAC(mac)
if node == nil {
t.nodes.Update(nil, mac, nil, "", "", "config")
node = t.nodes.GetByMAC(mac)
created = true
}
} else if ip := ref.ParseIP(); ip != nil {
node = t.nodes.GetByIP(ip)
if node == nil {
t.nodes.Update(nil, nil, []net.IP{ip}, "", "", "config")
node = t.nodes.GetByIP(ip)
created = true
}
}
if node == nil {
continue
}
if created {
node.Missing = true
t.errors.SetMissing(node)
}
}
}
func (t *Tendrils) Run() { func (t *Tendrils) Run() {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
@@ -183,7 +141,6 @@ func (t *Tendrils) Run() {
continue continue
} }
t.config = cfg t.config = cfg
t.syncConfigNodes()
log.Printf("reloaded config from %s", t.ConfigFile) log.Printf("reloaded config from %s", t.ConfigFile)
t.NotifyUpdate() t.NotifyUpdate()
} }
@@ -196,7 +153,6 @@ func (t *Tendrils) Run() {
t.config = cfg t.config = cfg
t.populateLocalAddresses() t.populateLocalAddresses()
t.syncConfigNodes()
t.startHTTPServer() t.startHTTPServer()
if !t.DisableARP { if !t.DisableARP {

View File

@@ -140,7 +140,6 @@ type Node struct {
PoEBudget *PoEBudget `json:"poe_budget,omitempty"` PoEBudget *PoEBudget `json:"poe_budget,omitempty"`
IsDanteClockMaster bool `json:"is_dante_clock_master,omitempty"` IsDanteClockMaster bool `json:"is_dante_clock_master,omitempty"`
DanteTxChannels string `json:"dante_tx_channels,omitempty"` DanteTxChannels string `json:"dante_tx_channels,omitempty"`
Missing bool `json:"missing,omitempty"`
pollTrigger chan struct{} pollTrigger chan struct{}
} }
@@ -160,7 +159,6 @@ func (n *Node) WithInterface(ifaceKey string) *Node {
PoEBudget: n.PoEBudget, PoEBudget: n.PoEBudget,
IsDanteClockMaster: n.IsDanteClockMaster, IsDanteClockMaster: n.IsDanteClockMaster,
DanteTxChannels: n.DanteTxChannels, DanteTxChannels: n.DanteTxChannels,
Missing: n.Missing,
} }
} }