Skip to content

Commit 2fa0e14

Browse files
Merge pull request #30830 from sgoveas/bm_util
NO-JIRA: Add a singleton instance for list of nodes
2 parents 7eb5184 + 3cb7c99 commit 2fa0e14

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

test/extended/util/compat_otp/upibaremetalrdu_client.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package compat_otp
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
7+
"os"
8+
"path/filepath"
9+
"sync"
610
"time"
711

812
"github.com/gebn/bmc"
913
"github.com/gebn/bmc/pkg/ipmi"
1014
o "github.com/onsi/gomega"
15+
"gopkg.in/yaml.v3"
1116
e2e "k8s.io/kubernetes/test/e2e/framework"
1217
)
1318

@@ -16,6 +21,17 @@ const (
1621
BMPoweredOff = "poweredoff"
1722
)
1823

24+
// RDU2Hosts holds the collection of RDU2 hosts and provides methods to manage them
25+
type RDU2Hosts struct {
26+
hostsMap map[string]*RDU2Host
27+
mu sync.RWMutex
28+
}
29+
30+
var (
31+
rdu2HostsSingleton *RDU2Hosts
32+
singletonMu sync.Mutex
33+
)
34+
1935
// RDU2Host models the RDU2 host (partial representation)
2036
type RDU2Host struct {
2137
Name string `yaml:"name"`
@@ -25,6 +41,87 @@ type RDU2Host struct {
2541
BmcForwardedPort uint16 `yaml:"bmc_forwarded_port"`
2642
Host string `yaml:"host"`
2743
JumpHost string `yaml:"-"`
44+
MacAddress string `yaml:"mac"`
45+
RedfishScheme string `yaml:"redfish_scheme"`
46+
RedfishBaseURI string `yaml:"redfish_base_uri"`
47+
}
48+
49+
// newRDU2Hosts creates a new RDU2Hosts instance by reading the hosts.yaml file
50+
func newRDU2Hosts() (*RDU2Hosts, error) {
51+
sharedDir := os.Getenv("SHARED_DIR")
52+
if sharedDir == "" {
53+
return nil, fmt.Errorf("SHARED_DIR is not set")
54+
}
55+
hostsFilePath := filepath.Join(sharedDir, "hosts.yaml")
56+
57+
yamlBytes, err := os.ReadFile(hostsFilePath)
58+
if err != nil {
59+
return nil, fmt.Errorf("failed to read hosts.yaml: %w", err)
60+
}
61+
62+
// Unmarshal the yaml into a slice of RDU2Host objects
63+
var hostsData []RDU2Host
64+
dec := yaml.NewDecoder(bytes.NewReader(yamlBytes))
65+
dec.KnownFields(true)
66+
err = dec.Decode(&hostsData)
67+
if err != nil {
68+
return nil, fmt.Errorf("failed to parse hosts.yaml: %w", err)
69+
}
70+
71+
if len(hostsData) == 0 {
72+
return nil, fmt.Errorf("hosts.yaml contains no hosts")
73+
}
74+
75+
// Convert slice to map of name to RDU2Host objects to allow lookup by name
76+
hostsMap := make(map[string]*RDU2Host, len(hostsData))
77+
for i := range hostsData {
78+
if hostsData[i].Name == "" {
79+
return nil, fmt.Errorf("hosts.yaml entry at index %d has empty name", i)
80+
}
81+
if _, exists := hostsMap[hostsData[i].Name]; exists {
82+
return nil, fmt.Errorf("duplicate host name %q in hosts.yaml", hostsData[i].Name)
83+
}
84+
hostsMap[hostsData[i].Name] = &hostsData[i]
85+
}
86+
87+
return &RDU2Hosts{
88+
hostsMap: hostsMap,
89+
}, nil
90+
}
91+
92+
// copyMap returns a deep copy of the hosts map to prevent external modifications
93+
func (r *RDU2Hosts) copyMap() map[string]*RDU2Host {
94+
r.mu.RLock()
95+
defer r.mu.RUnlock()
96+
97+
hostsCopy := make(map[string]*RDU2Host, len(r.hostsMap))
98+
for k, v := range r.hostsMap {
99+
if v == nil {
100+
hostsCopy[k] = nil
101+
continue
102+
}
103+
hostCopy := *v
104+
hostsCopy[k] = &hostCopy
105+
}
106+
return hostsCopy
107+
}
108+
109+
// GetRDU2HostsList returns the singleton instance of RDU2Hosts map
110+
// It initializes the singleton on first call by reading the hosts.yaml file
111+
// Returns a copy of the map to prevent external modifications
112+
func GetRDU2HostsList() (map[string]*RDU2Host, error) {
113+
singletonMu.Lock()
114+
defer singletonMu.Unlock()
115+
if rdu2HostsSingleton != nil {
116+
return rdu2HostsSingleton.copyMap(), nil
117+
}
118+
119+
s, err := newRDU2Hosts()
120+
if err != nil {
121+
return nil, err
122+
}
123+
rdu2HostsSingleton = s
124+
return s.copyMap(), nil
28125
}
29126

30127
// StopUPIbaremetalInstance power off the BM machine

0 commit comments

Comments
 (0)