diff --git a/config/asrockrack/asrockrack.go b/config/asrockrack/asrockrack.go new file mode 100644 index 0000000..6c5fcd8 --- /dev/null +++ b/config/asrockrack/asrockrack.go @@ -0,0 +1,121 @@ +package config + +import ( + "github.com/bmc-toolbox/common/config" + + "encoding/xml" + "errors" + "strings" +) + +var errUnknownConfigFormat = errors.New("unknown config format") + +type ASRockRackVendorConfigManager 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 New(configFormat string) (config.VendorConfigManager, error) { + asrr := &ASRockRackVendorConfigManager{} + + switch strings.ToLower(configFormat) { + case "json": + asrr.ConfigFormat = strings.ToLower(configFormat) + default: + return nil, errors.New("unknown config format") + } + + 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 *ASRockRackVendorConfigManager) 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 *ASRockRackVendorConfigManager) 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 *ASRockRackVendorConfigManager) Raw(name, value string, menuPath []string) { + // c := cm.FindComponent(fqdd) + // attr := cm.FindComponentAttribute(c, name) + // attr.Value = value + // return nil +} + +func (cm *ASRockRackVendorConfigManager) 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 "", errUnknownConfigFormat + } +} + +// Generic config options + +func (cm *ASRockRackVendorConfigManager) EnableTPM() { + // Unimplemented +} + +func (cm *ASRockRackVendorConfigManager) EnableSRIOV() { + // Unimplemented +} diff --git a/config/dell/dell.go b/config/dell/dell.go new file mode 100644 index 0000000..6024dfc --- /dev/null +++ b/config/dell/dell.go @@ -0,0 +1,131 @@ +package dell + +import ( + "github.com/bmc-toolbox/common/config" + + "encoding/json" + "encoding/xml" + "errors" + "strings" +) + +var errUnknownConfigFormat = errors.New("unknown config format") + +type dellVendorConfigManager 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 New(configFormat string) (config.VendorConfigManager, error) { + dell := &dellVendorConfigManager{} + + switch strings.ToLower(configFormat) { + case "xml", "json": + dell.ConfigFormat = strings.ToLower(configFormat) + default: + return nil, errors.New("unknown config format") + } + + 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 *dellVendorConfigManager) 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 *dellVendorConfigManager) 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 *dellVendorConfigManager) Raw(name, value string, menuPath []string) { + c := cm.FindComponent(menuPath[0]) + attr := cm.FindComponentAttribute(c, name) + attr.Value = value +} + +func (cm *dellVendorConfigManager) 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 "", errUnknownConfigFormat + } +} + +// Generic config options + +func (cm *dellVendorConfigManager) EnableTPM() { + cm.Raw("EnableTPM", "Enabled", []string{"BIOS.Setup.1-1"}) +} + +func (cm *dellVendorConfigManager) EnableSRIOV() { + // TODO(jwb) How do we want to handle enabling this for different NICs + cm.Raw("VirtualizationMode", "SRIOV", []string{"NIC.Slot.3-1-1"}) +} diff --git a/config/interface.go b/config/interface.go new file mode 100644 index 0000000..7503bff --- /dev/null +++ b/config/interface.go @@ -0,0 +1,9 @@ +package config + +type VendorConfigManager interface { + EnableTPM() + EnableSRIOV() + + Raw(name, value string, menuPath []string) + Marshal() (string, error) +} diff --git a/config/supermicro/supermicro.go b/config/supermicro/supermicro.go new file mode 100644 index 0000000..0493301 --- /dev/null +++ b/config/supermicro/supermicro.go @@ -0,0 +1,132 @@ +package config + +import ( + "encoding/xml" + "errors" + "strings" + + "github.com/bmc-toolbox/common/config" +) + +var errUnknownConfigFormat = errors.New("unknown config format") + +type SupermicroVendorConfigManager struct { + ConfigFormat string + ConfigData *SupermicroConfig +} + +type SupermicroConfig struct { + BiosCfg *SupermicroBiosCfg `xml:"BiosCfg"` +} + +type SupermicroBiosCfg struct { + XMLName xml.Name `xml:"BiosCfg"` + Menus []*SupermicroBiosCfgMenu `xml:"Menu"` +} + +type SupermicroBiosCfgMenu struct { + XMLName xml.Name `xml:"Menu"` + Name string `xml:"name,attr"` + Settings []*SupermicroBiosCfgSetting `xml:"Setting"` + Menus []*SupermicroBiosCfgMenu `xml:"Menu"` +} + +type SupermicroBiosCfgSetting 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 New(configFormat string) (config.VendorConfigManager, error) { + supermicro := &SupermicroVendorConfigManager{} + + switch strings.ToLower(configFormat) { + case "xml": + supermicro.ConfigFormat = strings.ToLower(configFormat) + default: + return nil, errors.New("unknown config format") + } + + supermicro.ConfigData = &SupermicroConfig{ + BiosCfg: &SupermicroBiosCfg{}, + } + + return supermicro, nil +} + +// FindMenu locates an existing SupermicroBiosCfgMenu if one exists in the ConfigData, if not +// it creates one and returns a pointer to that. +func (cm *SupermicroVendorConfigManager) FindMenu(menuName string, menuRoot *SupermicroBiosCfgMenu) (m *SupermicroBiosCfgMenu) { + // root is cm.ConfigData.BiosCfg.Menus + for _, m = range menuRoot.Menus { + if m.Name == menuName { + return + } + } + + m.Name = menuName + + menuRoot.Menus = append(menuRoot.Menus, m) + + return +} + +// FindMenuSetting locates an existing SupermicroBiosCfgSetting if one exists in the +// ConfigData, if not it creates one and returns a pointer to that. +func (cm *SupermicroVendorConfigManager) FindMenuSetting(m *SupermicroBiosCfgMenu, name string) (s *SupermicroBiosCfgSetting) { + 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 *SupermicroVendorConfigManager) Raw(name, value string, menuPath []string) { + var menus []*SupermicroBiosCfgMenu + + for i, name := range menuPath { + var m *SupermicroBiosCfgMenu + + if i == 0 { + m = cm.FindMenu(name, cm.ConfigData.BiosCfg.Menus[0]) + } else { + m = cm.FindMenu(name, menus[i-1]) + } + + menus = append(menus, m) + } +} + +func (cm *SupermicroVendorConfigManager) 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 "", errUnknownConfigFormat + } +} + +// Generic config options + +func (cm *SupermicroVendorConfigManager) EnableTPM() { + cm.Raw(" Security Device Support", "Enable", []string{"Trusted Computing"}) + cm.Raw(" SHA-1 PCR Bank", "Enabled", []string{"Trusted Computing"}) +} + +func (cm *SupermicroVendorConfigManager) EnableSRIOV() { + cm.Raw("SR-IOV Support", "Enabled", []string{"Advanced", "PCIe/PCI/PnP Configuration"}) +}