Add recursive getter functions
When transforming a NodeConf struct to a NodeInfo (get the NodeInfo from the Nodconf) nested structures were seperately handled. This means there were seperate handles for e.g *Netdevs and *IpmiConfig. The new getter traverses through the datastucture and sets the right value for an Entry struct, but calls itself again if a Pointer is detected. This adds the posiblity to add new nested structures to NodeConf and NodeInfo without the need of seperate handling them in the transformer functions. Signed-off-by: Christian Goll <cgoll@suse.de>
This commit is contained in:
committed by
Jonathon Anderson
parent
f2bc70ad00
commit
fdd233a25f
@@ -299,13 +299,14 @@ ipmi: {}
|
|||||||
t.Errorf("Got wrong yml, wanted:\n'%s'\nGot:\n'%s'", wanted, string(ymlByte))
|
t.Errorf("Got wrong yml, wanted:\n'%s'\nGot:\n'%s'", wanted, string(ymlByte))
|
||||||
}
|
}
|
||||||
delete(test_node4.Tags, "foo")
|
delete(test_node4.Tags, "foo")
|
||||||
|
nodeConf = NewConf()
|
||||||
nodeConf.GetFrom(test_node4)
|
nodeConf.GetFrom(test_node4)
|
||||||
nodeConf.Flatten()
|
nodeConf.Flatten()
|
||||||
ymlByte, _ = yaml.Marshal(nodeConf)
|
ymlByte, _ = yaml.Marshal(nodeConf)
|
||||||
wanted = `{}
|
wanted = `{}
|
||||||
`
|
`
|
||||||
if string(ymlByte) != wanted {
|
if string(ymlByte) != wanted {
|
||||||
t.Errorf("Couldn't remove tag'%s'", string(ymlByte))
|
t.Errorf("Couldn't remove tag, wanted:\n%s\nGot:\n%s", wanted, string(ymlByte))
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@ the underlying entries using GetReal, so just the explicit values
|
|||||||
go do disk.
|
go do disk.
|
||||||
*/
|
*/
|
||||||
func (nodeConf *NodeConf) GetRealFrom(nodeInfo NodeInfo) {
|
func (nodeConf *NodeConf) GetRealFrom(nodeInfo NodeInfo) {
|
||||||
nodeConf.getterFrom(nodeInfo, (*Entry).GetReal, (*Entry).GetRealSlice)
|
recursiveGetter(&nodeInfo, nodeConf, (*Entry).GetReal, (*Entry).GetRealSlice)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -23,168 +24,67 @@ Populates a NodeConf struct from a NodeInfo, with the combined
|
|||||||
values from the underlying entries using Get.
|
values from the underlying entries using Get.
|
||||||
*/
|
*/
|
||||||
func (nodeConf *NodeConf) GetFrom(nodeInfo NodeInfo) {
|
func (nodeConf *NodeConf) GetFrom(nodeInfo NodeInfo) {
|
||||||
nodeConf.getterFrom(nodeInfo, (*Entry).Get, (*Entry).GetSlice)
|
recursiveGetter(&nodeInfo, nodeConf, (*Entry).Get, (*Entry).GetSlice)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Abstract function which populates a NodeConf from the given NodeInfo
|
Abstract function which populates a NodeConf from the given NodeInfo
|
||||||
via getter functions.
|
via getter functions. Calls recursive itself for nested structures.
|
||||||
|
Panics if the NodeConf has fields which are not type of string,[]string,map[string]*ptr
|
||||||
*/
|
*/
|
||||||
func (nodeConf *NodeConf) getterFrom(nodeInfo NodeInfo,
|
func recursiveGetter(
|
||||||
|
source, target interface{},
|
||||||
getter func(*Entry) string,
|
getter func(*Entry) string,
|
||||||
getterSlice func(*Entry) []string) {
|
getterSlice func(*Entry) []string) {
|
||||||
nodeInfoType := reflect.TypeOf(nodeInfo)
|
sourceValue := reflect.ValueOf(source)
|
||||||
nodeInfoVal := reflect.ValueOf(nodeInfo)
|
targetType := reflect.TypeOf(target)
|
||||||
configVal := reflect.ValueOf(nodeConf)
|
targetValue := reflect.ValueOf(target)
|
||||||
// now iterate of every field
|
if targetValue.Elem().Kind() == reflect.Struct && sourceValue.Elem().Kind() == reflect.Struct {
|
||||||
for i := 0; i < nodeInfoType.NumField(); i++ {
|
for i := 0; i < targetType.Elem().NumField(); i++ {
|
||||||
// found field with same name for Conf and Info
|
sourceValueMatched := sourceValue.Elem().FieldByName(targetType.Elem().Field(i).Name)
|
||||||
confField := configVal.Elem().FieldByName(nodeInfoType.Field(i).Name)
|
if sourceValueMatched.IsValid() {
|
||||||
if confField.IsValid() {
|
if sourceValueMatched.Type() == reflect.TypeOf(Entry{}) {
|
||||||
if nodeInfoVal.Field(i).Type() == reflect.TypeOf(Entry{}) {
|
// get the fields which are part of the struct
|
||||||
if confField.Type().Kind() == reflect.String {
|
switch targetValue.Elem().Field(i).Type() {
|
||||||
newValue := (confField.Addr().Interface()).(*string)
|
case reflect.TypeOf(""):
|
||||||
entryVal := nodeInfoVal.Field(i).Interface().(Entry)
|
newValue := (targetValue.Elem().Field(i).Addr().Interface()).(*string)
|
||||||
*newValue = getter(&entryVal)
|
source := sourceValueMatched.Interface().(Entry)
|
||||||
} else if confField.Type() == reflect.TypeOf([]string{}) {
|
*newValue = getter(&source)
|
||||||
newValue := (confField.Addr().Interface()).(*[]string)
|
case reflect.TypeOf([]string{}):
|
||||||
entryVal := nodeInfoVal.Field(i).Interface().(Entry)
|
newValue := (targetValue.Elem().Field(i).Addr().Interface()).(*[]string)
|
||||||
*newValue = getterSlice(&entryVal)
|
source := sourceValueMatched.Interface().(Entry)
|
||||||
}
|
*newValue = getterSlice(&source)
|
||||||
} else if nodeInfoVal.Field(i).Type() == reflect.TypeOf(map[string]*Entry{}) {
|
default:
|
||||||
entryMap := nodeInfoVal.Field(i).Interface().(map[string]*Entry)
|
panic(fmt.Errorf("can't convert an Entry to %s", targetValue.Elem().Field(i).Type()))
|
||||||
confMap := confField.Interface().(map[string]string)
|
}
|
||||||
|
} else if sourceValueMatched.Kind() == reflect.Ptr {
|
||||||
|
// if we get a pointer, initialize if empty and then have a recursive call
|
||||||
|
if targetValue.Elem().Field(i).IsZero() {
|
||||||
|
targetValue.Elem().Field(i).Set(reflect.New(targetType.Elem().Field(i).Type.Elem()))
|
||||||
|
}
|
||||||
|
recursiveGetter(sourceValueMatched.Interface(), targetValue.Elem().Field(i).Interface(), getter, getterSlice)
|
||||||
|
} else if sourceValueMatched.Type().Kind() == reflect.Map {
|
||||||
|
if targetValue.Elem().Field(i).IsZero() {
|
||||||
|
targetValue.Elem().Field(i).Set(reflect.MakeMap(targetType.Elem().Field(i).Type))
|
||||||
|
}
|
||||||
|
sourceIter := sourceValueMatched.MapRange()
|
||||||
|
if sourceValueMatched.Type() == reflect.TypeOf(map[string]*Entry{}) {
|
||||||
|
// go over a simple map with strings
|
||||||
|
for sourceIter.Next() {
|
||||||
|
if !targetValue.Elem().Field(i).MapIndex(sourceIter.Key()).IsValid() {
|
||||||
|
str := getter((sourceIter.Value().Interface()).(*Entry))
|
||||||
|
targetValue.Elem().Field(i).SetMapIndex(sourceIter.Key(), reflect.ValueOf(str))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// now the complicated map which contains pointers to objects
|
||||||
|
for sourceIter.Next() {
|
||||||
|
if !targetValue.Elem().Field(i).MapIndex(sourceIter.Key()).IsValid() {
|
||||||
|
newPtr := reflect.New(targetType.Elem().Field(i).Type.Elem().Elem())
|
||||||
|
targetValue.Elem().Field(i).SetMapIndex(sourceIter.Key(), newPtr)
|
||||||
|
}
|
||||||
|
recursiveGetter(sourceIter.Value().Interface(), targetValue.Elem().Field(i).MapIndex(sourceIter.Key()).Interface(), getter, getterSlice)
|
||||||
|
|
||||||
if len(confMap) > len(entryMap) {
|
|
||||||
for confKey := range confMap {
|
|
||||||
foundKey := false
|
|
||||||
for entrKey := range entryMap {
|
|
||||||
if confKey == entrKey {
|
|
||||||
foundKey = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !foundKey {
|
|
||||||
delete(confMap, confKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for key, val := range entryMap {
|
|
||||||
confMap[key] = getter(val)
|
|
||||||
}
|
|
||||||
} else if nodeInfoVal.Field(i).Type().Kind() == reflect.Ptr && !nodeInfoVal.Field(i).IsNil() {
|
|
||||||
// initialize the nested NodeConf structs, but only if these will be set
|
|
||||||
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 = getter(&entryVal)
|
|
||||||
} else if nestedVal.Type() == reflect.TypeOf([]string{}) {
|
|
||||||
newValue := (nestedVal.Addr().Interface()).(*[]string)
|
|
||||||
entryVal := nestedInfoVal.Elem().Field(j).Interface().(Entry)
|
|
||||||
*newValue = getterSlice(&entryVal)
|
|
||||||
|
|
||||||
}
|
|
||||||
} 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)
|
|
||||||
confMap := nestedVal.Interface().(map[string]string)
|
|
||||||
if len(confMap) > len(entryMap) {
|
|
||||||
for confKey := range confMap {
|
|
||||||
foundKey := false
|
|
||||||
for entrKey := range entryMap {
|
|
||||||
if confKey == entrKey {
|
|
||||||
foundKey = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !foundKey {
|
|
||||||
delete(confMap, confKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for key, val := range entryMap {
|
|
||||||
confMap[key] = getter(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if nodeInfoVal.Field(i).Type() == reflect.TypeOf(map[string]*NetDevEntry{}) {
|
|
||||||
if confField.IsNil() {
|
|
||||||
netMapPtr := confField.Addr().Interface().(*map[string](*NetDevs))
|
|
||||||
*netMapPtr = make(map[string](*NetDevs))
|
|
||||||
}
|
|
||||||
nestedMap := nodeInfoVal.Field(i).Interface().(map[string]*NetDevEntry)
|
|
||||||
netMap := confField.Interface().(map[string](*NetDevs))
|
|
||||||
// check if a network was deleted
|
|
||||||
if len(netMap) > len(nestedMap) {
|
|
||||||
for netMapKey := range netMap {
|
|
||||||
foundKey := false
|
|
||||||
for nestedMapKey := range nestedMap {
|
|
||||||
if netMapKey == nestedMapKey {
|
|
||||||
foundKey = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !foundKey {
|
|
||||||
delete(netMap, netMapKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for netName, netVal := range nestedMap {
|
|
||||||
netValsType := reflect.ValueOf(netVal)
|
|
||||||
if _, ok := netMap[netName]; !ok {
|
|
||||||
netMap[netName] = new(NetDevs)
|
|
||||||
}
|
|
||||||
netConfType := reflect.TypeOf(*netMap[netName])
|
|
||||||
netConfVal := reflect.ValueOf(netMap[netName])
|
|
||||||
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 = getter((netVal.Addr().Interface()).(*Entry))
|
|
||||||
} else if netVal.Type() == reflect.TypeOf(map[string]*Entry{}) {
|
|
||||||
entryMap := netVal.Interface().(map[string](*Entry))
|
|
||||||
confMap := netConfVal.Elem().Field(j).Interface().(map[string]string)
|
|
||||||
if confMap == nil {
|
|
||||||
confMapPtr := netConfVal.Elem().Field(j).Addr().Interface().(*map[string]string)
|
|
||||||
*confMapPtr = make(map[string]string)
|
|
||||||
}
|
|
||||||
if len(confMap) > len(entryMap) {
|
|
||||||
for confMapKey := range confMap {
|
|
||||||
foundKey := false
|
|
||||||
for entryMapKey := range entryMap {
|
|
||||||
if confMapKey == entryMapKey {
|
|
||||||
foundKey = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !foundKey {
|
|
||||||
delete(netConfVal.Elem().Field(j).Interface().(map[string]string), confMapKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for key, val := range entryMap {
|
|
||||||
netConfVal.Elem().Field(j).Interface().(map[string]string)[key] = getter(val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,8 +250,11 @@ or *KernelConf, these pointer will set to nil. This will remove something like
|
|||||||
ipmi: {} from nodes.conf
|
ipmi: {} from nodes.conf
|
||||||
*/
|
*/
|
||||||
func (info *NodeConf) Flatten() {
|
func (info *NodeConf) Flatten() {
|
||||||
confType := reflect.TypeOf(info)
|
recursiveFlatten(info)
|
||||||
confVal := reflect.ValueOf(info)
|
}
|
||||||
|
func recursiveFlatten(strct interface{}) {
|
||||||
|
confType := reflect.TypeOf(strct)
|
||||||
|
confVal := reflect.ValueOf(strct)
|
||||||
for j := 0; j < confType.Elem().NumField(); j++ {
|
for j := 0; j < confType.Elem().NumField(); j++ {
|
||||||
if confVal.Elem().Field(j).Type().Kind() == reflect.Ptr && !confVal.Elem().Field(j).IsNil() {
|
if confVal.Elem().Field(j).Type().Kind() == reflect.Ptr && !confVal.Elem().Field(j).IsNil() {
|
||||||
// iterate now over the ptr fields
|
// iterate now over the ptr fields
|
||||||
@@ -371,14 +274,7 @@ func (info *NodeConf) Flatten() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if setToNil {
|
if setToNil {
|
||||||
switch confType.Elem().Field(j).Type {
|
confVal.Elem().Field(j).Set(reflect.Zero(confVal.Elem().Field(j).Type()))
|
||||||
case reflect.TypeOf((*IpmiConf)(nil)):
|
|
||||||
ptr := confVal.Elem().Field(j).Addr().Interface().(**IpmiConf)
|
|
||||||
*ptr = (*IpmiConf)(nil)
|
|
||||||
case reflect.TypeOf((*KernelConf)(nil)):
|
|
||||||
ptr := confVal.Elem().Field(j).Addr().Interface().(**KernelConf)
|
|
||||||
*ptr = (*KernelConf)(nil)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user