Skip to content

Commit

Permalink
Add Supermicro DumpService object (#376)
Browse files Browse the repository at this point in the history
This adds a DumpService OEM object for Supermicro systems.

Signed-off-by: Sean McGinnis <[email protected]>
  • Loading branch information
stmcginnis authored Oct 17, 2024
1 parent 4c227db commit aa597ec
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 4 deletions.
123 changes: 123 additions & 0 deletions oem/smc/dumpservice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//
// SPDX-License-Identifier: BSD-3-Clause
//

package smc

import (
"encoding/json"
"errors"

"github.com/stmcginnis/gofish/common"
)

// Dump represents a dump from the DumpService.
// NOTE: This is another one where the jsonschema reported by SMC appears to be
// wildly inaccurate. Use with caution.
type Dump struct {
common.Entity

AttestationFile []string
}

// GetDump will get a Dump instance from the service.
func GetDump(c common.Client, uri string) (*Dump, error) {
return common.GetObject[Dump](c, uri)
}

// ListReferencedDumps gets the collection of Dumps from
// a provided reference.
func ListReferencedDumps(c common.Client, uri string) ([]*Dump, error) {
return common.GetCollectionObjects[Dump](c, uri)
}

// DumpService is the dump service instance associated with the system.
type DumpService struct {
common.Entity

// Link to a DumpCollection.
dumps string

createDumpTarget string
deleteAllTarget string
collectTarget string
}

// UnmarshalJSON unmarshals an DumpService object from the raw JSON.
func (ds *DumpService) UnmarshalJSON(b []byte) error {
type temp DumpService
var t struct {
temp
Dumps common.Link
Actions struct {
CreateDump common.ActionTarget `json:"#SmcDumpService.CreateDump"`
DeleteAll common.ActionTarget `json:"#SmcDumpService.DeleteAll"`
Collect common.ActionTarget `json:"#OemDumpService.Collect"`
}
}

err := json.Unmarshal(b, &t)
if err != nil {
return err
}

*ds = DumpService(t.temp)

ds.dumps = t.Dumps.String()

ds.createDumpTarget = t.Actions.CreateDump.Target
ds.deleteAllTarget = t.Actions.DeleteAll.Target
ds.collectTarget = t.Actions.Collect.Target

return nil
}

// GetDefaultDumpService will get the default DumpService instance from the service.
func GetDefaultDumpService(c common.Client) (*DumpService, error) {
return common.GetObject[DumpService](c, "/redfish/v1/Oem/Supermicro/DumpService/")
}

// GetDumpService will get a DumpService instance from the service.
func GetDumpService(c common.Client, uri string) (*DumpService, error) {
return common.GetObject[DumpService](c, uri)
}

// CreateDump creates a new dump. Allowable dumpType is usually only
// "Host Dump".
func (ds *DumpService) CreateDump(dumpType string) error {
if ds.createDumpTarget == "" {
return errors.New("create dump is not supported by this system")
}

return ds.Post(ds.createDumpTarget, map[string]any{
"DumpType": dumpType,
})
}

// DeleteAll deletes all dumps.
func (ds *DumpService) DeleteAll() error {
if ds.deleteAllTarget == "" {
return errors.New("delete all is not supported by this system")
}

return ds.Post(ds.deleteAllTarget, nil)
}

// Collect collects a dump.
// dumptType is usually only "HGXLogDump".
// actionType is usually one of "Create", "Delete", "Download", or "Query".
func (ds *DumpService) Collect(dumpType, actionType string) error {
if ds.collectTarget == "" {
return errors.New("collect is not supported by this system")
}

return ds.Post(ds.collectTarget, map[string]any{
"DumpType": dumpType,
"ActionType": actionType,
})
}

// Dumps will get the Dumps from the service.
func (ds *DumpService) Dumps() ([]*Dump, error) {
return ListReferencedDumps(ds.GetClient(), ds.dumps)
}
105 changes: 105 additions & 0 deletions oem/smc/dumpservice_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//
// SPDX-License-Identifier: BSD-3-Clause
//

package smc

import (
"encoding/json"
"testing"
)

var dumpServiceBody = `{
"@odata.type": "#DumpService.v1_0_2.DumpService",
"@odata.id": "/redfish/v1/Oem/Supermicro/DumpService",
"Id": "DumpService",
"Name": "Dump Service",
"Description": "Dump Service",
"Dumps": {
"@odata.id": "/redfish/v1/Oem/Supermicro/DumpService/Dumps"
},
"Actions": {
"Oem": {},
"#SmcDumpService.CreateDump": {
"target": "/redfish/v1/Oem/Supermicro/DumpService/Actions/SmcDumpService.CreateDump",
"@Redfish.ActionInfo": "/redfish/v1/Oem/Supermicro/DumpService/CreateDumpActionInfo"
},
"#SmcDumpService.DeleteAll": {
"target": "/redfish/v1/Oem/Supermicro/DumpService/Actions/SmcDumpService.DeleteAll"
},
"#OemDumpService.Collect": {
"target": "/redfish/v1/Oem/Supermicro/DumpService/Actions/OemDumpService.Collect",
"@Redfish.ActionInfo": "/redfish/v1/Oem/Supermicro/DumpService/CollectActionInfo"
}
},
"@odata.etag": "\"697e2b05b6d5d49940bc0fd68803608b\""
}`

var dumpBody = `{
"@odata.type": "#Dump.v1_1_0.Dump",
"@odata.id": "/redfish/v1/Oem/Supermicro/DumpService/Dumps/AttestationDump",
"Id": "AttestationDump",
"Name": "AttestationDump",
"Description": "Supermicro Attestation Dump Service",
"AttestationFile": [
"attd_BS=OM243S046922_2024-09-18T18:10:52-07:00.bin",
"attd_BS=OM243S046922_MB_2024-05-23T13:54:08+08:00.bin"
],
"Actions": {
"Oem": {},
"#SmcAttestationDump.Generate": {
"target": "/redfish/v1/Oem/Supermicro/DumpService/Dumps/AttestationDump/Actions/SmcAttestationDump.Generate"
},
"#SmcAttestationDump.Download": {
"target": "/redfish/v1/Oem/Supermicro/DumpService/Dumps/AttestationDump/Actions/SmcAttestationDump.Download"
},
"#SmcAttestationDump.Delete": {
"target": "/redfish/v1/Oem/Supermicro/DumpService/Dumps/AttestationDump/Actions/SmcAttestationDump.Delete"
}
},
"@odata.etag": "\"0e25db1a4c2d3d4a28cda306e1b29abe\""
}`

// TestSmcDumpService tests the parsing of the DumpService oem field
func TestSmcDumpService(t *testing.T) {
ds := &DumpService{}
if err := json.Unmarshal([]byte(dumpServiceBody), ds); err != nil {
t.Fatalf("error decoding json: %v", err)
}

if ds.ID != "DumpService" {
t.Errorf("unexpected ID: %s", ds.ID)
}

if ds.collectTarget != "/redfish/v1/Oem/Supermicro/DumpService/Actions/OemDumpService.Collect" {
t.Errorf("unexpected install target: %s", ds.collectTarget)
}

if ds.createDumpTarget != "/redfish/v1/Oem/Supermicro/DumpService/Actions/SmcDumpService.CreateDump" {
t.Errorf("unexpected ssl cert link: %s", ds.createDumpTarget)
}

if ds.deleteAllTarget != "/redfish/v1/Oem/Supermicro/DumpService/Actions/SmcDumpService.DeleteAll" {
t.Errorf("unexpected ipmi config link: %s", ds.deleteAllTarget)
}

if ds.dumps != "/redfish/v1/Oem/Supermicro/DumpService/Dumps" {
t.Errorf("unexpected dumps link: %s", ds.dumps)
}
}

// TestSmcDump tests the parsing of the Dumpobject.
func TestSmcDump(t *testing.T) {
ds := &Dump{}
if err := json.Unmarshal([]byte(dumpBody), ds); err != nil {
t.Fatalf("error decoding json: %v", err)
}

if ds.ID != "AttestationDump" {
t.Errorf("unexpected ID: %s", ds.ID)
}

if len(ds.AttestationFile) != 2 {
t.Errorf("unexpected number of attestation files: %d", len(ds.AttestationFile))
}
}
4 changes: 2 additions & 2 deletions oem/smc/updateservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@ func GetUpdateService(c common.Client, uri string) (*UpdateService, error) {
return common.GetObject[UpdateService](c, uri)
}

// ActivateLicense performs the ActivateLicense action of the UpdateService.
// Install performs an install of an update.
func (us *UpdateService) Install(targets, installOptions []string) error {
if us.installTarget == "" {
return errors.New("Install is not supported by this system")
return errors.New("install is not supported by this system")
}

return us.Post(us.installTarget, map[string]any{
Expand Down
4 changes: 2 additions & 2 deletions oem/smc/updateservice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ var updateServiceBody = `{
"@odata.etag": "\"e9b94401dae9992fef2e71ef30cbcfdc\""
}`

// TestSmcUpdateServiceOem tests the parsing of the UpdateService oem field
func TestSmcUpdateServiceOem(t *testing.T) {
// TestSmcUpdateService tests the parsing of the UpdateService oem field
func TestSmcUpdateService(t *testing.T) {
us := &redfish.UpdateService{}
if err := json.Unmarshal([]byte(updateServiceBody), us); err != nil {
t.Fatalf("error decoding json: %v", err)
Expand Down

0 comments on commit aa597ec

Please sign in to comment.