Files
cloudpods/pkg/util/redfish/hprest/hprest.go
T

293 lines
8.1 KiB
Go

// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hprest
import (
"context"
"fmt"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/util/redfish"
)
const (
basePath = "/rest/v1"
linkKey = "href"
memberKey = "Member"
versionKey = "ServiceVersion"
)
type SHpRestApiFactory struct {
}
func (f *SHpRestApiFactory) Name() string {
return "HpRest"
}
func (f *SHpRestApiFactory) NewApi(endpoint, username, password string, debug bool) redfish.IRedfishDriver {
return NewHpRestApi(endpoint, username, password, debug)
}
func init() {
redfish.RegisterApiFactory(&SHpRestApiFactory{})
}
type SHpRestApi struct {
redfish.SBaseRedfishClient
}
func NewHpRestApi(endpoint, username, password string, debug bool) redfish.IRedfishDriver {
api := &SHpRestApi{
SBaseRedfishClient: redfish.NewBaseRedfishClient(endpoint, username, password, debug),
}
api.SetVirtualObject(api)
return api
}
func (r *SHpRestApi) BasePath() string {
return basePath
}
func (r *SHpRestApi) GetParent(parent jsonutils.JSONObject) jsonutils.JSONObject {
obj, _ := parent.Get("links")
if obj != nil {
return obj
}
return jsonutils.NewDict()
}
func (r *SHpRestApi) VersionKey() string {
return versionKey
}
func (r *SHpRestApi) LinkKey() string {
return linkKey
}
func (r *SHpRestApi) MemberKey() string {
return memberKey
}
func (r *SHpRestApi) LogItemsKey() string {
return "Items"
}
func (r *SHpRestApi) Probe(ctx context.Context) error {
err := r.SBaseRedfishClient.Probe(ctx)
if err != nil {
return errors.Wrap(err, "r.SBaseRedfishClient.Probe")
}
resp, err := r.Get(ctx, "/rest/v1/resourcedirectory")
if err != nil {
return errors.Wrap(err, "Get /rest/v1/resourcedirectory")
}
if r.IsDebug {
log.Debugf("%s", resp.PrettyString())
}
return nil
}
func (r *SHpRestApi) GetVirtualCdromInfo(ctx context.Context) (string, redfish.SCdromInfo, error) {
path, cdInfo, err := r.SBaseRedfishClient.GetVirtualCdromInfo(ctx)
if err == nil {
cdInfo.SupportAction = true
}
return path, cdInfo, err
}
func (r *SHpRestApi) GetSystemInfo(ctx context.Context) (string, redfish.SSystemInfo, error) {
sysInfo := redfish.SSystemInfo{}
path, resp, err := r.GetResource(ctx, "Systems", "0")
if err != nil {
return path, sysInfo, errors.Wrap(err, "r.GetResource Systems")
}
err = resp.Unmarshal(&sysInfo)
if err != nil {
return path, sysInfo, errors.Wrap(err, "resp.Unmarshal")
}
memGB, _ := resp.Int("Memory", "TotalSystemMemoryGB")
sysInfo.MemoryGB = int(memGB)
cpuCnt, _ := resp.Int("Processors", "Count")
cpuDesc, _ := resp.GetString("Processors", "ProcessorFamily")
sysInfo.NodeCount = int(cpuCnt)
sysInfo.CpuDesc = strings.TrimSpace(cpuDesc)
power, _ := resp.GetString("Power")
sysInfo.PowerState = strings.TrimSpace(power)
sysInfo.SerialNumber = strings.TrimSpace(sysInfo.SerialNumber)
sysInfo.SKU = strings.TrimSpace(sysInfo.SKU)
sysInfo.Model = strings.TrimSpace(sysInfo.Model)
sysInfo.Manufacturer = strings.TrimSpace(sysInfo.Manufacturer)
nextBootDev, _ := resp.GetString("Boot", "BootSourceOverrideTarget")
sysInfo.NextBootDev = strings.TrimSpace(nextBootDev)
nextBootDevSupports, _ := resp.GetArray("Boot", "BootSourceOverrideSupported")
sysInfo.NextBootDevSupported = make([]string, len(nextBootDevSupports))
for i := range nextBootDevSupports {
devStr, _ := nextBootDevSupports[i].GetString()
sysInfo.NextBootDevSupported[i] = devStr
}
AvailableActions, _ := resp.GetArray("AvailableActions")
if AvailableActions != nil {
resetCapabilities, _ := AvailableActions[0].GetArray("Capabilities")
if resetCapabilities != nil {
resetTypeValues, _ := resetCapabilities[0].GetArray("AllowableValues")
sysInfo.ResetTypeSupported = make([]string, len(resetTypeValues))
for i := range resetTypeValues {
resetTypeStr, _ := resetTypeValues[i].GetString()
sysInfo.ResetTypeSupported[i] = resetTypeStr
}
}
}
macArray, _ := resp.GetArray("HostCorrelation", "HostMACAddress")
if len(macArray) > 0 {
sysInfo.EthernetNICs = make([]string, len(macArray))
for i := range macArray {
macAddr, _ := macArray[i].GetString()
sysInfo.EthernetNICs[i] = netutils.FormatMacAddr(macAddr)
}
}
return path, sysInfo, nil
}
func (r *SHpRestApi) Reset(ctx context.Context, action string) error {
path, sysInfo, err := r.IRedfishDriver().GetSystemInfo(ctx)
if err != nil {
return errors.Wrap(err, "r.GetSystemInfo")
}
if !utils.IsInStringArray(action, sysInfo.ResetTypeSupported) {
return errors.Wrapf(httperrors.ErrBadRequest, "%s not supported: %s", action, sysInfo.ResetTypeSupported)
}
params := jsonutils.NewDict()
params.Add(jsonutils.NewString(action), "ResetType")
params.Add(jsonutils.NewString("Reset"), "Action")
_, resp, err := r.Post(ctx, path, params)
if err != nil {
return errors.Wrap(err, "Action.Reset")
}
if r.IsDebug {
log.Debugf("%s", resp)
}
return nil
}
func (r *SHpRestApi) BmcReset(ctx context.Context) error {
path, _, err := r.GetResource(ctx, "Managers", "0")
if err != nil {
return errors.Wrap(err, "r.GetSystemInfo")
}
params := jsonutils.NewDict()
params.Add(jsonutils.NewString("Reset"), "Action")
_, resp, err := r.Post(ctx, path, params)
if err != nil {
return errors.Wrap(err, "Actions/Manager.Reset")
}
log.Debugf("%s", resp)
return nil
}
func (r *SHpRestApi) readLogs(ctx context.Context, subsys string, since time.Time) ([]redfish.SEvent, error) {
_, manager, err := r.GetResource(ctx, subsys, "0", "Logs", "0")
if err != nil {
return nil, errors.Wrap(err, "GetResource Managers 0")
}
manager = r.IRedfishDriver().GetParent(manager)
entries, _ := manager.GetArray("Entries")
if len(entries) == 0 {
return nil, errors.Error("no log entries")
}
path, _ := entries[0].GetString(r.IRedfishDriver().LinkKey())
if len(path) == 0 {
return nil, errors.Wrap(err, "no valid url???")
}
nextPath := path
events := make([]redfish.SEvent, 0)
for {
resp, err := r.Get(ctx, nextPath)
if err != nil {
return nil, errors.Wrap(err, nextPath)
}
tmpEvents := make([]redfish.SEvent, 0)
err = resp.Unmarshal(&tmpEvents, "Items")
if err != nil {
return nil, errors.Wrap(err, "resp.Unmarshal")
}
timeBreak := false
for i := range tmpEvents {
if !since.IsZero() && tmpEvents[i].Created.Before(since) {
timeBreak = true
break
}
events = append(events, tmpEvents[i])
}
if timeBreak {
break
}
nextPage, _ := resp.Int("links", "NextPage", "page")
if nextPage > 0 {
nextPath = fmt.Sprintf("%s?page=%d", path, nextPage)
} else {
break
}
}
return events, nil
}
func (r *SHpRestApi) ReadSystemLogs(ctx context.Context, since time.Time) ([]redfish.SEvent, error) {
return r.readLogs(ctx, "Systems", since)
}
func (r *SHpRestApi) ReadManagerLogs(ctx context.Context, since time.Time) ([]redfish.SEvent, error) {
return r.readLogs(ctx, "Managers", since)
}
func (r *SHpRestApi) clearLogs(ctx context.Context, subsys string) error {
path, _, err := r.GetResource(ctx, subsys, "0", "Logs", "0")
if err != nil {
return errors.Wrap(err, "GetResource Managers 0")
}
params := jsonutils.NewDict()
params.Add(jsonutils.NewString("ClearLog"), "Action")
_, resp, err := r.Post(ctx, path, params)
if err != nil {
return errors.Wrap(err, "r.Post")
}
if r.IsDebug {
log.Debugf("%s", resp.PrettyString())
}
return nil
}
func (r *SHpRestApi) ClearSystemLogs(ctx context.Context) error {
return r.clearLogs(ctx, "Systems")
}
func (r *SHpRestApi) ClearManagerLogs(ctx context.Context) error {
return r.clearLogs(ctx, "Managers")
}