From 41d12888abc3da021904c543351d73f8c71ab451 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Fri, 5 Aug 2022 12:33:58 +0200 Subject: [PATCH] reflections for unmarshal --- internal/app/wwctl/node/list/main.go | 3 + internal/app/wwctl/profile/delete/main.go | 5 +- internal/pkg/api/node/methods.go | 2 +- internal/pkg/node/constructors.go | 144 +---------- internal/pkg/node/datastructure.go | 2 +- internal/pkg/node/methods.go | 37 +-- internal/pkg/node/modifiers.go | 121 +-------- internal/pkg/node/transformers.go | 283 ++++++++++++++++++++++ 8 files changed, 320 insertions(+), 277 deletions(-) create mode 100644 internal/pkg/node/transformers.go diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 602687eb..1a5d8515 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -72,6 +72,9 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { fieldName = "tag:" + subkeys[1] case "IpmiEntry": fieldName = ipmiLopt[subkeys[1]] + if len(subkeys) == 3 { + fieldName = "ipmikey:" + subkeys[2] + } case "KernelEntry": fieldName = kernelLopt[subkeys[1]] case "NetDevEntry": diff --git a/internal/app/wwctl/profile/delete/main.go b/internal/app/wwctl/profile/delete/main.go index b16696a6..f71e1f18 100644 --- a/internal/app/wwctl/profile/delete/main.go +++ b/internal/app/wwctl/profile/delete/main.go @@ -5,7 +5,6 @@ import ( "os" "github.com/hpcng/warewulf/internal/pkg/node" - "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/manifoldco/promptui" "github.com/pkg/errors" @@ -36,10 +35,10 @@ func CobraRunE(cmd *cobra.Command, args []string) error { os.Exit(1) } for _, n := range nodes { - for _, np := range n.Profiles { + for _, np := range n.Profiles.GetSlice() { if np == r { wwlog.Printf(wwlog.VERBOSE, "Removing profile from node %s: %s\n", n.Id.Get(), r) - n.Profiles = util.SliceRemoveElement(n.Profiles, r) + n.Profiles.SliceRemoveElement(r) err := nodeDB.NodeUpdate(n) if err != nil { return errors.Wrap(err, "failed to update node") diff --git a/internal/pkg/api/node/methods.go b/internal/pkg/api/node/methods.go index 57428170..8943d455 100644 --- a/internal/pkg/api/node/methods.go +++ b/internal/pkg/api/node/methods.go @@ -72,7 +72,7 @@ func GetFields(n interface{}) map[string]*wwapiv1.NodeField { } } default: - fmt.Println(nodeType.Field(i).Type) + panic(fmt.Sprintf("Can't handle: %s\n", nodeType.Field(i).Type)) } } return fieldMap diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index b3f03a2f..a8690d44 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -4,7 +4,6 @@ import ( "errors" "io/ioutil" "path" - "reflect" "sort" "strings" @@ -42,76 +41,6 @@ func New() (NodeYaml, error) { return ret, nil } -func (node *NodeInfo) initFrom(n *NodeConf) { - 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 { - (nodeInfoVal.Elem().Field(i).Addr().Interface()).(*Entry).Set(valField.String()) - } else if valField.Type() == reflect.TypeOf([]string{}) { - (nodeInfoVal.Elem().Field(i).Addr().Interface()).(*Entry).SetSlice(valField.Interface().([]string)) - } - } else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr && !valField.IsZero() { - nestedInfoType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface()) - netstedInfoVal := 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 netstedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(Entry{}) { - netstedInfoVal.Elem().Field(j).Addr().Interface().(*Entry).Set(nestedVal.String()) - } - } - } - } else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*Entry)(nil)) { - confMap := valField.Interface().(map[string]string) - for key, val := range confMap { - var entr Entry - entr.Set(val) - (nodeInfoVal.Elem().Field(i).Interface()).(map[string](*Entry))[key] = &entr - } - } else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*NetDevEntry)(nil)) { - nestedMap := valField.Interface().(map[string](*NetDevs)) - for netName, netVals := range nestedMap { - netValsType := reflect.ValueOf(netVals) - netMap := nodeInfoVal.Elem().Field(i).Interface().(map[string](*NetDevEntry)) - var newNet NetDevEntry - newNet.Tags = make(map[string]*Entry) - // This should be done a bit down, but didn'tknow how to do it - netMap[netName] = &newNet - netInfoType := reflect.TypeOf(newNet) - netInfoVal := reflect.ValueOf(&newNet) - for j := 0; j < netInfoType.NumField(); j++ { - netVal := netValsType.Elem().FieldByName(netInfoType.Field(j).Name) - if netVal.IsValid() { - if netVal.Type().Kind() == reflect.String { - netInfoVal.Elem().Field(j).Addr().Interface().((*Entry)).Set(netVal.String()) - if netInfoType.Field(j).Name == "Netmask" { - netInfoVal.Elem().Field(j).Addr().Interface().((*Entry)).SetDefault("255.255.255.0") - } - } 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) - netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key] = &entr - } - } - } - } - } - } - } - } - -} - /* Get all the nodes of a configuration. This function also merges the nodes with the given profiles and set the default values @@ -147,9 +76,9 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) { } // special handling for profile to get the default one if len(node.Profiles) == 0 { - n.Profiles = []string{"default"} + n.Profiles.SetSlice([]string{"default"}) } else { - n.Profiles = node.Profiles + n.Profiles.SetSlice(node.Profiles) } // node explciti nodename field in NodeConf n.Id.Set(nodename) @@ -158,7 +87,7 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) { node.Tags[keyname] = key delete(node.Keys, keyname) } - n.initFrom(node) + n.setFrom(node) // backward compatibility n.Ipmi.Ipaddr.Set(node.IpmiIpaddr) n.Ipmi.Netmask.Set(node.IpmiNetmask) @@ -187,75 +116,14 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) { node.Tags = make(map[string]string) } - for _, profileName := range n.Profiles { + for _, profileName := range n.Profiles.GetSlice() { if _, ok := config.NodeProfiles[profileName]; !ok { wwlog.Printf(wwlog.WARN, "Profile not found for node '%s': %s\n", nodename, profileName) continue } // 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) - nodeInfoVal := reflect.ValueOf(&n) - nodeInfoType := reflect.TypeOf(&n) - profileConfVal := reflect.ValueOf(config.NodeProfiles[profileName]) - for i := 0; i < nodeInfoType.Elem().NumField(); i++ { - valField := profileConfVal.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 { - (nodeInfoVal.Elem().Field(i).Addr().Interface()).(*Entry).SetAlt(valField.String(), profileName) - } else if valField.Type() == reflect.TypeOf([]string{}) { - (nodeInfoVal.Elem().Field(i).Addr().Interface()).(*Entry).SetAltSlice(valField.Interface().([]string), profileName) - } - } else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr && !valField.IsZero() { - nestedInfoType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface()) - netstedInfoVal := 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 netstedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(Entry{}) { - netstedInfoVal.Elem().Field(j).Addr().Interface().(*Entry).SetAlt(nestedVal.String(), profileName) - } - } - } - } else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*Entry)(nil)) { - confMap := valField.Interface().(map[string]string) - for key, val := range confMap { - var entr Entry - entr.SetAlt(val, profileName) - (nodeInfoVal.Elem().Field(i).Interface()).(map[string](*Entry))[key] = &entr - } - } else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*NetDevEntry)(nil)) { - nestedMap := valField.Interface().(map[string](*NetDevs)) - for netName, netVals := range nestedMap { - netValsType := reflect.ValueOf(netVals) - netMap := nodeInfoVal.Elem().Field(i).Interface().(map[string](*NetDevEntry)) - var newNet NetDevEntry - newNet.Tags = make(map[string]*Entry) - // This should be done a bit down, but didn'tknow how to do it - netMap[netName] = &newNet - netInfoType := reflect.TypeOf(newNet) - netInfoVal := reflect.ValueOf(&newNet) - for j := 0; j < netInfoType.NumField(); j++ { - netVal := netValsType.Elem().FieldByName(netInfoType.Field(j).Name) - if netVal.IsValid() { - if netVal.Type().Kind() == reflect.String { - netInfoVal.Elem().Field(j).Addr().Interface().((*Entry)).SetAlt(netVal.String(), profileName) - } else if netVal.Type() == reflect.TypeOf(map[string]string{}) { - // normally the map should be created here, but did not manage it - for key, val := range (netVal.Interface()).(map[string]string) { - var entr Entry - entr.SetAlt(val, profileName) - netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key] = &entr - } - } - } - } - } - } - } - } + config.NodeProfiles[profileName].setAltFrom(n, profileName) } ret = append(ret, n) } @@ -287,7 +155,7 @@ func (config *NodeYaml) FindAllProfiles() ([]NodeInfo, error) { profile.Tags[keyname] = key delete(profile.Keys, keyname) } - p.initFrom(profile) + p.setFrom(profile) p.Ipmi.Ipaddr.Set(profile.IpmiIpaddr) p.Ipmi.Netmask.Set(profile.IpmiNetmask) p.Ipmi.Port.Set(profile.IpmiPort) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index 5f2d0e82..1255dd53 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -120,7 +120,7 @@ type NodeInfo struct { AssetKey Entry Kernel *KernelEntry Ipmi *IpmiEntry - Profiles []string + Profiles Entry NetDevs map[string]*NetDevEntry Tags map[string]*Entry } diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go index c27785ec..a8713e8f 100644 --- a/internal/pkg/node/methods.go +++ b/internal/pkg/node/methods.go @@ -50,10 +50,10 @@ func FilterByName(set []NodeInfo, searchList []string) []NodeInfo { *********/ /* - Set value. If argument is 'UNDEF', 'DELETE', - 'UNSET" or '--' the value is removed. - N.B. the '--' might never ever happen as '--' - is parsed out by cobra +Set value. If argument is 'UNDEF', 'DELETE', +'UNSET" or '--' the value is removed. +N.B. the '--' might never ever happen as '--' +is parsed out by cobra */ func (ent *Entry) Set(val string) { if val == "" { @@ -147,6 +147,13 @@ func (ent *Entry) SetDefaultSlice(val []string) { } +/* +Remove a elemnt from a slice +*/ +func (ent *Entry) SliceRemoveElement(val string) { + util.SliceRemoveElement(ent.value, val) +} + /********** * * Gets @@ -340,7 +347,7 @@ func SetEntry(entryPtr interface{}, val interface{}) { /* Add an entry in a map */ -func AddEntry(entryMapInt interface{}, val interface{}) { +func addEntry(entryMapInt interface{}, val interface{}) { if reflect.TypeOf(entryMapInt) == reflect.TypeOf((*map[string]*Entry)(nil)) { if reflect.ValueOf(entryMapInt).Elem().IsNil() { newMap := make(map[string]*Entry) @@ -369,7 +376,7 @@ func AddEntry(entryMapInt interface{}, val interface{}) { /* Del an entry in a map */ -func DelEntry(entryMapInt interface{}, val interface{}) { +func delEntry(entryMapInt interface{}, val interface{}) { if reflect.TypeOf(entryMapInt) == reflect.TypeOf((*map[string]*Entry)(nil)) { entryMap := entryMapInt.(*map[string]*Entry) str, ok := (val).(string) @@ -411,9 +418,9 @@ func (node *NodeInfo) SetField(fieldName string, val interface{}) { fieldMap := reflect.ValueOf(node).Elem().FieldByName(fieldNames[1]) if fieldMap.IsValid() { if fieldNames[0] == "del" { - DelEntry(fieldMap.Addr().Elem().Interface(), val) + delEntry(fieldMap.Addr().Interface(), val) } else if fieldNames[0] == "add" { - AddEntry(fieldMap.Addr().Elem().Interface(), val) + addEntry(fieldMap.Addr().Interface(), val) } } else { panic(fmt.Sprintf("invalid del/add operation with name %s called, field %s does not exists\n", fieldName, fieldNames[0])) @@ -427,7 +434,6 @@ func (node *NodeInfo) SetField(fieldName string, val interface{}) { (*entry).SetField(strings.Join(fieldNames[1:], "."), val) case reflect.TypeOf((**IpmiEntry)(nil)): entry := nestedField.Addr().Interface().(**IpmiEntry) - fmt.Println(fieldNames) (*entry).SetField(strings.Join(fieldNames[1:], "."), val) case reflect.TypeOf((*map[string]*NetDevEntry)(nil)): if len(fieldNames) >= 3 { @@ -465,9 +471,9 @@ func (node *KernelEntry) SetField(fieldName string, val interface{}) { valFields := strings.Split(fieldName, ".") field = reflect.ValueOf(node).Elem().FieldByName(valFields[1]) if field.IsValid() && len(valFields) == 2 && valFields[0] == "add" { - AddEntry(field.Addr().Interface(), val) + addEntry(field.Addr().Interface(), val) } else if field.IsValid() && len(valFields) == 2 && valFields[0] == "del" { - DelEntry(field.Addr().Interface(), val) + delEntry(field.Addr().Interface(), val) } else { panic(fmt.Sprintf("field %s does not exists in node.NetDevEntry\n", fieldName)) } @@ -482,13 +488,12 @@ func (node *IpmiEntry) SetField(fieldName string, val interface{}) { if field.IsValid() { SetEntry(field.Addr().Interface(), val) } else { - fmt.Println(fieldName) valFields := strings.Split(fieldName, ".") field = reflect.ValueOf(node).Elem().FieldByName(valFields[1]) if field.IsValid() && len(valFields) == 2 && valFields[0] == "add" { - AddEntry(field.Addr().Interface(), val) + addEntry(field.Addr().Interface(), val) } else if field.IsValid() && len(valFields) == 2 && valFields[0] == "del" { - DelEntry(field.Addr().Interface(), val) + delEntry(field.Addr().Interface(), val) } else { panic(fmt.Sprintf("field %s does not exists in node.NetDevEntry\n", fieldName)) } @@ -506,9 +511,9 @@ func (node *NetDevEntry) SetField(fieldName string, val interface{}) { valFields := strings.Split(fieldName, ".") field = reflect.ValueOf(node).Elem().FieldByName(valFields[1]) if field.IsValid() && len(valFields) == 2 && valFields[0] == "add" { - AddEntry(field.Addr().Interface(), val) + addEntry(field.Addr().Interface(), val) } else if field.IsValid() && len(valFields) == 2 && valFields[0] == "del" { - DelEntry(field.Addr().Interface(), val) + delEntry(field.Addr().Interface(), val) } else { panic(fmt.Sprintf("field %s does not exists in node.NetDevEntry\n", fieldName)) } diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index 4d094dc6..bb3a5677 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -29,7 +29,7 @@ func (config *NodeYaml) AddNode(nodeID string) (NodeInfo, error) { config.Nodes[nodeID].Profiles = []string{"default"} config.Nodes[nodeID].NetDevs = make(map[string]*NetDevs) n.Id.Set(nodeID) - n.Profiles = []string{"default"} + n.Profiles.SetSlice([]string{"default"}) n.NetDevs = make(map[string]*NetDevEntry) n.Ipmi = new(IpmiEntry) n.Kernel = new(KernelEntry) @@ -55,68 +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].Comment = node.Comment.GetReal() - config.Nodes[nodeID].ContainerName = node.ContainerName.GetReal() - config.Nodes[nodeID].ClusterName = node.ClusterName.GetReal() - config.Nodes[nodeID].Ipxe = node.Ipxe.GetReal() - config.Nodes[nodeID].Init = node.Init.GetReal() - - if node.Kernel != nil && (node.Kernel.Override.GotReal() || node.Kernel.Args.GotReal()) { - config.Nodes[nodeID].Kernel = new(KernelConf) - config.Nodes[nodeID].Kernel.Override = node.Kernel.Override.GetReal() - config.Nodes[nodeID].Kernel.Args = node.Kernel.Args.GetReal() - } - - if node.Ipmi != nil && (node.Ipmi.Ipaddr.GotReal() || node.Ipmi.Netmask.GotReal() || - node.Ipmi.Port.GotReal() || node.Ipmi.Gateway.GotReal() || node.Ipmi.UserName.GotReal() || - node.Ipmi.Password.GotReal() || node.Ipmi.Interface.GotReal() || node.Ipmi.Write.GotReal()) { - config.Nodes[nodeID].Ipmi = new(IpmiConf) - config.Nodes[nodeID].Ipmi.Ipaddr = node.Ipmi.Ipaddr.GetReal() - config.Nodes[nodeID].Ipmi.Netmask = node.Ipmi.Netmask.GetReal() - config.Nodes[nodeID].Ipmi.Port = node.Ipmi.Port.GetReal() - config.Nodes[nodeID].Ipmi.Gateway = node.Ipmi.Gateway.GetReal() - config.Nodes[nodeID].Ipmi.UserName = node.Ipmi.UserName.GetReal() - config.Nodes[nodeID].Ipmi.Password = node.Ipmi.Password.GetReal() - config.Nodes[nodeID].Ipmi.Interface = node.Ipmi.Interface.GetReal() - config.Nodes[nodeID].Ipmi.Write = node.Ipmi.Write.Get() - } - config.Nodes[nodeID].RuntimeOverlay = node.RuntimeOverlay.GetRealSlice() - config.Nodes[nodeID].SystemOverlay = node.SystemOverlay.GetRealSlice() - config.Nodes[nodeID].Root = node.Root.GetReal() - config.Nodes[nodeID].AssetKey = node.AssetKey.GetReal() - config.Nodes[nodeID].Discoverable = node.Discoverable.GetReal() - - config.Nodes[nodeID].Profiles = node.Profiles - - config.Nodes[nodeID].NetDevs = make(map[string]*NetDevs) - for devname, netdev := range node.NetDevs { - var newdev NetDevs - config.Nodes[nodeID].NetDevs[devname] = &newdev - - config.Nodes[nodeID].NetDevs[devname].Device = netdev.Device.GetReal() - config.Nodes[nodeID].NetDevs[devname].Ipaddr = netdev.Ipaddr.GetReal() - config.Nodes[nodeID].NetDevs[devname].Netmask = netdev.Netmask.GetReal() - config.Nodes[nodeID].NetDevs[devname].Hwaddr = netdev.Hwaddr.GetReal() - config.Nodes[nodeID].NetDevs[devname].Gateway = netdev.Gateway.GetReal() - config.Nodes[nodeID].NetDevs[devname].Type = netdev.Type.GetReal() - config.Nodes[nodeID].NetDevs[devname].OnBoot = netdev.OnBoot.GetReal() - config.Nodes[nodeID].NetDevs[devname].Primary = netdev.Primary.GetReal() - config.Nodes[nodeID].NetDevs[devname].Tags = make(map[string]string) - for keyname, key := range netdev.Tags { - if key.GetReal() != "" { - config.Nodes[nodeID].NetDevs[devname].Tags[keyname] = key.GetReal() - } - } - } - - config.Nodes[nodeID].Tags = make(map[string]string) - for keyname, key := range node.Tags { - if key.GetReal() != "" { - config.Nodes[nodeID].Tags[keyname] = key.GetReal() - } - } - + config.Nodes[nodeID].getRealFrom(node) return nil } @@ -164,61 +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].Comment = profile.Comment.GetReal() - config.NodeProfiles[profileID].ContainerName = profile.ContainerName.GetReal() - config.NodeProfiles[profileID].Ipxe = profile.Ipxe.GetReal() - config.NodeProfiles[profileID].Init = profile.Init.GetReal() - config.NodeProfiles[profileID].ClusterName = profile.ClusterName.GetReal() - if profile.Kernel.Override.GotReal() || profile.Kernel.Args.GotReal() { - config.NodeProfiles[profileID].Kernel = new(KernelConf) - config.NodeProfiles[profileID].Kernel.Override = profile.Kernel.Override.GetReal() - config.NodeProfiles[profileID].Kernel.Args = profile.Kernel.Args.GetReal() - } - if profile.Ipmi.Ipaddr.GotReal() || profile.Ipmi.Netmask.GotReal() || - profile.Ipmi.Port.GotReal() || profile.Ipmi.Gateway.GotReal() || profile.Ipmi.UserName.GotReal() || - profile.Ipmi.Password.GotReal() || profile.Ipmi.Interface.GotReal() || profile.Ipmi.Write.GotReal() { - config.NodeProfiles[profileID].Ipmi = new(IpmiConf) - config.NodeProfiles[profileID].Ipmi.Ipaddr = profile.Ipmi.Ipaddr.GetReal() - config.NodeProfiles[profileID].Ipmi.Netmask = profile.Ipmi.Netmask.GetReal() - config.NodeProfiles[profileID].Ipmi.Port = profile.Ipmi.Port.GetReal() - config.NodeProfiles[profileID].Ipmi.Gateway = profile.Ipmi.Gateway.GetReal() - config.NodeProfiles[profileID].Ipmi.UserName = profile.Ipmi.UserName.GetReal() - config.NodeProfiles[profileID].Ipmi.Password = profile.Ipmi.Password.GetReal() - config.NodeProfiles[profileID].Ipmi.Interface = profile.Ipmi.Interface.GetReal() - config.NodeProfiles[profileID].Ipmi.Write = profile.Ipmi.Interface.Get() - } - config.NodeProfiles[profileID].RuntimeOverlay = profile.RuntimeOverlay.GetRealSlice() - config.NodeProfiles[profileID].SystemOverlay = profile.SystemOverlay.GetRealSlice() - config.NodeProfiles[profileID].Root = profile.Root.GetReal() - config.NodeProfiles[profileID].AssetKey = profile.AssetKey.GetReal() - config.NodeProfiles[profileID].Discoverable = profile.Discoverable.GetReal() - - config.NodeProfiles[profileID].Profiles = profile.Profiles - - config.NodeProfiles[profileID].NetDevs = make(map[string]*NetDevs) - for devname, netdev := range profile.NetDevs { - var newdev NetDevs - config.NodeProfiles[profileID].NetDevs[devname] = &newdev - - config.NodeProfiles[profileID].NetDevs[devname].Device = netdev.Device.GetReal() - config.NodeProfiles[profileID].NetDevs[devname].Ipaddr = netdev.Ipaddr.GetReal() - config.NodeProfiles[profileID].NetDevs[devname].Netmask = netdev.Netmask.GetReal() - config.NodeProfiles[profileID].NetDevs[devname].Hwaddr = netdev.Hwaddr.GetReal() - config.NodeProfiles[profileID].NetDevs[devname].Gateway = netdev.Gateway.GetReal() - config.NodeProfiles[profileID].NetDevs[devname].Type = netdev.Type.GetReal() - config.NodeProfiles[profileID].NetDevs[devname].OnBoot = netdev.OnBoot.GetReal() - config.NodeProfiles[profileID].NetDevs[devname].Primary = netdev.Primary.GetReal() - config.NodeProfiles[profileID].NetDevs[devname].Tags = make(map[string]string) - for key := range netdev.Tags { - config.NodeProfiles[profileID].NetDevs[devname].Tags[key] = netdev.Tags[key].GetReal() - } - } - - config.NodeProfiles[profileID].Tags = make(map[string]string) - for keyname, key := range profile.Tags { - config.NodeProfiles[profileID].Tags[keyname] = key.GetReal() - } - + config.NodeProfiles[profileID].getRealFrom(profile) return nil } diff --git a/internal/pkg/node/transformers.go b/internal/pkg/node/transformers.go new file mode 100644 index 00000000..f8bb58a9 --- /dev/null +++ b/internal/pkg/node/transformers.go @@ -0,0 +1,283 @@ +package node + +import "reflect" + +/* +Populates a NodeConf struct (the one which goes to disk) from a +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) { + 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.GetReal() + } else if confField.Type() == reflect.TypeOf([]string{}) { + newValue := (confField.Addr().Interface()).(*[]string) + entryVal := nodeInfoVal.Field(i).Interface().(Entry) + *newValue = entryVal.GetRealSlice() + } + } else if nodeInfoVal.Field(i).Type() == reflect.TypeOf(map[string]*Entry{}) { + entryMap := nodeInfoVal.Field(i).Interface().(map[string]*Entry) + for key, val := range entryMap { + confField.Interface().(map[string]string)[key] = val.GetReal() + } + } 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 + } + } + needNestedStruct := false + 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.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{}) { + 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.GetReal() + } + } + //} + } + // 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 { + netValsType := reflect.ValueOf(netVal) + 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).GetReal() + } 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) { + 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 { + (nodeInfoVal.Elem().Field(i).Addr().Interface()).(*Entry).Set(valField.String()) + } else if valField.Type() == reflect.TypeOf([]string{}) { + (nodeInfoVal.Elem().Field(i).Addr().Interface()).(*Entry).SetSlice(valField.Interface().([]string)) + } + } else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr && !valField.IsZero() { + nestedInfoType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface()) + netstedInfoVal := 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 netstedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(Entry{}) { + netstedInfoVal.Elem().Field(j).Addr().Interface().(*Entry).Set(nestedVal.String()) + } else { + confMap := nestedVal.Interface().(map[string]string) + if netstedInfoVal.Elem().Field(j).IsNil() { + newMap := make(map[string]*Entry) + mapPtr := (netstedInfoVal.Elem().Field(j).Addr().Interface()).(*map[string](*Entry)) + *mapPtr = newMap + } + for key, val := range confMap { + var entr Entry + entr.Set(val) + (netstedInfoVal.Elem().Field(j).Interface()).(map[string](*Entry))[key] = &entr + } + } + } + } + } else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*Entry)(nil)) { + confMap := valField.Interface().(map[string]string) + for key, val := range confMap { + var entr Entry + entr.Set(val) + (nodeInfoVal.Elem().Field(i).Interface()).(map[string](*Entry))[key] = &entr + } + } else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*NetDevEntry)(nil)) { + nestedMap := valField.Interface().(map[string](*NetDevs)) + for netName, netVals := range nestedMap { + netValsType := reflect.ValueOf(netVals) + netMap := nodeInfoVal.Elem().Field(i).Interface().(map[string](*NetDevEntry)) + var newNet NetDevEntry + newNet.Tags = make(map[string]*Entry) + // This should be done a bit down, but didn't know how to do it + netMap[netName] = &newNet + netInfoType := reflect.TypeOf(newNet) + netInfoVal := reflect.ValueOf(&newNet) + for j := 0; j < netInfoType.NumField(); j++ { + netVal := netValsType.Elem().FieldByName(netInfoType.Field(j).Name) + if netVal.IsValid() { + if netVal.Type().Kind() == reflect.String { + netInfoVal.Elem().Field(j).Addr().Interface().((*Entry)).Set(netVal.String()) + if netInfoType.Field(j).Name == "Netmask" { + netInfoVal.Elem().Field(j).Addr().Interface().((*Entry)).SetDefault("255.255.255.0") + } + } 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) + netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key] = &entr + } + } + } + } + } + } + } + } +} + +/* +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 +from. +*/ +func (node *NodeConf) setAltFrom(nodeInfo NodeInfo, profileName string) { + nodeInfoVal := reflect.ValueOf(&nodeInfo) + nodeInfoType := reflect.TypeOf(&nodeInfo) + profileConfVal := reflect.ValueOf(node) + for i := 0; i < nodeInfoType.Elem().NumField(); i++ { + valField := profileConfVal.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 { + (nodeInfoVal.Elem().Field(i).Addr().Interface()).(*Entry).SetAlt(valField.String(), profileName) + } else if valField.Type() == reflect.TypeOf([]string{}) { + (nodeInfoVal.Elem().Field(i).Addr().Interface()).(*Entry).SetAltSlice(valField.Interface().([]string), profileName) + } + } else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr && !valField.IsZero() { + nestedInfoType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface()) + netstedInfoVal := 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 netstedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(Entry{}) { + netstedInfoVal.Elem().Field(j).Addr().Interface().(*Entry).SetAlt(nestedVal.String(), profileName) + } + } + } + } else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*Entry)(nil)) { + confMap := valField.Interface().(map[string]string) + for key, val := range confMap { + var entr Entry + entr.SetAlt(val, profileName) + (nodeInfoVal.Elem().Field(i).Interface()).(map[string](*Entry))[key] = &entr + } + } else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string](*NetDevEntry)(nil)) { + nestedMap := valField.Interface().(map[string](*NetDevs)) + for netName, netVals := range nestedMap { + netValsType := reflect.ValueOf(netVals) + netMap := nodeInfoVal.Elem().Field(i).Interface().(map[string](*NetDevEntry)) + var newNet NetDevEntry + newNet.Tags = make(map[string]*Entry) + // This should be done a bit down, but didn'tknow how to do it + netMap[netName] = &newNet + netInfoType := reflect.TypeOf(newNet) + netInfoVal := reflect.ValueOf(&newNet) + for j := 0; j < netInfoType.NumField(); j++ { + netVal := netValsType.Elem().FieldByName(netInfoType.Field(j).Name) + if netVal.IsValid() { + if netVal.Type().Kind() == reflect.String { + netInfoVal.Elem().Field(j).Addr().Interface().((*Entry)).SetAlt(netVal.String(), profileName) + } else if netVal.Type() == reflect.TypeOf(map[string]string{}) { + // normally the map should be created here, but did not manage it + for key, val := range (netVal.Interface()).(map[string]string) { + var entr Entry + entr.SetAlt(val, profileName) + netInfoVal.Elem().Field(j).Interface().((map[string](*Entry)))[key] = &entr + } + } + } + } + } + } + } + } +}