Skip to content

Commit

Permalink
Fix system settings (#239)
Browse files Browse the repository at this point in the history
* feat: add settings to system

* fix: test for bios

* fix: linter for settings
  • Loading branch information
Danile71 authored Mar 1, 2023
1 parent 92eec8c commit 4f0b2dc
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 44 deletions.
45 changes: 3 additions & 42 deletions redfish/bios.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,6 @@ import (
"github.com/stmcginnis/gofish/common"
)

// BiosAttributes handles the Bios attribute values that may be any of several
// types and adds some basic helper methods to make accessing values easier.
type BiosAttributes map[string]interface{}

// String gets the string representation of the attribute value.
func (ba BiosAttributes) String(name string) string {
if val, ok := ba[name]; ok {
return fmt.Sprintf("%v", val)
}

return ""
}

// Float64 gets the value as a float64 or 0 if that is not possible.
func (ba BiosAttributes) Float64(name string) float64 {
if val, ok := ba[name]; ok {
return val.(float64)
}

return 0
}

// Int gets the value as an integer or 0 if that is not possible.
func (ba BiosAttributes) Int(name string) int {
// Integer values may be interpeted as float64, so get it as that first,
// then coerce down to int.
floatVal := int(ba.Float64(name))
return (floatVal)
}

// Bool gets the value as a boolean or returns false.
func (ba BiosAttributes) Bool(name string) bool {
maybeBool := ba.String(name)
maybeBool = strings.ToLower(maybeBool)
return (maybeBool == "true" ||
maybeBool == "1" ||
maybeBool == "enabled")
}

// Bios is used to represent BIOS attributes.
type Bios struct {
common.Entity
Expand All @@ -69,7 +30,7 @@ type Bios struct {
// that Attribute Registry by their attribute name. Attributes in this
// Attribute Registry with the AttributeType of Enumeration shall use valid
// ValueName values in this object, as listed in that Attribute Registry.
Attributes BiosAttributes
Attributes SettingsAttributes
// Attributes are additional properties in this object, and can be looked up
// in the Attribute Registry by their AttributeName.
// Attributes string
Expand Down Expand Up @@ -236,7 +197,7 @@ func (bios *Bios) AllowedAttributeUpdateApplyTimes() []common.ApplyTime {
}

// UpdateBiosAttributesApplyAt is used to update attribute values and set apply time together
func (bios *Bios) UpdateBiosAttributesApplyAt(attrs BiosAttributes, applyTime common.ApplyTime) error {
func (bios *Bios) UpdateBiosAttributesApplyAt(attrs SettingsAttributes, applyTime common.ApplyTime) error { //nolint:dupl
payload := make(map[string]interface{})

// Get a representation of the object's original state so we can find what
Expand Down Expand Up @@ -284,7 +245,7 @@ func (bios *Bios) UpdateBiosAttributesApplyAt(attrs BiosAttributes, applyTime co
}

// UpdateBiosAttributes is used to update attribute values.
func (bios *Bios) UpdateBiosAttributes(attrs BiosAttributes) error {
func (bios *Bios) UpdateBiosAttributes(attrs SettingsAttributes) error {
return bios.UpdateBiosAttributesApplyAt(attrs, "")
}

Expand Down
4 changes: 2 additions & 2 deletions redfish/bios_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func TestUpdateBiosAttributes(t *testing.T) {
testClient := &common.TestClient{}
result.SetClient(testClient)

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

if err != nil {
Expand Down Expand Up @@ -231,7 +231,7 @@ func TestUpdateBiosAttributesApplyAt(t *testing.T) {
testClient := &common.TestClient{}
result.SetClient(testClient)

update := BiosAttributes{"AssetTag": "test"}
update := SettingsAttributes{"AssetTag": "test"}
err = result.UpdateBiosAttributesApplyAt(update, common.AtMaintenanceWindowStartApplyTime)

if err != nil {
Expand Down
67 changes: 67 additions & 0 deletions redfish/computersystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"reflect"
"strings"

"github.com/stmcginnis/gofish/common"
)
Expand Down Expand Up @@ -541,6 +542,10 @@ type ComputerSystem struct {
SupportedResetTypes []ResetType
// setDefaultBootOrderTarget is the URL to send SetDefaultBootOrder actions to.
setDefaultBootOrderTarget string
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
// ManagedBy An array of references to the Managers responsible for this system.
// This is temporary until a proper method can be implemented to actually
// retrieve those objects directly.
Expand Down Expand Up @@ -578,6 +583,7 @@ func (computersystem *ComputerSystem) UnmarshalJSON(b []byte) error {
PCIeDevices common.Links
PCIeFunctions common.Links
Links CSLinks
Settings common.Settings `json:"@Redfish.Settings"`
}

err := json.Unmarshal(b, &t)
Expand Down Expand Up @@ -605,6 +611,14 @@ func (computersystem *ComputerSystem) UnmarshalJSON(b []byte) error {
computersystem.SupportedResetTypes = t.Actions.ComputerSystemReset.AllowedResetTypes
computersystem.setDefaultBootOrderTarget = t.Actions.SetDefaultBootOrder.Target
computersystem.ManagedBy = t.Links.ManagedBy.ToStrings()
computersystem.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.
computersystem.settingsTarget = t.Settings.SettingsObject.String()
if computersystem.settingsTarget == "" {
computersystem.settingsTarget = computersystem.ODataID
}

// This is a read/write object, so we need to save the raw object data for later
computersystem.rawData = b
Expand Down Expand Up @@ -860,6 +874,59 @@ func (computersystem *ComputerSystem) Reset(resetType ResetType) error {
return computersystem.Post(computersystem.resetTarget, t)
}

// UpdateBootAttributesApplyAt is used to update attribute values and set apply time together
func (computersystem *ComputerSystem) UpdateBootAttributesApplyAt(attrs SettingsAttributes, applyTime common.ApplyTime) error { //nolint:dupl
payload := make(map[string]interface{})

// Get a representation of the object's original state so we can find what
// to update.
original := new(Bios)
err := original.UnmarshalJSON(computersystem.rawData)
if err != nil {
return err
}

for key := range attrs {
if strings.HasPrefix(key, "BootTypeOrder") ||
original.Attributes[key] != attrs[key] {
payload[key] = attrs[key]
}
}

resp, err := computersystem.Client.Get(computersystem.settingsTarget)
if err != nil {
return err
}
defer resp.Body.Close()

// 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{}{"Boot": payload}
if applyTime != "" {
data["@Redfish.SettingsApplyTime"] = map[string]string{"ApplyTime": string(applyTime)}
}

var header = make(map[string]string)
if resp.Header["Etag"] != nil {
header["If-Match"] = resp.Header["Etag"][0]
}

resp, err = computersystem.Client.PatchWithHeaders(computersystem.settingsTarget, data, header)
if err != nil {
return err
}
defer resp.Body.Close()
}

return nil
}

// UpdateBootAttributes is used to update attribute values.
func (computersystem *ComputerSystem) UpdateBootAttributes(attrs SettingsAttributes) error {
return computersystem.UpdateBootAttributesApplyAt(attrs, "")
}

// SetDefaultBootOrder shall set the BootOrder array to the default settings.
func (computersystem *ComputerSystem) SetDefaultBootOrder() error {
// This action wasn't added until 1.5.0, make sure this is supported.
Expand Down
49 changes: 49 additions & 0 deletions redfish/settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// SPDX-License-Identifier: BSD-3-Clause
//

package redfish

import (
"fmt"
"strings"
)

// SettingsAttributes handles the settings attribute values that may be any of several
// types and adds some basic helper methods to make accessing values easier.
type SettingsAttributes map[string]interface{}

// String gets the string representation of the attribute value.
func (ba SettingsAttributes) String(name string) string {
if val, ok := ba[name]; ok {
return fmt.Sprintf("%v", val)
}

return ""
}

// Float64 gets the value as a float64 or 0 if that is not possible.
func (ba SettingsAttributes) Float64(name string) float64 {
if val, ok := ba[name]; ok {
return val.(float64)
}

return 0
}

// Int gets the value as an integer or 0 if that is not possible.
func (ba SettingsAttributes) Int(name string) int {
// Integer values may be interpeted as float64, so get it as that first,
// then coerce down to int.
floatVal := int(ba.Float64(name))
return (floatVal)
}

// Bool gets the value as a boolean or returns false.
func (ba SettingsAttributes) Bool(name string) bool {
maybeBool := ba.String(name)
maybeBool = strings.ToLower(maybeBool)
return (maybeBool == "true" ||
maybeBool == "1" ||
maybeBool == "enabled")
}

0 comments on commit 4f0b2dc

Please sign in to comment.