Add recursive setter functions
when transforming a NodeInfo struct to a NodeConf (set the NodeConf from the NodeInfo) nested structures were seperately handled. This means a there were seperate handles for e.g *Netdevs and *IpmiConfig. The new getter traverses through the datastucture and sets the right value for a 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 seperately handling them in the transformer functions. Signed-off-by: Christian Goll <cgoll@suse.de>
This commit is contained in:
committed by
Jonathon Anderson
parent
fdd233a25f
commit
c55c5a2ac4
@@ -166,7 +166,7 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) {
|
||||
n.SetFrom(node)
|
||||
// only now the netdevs start to exist so that default values can be set
|
||||
for _, netdev := range n.NetDevs {
|
||||
netdev.SetDefFrom(defConfNet)
|
||||
SetDefFrom(defConfNet, netdev)
|
||||
}
|
||||
// backward compatibility
|
||||
n.Ipmi.Ipaddr.Set(node.IpmiIpaddr)
|
||||
|
||||
@@ -380,11 +380,6 @@ func NewInfo() (nodeInfo NodeInfo) {
|
||||
return nodeInfo
|
||||
}
|
||||
|
||||
func NewNetDevEntry() (netdev NetDevEntry) {
|
||||
netdev.Tags = make(map[string]*Entry)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Get a entry by its name
|
||||
*/
|
||||
|
||||
@@ -48,12 +48,19 @@ func (config *NodeYaml) DelNode(nodeID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
update the node in the database
|
||||
*/
|
||||
func (config *NodeYaml) NodeUpdate(node NodeInfo) error {
|
||||
nodeID := node.Id.Get()
|
||||
|
||||
wwlog.Debug("updating node %s: %v", nodeID, node)
|
||||
if _, ok := config.Nodes[nodeID]; !ok {
|
||||
return errors.New("Nodename does not exist: " + nodeID)
|
||||
}
|
||||
// maps may have deleted elements which will not be updated
|
||||
// so we delete the node and call GetRealFrom on an empty NodeConv
|
||||
delete(config.Nodes, nodeID)
|
||||
config.Nodes[nodeID] = new(NodeConf)
|
||||
config.Nodes[nodeID].GetRealFrom(node)
|
||||
return nil
|
||||
}
|
||||
@@ -102,6 +109,10 @@ func (config *NodeYaml) ProfileUpdate(profile NodeInfo) error {
|
||||
if _, ok := config.NodeProfiles[profileID]; !ok {
|
||||
return errors.New("Profile name does not exist: " + profileID)
|
||||
}
|
||||
// maps may have deleted elements which will not be updated
|
||||
// so we delete the profile and call GetRealFrom on an empty NodeConv
|
||||
delete(config.NodeProfiles, profileID)
|
||||
config.NodeProfiles[profileID] = new(NodeConf)
|
||||
config.NodeProfiles[profileID].GetRealFrom(profile)
|
||||
return nil
|
||||
}
|
||||
@@ -133,7 +144,6 @@ func (config *NodeYaml) Persist() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// Dump returns a YAML document representing the nodeDb
|
||||
// instance. Passes through any errors generated by yaml.Marshal.
|
||||
func (config *NodeYaml) Dump() ([]byte, error) {
|
||||
|
||||
@@ -104,17 +104,17 @@ func (node *NodeInfo) SetFrom(n *NodeConf) {
|
||||
setSliceWrap := func(entr *Entry, val []string, nameArg string) {
|
||||
entr.SetSlice(val)
|
||||
}
|
||||
node.setterFrom(n, "", setWrap, setSliceWrap)
|
||||
recursiveSetter(n, node, "", setWrap, setSliceWrap)
|
||||
}
|
||||
|
||||
/*
|
||||
Populates all fields of NodeInfo with SetAlt from the
|
||||
values of NodeConf. The string profileName is used to
|
||||
destermine from which source/NodeInfo the entry came
|
||||
determine from which source/NodeInfo the entry came
|
||||
from.
|
||||
*/
|
||||
func (node *NodeInfo) SetAltFrom(n *NodeConf, profileName string) {
|
||||
node.setterFrom(n, profileName, (*Entry).SetAlt, (*Entry).SetAltSlice)
|
||||
recursiveSetter(n, node, profileName, (*Entry).SetAlt, (*Entry).SetAltSlice)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -128,120 +128,95 @@ func (node *NodeInfo) SetDefFrom(n *NodeConf) {
|
||||
setSliceWrap := func(entr *Entry, val []string, nameArg string) {
|
||||
entr.SetDefaultSlice(val)
|
||||
}
|
||||
node.setterFrom(n, "", setWrap, setSliceWrap)
|
||||
recursiveSetter(n, node, "", setWrap, setSliceWrap)
|
||||
}
|
||||
|
||||
func SetDefFrom(source, target interface{}) {
|
||||
setWrap := func(entr *Entry, val string, nameArg string) {
|
||||
entr.SetDefault(val)
|
||||
}
|
||||
setSliceWrap := func(entr *Entry, val []string, nameArg string) {
|
||||
entr.SetDefaultSlice(val)
|
||||
}
|
||||
recursiveSetter(source, target, "", setWrap, setSliceWrap)
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Abstract function which populates a NodeInfo from a NodeConf via
|
||||
setter functionns.
|
||||
setter functions. Panics if other type than string, []string *ptr is used in NodeConf.
|
||||
*/
|
||||
func (node *NodeInfo) setterFrom(n *NodeConf, nameArg string,
|
||||
setter func(*Entry, string, string),
|
||||
func recursiveSetter(source, target interface{}, nameArg string, setter func(*Entry, string, string),
|
||||
setterSlice func(*Entry, []string, string)) {
|
||||
// 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)
|
||||
}
|
||||
// also n could be nil
|
||||
if n == nil {
|
||||
myn := NewConf()
|
||||
n = &myn
|
||||
}
|
||||
nodeInfoVal := reflect.ValueOf(node)
|
||||
nodeInfoType := reflect.TypeOf(node)
|
||||
nodeConfVal := reflect.ValueOf(n)
|
||||
// now iterate of every field
|
||||
for i := 0; i < nodeInfoType.Elem().NumField(); i++ {
|
||||
valField := nodeConfVal.Elem().FieldByName(nodeInfoType.Elem().Field(i).Name)
|
||||
if valField.IsValid() {
|
||||
// found field with same name for Conf and Info
|
||||
if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(Entry{}) {
|
||||
if valField.Type().Kind() == reflect.String {
|
||||
setter(nodeInfoVal.Elem().Field(i).Addr().Interface().(*Entry), valField.String(), nameArg)
|
||||
} else if valField.Type() == reflect.TypeOf([]string{}) {
|
||||
setterSlice(nodeInfoVal.Elem().Field(i).Addr().Interface().(*Entry), valField.Interface().([]string), nameArg)
|
||||
}
|
||||
} else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr && !valField.IsZero() {
|
||||
nestedInfoType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface())
|
||||
nestedInfoVal := reflect.ValueOf(nodeInfoVal.Elem().Field(i).Interface())
|
||||
nestedConfVal := reflect.ValueOf(valField.Interface())
|
||||
for j := 0; j < nestedInfoType.Elem().NumField(); j++ {
|
||||
nestedVal := nestedConfVal.Elem().FieldByName(nestedInfoType.Elem().Field(j).Name)
|
||||
if nestedVal.IsValid() {
|
||||
if nestedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(Entry{}) {
|
||||
setter(nestedInfoVal.Elem().Field(j).Addr().Interface().(*Entry), nestedVal.String(), nameArg)
|
||||
} else if nestedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(map[string](*Entry){}) {
|
||||
confMap := nestedVal.Interface().(map[string]string)
|
||||
if nestedInfoVal.Elem().Field(j).IsNil() {
|
||||
ptr := nestedInfoVal.Elem().Field(j).Addr().Interface().(*map[string](*Entry))
|
||||
*ptr = make(map[string]*Entry)
|
||||
}
|
||||
tagMap := nestedInfoVal.Elem().Field(j).Interface().(map[string](*Entry))
|
||||
for key, val := range confMap {
|
||||
if entr, ok := tagMap[key]; ok {
|
||||
setter(entr, val, nameArg)
|
||||
} else {
|
||||
entr := new(Entry)
|
||||
tagMap[key] = entr
|
||||
setter(entr, val, nameArg)
|
||||
sourceValue := reflect.ValueOf(source)
|
||||
targetType := reflect.TypeOf(target)
|
||||
targetValue := reflect.ValueOf(target)
|
||||
if targetValue.Elem().Kind() == reflect.Struct && sourceValue.Elem().Kind() == reflect.Struct {
|
||||
for i := 0; i < targetType.Elem().NumField(); i++ {
|
||||
sourceValueMatched := sourceValue.Elem().FieldByName(targetType.Elem().Field(i).Name)
|
||||
if sourceValueMatched.IsValid() {
|
||||
if targetValue.Elem().Field(i).Type() == reflect.TypeOf(Entry{}) {
|
||||
// get the fields which are part of the struct
|
||||
switch sourceValueMatched.Type() {
|
||||
case reflect.TypeOf(""):
|
||||
setter(targetValue.Elem().Field(i).Addr().Interface().(*Entry), sourceValueMatched.String(), nameArg)
|
||||
case reflect.TypeOf([]string{}):
|
||||
setterSlice(targetValue.Elem().Field(i).Addr().Interface().(*Entry), sourceValueMatched.Interface().([]string), nameArg)
|
||||
default:
|
||||
panic(fmt.Errorf("can't convert an Entry to %s", targetValue.Elem().Field(i).Type()))
|
||||
}
|
||||
} 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()))
|
||||
}
|
||||
recursiveSetter(sourceValueMatched.Interface(), targetValue.Elem().Field(i).Interface(), nameArg, setter, setterSlice)
|
||||
} 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))
|
||||
}
|
||||
// delete a ap element which is only in the target
|
||||
if targetValue.Elem().Field(i).Len() > 0 && targetValue.Elem().Field(i).Len() < 0 {
|
||||
sourceIter := sourceValueMatched.MapRange()
|
||||
targetIter := targetValue.Elem().Field(i).MapRange()
|
||||
for targetIter.Next() {
|
||||
sameKey := false
|
||||
for sourceIter.Next() {
|
||||
if sourceIter.Key() == targetIter.Key() {
|
||||
sameKey = true
|
||||
}
|
||||
}
|
||||
if !sameKey {
|
||||
targetValue.Elem().Field(i).SetMapIndex(targetIter.Key(), reflect.Value{})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*Entry)(nil)) {
|
||||
confMap := valField.Interface().(map[string]string)
|
||||
for key, val := range confMap {
|
||||
tagMap := nodeInfoVal.Elem().Field(i).Interface().(map[string](*Entry))
|
||||
if nodeInfoVal.Elem().Field(i).IsNil() {
|
||||
tagMap = make(map[string]*Entry)
|
||||
}
|
||||
if entr, ok := tagMap[key]; ok {
|
||||
setter(entr, val, nameArg)
|
||||
} else {
|
||||
entr := new(Entry)
|
||||
tagMap[key] = entr
|
||||
setter(entr, val, nameArg)
|
||||
}
|
||||
}
|
||||
} else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*NetDevEntry)(nil)) {
|
||||
netValMap := valField.Interface().(map[string](*NetDevs))
|
||||
for netName, netVals := range netValMap {
|
||||
netValsType := reflect.ValueOf(netVals)
|
||||
netMap := nodeInfoVal.Elem().Field(i).Interface().(map[string](*NetDevEntry))
|
||||
if nodeInfoVal.Elem().Field(i).IsNil() {
|
||||
netMap = make(map[string]*NetDevEntry)
|
||||
}
|
||||
if _, ok := netMap[netName]; !ok {
|
||||
var newNet NetDevEntry
|
||||
newNet.Tags = make(map[string]*Entry)
|
||||
netMap[netName] = &newNet
|
||||
}
|
||||
netInfoType := reflect.TypeOf(*netMap[netName])
|
||||
netInfoVal := reflect.ValueOf(netMap[netName])
|
||||
for j := 0; j < netInfoType.NumField(); j++ {
|
||||
netVal := netValsType.Elem().FieldByName(netInfoType.Field(j).Name)
|
||||
if netVal.IsValid() {
|
||||
if netVal.Type().Kind() == reflect.String {
|
||||
setter(netInfoVal.Elem().Field(j).Addr().Interface().((*Entry)), netVal.String(), nameArg)
|
||||
} else if netVal.Type() == reflect.TypeOf(map[string]string{}) {
|
||||
for key, val := range (netVal.Interface()).(map[string]string) {
|
||||
//netTagMap := netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))
|
||||
if _, ok := netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key]; !ok {
|
||||
netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key] = new(Entry)
|
||||
}
|
||||
setter(netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key], val, nameArg)
|
||||
}
|
||||
sourceIter := sourceValueMatched.MapRange()
|
||||
if sourceValueMatched.Type().Elem() == reflect.TypeOf("") {
|
||||
// go over a simple map with strings
|
||||
for sourceIter.Next() {
|
||||
if !targetValue.Elem().Field(i).MapIndex(sourceIter.Key()).IsValid() {
|
||||
newEntr := new(Entry)
|
||||
setter(newEntr, sourceIter.Value().String(), nameArg)
|
||||
targetValue.Elem().Field(i).SetMapIndex(sourceIter.Key(), reflect.ValueOf(newEntr))
|
||||
}
|
||||
}
|
||||
} 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)
|
||||
}
|
||||
recursiveSetter(sourceIter.Value().Interface(), targetValue.Elem().Field(i).MapIndex(sourceIter.Key()).Interface(), nameArg, setter, setterSlice)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -280,78 +255,6 @@ func recursiveFlatten(strct interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Populates all fields of NetDevEntry with Set from the
|
||||
values of NetDevs.
|
||||
Actually not used, just for completeness.
|
||||
*/
|
||||
func (netDev *NetDevEntry) SetFrom(netYaml *NetDevs) {
|
||||
setWrap := func(entr *Entry, val string, nameArg string) {
|
||||
entr.Set(val)
|
||||
}
|
||||
setSliceWrap := func(entr *Entry, val []string, nameArg string) {
|
||||
entr.SetSlice(val)
|
||||
}
|
||||
netDev.setterFrom(netYaml, "", setWrap, setSliceWrap)
|
||||
}
|
||||
|
||||
/*
|
||||
Populates all fields of NetDevEntry with SetAlt from the
|
||||
values of NetDevs. The string profileName is used to
|
||||
destermine from which source/NodeInfo the entry came
|
||||
from.
|
||||
Actually not used, just for completeness.
|
||||
*/
|
||||
func (netDev *NetDevEntry) SetAltFrom(netYaml *NetDevs, profileName string) {
|
||||
netDev.setterFrom(netYaml, profileName, (*Entry).SetAlt, (*Entry).SetAltSlice)
|
||||
}
|
||||
|
||||
/*
|
||||
Populates all fields of NodeInfo with SetDefault from the
|
||||
values of NodeConf.
|
||||
*/
|
||||
func (netDev *NetDevEntry) SetDefFrom(netYaml *NetDevs) {
|
||||
setWrap := func(entr *Entry, val string, nameArg string) {
|
||||
entr.SetDefault(val)
|
||||
}
|
||||
setSliceWrap := func(entr *Entry, val []string, nameArg string) {
|
||||
entr.SetDefaultSlice(val)
|
||||
}
|
||||
netDev.setterFrom(netYaml, "", setWrap, setSliceWrap)
|
||||
}
|
||||
|
||||
/*
|
||||
Abstract function for setting a NetDevEntry from a NetDevs
|
||||
*/
|
||||
func (netDev *NetDevEntry) setterFrom(netYaml *NetDevs, nameArg string,
|
||||
setter func(*Entry, string, string),
|
||||
setterSlice func(*Entry, []string, string)) {
|
||||
// check if netYaml is empty
|
||||
if netYaml == nil {
|
||||
netYaml = new(NetDevs)
|
||||
}
|
||||
netValues := reflect.ValueOf(netDev)
|
||||
netInfoType := reflect.TypeOf(*netYaml)
|
||||
netInfoVal := reflect.ValueOf(*netYaml)
|
||||
for j := 0; j < netInfoType.NumField(); j++ {
|
||||
netVal := netValues.Elem().FieldByName(netInfoType.Field(j).Name)
|
||||
if netVal.IsValid() {
|
||||
if netInfoVal.Field(j).Type().Kind() == reflect.String {
|
||||
setter(netVal.Addr().Interface().((*Entry)), netInfoVal.Field(j).String(), nameArg)
|
||||
} else if netVal.Type() == reflect.TypeOf(map[string]string{}) {
|
||||
// danger zone following code is not tested
|
||||
for key, val := range (netVal.Interface()).(map[string]string) {
|
||||
//netTagMap := netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))
|
||||
if _, ok := netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key]; !ok {
|
||||
netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key] = new(Entry)
|
||||
}
|
||||
setter(netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key], val, nameArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Create a string slice, where every element represents a yaml entry
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user