Skip to content

Commit

Permalink
Merge pull request #12 from bmc-toolbox/hw-config-0
Browse files Browse the repository at this point in the history
VendorConfigManager implementations for dell, supermicro and asrockrack
  • Loading branch information
splaspood authored Apr 15, 2024
2 parents 7bcbcca + 3a648b8 commit 268411c
Show file tree
Hide file tree
Showing 5 changed files with 428 additions and 0 deletions.
116 changes: 116 additions & 0 deletions config/asrockrack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
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, vendorOptions map[string]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) {
if cm.ConfigData.BiosCfg.Menus == nil {
return
}

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
}
141 changes: 141 additions & 0 deletions config/dell.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
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 `xml:"SetOnImport,omitempty" json:"SetOnImport,omitempty"`
Comment string `xml:"Comment,omitempty" json:"Comment,omitempty"`
Value string `xml:",chardata" json:"Value"`
}

func NewDellVendorConfigManager(configFormat string, vendorOptions map[string]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{},
}

dell.setSystemConfiguration(vendorOptions["model"], vendorOptions["servicetag"])

return dell, nil
}

func (cm *dellVendorConfig) setSystemConfiguration(model, servicetag string) {
cm.ConfigData.SystemConfiguration.Model = model
cm.ConfigData.SystemConfiguration.ServiceTag = servicetag
// TODO(jwb) Make this 'now'
cm.ConfigData.SystemConfiguration.TimeStamp = "Tue Nov 2 21:19:16 2021"
}

// 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 = &dellComponent{
XMLName: xml.Name{},
FQDD: fqdd,
Attributes: []*dellComponentAttribute{},
}

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 = &dellComponentAttribute{
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.SystemConfiguration)
if err != nil {
return "", err
}

return string(x), nil
case "json":
x, err := json.Marshal(cm.ConfigData.SystemConfiguration)
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, vendorOptions map[string]string) (VendorConfigManager, error) {
switch strings.ToLower(vendorName) {
case common.VendorDell:
return NewDellVendorConfigManager(configFormat, vendorOptions)
case common.VendorSupermicro:
return NewSupermicroVendorConfigManager(configFormat, vendorOptions)
case common.VendorAsrockrack:
return NewAsrockrackVendorConfigManager(configFormat, vendorOptions)
default:
return nil, UnknownVendorError(strings.ToLower(vendorName))
}
}
Loading

0 comments on commit 268411c

Please sign in to comment.