diff --git a/internal/pkg/api/node/node.go b/internal/pkg/api/node/node.go index 14263082..df1c64f3 100644 --- a/internal/pkg/api/node/node.go +++ b/internal/pkg/api/node/node.go @@ -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) { diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index a8690d44..8afb52ae 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -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) diff --git a/internal/pkg/node/methods.go b/internal/pkg/node/methods.go index a8713e8f..b9e77ceb 100644 --- a/internal/pkg/node/methods.go +++ b/internal/pkg/node/methods.go @@ -16,6 +16,7 @@ import ( * Filters * *********/ + /* Filter a given slice of NodeInfo against a given regular expression diff --git a/internal/pkg/node/modifiers.go b/internal/pkg/node/modifiers.go index bb3a5677..a89b06de 100644 --- a/internal/pkg/node/modifiers.go +++ b/internal/pkg/node/modifiers.go @@ -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 } diff --git a/internal/pkg/node/transformers.go b/internal/pkg/node/transformers.go index f8bb58a9..1428500b 100644 --- a/internal/pkg/node/transformers.go +++ b/internal/pkg/node/transformers.go @@ -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) diff --git a/internal/pkg/overlay/datastructure.go b/internal/pkg/overlay/datastructure.go index 4a0575af..60716dc7 100644 --- a/internal/pkg/overlay/datastructure.go +++ b/internal/pkg/overlay/datastructure.go @@ -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