use reflect on overlays

This commit is contained in:
Christian Goll
2022-08-10 15:29:55 +02:00
parent 41d12888ab
commit 8c2d40881d
6 changed files with 157 additions and 104 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"os"
"sort"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/node"
@@ -177,7 +178,7 @@ func NodeList(nodeNames []string) (nodeInfo []*wwapiv1.NodeInfo, err error) {
}
nodeNames = hostlist.Expand(nodeNames)
sort.Strings(nodeNames)
// Translate to the protobuf structure so wwapiv1 can use this across the wire.
// This is the same logic as was in wwctl.
for _, n := range node.FilterByName(nodes, nodeNames) {

View File

@@ -87,7 +87,7 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) {
node.Tags[keyname] = key
delete(node.Keys, keyname)
}
n.setFrom(node)
n.SetFrom(node)
// backward compatibility
n.Ipmi.Ipaddr.Set(node.IpmiIpaddr)
n.Ipmi.Netmask.Set(node.IpmiNetmask)
@@ -123,7 +123,7 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) {
}
// can't call setFrom() as we have to use SetAlt instead of Set for an Entry
wwlog.Printf(wwlog.VERBOSE, "Merging profile into node: %s <- %s\n", nodename, profileName)
config.NodeProfiles[profileName].setAltFrom(n, profileName)
config.NodeProfiles[profileName].SetAltFrom(n, profileName)
}
ret = append(ret, n)
}
@@ -155,7 +155,7 @@ func (config *NodeYaml) FindAllProfiles() ([]NodeInfo, error) {
profile.Tags[keyname] = key
delete(profile.Keys, keyname)
}
p.setFrom(profile)
p.SetFrom(profile)
p.Ipmi.Ipaddr.Set(profile.IpmiIpaddr)
p.Ipmi.Netmask.Set(profile.IpmiNetmask)
p.Ipmi.Port.Set(profile.IpmiPort)

View File

@@ -16,6 +16,7 @@ import (
* Filters
*
*********/
/*
Filter a given slice of NodeInfo against a given
regular expression

View File

@@ -55,7 +55,7 @@ func (config *NodeYaml) NodeUpdate(node NodeInfo) error {
if _, ok := config.Nodes[nodeID]; !ok {
return errors.New("Nodename does not exist: " + nodeID)
}
config.Nodes[nodeID].getRealFrom(node)
config.Nodes[nodeID].GetRealFrom(node)
return nil
}
@@ -103,7 +103,7 @@ func (config *NodeYaml) ProfileUpdate(profile NodeInfo) error {
if _, ok := config.NodeProfiles[profileID]; !ok {
return errors.New("Profile name does not exist: " + profileID)
}
config.NodeProfiles[profileID].getRealFrom(profile)
config.NodeProfiles[profileID].GetRealFrom(profile)
return nil
}

View File

@@ -1,6 +1,8 @@
package node
import "reflect"
import (
"reflect"
)
/*
Populates a NodeConf struct (the one which goes to disk) from a
@@ -8,7 +10,7 @@ NodeInfo (which just lives in memory), with the values from all
the underlying entries using GetReal, so just the explicit values
go do disk.
*/
func (nodeConf *NodeConf) getRealFrom(nodeInfo NodeInfo) {
func (nodeConf *NodeConf) GetRealFrom(nodeInfo NodeInfo) {
nodeInfoType := reflect.TypeOf(nodeInfo)
nodeInfoVal := reflect.ValueOf(nodeInfo)
configVal := reflect.ValueOf(nodeConf)
@@ -45,7 +47,6 @@ func (nodeConf *NodeConf) getRealFrom(nodeInfo NodeInfo) {
*newConfPtr = &newConf
}
}
needNestedStruct := false
nestedInfoType := reflect.TypeOf(nodeInfoVal.Field(i).Interface())
nestedInfoVal := reflect.ValueOf(nodeInfoVal.Field(i).Interface())
nestedConfVal := reflect.ValueOf(confField.Interface())
@@ -56,12 +57,10 @@ func (nodeConf *NodeConf) getRealFrom(nodeInfo NodeInfo) {
newValue := (nestedVal.Addr().Interface()).(*string)
entryVal := nestedInfoVal.Elem().Field(j).Interface().(Entry)
*newValue = entryVal.GetReal()
needNestedStruct = needNestedStruct || entryVal.GotReal()
} else if nestedVal.Type() == reflect.TypeOf([]string{}) {
newValue := (nestedVal.Addr().Interface()).(*[]string)
entryVal := nestedInfoVal.Elem().Field(j).Interface().(Entry)
*newValue = entryVal.GetRealSlice()
needNestedStruct = needNestedStruct || entryVal.GotReal()
}
} else if nestedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(map[string]*Entry{}) {
@@ -76,18 +75,7 @@ func (nodeConf *NodeConf) getRealFrom(nodeInfo NodeInfo) {
}
//}
}
// Check if the nested struct has any values, if not replace it with a nil pointer so
// that it does not get unmarshalled to someting like ipmi: {}
if !needNestedStruct {
switch confField.Type() {
case reflect.TypeOf((*IpmiConf)(nil)):
newConf := (confField.Addr().Interface()).(**IpmiConf)
*newConf = (*IpmiConf)(nil)
case reflect.TypeOf((*KernelConf)(nil)):
newConf := (confField.Addr().Interface()).(**KernelConf)
*newConf = (*KernelConf)(nil)
}
}
} else if nodeInfoVal.Field(i).Type() == reflect.TypeOf(map[string]*NetDevEntry{}) {
nestedMap := nodeInfoVal.Field(i).Interface().(map[string]*NetDevEntry)
for netName, netVal := range nestedMap {
@@ -126,11 +114,130 @@ func (nodeConf *NodeConf) getRealFrom(nodeInfo NodeInfo) {
}
}
/*
Populates a NodeConf struct from a NodeInfo, with the combined
values from the underlying entries using Get.
*/
func (nodeConf *NodeConf) GetFrom(nodeInfo NodeInfo) {
nodeInfoType := reflect.TypeOf(nodeInfo)
nodeInfoVal := reflect.ValueOf(nodeInfo)
configVal := reflect.ValueOf(nodeConf)
// now iterate of every field
for i := 0; i < nodeInfoType.NumField(); i++ {
// found field with same name for Conf and Info
confField := configVal.Elem().FieldByName(nodeInfoType.Field(i).Name)
if confField.IsValid() {
if nodeInfoVal.Field(i).Type() == reflect.TypeOf(Entry{}) {
if confField.Type().Kind() == reflect.String {
newValue := (confField.Addr().Interface()).(*string)
entryVal := nodeInfoVal.Field(i).Interface().(Entry)
*newValue = entryVal.Get()
} else if confField.Type() == reflect.TypeOf([]string{}) {
newValue := (confField.Addr().Interface()).(*[]string)
entryVal := nodeInfoVal.Field(i).Interface().(Entry)
*newValue = entryVal.GetSlice()
}
} else if nodeInfoVal.Field(i).Type() == reflect.TypeOf(map[string]*Entry{}) {
if confField.IsNil() {
confFieldPtr := confField.Addr().Interface().(*map[string]string)
*confFieldPtr = make(map[string]string)
}
entryMap := nodeInfoVal.Field(i).Interface().(map[string]*Entry)
for key, val := range entryMap {
confField.Interface().(map[string]string)[key] = val.Get()
}
} else if nodeInfoVal.Field(i).Type().Kind() == reflect.Ptr {
if confField.Addr().Elem().IsZero() {
switch confField.Addr().Elem().Type() {
case reflect.TypeOf((*KernelConf)(nil)):
var newConf KernelConf
newConfPtr := (confField.Addr().Elem().Addr().Interface()).(**KernelConf)
*newConfPtr = &newConf
case reflect.TypeOf((*IpmiConf)(nil)):
var newConf IpmiConf
newConfPtr := (confField.Addr().Elem().Addr().Interface()).(**IpmiConf)
*newConfPtr = &newConf
}
}
nestedInfoType := reflect.TypeOf(nodeInfoVal.Field(i).Interface())
nestedInfoVal := reflect.ValueOf(nodeInfoVal.Field(i).Interface())
nestedConfVal := reflect.ValueOf(confField.Interface())
for j := 0; j < nestedInfoType.Elem().NumField(); j++ {
nestedVal := nestedConfVal.Elem().FieldByName(nestedInfoType.Elem().Field(j).Name)
if nestedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(Entry{}) {
if nestedVal.Type().Kind() == reflect.String {
newValue := (nestedVal.Addr().Interface()).(*string)
entryVal := nestedInfoVal.Elem().Field(j).Interface().(Entry)
*newValue = entryVal.Get()
} else if nestedVal.Type() == reflect.TypeOf([]string{}) {
newValue := (nestedVal.Addr().Interface()).(*[]string)
entryVal := nestedInfoVal.Elem().Field(j).Interface().(Entry)
*newValue = entryVal.GetSlice()
}
} else if nestedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(map[string]*Entry{}) {
if nestedVal.IsNil() {
mapPtr := nestedVal.Addr().Interface().(*map[string]string)
*mapPtr = make(map[string]string)
}
entryMap := nestedInfoVal.Elem().Field(j).Interface().(map[string]*Entry)
for key, val := range entryMap {
nestedVal.Interface().(map[string]string)[key] = val.Get()
}
}
}
} else if nodeInfoVal.Field(i).Type() == reflect.TypeOf(map[string]*NetDevEntry{}) {
nestedMap := nodeInfoVal.Field(i).Interface().(map[string]*NetDevEntry)
for netName, netVal := range nestedMap {
netValsType := reflect.ValueOf(netVal)
if confField.IsNil() {
netMapPtr := confField.Addr().Interface().(*map[string](*NetDevs))
*netMapPtr = make(map[string](*NetDevs))
}
netMap := confField.Interface().(map[string](*NetDevs))
var newNet NetDevs
newNet.Tags = make(map[string]string)
netMap[netName] = &newNet
netConfType := reflect.TypeOf(newNet)
netConfVal := reflect.ValueOf(&newNet)
for j := 0; j < netConfType.NumField(); j++ {
netVal := netValsType.Elem().FieldByName(netConfType.Field(j).Name)
if netVal.IsValid() {
if netVal.Type() == reflect.TypeOf(Entry{}) {
newVal := netConfVal.Elem().Field(j).Addr().Interface().((*string))
*newVal = (netVal.Addr().Interface()).(*Entry).Get()
} else if netVal.Type() == reflect.TypeOf(map[string]string{}) {
// normaly the map should be created here, but did not manage it
for key, val := range (netVal.Interface()).(map[string]string) {
var entr Entry
entr.Set(val)
netConfVal.Elem().Field(j).Interface().((map[string](*Entry)))[key] = &entr
}
}
}
}
}
}
} /*else {
// NodeInfo has the Id field, nodeConf not
fmt.Println("INVALID", nodeInfoType.Field(i).Name)
} */
}
}
/*
Populates all fields of NodeInfo with Set from the
values of NodeConf.
*/
func (node *NodeInfo) setFrom(n *NodeConf) {
func (node *NodeInfo) SetFrom(n *NodeConf) {
// get the full memory, taking the shortcut and init Ipmi and Kernel directly
if node.Kernel == nil {
node.Kernel = new(KernelEntry)
}
if node.Ipmi == nil {
node.Ipmi = new(IpmiEntry)
}
nodeInfoVal := reflect.ValueOf(node)
nodeInfoType := reflect.TypeOf(node)
nodeConfVal := reflect.ValueOf(n)
@@ -217,7 +324,7 @@ values of NodeConf. The string profileName is used to
destermine from which source/NodeInfo the entry came
from.
*/
func (node *NodeConf) setAltFrom(nodeInfo NodeInfo, profileName string) {
func (node *NodeConf) SetAltFrom(nodeInfo NodeInfo, profileName string) {
nodeInfoVal := reflect.ValueOf(&nodeInfo)
nodeInfoType := reflect.TypeOf(&nodeInfo)
profileConfVal := reflect.ValueOf(node)

View File

@@ -16,33 +16,25 @@ struct which contains the variables to which are available in
the templates.
*/
type TemplateStruct struct {
Id string
Hostname string
ClusterName string
Container string
Kernel *node.KernelConf
Init string
Root string
Ipmi *node.IpmiConf
RuntimeOverlay string
SystemOverlay string
NetDevs map[string]*node.NetDevs
Tags map[string]string
Keys map[string]string
AllNodes []node.NodeInfo
BuildHost string
BuildTime string
BuildTimeUnix string
BuildSource string
Ipaddr string
Ipaddr6 string
Netmask string
Network string
NetworkCIDR string
Ipv6 bool
Dhcp warewulfconf.DhcpConf
Nfs warewulfconf.NfsConf
Warewulf warewulfconf.WarewulfConf
Id string
Hostname string
BuildHost string
BuildTime string
BuildTimeUnix string
BuildSource string
Ipaddr string
Ipaddr6 string
Netmask string
Network string
NetworkCIDR string
Ipv6 bool
Dhcp warewulfconf.DhcpConf
Nfs warewulfconf.NfsConf
Warewulf warewulfconf.WarewulfConf
AllNodes []node.NodeInfo
node.NodeConf
// backward compatiblity
Container string
}
/*
@@ -65,63 +57,12 @@ func InitStruct(nodeInfo node.NodeInfo) TemplateStruct {
wwlog.Printf(wwlog.ERROR, "%s\n", err)
os.Exit(1)
}
tstruct.Kernel = new(node.KernelConf)
tstruct.Ipmi = new(node.IpmiConf)
// init some convininence vars
tstruct.Id = nodeInfo.Id.Get()
tstruct.Hostname = nodeInfo.Id.Get()
tstruct.Id = nodeInfo.Id.Get()
tstruct.Hostname = nodeInfo.Id.Get()
tstruct.ClusterName = nodeInfo.ClusterName.Get()
tstruct.Container = nodeInfo.ContainerName.Get()
tstruct.Kernel.Version = nodeInfo.Kernel.Override.Get()
tstruct.Kernel.Override = nodeInfo.Kernel.Override.Get()
tstruct.Kernel.Args = nodeInfo.Kernel.Args.Get()
tstruct.Init = nodeInfo.Init.Get()
tstruct.Root = nodeInfo.Root.Get()
tstruct.Ipmi.Ipaddr = nodeInfo.Ipmi.Ipaddr.Get()
tstruct.Ipmi.Netmask = nodeInfo.Ipmi.Netmask.Get()
tstruct.Ipmi.Port = nodeInfo.Ipmi.Port.Get()
tstruct.Ipmi.Gateway = nodeInfo.Ipmi.Gateway.Get()
tstruct.Ipmi.UserName = nodeInfo.Ipmi.UserName.Get()
tstruct.Ipmi.Password = nodeInfo.Ipmi.Password.Get()
tstruct.Ipmi.Interface = nodeInfo.Ipmi.Interface.Get()
tstruct.Ipmi.Write = nodeInfo.Ipmi.Write.Get()
tstruct.RuntimeOverlay = nodeInfo.RuntimeOverlay.Print()
tstruct.SystemOverlay = nodeInfo.SystemOverlay.Print()
tstruct.NetDevs = make(map[string]*node.NetDevs)
tstruct.Keys = make(map[string]string)
tstruct.Tags = make(map[string]string)
for devname, netdev := range nodeInfo.NetDevs {
var nd node.NetDevs
tstruct.NetDevs[devname] = &nd
tstruct.NetDevs[devname].Device = netdev.Device.Get()
tstruct.NetDevs[devname].Hwaddr = netdev.Hwaddr.Get()
tstruct.NetDevs[devname].Ipaddr = netdev.Ipaddr.Get()
tstruct.NetDevs[devname].Netmask = netdev.Netmask.Get()
tstruct.NetDevs[devname].Gateway = netdev.Gateway.Get()
tstruct.NetDevs[devname].Type = netdev.Type.Get()
tstruct.NetDevs[devname].OnBoot = netdev.OnBoot.Get()
tstruct.NetDevs[devname].Primary = netdev.Primary.Get()
mask := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4())
ipaddr := net.ParseIP(netdev.Ipaddr.Get()).To4()
netaddr := net.IPNet{IP: ipaddr, Mask: mask}
netPrefix, _ := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()).Size()
tstruct.NetDevs[devname].Prefix = strconv.Itoa(netPrefix)
tstruct.NetDevs[devname].IpCIDR = netaddr.String()
tstruct.NetDevs[devname].Ipaddr6 = netdev.Ipaddr6.Get()
tstruct.NetDevs[devname].Tags = make(map[string]string)
for key, value := range netdev.Tags {
tstruct.NetDevs[devname].Tags[key] = value.Get()
}
}
// Backwards compatibility for templates using "Keys"
for keyname, key := range nodeInfo.Tags {
tstruct.Keys[keyname] = key.Get()
}
for keyname, key := range nodeInfo.Tags {
tstruct.Tags[keyname] = key.Get()
}
tstruct.AllNodes = allNodes
tstruct.Nfs = *controller.Nfs
tstruct.Dhcp = *controller.Dhcp
@@ -142,6 +83,9 @@ func InitStruct(nodeInfo node.NodeInfo) TemplateStruct {
dt := time.Now()
tstruct.BuildTime = dt.Format("01-02-2006 15:04:05 MST")
tstruct.BuildTimeUnix = strconv.FormatInt(dt.Unix(), 10)
tstruct.NodeConf.GetFrom(nodeInfo)
// backward compatibilty
tstruct.Container = tstruct.ContainerName
return tstruct