Skip to content
Closed
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
77 changes: 77 additions & 0 deletions oem/nvidia/mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// SPDX-License-Identifier: BSD-3-Clause
//

package nvidia

import (
"context"
"encoding/json"
"errors"

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

// ModeValue is the operating mode reported by the NVIDIA DPU OEM mode resource.
type ModeValue string

const (
// DPUMode configures the device as a DPU.
DPUMode ModeValue = "DpuMode"
// NICMode configures the device as a NIC.
NICMode ModeValue = "NicMode"
)

// Mode is the NVIDIA OEM mode resource for a DPU system.
type Mode struct {
common.Entity

Mode ModeValue

setTarget string
}

// UnmarshalJSON unmarshals a Mode object from the raw JSON.
func (m *Mode) UnmarshalJSON(b []byte) error {
type temp Mode
var t struct {
temp
Actions struct {
Set common.ActionTarget `json:"#Mode.Set"`
}
}

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

*m = Mode(t.temp)
m.setTarget = t.Actions.Set.Target

return nil
}

// GetMode will get the Mode instance from the service.
func GetMode(c common.Client, uri string, queryOpts ...common.QueryGroupOption) (*Mode, error) {
return GetModeWithContext(common.ContextOf(c), c, uri, queryOpts...)
}

// GetModeWithContext will get the Mode instance from the service.
func GetModeWithContext(ctx context.Context, c common.Client, uri string, queryOpts ...common.QueryGroupOption) (*Mode, error) {
return common.GetObjectWithContext[Mode](ctx, c, uri, queryOpts...)
}

// SetMode performs the Mode.Set action.
func (m *Mode) SetMode(mode ModeValue) error {
return m.SetModeWithContext(common.ContextOf(m.GetClient()), mode)
}

// SetModeWithContext performs the Mode.Set action.
func (m *Mode) SetModeWithContext(ctx context.Context, mode ModeValue) error {
if m.setTarget == "" {
return errors.New("Mode.Set is not supported by this system")
}

return m.PostWithContext(ctx, m.setTarget, map[string]any{"Mode": mode})
}
83 changes: 83 additions & 0 deletions oem/nvidia/mode_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//
// SPDX-License-Identifier: BSD-3-Clause
//

package nvidia

import (
"encoding/json"
"net/http"
"strings"
"testing"

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

const modeBody = `{
"@odata.id": "/redfish/v1/Systems/Bluefield/Oem/Nvidia",
"@odata.type": "#NvidiaMode.v1_0_0.Mode",
"Id": "Nvidia",
"Mode": "NicMode",
"Actions": {
"#Mode.Set": {
"target": "/redfish/v1/Systems/Bluefield/Oem/Nvidia/Actions/AdvertisedMode.Set",
"@Redfish.ActionInfo": "/redfish/v1/Systems/Bluefield/Oem/Nvidia/ModeSetActionInfo"
}
}
}`

func TestModeUnmarshal(t *testing.T) {
var mode Mode
if err := json.Unmarshal([]byte(modeBody), &mode); err != nil {
t.Fatal(err)
}

if mode.Mode != NICMode {
t.Fatalf("Mode = %q, want %q", mode.Mode, NICMode)
}
if mode.setTarget != "/redfish/v1/Systems/Bluefield/Oem/Nvidia/Actions/AdvertisedMode.Set" {
t.Fatalf("setTarget = %q", mode.setTarget)
}
}

func TestModeSetMode(t *testing.T) {
client := &common.TestClient{
CustomReturnForActions: map[string][]interface{}{
http.MethodPost: {
&http.Response{StatusCode: http.StatusOK, Body: http.NoBody},
},
},
}
mode := &Mode{setTarget: "/redfish/v1/Systems/Bluefield/Oem/Nvidia/Actions/AdvertisedMode.Set"}
mode.SetClient(client)

if err := mode.SetMode(DPUMode); err != nil {
t.Fatal(err)
}

calls := client.CapturedCalls()
if len(calls) != 1 {
t.Fatalf("calls = %d, want 1", len(calls))
}
if calls[0].Action != http.MethodPost {
t.Fatalf("Action = %q, want %q", calls[0].Action, http.MethodPost)
}
if calls[0].URL != "/redfish/v1/Systems/Bluefield/Oem/Nvidia/Actions/AdvertisedMode.Set" {
t.Fatalf("URL = %q", calls[0].URL)
}
if !strings.Contains(calls[0].Payload, "Mode:DpuMode") {
t.Fatalf("Payload = %q", calls[0].Payload)
}
}

func TestModeSetModeRequiresActionTarget(t *testing.T) {
mode := &Mode{}

err := mode.SetMode(DPUMode)
if err == nil {
t.Fatal("SetMode succeeded without an action target")
}
if err.Error() != "Mode.Set is not supported by this system" {
t.Fatalf("error = %q", err)
}
}