supermicro.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package supermicro
  15. import (
  16. "context"
  17. "time"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/httputils"
  22. "yunion.io/x/onecloud/pkg/httperrors"
  23. "yunion.io/x/onecloud/pkg/util/redfish"
  24. "yunion.io/x/onecloud/pkg/util/redfish/bmconsole"
  25. "yunion.io/x/onecloud/pkg/util/redfish/generic"
  26. )
  27. type SSupermicroRedfishApiFactory struct {
  28. }
  29. func (f *SSupermicroRedfishApiFactory) Name() string {
  30. return "Supermicro"
  31. }
  32. func (f *SSupermicroRedfishApiFactory) NewApi(endpoint, username, password string, debug bool) redfish.IRedfishDriver {
  33. return NewSupermicroRedfishApi(endpoint, username, password, debug)
  34. }
  35. func init() {
  36. redfish.RegisterApiFactory(&SSupermicroRedfishApiFactory{})
  37. }
  38. type SSupermicroRefishApi struct {
  39. generic.SGenericRefishApi
  40. }
  41. func NewSupermicroRedfishApi(endpoint, username, password string, debug bool) redfish.IRedfishDriver {
  42. api := &SSupermicroRefishApi{
  43. SGenericRefishApi: generic.SGenericRefishApi{
  44. SBaseRedfishClient: redfish.NewBaseRedfishClient(endpoint, username, password, debug),
  45. },
  46. }
  47. api.SetVirtualObject(api)
  48. return api
  49. }
  50. func (r *SSupermicroRefishApi) ParseRoot(root jsonutils.JSONObject) error {
  51. if root.Contains("UUID") && root.Contains("UpdateService") && root.Contains("Oem") {
  52. return nil
  53. }
  54. return errors.Error("not iDrac")
  55. }
  56. func (r *SSupermicroRefishApi) GetVirtualCdromJSON(ctx context.Context) (string, jsonutils.JSONObject, error) {
  57. _, resp, err := r.GetResource(ctx, "Managers", "0", "VirtualMedia")
  58. if err != nil {
  59. return "", nil, errors.Wrap(err, "r.GetResource")
  60. }
  61. log.Debugf("resp %s", resp)
  62. path, err := resp.GetString("Oem", "Supermicro", "VirtualMediaConfig", "@odata.id")
  63. if err != nil {
  64. return "", nil, errors.Wrap(err, "GetString Oem Supermicro VirtualMediaConfig @odata.id")
  65. }
  66. cdResp, err := r.Get(ctx, path)
  67. if err != nil {
  68. return "", nil, errors.Wrap(err, "Get Cdrom info fail")
  69. }
  70. if cdResp != nil {
  71. return path, cdResp, nil
  72. }
  73. return "", nil, httperrors.ErrNotFound
  74. }
  75. func (r *SSupermicroRefishApi) GetVirtualCdromInfo(ctx context.Context) (string, redfish.SCdromInfo, error) {
  76. cdInfo := redfish.SCdromInfo{}
  77. path, jsonResp, err := r.GetVirtualCdromJSON(ctx)
  78. if err != nil {
  79. return "", cdInfo, errors.Wrap(err, "r.GetVirtualCdromJSON")
  80. }
  81. imgPath, _ := jsonResp.GetString("Image")
  82. if imgPath == "null" {
  83. imgPath = ""
  84. }
  85. cdInfo.Image = imgPath
  86. if jsonResp.Contains("Actions") {
  87. cdInfo.SupportAction = true
  88. }
  89. return path, cdInfo, nil
  90. }
  91. func (r *SSupermicroRefishApi) MountVirtualCdrom(ctx context.Context, path string, cdromUrl string, boot bool) error {
  92. info := jsonutils.NewDict()
  93. info.Set("Image", jsonutils.NewString(cdromUrl))
  94. path = httputils.JoinPath(path, "Actions/VirtualMedia.InsertMedia")
  95. _, _, err := r.Post(ctx, path, info)
  96. if err != nil {
  97. return errors.Wrap(err, "r.Post")
  98. }
  99. // log.Debugf("%s", resp.PrettyString())
  100. if boot {
  101. err = r.SetNextBootVirtualCdrom(ctx)
  102. if err != nil {
  103. return errors.Wrap(err, "r.SetNextBootVirtualCdrom")
  104. }
  105. }
  106. return nil
  107. }
  108. func (r *SSupermicroRefishApi) UmountVirtualCdrom(ctx context.Context, path string) error {
  109. info := jsonutils.NewDict()
  110. path = httputils.JoinPath(path, "Actions/VirtualMedia.EjectMedia")
  111. _, _, err := r.Post(ctx, path, info)
  112. if err != nil {
  113. return errors.Wrap(err, "r.Post")
  114. }
  115. // log.Debugf("%s", resp.PrettyString())
  116. return nil
  117. }
  118. func (r *SSupermicroRefishApi) GetConsoleJNLP(ctx context.Context) (string, error) {
  119. bmc := bmconsole.NewBMCConsole(r.GetHost(), r.GetUsername(), r.GetPassword(), r.IsDebug)
  120. return bmc.GetSupermicroConsoleJNLP(ctx)
  121. }
  122. func (r *SSupermicroRefishApi) ReadSystemLogs(ctx context.Context, since time.Time) ([]redfish.SEvent, error) {
  123. _, resp, err := r.GetResource(ctx, "Managers", "0", "LogServices", "0", "Entries")
  124. if err != nil {
  125. return nil, errors.Wrap(err, "GetResource Managers 0 LogServices 0 Entries")
  126. }
  127. members, err := resp.GetArray("Members")
  128. if err != nil {
  129. return nil, errors.Wrap(err, "find Members")
  130. }
  131. events := make([]redfish.SEvent, 0)
  132. for i := range members {
  133. path, _ := members[i].GetString("@odata.id")
  134. resp, err := r.Get(ctx, path)
  135. if err != nil {
  136. log.Errorf("Get url for event %s error %s", path, err)
  137. continue
  138. }
  139. event := redfish.SEvent{}
  140. err = resp.Unmarshal(&event)
  141. if err == nil {
  142. event.Type, _ = resp.GetString("EntryType")
  143. event.Severity, _ = resp.GetString("EntryCode")
  144. events = append(events, event)
  145. } else {
  146. log.Errorf("unmarshal event fail %s %s", resp, err)
  147. }
  148. }
  149. return events, nil
  150. }
  151. func (r *SSupermicroRefishApi) ReadManagerLogs(ctx context.Context, since time.Time) ([]redfish.SEvent, error) {
  152. return nil, httperrors.ErrNotSupported
  153. }
  154. func (r *SSupermicroRefishApi) GetClearSystemLogsPath() string {
  155. return "/redfish/v1/Managers/1/LogServices/Log1/Actions/LogService.Reset"
  156. }
  157. func (r *SSupermicroRefishApi) GetClearManagerLogsPath() string {
  158. return "/redfish/v1/Managers/1/LogServices/Log1/Actions/LogService.Reset"
  159. }
  160. func (r *SSupermicroRefishApi) GetPowerPath() string {
  161. return "/redfish/v1/Chassis/1/Power"
  162. }
  163. func (r *SSupermicroRefishApi) GetThermalPath() string {
  164. return "/redfish/v1/Chassis/1/Thermal"
  165. }
  166. type sNtpConf struct {
  167. NTPEnable bool `json:"NTPEnable"`
  168. PrimaryNTPServer string `json:"PrimaryNTPServer"`
  169. SecondaryNTPServer string `json:"SecondaryNTPServer"`
  170. }
  171. func (r *SSupermicroRefishApi) GetNTPConf(ctx context.Context) (redfish.SNTPConf, error) {
  172. ntpConf := redfish.SNTPConf{}
  173. _, resp, err := r.GetResource(ctx, "Managers", "0")
  174. if err != nil {
  175. return ntpConf, errors.Wrap(err, "GetResource")
  176. }
  177. path, err := resp.GetString("Oem", "Supermicro", "NTP", "@odata.id")
  178. if err != nil {
  179. return ntpConf, errors.Wrap(err, "GetString \"Oem\", \"Supermicro\", \"NTP\", \"@odata.id\"")
  180. }
  181. resp, err = r.Get(ctx, path)
  182. if err != nil {
  183. return ntpConf, errors.Wrapf(err, "Get %s fail %s", path, err)
  184. }
  185. conf := sNtpConf{}
  186. err = resp.Unmarshal(&conf)
  187. if err != nil {
  188. return ntpConf, errors.Wrap(err, "resp.Unmarshal NTP")
  189. }
  190. ntpConf.ProtocolEnabled = conf.NTPEnable
  191. if len(conf.PrimaryNTPServer) > 0 {
  192. ntpConf.NTPServers = append(ntpConf.NTPServers, conf.PrimaryNTPServer)
  193. }
  194. if len(conf.SecondaryNTPServer) > 0 {
  195. ntpConf.NTPServers = append(ntpConf.NTPServers, conf.SecondaryNTPServer)
  196. }
  197. return ntpConf, nil
  198. }
  199. func (r *SSupermicroRefishApi) SetNTPConf(ctx context.Context, conf redfish.SNTPConf) error {
  200. _, resp, err := r.GetResource(ctx, "Managers", "0")
  201. if err != nil {
  202. return errors.Wrap(err, "GetResource")
  203. }
  204. path, err := resp.GetString("Oem", "Supermicro", "NTP", "@odata.id")
  205. if err != nil {
  206. return errors.Wrap(err, "GetString \"Oem\", \"Supermicro\", \"NTP\", \"@odata.id\"")
  207. }
  208. nconf := sNtpConf{
  209. NTPEnable: conf.ProtocolEnabled,
  210. }
  211. if len(conf.NTPServers) > 0 {
  212. nconf.PrimaryNTPServer = conf.NTPServers[0]
  213. }
  214. if len(conf.NTPServers) > 1 {
  215. nconf.SecondaryNTPServer = conf.NTPServers[1]
  216. }
  217. resp, err = r.Patch(ctx, path, jsonutils.Marshal(nconf))
  218. if err != nil {
  219. return errors.Wrap(err, "r.Patch")
  220. }
  221. if r.IsDebug {
  222. log.Debugf("%s", resp.PrettyString())
  223. }
  224. return nil
  225. }