Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Supermicro DumpService object #376

Merged
merged 1 commit into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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