11package compat_otp
22
33import (
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)
2036type 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