ilo.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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 ilo
  15. import (
  16. "context"
  17. "strings"
  18. "time"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/httputils"
  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 SILORedfishApiFactory struct {
  28. }
  29. func (f *SILORedfishApiFactory) Name() string {
  30. return "iLO"
  31. }
  32. func (f *SILORedfishApiFactory) NewApi(endpoint, username, password string, debug bool) redfish.IRedfishDriver {
  33. return NewILORedfishApi(endpoint, username, password, debug)
  34. }
  35. func init() {
  36. redfish.RegisterApiFactory(&SILORedfishApiFactory{})
  37. }
  38. type SILORefishApi struct {
  39. generic.SGenericRefishApi
  40. }
  41. func NewILORedfishApi(endpoint, username, password string, debug bool) redfish.IRedfishDriver {
  42. api := &SILORefishApi{
  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 *SILORefishApi) ParseRoot(root jsonutils.JSONObject) error {
  51. oemHp, _ := root.Get("Oem", "Hp")
  52. if oemHp != nil {
  53. return nil
  54. }
  55. return errors.Error("not iLO")
  56. }
  57. func (r *SILORefishApi) Probe(ctx context.Context) error {
  58. err := r.SGenericRefishApi.Probe(ctx)
  59. if err != nil {
  60. return errors.Wrap(err, "r.SGenericRefishApi.Probe")
  61. }
  62. if r.IsDebug {
  63. resp, err := r.Get(ctx, "/redfish/v1/ResourceDirectory/")
  64. if err != nil {
  65. return errors.Wrap(err, "r.Get /redfish/v1/ResourceDirectory/")
  66. }
  67. log.Debugf("%s", resp.PrettyString())
  68. }
  69. return nil
  70. }
  71. func (r *SILORefishApi) GetVirtualCdromInfo(ctx context.Context) (string, redfish.SCdromInfo, error) {
  72. path, cdInfo, err := r.SGenericRefishApi.GetVirtualCdromInfo(ctx)
  73. if err == nil {
  74. cdInfo.SupportAction = true
  75. }
  76. return path, cdInfo, err
  77. }
  78. func (r *SILORefishApi) SetNextBootVirtualCdrom(ctx context.Context) error {
  79. path, cdInfo, err := r.GetVirtualCdromJSON(ctx)
  80. if err != nil {
  81. return errors.Wrap(err, "GetVirtualCdromJSON")
  82. }
  83. var oemKey string
  84. nextBoot, err := cdInfo.Bool("Oem", "Hp", "BootOnNextServerReset")
  85. if err != nil {
  86. nextBoot, err = cdInfo.Bool("Oem", "Hpe", "BootOnNextServerReset")
  87. if err != nil {
  88. return errors.Wrap(err, "no BootOnNextServerReset found???")
  89. }
  90. oemKey = "Hpe"
  91. } else {
  92. oemKey = "Hp"
  93. }
  94. if !nextBoot {
  95. params := jsonutils.NewDict()
  96. params.Add(jsonutils.JSONTrue, "Oem", oemKey, "BootOnNextServerReset")
  97. resp, err := r.Patch(ctx, path, params)
  98. if err != nil {
  99. return errors.Wrap(err, "r.Patch")
  100. }
  101. if r.IsDebug {
  102. log.Debugf("%s", resp.PrettyString())
  103. }
  104. }
  105. return nil
  106. }
  107. func (r *SILORefishApi) readLogs(ctx context.Context, path string, subsys string, typeStr string, since time.Time) ([]redfish.SEvent, error) {
  108. if len(path) == 0 {
  109. var err error
  110. path, _, err = r.GetResource(ctx, subsys, "0", "LogServices", "0", "Entries")
  111. if err != nil {
  112. return nil, errors.Wrap(err, "GetResource")
  113. }
  114. }
  115. resp, err := r.Get(ctx, path)
  116. if err != nil {
  117. return nil, errors.Wrap(err, path)
  118. }
  119. paths, err := resp.GetArray(r.IRedfishDriver().MemberKey())
  120. if err != nil {
  121. return nil, errors.Wrap(err, "GetArray")
  122. }
  123. events := make([]redfish.SEvent, 0)
  124. for idx := len(paths) - 1; idx >= 0; idx -= 1 {
  125. eventPath, err := paths[idx].GetString(r.IRedfishDriver().LinkKey())
  126. if err != nil {
  127. return nil, errors.Wrap(err, "GetString")
  128. }
  129. eventResp, err := r.Get(ctx, eventPath)
  130. if err != nil {
  131. log.Errorf("GetEvent fail %s", err)
  132. continue
  133. }
  134. tmpEvent := redfish.SEvent{}
  135. err = eventResp.Unmarshal(&tmpEvent)
  136. if err != nil {
  137. return nil, errors.Wrap(err, "eventResp.Unmarshal")
  138. }
  139. if !since.IsZero() && tmpEvent.Created.Before(since) {
  140. break
  141. }
  142. tmpEvent.EventId, _ = eventResp.GetString("Oem", "Hp", "EventNumber")
  143. if len(tmpEvent.EventId) == 0 {
  144. tmpEvent.EventId, _ = eventResp.GetString("Oem", "Hpe", "EventNumber")
  145. }
  146. tmpEvent.Type = typeStr
  147. events = append(events, tmpEvent)
  148. }
  149. redfish.SortEvents(events)
  150. return events, nil
  151. }
  152. func (r *SILORefishApi) ReadSystemLogs(ctx context.Context, since time.Time) ([]redfish.SEvent, error) {
  153. return r.readLogs(ctx, "/redfish/v1/Systems/1/LogServices/IML/Entries/", "Systems", redfish.EVENT_TYPE_SYSTEM, since)
  154. }
  155. func (r *SILORefishApi) ReadManagerLogs(ctx context.Context, since time.Time) ([]redfish.SEvent, error) {
  156. return r.readLogs(ctx, "/redfish/v1/Managers/1/LogServices/IEL/Entries/", "Managers", redfish.EVENT_TYPE_MANAGER, since)
  157. }
  158. func (r *SILORefishApi) GetClearSystemLogsPath() string {
  159. return "/redfish/v1/Systems/1/LogServices/IML/Actions/LogService.ClearLog/"
  160. }
  161. func (r *SILORefishApi) GetClearManagerLogsPath() string {
  162. return "/redfish/v1/Managers/1/LogServices/IEL/Actions/LogService.ClearLog/"
  163. }
  164. func (r *SILORefishApi) ClearSystemLogs(ctx context.Context) error {
  165. return r.ClearLogs(ctx, r.IRedfishDriver().GetClearManagerLogsPath(), "Systems", 0)
  166. }
  167. func (r *SILORefishApi) ClearManagerLogs(ctx context.Context) error {
  168. return r.ClearLogs(ctx, r.IRedfishDriver().GetClearManagerLogsPath(), "Managers", 0)
  169. }
  170. func (r *SILORefishApi) LogItemsKey() string {
  171. return "Members"
  172. }
  173. func (r *SILORefishApi) GetIndicatorLED(ctx context.Context) (bool, error) {
  174. _, val, err := r.GetIndicatorLEDInternal(ctx, "Systems")
  175. if err != nil {
  176. return false, errors.Wrap(err, "r.GetIndicatorLEDInternal")
  177. }
  178. if strings.EqualFold(val, "Off") {
  179. return false, nil
  180. } else {
  181. return true, nil
  182. }
  183. }
  184. func (r *SILORefishApi) SetIndicatorLED(ctx context.Context, on bool) error {
  185. valStr := "Off"
  186. if on {
  187. valStr = "Lit"
  188. }
  189. return r.SetIndicatorLEDInternal(ctx, "Systems", valStr)
  190. }
  191. func (r *SILORefishApi) GetNTPConf(ctx context.Context) (redfish.SNTPConf, error) {
  192. ntpConf := redfish.SNTPConf{}
  193. path, _, err := r.GetResource(ctx, "Managers", "0")
  194. if err != nil {
  195. return ntpConf, errors.Wrap(err, "r.GetResource Managers 0")
  196. }
  197. dateUrl := httputils.JoinPath(path, "DateTime")
  198. resp, err := r.Get(ctx, dateUrl)
  199. if err != nil {
  200. return ntpConf, errors.Wrapf(err, "r.Get %s", dateUrl)
  201. }
  202. if r.IsDebug {
  203. log.Debugf("%s", resp.PrettyString())
  204. }
  205. ntpSrvs, _ := jsonutils.GetStringArray(resp, "StaticNTPServers")
  206. tz, _ := resp.GetString("TimeZone", "Name")
  207. ntpConf.NTPServers = make([]string, 0)
  208. for _, ntpsrv := range ntpSrvs {
  209. if len(ntpsrv) > 0 {
  210. ntpConf.NTPServers = append(ntpConf.NTPServers, ntpsrv)
  211. }
  212. }
  213. if len(ntpConf.NTPServers) > 0 {
  214. ntpConf.ProtocolEnabled = true
  215. }
  216. ntpConf.TimeZone = tz
  217. return ntpConf, nil
  218. }
  219. func (r *SILORefishApi) SetNTPConf(ctx context.Context, conf redfish.SNTPConf) error {
  220. path, _, err := r.GetResource(ctx, "Managers", "0")
  221. if err != nil {
  222. return errors.Wrap(err, "r.GetResource Managers 0")
  223. }
  224. if len(conf.NTPServers) > 2 {
  225. conf.NTPServers = conf.NTPServers[:2]
  226. }
  227. dateUrl := httputils.JoinPath(path, "DateTime")
  228. params := jsonutils.NewDict()
  229. params.Add(jsonutils.NewStringArray(conf.NTPServers), "StaticNTPServers")
  230. params.Add(jsonutils.NewString(conf.TimeZone), "TimeZone", "Name")
  231. resp, err := r.Patch(ctx, dateUrl, params)
  232. if err != nil {
  233. return errors.Wrapf(err, "r.Patch %s", dateUrl)
  234. }
  235. if r.IsDebug {
  236. log.Debugf("%s", resp.PrettyString())
  237. }
  238. return nil
  239. }
  240. func (r *SILORefishApi) GetConsoleJNLP(ctx context.Context) (string, error) {
  241. bmc := bmconsole.NewBMCConsole(r.GetHost(), r.GetUsername(), r.GetPassword(), r.IsDebug)
  242. return bmc.GetIloConsoleJNLP(ctx)
  243. }
  244. func (r *SILORefishApi) MountVirtualCdrom(ctx context.Context, path string, cdromUrl string, boot bool) error {
  245. info := jsonutils.NewDict()
  246. info.Set("Image", jsonutils.NewString(cdromUrl))
  247. if boot {
  248. cdInfo, err := r.Get(ctx, path)
  249. if err != nil {
  250. return errors.Wrapf(err, "Get %s", path)
  251. }
  252. var oemKey string
  253. _, err = cdInfo.Bool("Oem", "Hp", "BootOnNextServerReset")
  254. if err != nil {
  255. _, err = cdInfo.Bool("Oem", "Hpe", "BootOnNextServerReset")
  256. if err != nil {
  257. return errors.Wrap(err, "no BootOnNextServerReset found???")
  258. } else {
  259. oemKey = "Hpe"
  260. }
  261. } else {
  262. oemKey = "Hp"
  263. }
  264. info.Add(jsonutils.JSONTrue, "Oem", oemKey, "BootOnNextServerReset")
  265. }
  266. resp, err := r.Patch(ctx, path, info)
  267. if err != nil {
  268. return errors.Wrap(err, "r.Patch")
  269. }
  270. log.Debugf("%s", resp.PrettyString())
  271. return nil
  272. }
  273. func (r *SILORefishApi) GetPowerPath() string {
  274. return "/redfish/v1/Chassis/1/Power/"
  275. }
  276. func (r *SILORefishApi) GetThermalPath() string {
  277. return "/redfish/v1/Chassis/1/Thermal/"
  278. }