@@ -46,10 +46,14 @@ type SMDClient struct {
4646 tokenEndpoint string
4747 accessToken string
4848 nodes map [string ]NodeMapping
49- nodesMutex * sync.Mutex
49+ nodesMutex * sync.RWMutex
5050 nodes_last_update time.Time
5151 stopCacheRefresh chan struct {}
5252 stopOnce sync.Once
53+ // Reverse indexes for O(1) lookups
54+ ipToXname map [string ]string
55+ macToXname map [string ]string
56+ wgipToXname map [string ]string
5357}
5458
5559type NodeInterface struct {
@@ -62,6 +66,7 @@ type NodeInterface struct {
6266type NodeMapping struct {
6367 Xname string `json:"xname" yaml:"xname"`
6468 Interfaces []NodeInterface `json:"interfaces" yaml:"interfaces"`
69+ Groups []string `json:"groups" yaml:"groups"`
6570}
6671
6772// NewSMDClient creates a new SMDClient which connects to the SMD server at baseurl
@@ -105,10 +110,13 @@ func NewSMDClient(clusterName, baseurl, jwtURL, accessToken, certPath string, in
105110 smdBaseURL : baseurl ,
106111 tokenEndpoint : jwtURL ,
107112 accessToken : accessToken ,
108- nodesMutex : & sync.Mutex {},
113+ nodesMutex : & sync.RWMutex {},
109114 nodes_last_update : time .Now (),
110115 nodes : make (map [string ]NodeMapping ),
111116 stopCacheRefresh : make (chan struct {}),
117+ ipToXname : make (map [string ]string ),
118+ macToXname : make (map [string ]string ),
119+ wgipToXname : make (map [string ]string ),
112120 }
113121
114122 // Populate the cache initially
@@ -219,7 +227,7 @@ func (s *SMDClient) getSMD(ep string, smd interface{}) error {
219227}
220228
221229// PopulateNodes fetches the Ethernet interface data from the SMD server and populates the nodes map
222- // with the corresponding node information, including MAC addresses, IP addresses, and descriptions .
230+ // with the corresponding node information, including MAC addresses, IP addresses, descriptions, and group membership .
223231func (s * SMDClient ) PopulateNodes () {
224232 s .nodesMutex .Lock ()
225233 defer s .nodesMutex .Unlock ()
@@ -273,44 +281,77 @@ func (s *SMDClient) PopulateNodes() {
273281 s .nodes [ep .CompID ] = newNode
274282 }
275283 }
284+
285+ // Populate group membership for all nodes
286+ log .Debug ().Msg ("Fetching group membership for all nodes" )
287+ for xname , node := range s .nodes {
288+ ml := new (sm.Membership )
289+ membershipEp := "/hsm/v2/memberships/" + xname
290+ if err := s .getSMD (membershipEp , ml ); err != nil {
291+ log .Debug ().Err (err ).Msgf ("Failed to get group membership for %s" , xname )
292+ node .Groups = []string {} // Empty groups if fetch fails
293+ } else {
294+ node .Groups = ml .GroupLabels
295+ }
296+ s .nodes [xname ] = node
297+ }
298+
299+ // Build reverse indexes for O(1) lookups
300+ log .Debug ().Msg ("Building reverse indexes" )
301+ s .ipToXname = make (map [string ]string )
302+ s .macToXname = make (map [string ]string )
303+ s .wgipToXname = make (map [string ]string )
304+
305+ for xname , node := range s .nodes {
306+ for _ , iface := range node .Interfaces {
307+ if iface .IP != "" {
308+ s .ipToXname [strings .ToLower (iface .IP )] = xname
309+ }
310+ if iface .MAC != "" {
311+ s .macToXname [strings .ToLower (iface .MAC )] = xname
312+ }
313+ if iface .WGIP != "" {
314+ s .wgipToXname [strings .ToLower (iface .WGIP )] = xname
315+ }
316+ }
317+ }
318+
276319 s .nodes_last_update = time .Now ()
277- log .Debug ().Msg ("Nodes map populated" )
320+ log .Debug ().Msgf ("Nodes map populated with %d nodes, %d IP mappings, %d MAC mappings" ,
321+ len (s .nodes ), len (s .ipToXname ), len (s .macToXname ))
278322}
279323
280324// IDfromMAC returns the ID of the xname that has the MAC address
281325func (s * SMDClient ) IDfromMAC (mac string ) (string , error ) {
282- s .nodesMutex .Lock ()
283- defer s .nodesMutex .Unlock ()
326+ s .nodesMutex .RLock ()
327+ defer s .nodesMutex .RUnlock ()
284328
285- for _ , node := range s .nodes {
286- for _ , iface := range node .Interfaces {
287- if strings .EqualFold (mac , iface .MAC ) {
288- return node .Xname , nil
289- }
290- }
329+ key := strings .ToLower (mac )
330+ if xname , found := s .macToXname [key ]; found {
331+ return xname , nil
291332 }
292- return "" , errors . New ("MAC " + mac + " not found for an xname in nodes" )
333+ return "" , fmt . Errorf ("MAC %s not found for an xname in nodes" , mac )
293334}
294335
295336// IDfromIP returns the ID of the xname that has the IP address
296337func (s * SMDClient ) IDfromIP (ipaddr string ) (string , error ) {
297- s .nodesMutex .Lock ()
298- defer s .nodesMutex .Unlock ()
338+ s .nodesMutex .RLock ()
339+ defer s .nodesMutex .RUnlock ()
299340
300- for _ , node := range s .nodes {
301- for _ , iface := range node .Interfaces {
302- if strings .EqualFold (ipaddr , iface .IP ) || strings .EqualFold (ipaddr , iface .WGIP ) {
303- return node .Xname , nil
304- }
305- }
341+ key := strings .ToLower (ipaddr )
342+ if xname , found := s .ipToXname [key ]; found {
343+ return xname , nil
306344 }
307- return "" , errors .New ("IP address " + ipaddr + " not found for an xname in nodes" )
345+ if xname , found := s .wgipToXname [key ]; found {
346+ return xname , nil
347+ }
348+ return "" , fmt .Errorf ("IP address %s not found for an xname in nodes" , ipaddr )
308349}
309350
310351// IPfromID returns the IP address of the xname with the given ID
311352func (s * SMDClient ) IPfromID (id string ) (string , error ) {
312- s .nodesMutex .Lock ()
313- defer s .nodesMutex .Unlock ()
353+ s .nodesMutex .RLock ()
354+ defer s .nodesMutex .RUnlock ()
314355 if node , found := s .nodes [id ]; found {
315356 if node .Interfaces != nil {
316357 if len (node .Interfaces ) > 0 {
@@ -323,8 +364,8 @@ func (s *SMDClient) IPfromID(id string) (string, error) {
323364}
324365
325366func (s * SMDClient ) MACfromID (id string ) (string , error ) {
326- s .nodesMutex .Lock ()
327- defer s .nodesMutex .Unlock ()
367+ s .nodesMutex .RLock ()
368+ defer s .nodesMutex .RUnlock ()
328369 if node , found := s .nodes [id ]; found {
329370 if node .Interfaces != nil {
330371 if len (node .Interfaces ) > 0 {
@@ -343,13 +384,15 @@ func (s *SMDClient) GroupMembership(id string) ([]string, error) {
343384 log .Err (err ).Msg ("failed to get group membership" )
344385 return []string {}, err
345386 }
346- ml := new (sm.Membership )
347- ep := "/hsm/v2/memberships/" + id
348- err := s .getSMD (ep , ml )
349- if err != nil {
350- return nil , err
387+
388+ s .nodesMutex .RLock ()
389+ defer s .nodesMutex .RUnlock ()
390+
391+ if node , found := s .nodes [id ]; found {
392+ return node .Groups , nil
351393 }
352- return ml .GroupLabels , nil
394+
395+ return []string {}, fmt .Errorf ("node %s not found in cache" , id )
353396}
354397
355398func (s * SMDClient ) ComponentInformation (id string ) (base.Component , error ) {
@@ -372,6 +415,9 @@ func (s *SMDClient) AddWGIP(id string, wgip string) error {
372415 if node .Interfaces != nil {
373416 if len (node .Interfaces ) > 0 {
374417 node .Interfaces [0 ].WGIP = wgip
418+ s .nodes [id ] = node
419+ // Update reverse index
420+ s .wgipToXname [strings .ToLower (wgip )] = id
375421 return nil
376422 }
377423 return errors .New ("no interfaces found for ID " + id )
@@ -381,8 +427,8 @@ func (s *SMDClient) AddWGIP(id string, wgip string) error {
381427}
382428
383429func (s * SMDClient ) WGIPfromID (id string ) (string , error ) {
384- s .nodesMutex .Lock ()
385- defer s .nodesMutex .Unlock ()
430+ s .nodesMutex .RLock ()
431+ defer s .nodesMutex .RUnlock ()
386432 if node , found := s .nodes [id ]; found {
387433 if node .Interfaces != nil {
388434 if len (node .Interfaces ) > 0 {
0 commit comments