Skip to content

Commit

Permalink
Merge pull request #81 from stmcginnis/BiosSettings
Browse files Browse the repository at this point in the history
Add ability to set Bios attributes
  • Loading branch information
stmcginnis authored Aug 20, 2020
2 parents 9791c57 + 6f96df6 commit a93a78e
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 10 deletions.
4 changes: 2 additions & 2 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ type OperationApplyTimeSupport struct {
type PreferredApplyTime struct {
// ApplyTime shall indicate the preference
// on to when to apply the values in this Settings resource.
ApplyTime string
ApplyTime ApplyTime
// MaintenanceWindowDurationInSeconds shall
// indicate the end of the maintenance window as the number of seconds
// after the time specified by the MaintenanceWindowStartTime property.
Expand Down Expand Up @@ -688,7 +688,7 @@ type Settings struct {
Messages []Message
// SettingsObject shall be the URI of the resource to which a client must do
// a PUT or PATCH in order to modify this resource.
SettingsObject string
SettingsObject Link
// SupportedApplyTimes is A service shall advertise its applytime
// capabilities using this property as to when a Setting resource can be
// applied.
Expand Down
65 changes: 64 additions & 1 deletion redfish/bios.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ type Bios struct {
changePasswordTarget string
// resetBiosTarget is the URL to send ResetBios requests.
resetBiosTarget string
// settingsTarget is the URL to send settings update requests to.
settingsTarget string
// settingsApplyTimes is a set of allowed settings update apply times. If none
// are specified, then the system does not provide that information.
settingsApplyTimes []common.ApplyTime
// rawData holds the original serialized JSON so we can compare updates.
rawData []byte
}

// UnmarshalJSON unmarshals an Bios object from the raw JSON.
Expand All @@ -94,7 +101,8 @@ func (bios *Bios) UnmarshalJSON(b []byte) error {
}
var t struct {
temp
Actions Actions
Actions Actions
Settings common.Settings `json:"@Redfish.Settings"`
}

err := json.Unmarshal(b, &t)
Expand All @@ -107,6 +115,17 @@ func (bios *Bios) UnmarshalJSON(b []byte) error {
// Extract the links to other entities for later
bios.changePasswordTarget = t.Actions.ChangePassword.Target
bios.resetBiosTarget = t.Actions.ResetBios.Target
bios.settingsApplyTimes = t.Settings.SupportedApplyTimes

// Some implementations use a @Redfish.Settings object to direct settings updates to a
// different URL than the object being updated. Others don't, so handle both.
bios.settingsTarget = string(t.Settings.SettingsObject)
if bios.settingsTarget == "" {
bios.settingsTarget = bios.ODataID
}

// This is a read/write object, so we need to save the raw object data for later
bios.rawData = b

return nil
}
Expand Down Expand Up @@ -186,3 +205,47 @@ func (bios *Bios) ResetBios() error {
_, err := bios.Client.Post(bios.resetBiosTarget, nil)
return err
}

// AllowedAttributeUpdateApplyTimes returns the set of allowed apply times to request when
// setting the Bios attribute values.
func (bios *Bios) AllowedAttributeUpdateApplyTimes() []common.ApplyTime {
if len(bios.settingsApplyTimes) == 0 {
result := []common.ApplyTime{
common.ImmediateApplyTime,
common.OnResetApplyTime,
common.AtMaintenanceWindowStartApplyTime,
common.InMaintenanceWindowOnResetApplyTime,
}
return result
}
return bios.settingsApplyTimes
}

// UpdateBiosAttributes is used to update attribute values.
func (bios *Bios) UpdateBiosAttributes(attrs BiosAttributes) error {

payload := make(map[string]interface{})

// Get a representation of the object's original state so we can find what
// to update.
original := new(Bios)
original.UnmarshalJSON(bios.rawData)

for key := range attrs {
if original.Attributes[key] != attrs[key] {
payload[key] = attrs[key]
}
}

// If there are any allowed updates, try to send updates to the system and
// return the result.
if len(payload) > 0 {
data := map[string]interface{}{"Attributes": payload}
_, err := bios.Client.Patch(bios.settingsTarget, data)
if err != nil {
return err
}
}

return nil
}
122 changes: 115 additions & 7 deletions redfish/bios_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,29 @@ import (
"encoding/json"
"strings"
"testing"

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

var biosBody = strings.NewReader(
`{
var biosBody = `{
"@Redfish.Settings": {
"@odata.context": "/redfish/v1/$metadata#Settings.Settings",
"@odata.type": "#Settings.v1_2_1.Settings",
"SettingsObject": {
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Bios/Settings"
},
"SupportedApplyTimes": [
"OnReset",
"AtMaintenanceWindowStart",
"InMaintenanceWindowOnReset"
]
},
"@odata.type": "#Bios.v1_0_6.Bios",
"@odata.context": "/redfish/v1/$metadata#Bios.Bios",
"@odata.id": "/redfish/v1/Systems/437XR1138R2/BIOS",
"Id": "BIOS",
"Name": "BIOS Configuration Current Settings",
"Description": "BIOS Settings",
"Name": "BIOS Configuration Current Attributes",
"Description": "BIOS Attributes",
"AttributeRegistry": "BiosAttributeRegistryP89.v1_0_0",
"Attributes": {
"AdminPhone": "",
Expand All @@ -42,12 +55,45 @@ var biosBody = strings.NewReader(
"target": "/redfish/v1/Systems/437XR1138R2/BIOS/Actions/Bios.ChangePassword"
}
}
}`)
}`

var biosNoAttributesBody = `{
"@odata.type": "#Bios.v1_0_6.Bios",
"@odata.context": "/redfish/v1/$metadata#Bios.Bios",
"@odata.id": "/redfish/v1/Systems/437XR1138R2/BIOS",
"Id": "BIOS",
"Name": "BIOS Configuration Current Attributes",
"Description": "BIOS Attributes",
"AttributeRegistry": "BiosAttributeRegistryP89.v1_0_0",
"Attributes": {
"AdminPhone": "",
"BootMode": "Uefi",
"EmbeddedSata": "Raid",
"NicBoot1": "NetworkBoot",
"NicBoot2": "Disabled",
"PowerProfile": "MaxPerf",
"ProcCoreDisable": 3,
"ProcHyperthreading": "Enabled",
"ProcTurboMode": "Enabled",
"UsbControl": "UsbEnabled",
"BoolTest1": "True",
"BoolTest2": 1,
"BoolTest3": "NotBool"
},
"Actions": {
"#Bios.ResetBios": {
"target": "/redfish/v1/Systems/437XR1138R2/BIOS/Actions/Bios.ResetBios"
},
"#Bios.ChangePassword": {
"target": "/redfish/v1/Systems/437XR1138R2/BIOS/Actions/Bios.ChangePassword"
}
}
}`

// TestBios tests the parsing of Bios objects.
func TestBios(t *testing.T) {
var result Bios
err := json.NewDecoder(biosBody).Decode(&result)
err := json.NewDecoder(strings.NewReader(biosBody)).Decode(&result)

if err != nil {
t.Errorf("Error decoding JSON: %s", err)
Expand All @@ -57,7 +103,7 @@ func TestBios(t *testing.T) {
t.Errorf("Received invalid ID: %s", result.ID)
}

if result.Name != "BIOS Configuration Current Settings" {
if result.Name != "BIOS Configuration Current Attributes" {
t.Errorf("Received invalid name: %s", result.Name)
}

Expand Down Expand Up @@ -96,4 +142,66 @@ func TestBios(t *testing.T) {
if result.Attributes.Bool("BoolTest3") {
t.Errorf("Expected False boolean value for 'BoolTest3': %v", result.Attributes["BoolTest1"])
}

if len(result.settingsApplyTimes) != 3 {
t.Errorf("Invalid settings support apply times: %s", result.settingsApplyTimes)
}
}

// TestBiosAttributes tests the parsing of Bios objects @Redfish.Attributes.
func TestBiosAttributes(t *testing.T) {
var result Bios
err := json.NewDecoder(strings.NewReader(biosBody)).Decode(&result)

if err != nil {
t.Errorf("Error decoding JSON: %s", err)
}

if result.settingsTarget != "/redfish/v1/Systems/System.Embedded.1/Bios/Settings" {
t.Errorf("Invalid settings update target: %s", result.settingsTarget)
}
}

// TestBiosNoAttributes tests the parsing of Bios objects without @Redfish.Attributes.
func TestBiosNoAttributes(t *testing.T) {
var result Bios
err := json.NewDecoder(strings.NewReader(biosNoAttributesBody)).Decode(&result)

if err != nil {
t.Errorf("Error decoding JSON: %s", err)
}

if result.settingsTarget != "/redfish/v1/Systems/437XR1138R2/BIOS" {
t.Errorf("Invalid settings update target: %s", result.settingsTarget)
}
}

// TestUpdateBiosAttributes tests the UpdateBiosAttributes call.
func TestUpdateBiosAttributes(t *testing.T) {
var result Bios
err := json.NewDecoder(strings.NewReader(biosBody)).Decode(&result)

if err != nil {
t.Errorf("Error decoding JSON: %s", err)
}

testClient := &common.TestClient{}
result.SetClient(testClient)

update := BiosAttributes{"AssetTag": "test"}
err = result.UpdateBiosAttributes(update)

if err != nil {
t.Errorf("Error making UpdateBiosAttributes call: %s", err)
}

calls := testClient.CapturedCalls()

if len(calls) != 1 {
t.Errorf("Expected one call to be made, captured: %v", calls)
}

if !strings.Contains(calls[0].Payload, "AssetTag") {
t.Errorf("Unexpected update payload: %s", calls[0].Payload)
}
}

0 comments on commit a93a78e

Please sign in to comment.