Skip to content

Commit

Permalink
VendorConfigManager implementations for dell, supermicro and asrockrack
Browse files Browse the repository at this point in the history
  • Loading branch information
splaspood committed Dec 14, 2023
1 parent 5eb9915 commit b2f1dac
Show file tree
Hide file tree
Showing 5 changed files with 410 additions and 0 deletions.
112 changes: 112 additions & 0 deletions config/asrockrack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package config

import (
"encoding/xml"
"strings"
)

type asrockrackVendorConfig struct {
ConfigFormat string
ConfigData *asrockrackConfig
}

type asrockrackConfig struct {
BiosCfg *asrockrackBiosCfg `xml:"BiosCfg"`
}

type asrockrackBiosCfg struct {
XMLName xml.Name `xml:"BiosCfg"`
Menus []*asrockrackBiosCfgMenu `xml:"Menu"`
}

type asrockrackBiosCfgMenu struct {
XMLName xml.Name `xml:"Menu"`
Name string `xml:"name,attr"`
Settings []*asrockrackBiosCfgSetting `xml:"Setting"`
Menus []*asrockrackBiosCfgMenu `xml:"Menu"`
}

type asrockrackBiosCfgSetting struct {
XMLName xml.Name `xml:"Setting"`
Name string `xml:"Name,attr"`
Order string `xml:"order,attr"`
SelectedOption string `xml:"selectedOption,attr"`
Type string `xml:"type,attr"`
}

func NewAsrockrackVendorConfigManager(configFormat string) (VendorConfigManager, error) {
asrr := &asrockrackVendorConfig{}

switch strings.ToLower(configFormat) {
case "json":
asrr.ConfigFormat = strings.ToLower(configFormat)
default:
return nil, UnknownConfigFormatError(strings.ToLower(configFormat))
}

asrr.ConfigData = &asrockrackConfig{
BiosCfg: &asrockrackBiosCfg{},
}

return asrr, nil
}

// FindMenu locates an existing asrockrackBiosCfgMenu if one exists in the ConfigData, if not
// it creates one and returns a pointer to that.
func (cm *asrockrackVendorConfig) FindMenu(menuName string) (m *asrockrackBiosCfgMenu) {
for _, m = range cm.ConfigData.BiosCfg.Menus {
if m.Name == menuName {
return
}
}

m.Name = menuName

cm.ConfigData.BiosCfg.Menus = append(cm.ConfigData.BiosCfg.Menus, m)

return
}

// FindMenuSetting locates an existing asrockrackBiosCfgSetting if one exists in the
// ConfigData, if not it creates one and returns a pointer to that.
func (cm *asrockrackVendorConfig) FindMenuSetting(m *asrockrackBiosCfgMenu, name string) (s *asrockrackBiosCfgSetting) {
for _, s = range m.Settings {
if s.Name == name {
return
}
}

s.Name = name

m.Settings = append(m.Settings, s)

return
}

// TODO(jwb) How do we handle the random nature of sub menus here.. we could make the user pass the explicit pointer to a menu struct, or..
func (cm *asrockrackVendorConfig) Raw(name, value string, menuPath []string) {
}

func (cm *asrockrackVendorConfig) Marshal() (string, error) {
switch strings.ToLower(cm.ConfigFormat) {
case "xml":
x, err := xml.Marshal(cm.ConfigData)
if err != nil {
return "", err
}

return string(x), nil
default:
return "", UnknownConfigFormatError(strings.ToLower(cm.ConfigFormat))
}
}

// Generic config options

func (cm *asrockrackVendorConfig) EnableTPM() {
// Unimplemented
}

func (cm *asrockrackVendorConfig) EnableSRIOV() {
// Unimplemented
}
126 changes: 126 additions & 0 deletions config/dell.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package config

import (
"encoding/json"
"encoding/xml"
"strings"
)

type dellVendorConfig struct {
ConfigFormat string
ConfigData *dellConfig
}

type dellConfig struct {
SystemConfiguration *dellSystemConfiguration `xml:"SystemConfiguration" json:"SystemConfiguration"`
}

type dellSystemConfiguration struct {
XMLName xml.Name `xml:"SystemConfiguration"`
Model string `xml:"Model,attr" json:"Model"`
Comments []string `xml:"Comments>Comment,omitempty" json:"Comments,omitempty" `
ServiceTag string `xml:"ServiceTag,attr" json:"ServiceTag"`
TimeStamp string `xml:"TimeStamp,attr" json:"TimeStamp"`
Components []*dellComponent `xml:"Component" json:"Components"`
}

type dellComponent struct {
XMLName xml.Name `xml:"Component"`
FQDD string `xml:"FQDD,attr" json:"FQDD"`
Attributes []*dellComponentAttribute `xml:"Attribute" json:"Attributes"`
}

type dellComponentAttribute struct {
XMLName xml.Name `xml:"Attribute"`
Name string `xml:"Name,attr" json:"Name"`
SetOnImport bool `json:"SetOnImport"`
Comment string `json:"Comment"`
Value string `xml:",chardata" json:"Value"`
}

func NewDellVendorConfigManager(configFormat string) (VendorConfigManager, error) {
dell := &dellVendorConfig{}

switch strings.ToLower(configFormat) {
case "xml", "json":
dell.ConfigFormat = strings.ToLower(configFormat)
default:
return nil, UnknownConfigFormatError(strings.ToLower(configFormat))
}

dell.ConfigData = &dellConfig{
SystemConfiguration: &dellSystemConfiguration{},
}

return dell, nil
}

// FindComponent locates an existing DellComponent if one exists in the ConfigData, if not
// it creates one and returns a pointer to that.
func (cm *dellVendorConfig) FindComponent(fqdd string) (c *dellComponent) {
for _, c = range cm.ConfigData.SystemConfiguration.Components {
if c.FQDD == fqdd {
return
}
}

c.FQDD = fqdd

cm.ConfigData.SystemConfiguration.Components = append(cm.ConfigData.SystemConfiguration.Components, c)

return
}

// FindComponentAttribute locates an existing DellComponentAttribute if one exists in the
// ConfigData, if not it creates one and returns a pointer to that.
func (cm *dellVendorConfig) FindComponentAttribute(c *dellComponent, name string) (a *dellComponentAttribute) {
for _, a = range c.Attributes {
if a.Name == name {
return
}
}

a.Name = name

c.Attributes = append(c.Attributes, a)

return
}

func (cm *dellVendorConfig) Raw(name, value string, menuPath []string) {
c := cm.FindComponent(menuPath[0])
attr := cm.FindComponentAttribute(c, name)
attr.Value = value
}

func (cm *dellVendorConfig) Marshal() (string, error) {
switch strings.ToLower(cm.ConfigFormat) {
case "xml":
x, err := xml.Marshal(cm.ConfigData)
if err != nil {
return "", err
}

return string(x), nil
case "json":
x, err := json.Marshal(cm.ConfigData)
if err != nil {
return "", err
}

return string(x), nil
default:
return "", UnknownConfigFormatError(strings.ToLower(cm.ConfigFormat))
}
}

// Generic config options

func (cm *dellVendorConfig) EnableTPM() {
cm.Raw("EnableTPM", "Enabled", []string{"BIOS.Setup.1-1"})
}

func (cm *dellVendorConfig) EnableSRIOV() {
// TODO(jwb) How do we want to handle enabling this for different NICs
cm.Raw("VirtualizationMode", "SRIOV", []string{"NIC.Slot.3-1-1"})
}
17 changes: 17 additions & 0 deletions config/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package config

import (
"errors"
"fmt"
)

var errUnknownConfigFormat = errors.New("unknown config format")
var errUnknownVendor = errors.New("unknown/unsupported vendor")

func UnknownConfigFormatError(format string) error {
return fmt.Errorf("unknown config format %w : %s", errUnknownConfigFormat, format)
}

func UnknownVendorError(vendorName string) error {
return fmt.Errorf("unknown/unsupported vendor %w : %s", errUnknownVendor, vendorName)
}
28 changes: 28 additions & 0 deletions config/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package config

import (
"strings"

"github.com/bmc-toolbox/common"
)

type VendorConfigManager interface {
EnableTPM()
EnableSRIOV()

Raw(name, value string, menuPath []string)
Marshal() (string, error)
}

func NewVendorConfigManager(configFormat, vendorName string) (VendorConfigManager, error) {
switch strings.ToLower(vendorName) {
case common.VendorDell:
return NewDellVendorConfigManager(configFormat)
case common.VendorSupermicro:
return NewSupermicroVendorConfigManager(configFormat)
case common.VendorAsrockrack:
return NewAsrockrackVendorConfigManager(configFormat)
default:
return nil, UnknownVendorError(strings.ToLower(vendorName))
}
}
Loading

0 comments on commit b2f1dac

Please sign in to comment.