Merge branch 'RefactorFlags' into development
Signed-off-by: Christian Goll <cgoll@suse.de>
This commit is contained in:
28
CHANGELOG.md
28
CHANGELOG.md
@@ -33,6 +33,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
`wwctl --emptyconf genconfig warewulfconf print` for the available paths.
|
||||
- Added experimental dnsmasq support.
|
||||
|
||||
- new subcommand `wwctl genconf` is available with following subcommands:
|
||||
* `completions` which will create the files used for bash-completion. Also
|
||||
fish an zsh completions can be generated
|
||||
* `defaults` which will generate a valid `defaults.conf`
|
||||
* `man` which will generate the man pages in the specified directory
|
||||
* `reference` which will generate a reference documentation for the wwctl commands
|
||||
* `warwulfconf print` which will print the used `warewulf.conf`. If there is no valid
|
||||
`warewulf.conf` a valid configuration is provided, prefilled with default values
|
||||
and an IP configuration derived from the network configuration of the host
|
||||
- All paths can now be configured in `warewulf.conf`, check the paths section of of
|
||||
`wwctl --emptyconf genconfig warewulfconf print` for the available paths.
|
||||
- Added experimental dnsmasq support.
|
||||
|
||||
- new subcommand `wwctl genconf` is available with following subcommands:
|
||||
* `completions` which will create the files used for bash-completion. Also
|
||||
fish an zsh completions can be generated
|
||||
* `defaults` which will generate a valid `defaults.conf`
|
||||
* `man` which will generate the man pages in the specified directory
|
||||
* `reference` which will generate a reference documentation for the wwctl commands
|
||||
* `warwulfconf print` which will print the used `warewulf.conf`. If there is no valid
|
||||
`warewulf.conf` a valid configuration is provided, prefilled with default values
|
||||
and an IP configuration derived from the network configuration of the host
|
||||
- All paths can now be configured in `warewulf.conf`, check the paths section of of
|
||||
`wwctl --emptyconf genconfig warewulfconf print` for the available paths.
|
||||
- Added experimental dnsmasq support.
|
||||
- Check for formal correct IP and MAC addresses for command line options and
|
||||
when reading in the configurations
|
||||
|
||||
## [4.4.0] 2023-01-18
|
||||
|
||||
### Added
|
||||
|
||||
9
Makefile
9
Makefile
@@ -228,10 +228,11 @@ wwclient: $(WWCLIENT_DEPS)
|
||||
-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=/etc/warewulf/warewulf.conf'" -o ../../wwclient
|
||||
|
||||
man_pages: wwctl
|
||||
install -d man_pages
|
||||
./wwctl --emptyconf genconfig man man_pages
|
||||
cp docs/man/man5/*.5 ./man_pages/
|
||||
cd man_pages; for i in wwctl*1 *.5; do echo "Compressing manpage: $$i"; gzip --force $$i; done
|
||||
@install -d man_pages
|
||||
@./wwctl --emptyconf genconfig man man_pages
|
||||
@cp docs/man/man5/*.5 ./man_pages/
|
||||
@echo -n "Compressing manpage: "
|
||||
@cd man_pages; for i in wwctl*1 *.5; do gzip --force $$i; echo -n "$$i "; done; echo
|
||||
|
||||
update_configuration: vendor cmd/update_configuration/update_configuration.go
|
||||
cd cmd/update_configuration && go build -ldflags="-X 'github.com/hpcng/warewulf/internal/pkg/warewulfconf.ConfigFile=./etc/warewulf.conf'\
|
||||
|
||||
@@ -16,6 +16,12 @@ the required type is returned
|
||||
*/
|
||||
func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
// run converters for different types
|
||||
for _, c := range vars.converters {
|
||||
if err := c(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// remove the default network as all network values are assigned
|
||||
// to this network
|
||||
if _, ok := vars.nodeConf.NetDevs["default"]; ok && vars.netName != "" {
|
||||
|
||||
@@ -16,6 +16,7 @@ func Test_Add(t *testing.T) {
|
||||
args []string
|
||||
wantErr bool
|
||||
stdout string
|
||||
chkout bool
|
||||
outDb string
|
||||
}{
|
||||
{name: "single node add",
|
||||
@@ -39,6 +40,51 @@ nodes:
|
||||
n01:
|
||||
profiles:
|
||||
- foo
|
||||
`},
|
||||
{name: "single node add, discoverable true, explicit",
|
||||
args: []string{"--discoverable=true", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
discoverable: "true"
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "single node add, discoverable true with yes",
|
||||
args: []string{"--discoverable=yes", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
discoverable: "true"
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "single node add, discoverable wrong argument",
|
||||
args: []string{"--discoverable=maybe", "n01"},
|
||||
wantErr: true,
|
||||
stdout: "",
|
||||
chkout: false,
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes: {}
|
||||
`},
|
||||
{name: "single node add, discoverable false",
|
||||
args: []string{"--discoverable=false", "n01"},
|
||||
wantErr: false,
|
||||
stdout: "",
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes:
|
||||
n01:
|
||||
discoverable: "false"
|
||||
profiles:
|
||||
- default
|
||||
`},
|
||||
{name: "single node add with Kernel args",
|
||||
args: []string{"--kernelargs=foo", "n01"},
|
||||
@@ -94,6 +140,15 @@ nodes:
|
||||
network devices:
|
||||
default:
|
||||
ipaddr: 10.0.0.1
|
||||
`},
|
||||
{name: "single node with malformed ipaddr",
|
||||
args: []string{"--ipaddr=10.0.1", "n01"},
|
||||
wantErr: true,
|
||||
stdout: "",
|
||||
chkout: false,
|
||||
outDb: `WW_INTERNAL: 43
|
||||
nodeprofiles: {}
|
||||
nodes: {}
|
||||
`},
|
||||
{name: "three nodes with ipaddr",
|
||||
args: []string{"--ipaddr=10.10.0.1", "n[01-02,03]"},
|
||||
@@ -212,7 +267,7 @@ WW_INTERNAL: 43
|
||||
t.Errorf("DB dump is wrong, got:'%s'\nwant:'%s'", dump, tt.outDb)
|
||||
t.FailNow()
|
||||
}
|
||||
if buf.String() != tt.stdout {
|
||||
if tt.chkout && buf.String() != tt.stdout {
|
||||
t.Errorf("Got wrong output, got:'%s'\nwant:'%s'", buf.String(), tt.stdout)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ import (
|
||||
|
||||
// Holds the variables which are needed in CobraRunE
|
||||
type variables struct {
|
||||
netName string
|
||||
nodeConf node.NodeConf
|
||||
netName string
|
||||
nodeConf node.NodeConf
|
||||
converters []func() error
|
||||
}
|
||||
|
||||
// Returns the newly created command
|
||||
@@ -28,9 +29,8 @@ func GetCommand() *cobra.Command {
|
||||
RunE: CobraRunE(&vars),
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
}
|
||||
vars.nodeConf.CreateFlags(baseCmd, []string{"tagdel", "nettagdel", "ipmitagdel"})
|
||||
vars.converters = vars.nodeConf.CreateFlags(baseCmd, []string{"tagdel", "nettagdel", "ipmitagdel"})
|
||||
baseCmd.PersistentFlags().StringVar(&vars.netName, "netname", "", "Set network name for network options")
|
||||
|
||||
// register the command line completions
|
||||
if err := baseCmd.RegisterFlagCompletionFunc("container", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
list, _ := container.ListSources()
|
||||
|
||||
@@ -77,17 +77,38 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
// ignore error as only may occurs under strange circumstances
|
||||
buffer, _ := io.ReadAll(file)
|
||||
err = yaml.Unmarshal(buffer, modifiedNodeMap)
|
||||
if err == nil {
|
||||
nodeList := make([]string, len(nodeMap))
|
||||
i := 0
|
||||
for key := range nodeMap {
|
||||
nodeList[i] = key
|
||||
i++
|
||||
}
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Are you sure you want to modify %d nodes", len(modifiedNodeMap)))
|
||||
if !yes {
|
||||
if err != nil {
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Got following error on parsing: %s, Retry", err))
|
||||
if yes {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
var checkErrors []error
|
||||
for nodeName, node := range modifiedNodeMap {
|
||||
err = node.Check()
|
||||
if err != nil {
|
||||
checkErrors = append(checkErrors, fmt.Errorf("node: %s parse error: %s", nodeName, err))
|
||||
}
|
||||
}
|
||||
if len(checkErrors) != 0 {
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Got following error on parsing: %s, Retry", checkErrors))
|
||||
if yes {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
nodeList := make([]string, len(nodeMap))
|
||||
i := 0
|
||||
for key := range nodeMap {
|
||||
nodeList[i] = key
|
||||
i++
|
||||
}
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Are you sure you want to modify %d nodes", len(modifiedNodeMap)))
|
||||
if yes {
|
||||
err = apinode.NodeDelete(&wwapiv1.NodeDeleteParameter{NodeNames: nodeList, Force: true})
|
||||
if err != nil {
|
||||
wwlog.Verbose("Problem deleting nodes before modification %s")
|
||||
@@ -99,11 +120,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
os.Exit(1)
|
||||
}
|
||||
break
|
||||
} else {
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Got following error on parsing: %s, Retry", err))
|
||||
if !yes {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
|
||||
@@ -13,6 +13,12 @@ import (
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
// run converters for different types
|
||||
for _, c := range Converters {
|
||||
if err := c(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// remove the default network as the all network values are assigned
|
||||
// to this network
|
||||
if NetName != "default" {
|
||||
|
||||
@@ -38,11 +38,12 @@ var (
|
||||
SetYes bool
|
||||
SetForce bool
|
||||
NodeConf node.NodeConf
|
||||
Converters []func() error
|
||||
)
|
||||
|
||||
func init() {
|
||||
NodeConf = node.NewConf()
|
||||
NodeConf.CreateFlags(baseCmd, []string{})
|
||||
Converters = NodeConf.CreateFlags(baseCmd, []string{})
|
||||
baseCmd.PersistentFlags().StringVarP(&SetNetDevDel, "netdel", "D", "", "Delete the node's network device")
|
||||
baseCmd.PersistentFlags().StringVar(&NetName, "netname", "default", "Set network name for network options")
|
||||
baseCmd.PersistentFlags().BoolVarP(&SetNodeAll, "all", "a", false, "Set all nodes")
|
||||
|
||||
@@ -14,6 +14,12 @@ import (
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) (err error) {
|
||||
// run converters for different types
|
||||
for _, c := range Converters {
|
||||
if err := c(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// remove the default network as the all network values are assigned
|
||||
// to this network
|
||||
if NetName != "" {
|
||||
|
||||
@@ -25,12 +25,13 @@ var (
|
||||
SetForce bool
|
||||
NetName string
|
||||
ProfileConf node.NodeConf
|
||||
Converters []func() error
|
||||
)
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
ProfileConf = node.NewConf()
|
||||
ProfileConf.CreateFlags(baseCmd,
|
||||
Converters = ProfileConf.CreateFlags(baseCmd,
|
||||
[]string{"ipaddr", "ipaddr6", "ipmiaddr", "profile"})
|
||||
baseCmd.PersistentFlags().StringVar(&NetName, "netname", "", "Set network name for network options")
|
||||
// register the command line completions
|
||||
|
||||
@@ -71,24 +71,44 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
sum2 := hex.EncodeToString(hasher.Sum(nil))
|
||||
wwlog.Debug("Hashes are before %s and after %s\n", sum1, sum2)
|
||||
if sum1 != sum2 {
|
||||
wwlog.Debug("Nodes were modified")
|
||||
wwlog.Debug("Profiles were modified")
|
||||
modifiedProfileMap := make(map[string]*node.NodeConf)
|
||||
_, _ = file.Seek(0, 0)
|
||||
// ignore error as only may occurs under strange circumstances
|
||||
buffer, _ := io.ReadAll(file)
|
||||
err = yaml.Unmarshal(buffer, modifiedProfileMap)
|
||||
if err == nil {
|
||||
nodeList := make([]string, len(profileMap))
|
||||
i := 0
|
||||
for key := range profileMap {
|
||||
nodeList[i] = key
|
||||
i++
|
||||
}
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Are you sure you want to modify %d nodes", len(modifiedProfileMap)))
|
||||
if !yes {
|
||||
if err != nil {
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Got following error on parsing: %s, Retry", err))
|
||||
if yes {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
err = apiprofile.ProfileDelete(&wwapiv1.NodeDeleteParameter{NodeNames: nodeList, Force: true})
|
||||
}
|
||||
var checkErrors []error
|
||||
for nodeName, node := range modifiedProfileMap {
|
||||
err = node.Check()
|
||||
if err != nil {
|
||||
checkErrors = append(checkErrors, fmt.Errorf("profile: %s parse error: %s", nodeName, err))
|
||||
}
|
||||
}
|
||||
if len(checkErrors) != 0 {
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Got following error on parsing: %s, Retry", checkErrors))
|
||||
if yes {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
pList := make([]string, len(profileMap))
|
||||
i := 0
|
||||
for key := range profileMap {
|
||||
pList[i] = key
|
||||
i++
|
||||
}
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Are you sure you want to modify %d nodes", len(modifiedProfileMap)))
|
||||
if yes {
|
||||
err = apiprofile.ProfileDelete(&wwapiv1.NodeDeleteParameter{NodeNames: pList, Force: true})
|
||||
if err != nil {
|
||||
wwlog.Verbose("Problem deleting nodes before modification %s")
|
||||
}
|
||||
@@ -99,11 +119,6 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
os.Exit(1)
|
||||
}
|
||||
break
|
||||
} else {
|
||||
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Got following error on parsing: %s, Retry", err))
|
||||
if !yes {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
|
||||
@@ -38,11 +38,12 @@ var (
|
||||
SetForce bool
|
||||
NetName string
|
||||
ProfileConf node.NodeConf
|
||||
Converters []func() error
|
||||
)
|
||||
|
||||
func init() {
|
||||
ProfileConf = node.NewConf()
|
||||
ProfileConf.CreateFlags(baseCmd,
|
||||
Converters = ProfileConf.CreateFlags(baseCmd,
|
||||
[]string{"ipaddr", "ipaddr6", "ipmiaddr", "profile"})
|
||||
baseCmd.PersistentFlags().StringVar(&NetName, "netname", "default", "Set network name for network options")
|
||||
baseCmd.PersistentFlags().StringVarP(&SetNetDevDel, "netdel", "D", "", "Delete the node's network device")
|
||||
|
||||
@@ -60,6 +60,10 @@ func NodeAddFromYaml(nodeList *wwapiv1.NodeYaml) (err error) {
|
||||
return errors.Wrap(err, "Could not unmarshall Yaml: %s\n")
|
||||
}
|
||||
for nodeName, node := range nodeMap {
|
||||
err = node.Check()
|
||||
if err != nil {
|
||||
return errors.Errorf("error on node %s: %s", nodeName, err)
|
||||
}
|
||||
nodeDB.Nodes[nodeName] = node
|
||||
}
|
||||
err = nodeDB.Persist()
|
||||
|
||||
@@ -50,6 +50,12 @@ func NodeAdd(nap *wwapiv1.NodeAddParameter) (err error) {
|
||||
// only key
|
||||
}
|
||||
// setting node from the received yaml
|
||||
err = nodeConf.Check()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error on check of node %s: %s", n.Id.Get(), err)
|
||||
return
|
||||
|
||||
}
|
||||
n.SetFrom(&nodeConf)
|
||||
if netName != "" && nodeConf.NetDevs[netName].Ipaddr != "" {
|
||||
// if more nodes are added increment IPv4 address
|
||||
@@ -236,6 +242,12 @@ func NodeSetParameterCheck(set *wwapiv1.NodeSetParameter, console bool) (nodeDB
|
||||
wwlog.Error(fmt.Sprintf("%v", err.Error()))
|
||||
return
|
||||
}
|
||||
err = nodeConf.Check()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error on check of node %s: %s", n.Id.Get(), err)
|
||||
return
|
||||
|
||||
}
|
||||
n.SetFrom(&nodeConf)
|
||||
if set.NetdevDelete != "" {
|
||||
if _, ok := n.NetDevs[set.NetdevDelete]; !ok {
|
||||
|
||||
97
internal/pkg/node/checkconf.go
Normal file
97
internal/pkg/node/checkconf.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
)
|
||||
|
||||
/*
|
||||
Checks if for NodeConf all values can be parsed according to their type.
|
||||
*/
|
||||
func (nodeConf *NodeConf) Check() (err error) {
|
||||
nodeInfoType := reflect.TypeOf(nodeConf)
|
||||
nodeInfoVal := reflect.ValueOf(nodeConf)
|
||||
// now iterate of every field
|
||||
for i := 0; i < nodeInfoVal.Elem().NumField(); i++ {
|
||||
//wwlog.Debug("checking field: %s type: %s", nodeInfoType.Elem().Field(i).Name, nodeInfoVal.Elem().Field(i).Type())
|
||||
if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.String {
|
||||
newFmt, err := checker(nodeInfoVal.Elem().Field(i).Interface().(string), nodeInfoType.Elem().Field(i).Tag.Get("type"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("field: %s value:%s err: %s", nodeInfoType.Elem().Field(i).Name, nodeInfoVal.Elem().Field(i).String(), err)
|
||||
} else if newFmt != "" {
|
||||
nodeInfoVal.Elem().Field(i).SetString(newFmt)
|
||||
}
|
||||
} else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr && !nodeInfoVal.Elem().Field(i).IsNil() {
|
||||
nestType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface())
|
||||
nestVal := reflect.ValueOf(nodeInfoVal.Elem().Field(i).Interface())
|
||||
for j := 0; j < nestType.Elem().NumField(); j++ {
|
||||
if nestType.Elem().Field(j).Type.Kind() == reflect.String {
|
||||
//wwlog.Debug("checking field: %s type: %s", nestType.Elem().Field(j).Name, nestType.Elem().Field(j).Tag.Get("type"))
|
||||
newFmt, err := checker(nestVal.Elem().Field(j).Interface().(string), nestType.Elem().Field(j).Tag.Get("type"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("field: %s value:%s err: %s", nestType.Elem().Field(j).Name, nestVal.Elem().Field(j).String(), err)
|
||||
} else if newFmt != "" {
|
||||
nestVal.Elem().Field(j).SetString(newFmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string]*NetDevs(nil)) {
|
||||
netMap := nodeInfoVal.Elem().Field(i).Interface().(map[string]*NetDevs)
|
||||
for _, val := range netMap {
|
||||
netType := reflect.TypeOf(val)
|
||||
netVal := reflect.ValueOf(val)
|
||||
for j := 0; j < netType.Elem().NumField(); j++ {
|
||||
newFmt, err := checker(netVal.Elem().Field(j).String(), netType.Elem().Field(j).Tag.Get("type"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("field: %s value:%s err: %s", netType.Elem().Field(j).Name, netVal.Elem().Field(j).String(), err)
|
||||
} else if newFmt != "" {
|
||||
netVal.Elem().Field(j).SetString(newFmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checker(value string, valType string) (niceValue string, err error) {
|
||||
if valType == "" || value == "" || util.InSlice(GetUnsetVerbs(), value) {
|
||||
return "", nil
|
||||
}
|
||||
//wwlog.Debug("checker: %s is %s", value, valType)
|
||||
switch valType {
|
||||
case "":
|
||||
return "", nil
|
||||
case "bool":
|
||||
if strings.ToLower(value) == "yes" {
|
||||
return "true", nil
|
||||
}
|
||||
if strings.ToLower(value) == "no" {
|
||||
return "false", nil
|
||||
}
|
||||
myBool, err := strconv.ParseBool(value)
|
||||
return strconv.FormatBool(myBool), err
|
||||
case "IP":
|
||||
if addr := net.ParseIP(value); addr == nil {
|
||||
return "", fmt.Errorf("%s can't be parsed to ip address", value)
|
||||
} else {
|
||||
return addr.String(), nil
|
||||
}
|
||||
case "MAC":
|
||||
if mac, err := net.ParseMAC(value); err != nil {
|
||||
return "", fmt.Errorf("%s can't be parsed to MAC address: %s", value, err)
|
||||
} else {
|
||||
return mac.String(), nil
|
||||
}
|
||||
case "uint":
|
||||
if _, err := strconv.ParseUint(value, 10, 64); err != nil {
|
||||
return "", fmt.Errorf("%s is not a uint: %s", value, err)
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package node
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
@@ -71,6 +72,21 @@ func New() (NodeYaml, error) {
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
wwlog.Debug("Checking nodes for types")
|
||||
for nodeName, node := range ret.Nodes {
|
||||
err = node.Check()
|
||||
if err != nil {
|
||||
wwlog.Warn("node: %s parsing error: %s", nodeName, err)
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
for profileName, profile := range ret.NodeProfiles {
|
||||
err = profile.Check()
|
||||
if err != nil {
|
||||
wwlog.Warn("node: %s parsing error: %s", profileName, err)
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
|
||||
wwlog.Debug("Returning node object")
|
||||
cachedDB = ret
|
||||
@@ -119,12 +135,13 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) {
|
||||
defData, err := os.ReadFile(DefaultConfig)
|
||||
if err != nil {
|
||||
wwlog.Verbose("Couldn't read DefaultConfig :%s\n", err)
|
||||
wwlog.Verbose("Using building defaults")
|
||||
defData = []byte(FallBackConf)
|
||||
}
|
||||
wwlog.Debug("Unmarshalling default config\n")
|
||||
err = yaml.Unmarshal(defData, &defConf)
|
||||
if err != nil {
|
||||
wwlog.Verbose("Couldn't unmarshall defaults from file :%s\n", err)
|
||||
wwlog.Verbose("Using building defaults")
|
||||
err = yaml.Unmarshal([]byte(FallBackConf), &defConf)
|
||||
if err != nil {
|
||||
wwlog.Warn("Could not get any defaults")
|
||||
@@ -165,6 +182,10 @@ func (config *NodeYaml) FindAllNodes() ([]NodeInfo, error) {
|
||||
node.Tags[keyname] = key
|
||||
delete(node.Keys, keyname)
|
||||
}
|
||||
err = node.Check()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("node: %s check error: %s", nodename, err)
|
||||
}
|
||||
n.SetFrom(node)
|
||||
// only now the netdevs start to exist so that default values can be set
|
||||
for _, netdev := range n.NetDevs {
|
||||
|
||||
@@ -44,7 +44,7 @@ type NodeConf struct {
|
||||
Init string `yaml:"init,omitempty" lopt:"init" sopt:"i" comment:"Define the init process to boot the container"`
|
||||
Root string `yaml:"root,omitempty" lopt:"root" comment:"Define the rootfs" `
|
||||
AssetKey string `yaml:"asset key,omitempty" lopt:"asset" comment:"Set the node's Asset tag (key)"`
|
||||
Discoverable string `yaml:"discoverable,omitempty" lopt:"discoverable" comment:"Make discoverable in given network (yes/no)"`
|
||||
Discoverable string `yaml:"discoverable,omitempty" lopt:"discoverable" sopt:"e" comment:"Make discoverable in given network (true/false)" type:"bool"`
|
||||
Profiles []string `yaml:"profiles,omitempty" lopt:"profile" sopt:"P" comment:"Set the node's profile members (comma separated)"`
|
||||
NetDevs map[string]*NetDevs `yaml:"network devices,omitempty"`
|
||||
Tags map[string]string `yaml:"tags,omitempty" lopt:"tagadd" comment:"base key"`
|
||||
@@ -56,12 +56,12 @@ type NodeConf struct {
|
||||
type IpmiConf struct {
|
||||
UserName string `yaml:"username,omitempty" lopt:"ipmiuser" comment:"Set the IPMI username"`
|
||||
Password string `yaml:"password,omitempty" lopt:"ipmipass" comment:"Set the IPMI password"`
|
||||
Ipaddr string `yaml:"ipaddr,omitempty" lopt:"ipmiaddr" comment:"Set the IPMI IP address"`
|
||||
Netmask string `yaml:"netmask,omitempty" lopt:"ipminetmask" comment:"Set the IPMI netmask"`
|
||||
Ipaddr string `yaml:"ipaddr,omitempty" lopt:"ipmiaddr" comment:"Set the IPMI IP address" type:"IP"`
|
||||
Netmask string `yaml:"netmask,omitempty" lopt:"ipminetmask" comment:"Set the IPMI netmask" type:"IP"`
|
||||
Port string `yaml:"port,omitempty" lopt:"ipmiport" comment:"Set the IPMI port"`
|
||||
Gateway string `yaml:"gateway,omitempty" lopt:"ipmigateway" comment:"Set the IPMI gateway"`
|
||||
Gateway string `yaml:"gateway,omitempty" lopt:"ipmigateway" comment:"Set the IPMI gateway" type:"IP"`
|
||||
Interface string `yaml:"interface,omitempty" lopt:"ipmiinterface" comment:"Set the node's IPMI interface (defaults: 'lan')"`
|
||||
Write string `yaml:"write,omitempty" lopt:"ipmiwrite" comment:"Enable the write of impi configuration (yes/no)"`
|
||||
Write string `yaml:"write,omitempty" lopt:"ipmiwrite" comment:"Enable the write of impi configuration (true/false)" type:"bool"`
|
||||
Tags map[string]string `yaml:"tags,omitempty" lopt:"ipmitagadd" comment:"add ipmitags"`
|
||||
TagsDel []string `yaml:"tagsdel,omitempty" lopt:"ipmitagdel" comment:"remove ipmitags"` // should not go to disk only to wire
|
||||
}
|
||||
@@ -73,16 +73,18 @@ type KernelConf struct {
|
||||
|
||||
type NetDevs struct {
|
||||
Type string `yaml:"type,omitempty" lopt:"type" sopt:"T" comment:"Set device type of given network"`
|
||||
OnBoot string `yaml:"onboot,omitempty" lopt:"onboot" comment:"Enable/disable network device (yes/no)"`
|
||||
OnBoot string `yaml:"onboot,omitempty" lopt:"onboot" comment:"Enable/disable network device (true/false)" type:"bool"`
|
||||
Device string `yaml:"device,omitempty" lopt:"netdev" sopt:"N" comment:"Set the device for given network"`
|
||||
Hwaddr string `yaml:"hwaddr,omitempty" lopt:"hwaddr" sopt:"H" comment:"Set the device's HW address for given network"`
|
||||
Ipaddr string `yaml:"ipaddr,omitempty" comment:"IPv4 address in given network" sopt:"I" lopt:"ipaddr"`
|
||||
Hwaddr string `yaml:"hwaddr,omitempty" lopt:"hwaddr" sopt:"H" comment:"Set the device's HW address for given network" type:"MAC"`
|
||||
Ipaddr string `yaml:"ipaddr,omitempty" comment:"IPv4 address in given network" sopt:"I" lopt:"ipaddr" type:"IP"`
|
||||
IpCIDR string `yaml:"ipcidr,omitempty"`
|
||||
Ipaddr6 string `yaml:"ip6addr,omitempty" lopt:"ipaddr6" comment:"IPv6 address"`
|
||||
Ipaddr6 string `yaml:"ip6addr,omitempty" lopt:"ipaddr6" comment:"IPv6 address" type:"IP"`
|
||||
Prefix string `yaml:"prefix,omitempty"`
|
||||
Netmask string `yaml:"netmask,omitempty" lopt:"netmask" sopt:"M" comment:"Set the networks netmask"`
|
||||
Gateway string `yaml:"gateway,omitempty" lopt:"gateway" sopt:"G" comment:"Set the node's network device gateway"`
|
||||
MTU string `yaml:"mtu,omitempty" lopt:"mtu" comment:"Set the mtu"`
|
||||
Netmask string `yaml:"netmask,omitempty" lopt:"netmask" sopt:"M" comment:"Set the networks netmask" type:"IP"`
|
||||
Gateway string `yaml:"gateway,omitempty" lopt:"gateway" sopt:"G" comment:"Set the node's network device gateway" type:"IP"`
|
||||
MTU string `yaml:"mtu,omitempty" lopt:"mtu" comment:"Set the mtu" type:"uint"`
|
||||
Primary string `yaml:"primary,omitempty" lopt:"primary" comment:"Enable/disable network device as primary (true/false)" type:"bool"`
|
||||
Default string `yaml:"default,omitempty"` /* backward compatibility */
|
||||
Tags map[string]string `yaml:"tags,omitempty" lopt:"nettagadd" comment:"network tags"`
|
||||
TagsDel []string `yaml:"tagsdel,omitempty" lopt:"nettagdel" comment:"delete network tags"` // should not go to disk only to wire
|
||||
}
|
||||
|
||||
240
internal/pkg/node/flags.go
Normal file
240
internal/pkg/node/flags.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
/*
|
||||
Create cmd line flags from the NodeConf fields. Returns a []func() where every function
|
||||
must be called, as the commandline parser returns e.g. netip.IP objects which must be parsedf
|
||||
back to strings.
|
||||
*/
|
||||
func (nodeConf *NodeConf) CreateFlags(baseCmd *cobra.Command, excludeList []string) (converters []func() error) {
|
||||
nodeInfoType := reflect.TypeOf(nodeConf)
|
||||
nodeInfoVal := reflect.ValueOf(nodeConf)
|
||||
// now iterate of every field
|
||||
for i := 0; i < nodeInfoVal.Elem().NumField(); i++ {
|
||||
if nodeInfoType.Elem().Field(i).Tag.Get("comment") != "" &&
|
||||
!util.InSlice(excludeList, nodeInfoType.Elem().Field(i).Tag.Get("lopt")) {
|
||||
field := nodeInfoVal.Elem().Field(i)
|
||||
converters = append(converters, createFlags(baseCmd, excludeList, nodeInfoType.Elem().Field(i), &field)...)
|
||||
} else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr {
|
||||
nestType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface())
|
||||
nestVal := reflect.ValueOf(nodeInfoVal.Elem().Field(i).Interface())
|
||||
for j := 0; j < nestType.Elem().NumField(); j++ {
|
||||
field := nestVal.Elem().Field(j)
|
||||
converters = append(converters, createFlags(baseCmd, excludeList, nestType.Elem().Field(j), &field)...)
|
||||
}
|
||||
} else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string]*NetDevs(nil)) {
|
||||
netMap := nodeInfoVal.Elem().Field(i).Interface().(map[string]*NetDevs)
|
||||
// add a default network so that it can hold values
|
||||
key := "default"
|
||||
if len(netMap) == 0 {
|
||||
netMap[key] = new(NetDevs)
|
||||
} else {
|
||||
for keyIt := range netMap {
|
||||
key = keyIt
|
||||
break
|
||||
}
|
||||
}
|
||||
netType := reflect.TypeOf(netMap[key])
|
||||
netVal := reflect.ValueOf(netMap[key])
|
||||
for j := 0; j < netType.Elem().NumField(); j++ {
|
||||
field := netVal.Elem().Field(j)
|
||||
converters = append(converters, createFlags(baseCmd, excludeList, netType.Elem().Field(j), &field)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return converters
|
||||
}
|
||||
|
||||
/*
|
||||
Helper function to create the different PerisitantFlags() for different types.
|
||||
*/
|
||||
func createFlags(baseCmd *cobra.Command, excludeList []string,
|
||||
myType reflect.StructField, myVal *reflect.Value) (converters []func() error) {
|
||||
if myType.Tag.Get("lopt") != "" {
|
||||
if myType.Type.Kind() == reflect.String {
|
||||
ptr := myVal.Addr().Interface().(*string)
|
||||
switch myType.Tag.Get("type") {
|
||||
case "uint":
|
||||
converters = append(converters, func() error {
|
||||
if !util.InSlice(GetUnsetVerbs(), *ptr) && *ptr != "" {
|
||||
_, err := strconv.ParseUint(myType.Tag.Get(*ptr), 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
myType.Tag.Get("default"),
|
||||
myType.Tag.Get("comment"))
|
||||
} else {
|
||||
baseCmd.PersistentFlags().StringVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("default"),
|
||||
myType.Tag.Get("comment"))
|
||||
}
|
||||
case "bool":
|
||||
/*
|
||||
Can't use the bool var from pflag as we need the UNSET verbs to be passwd correctly
|
||||
*/
|
||||
converters = append(converters, func() error {
|
||||
if !util.InSlice(GetUnsetVerbs(), *ptr) && *ptr != "" {
|
||||
if strings.ToLower(*ptr) == "yes" {
|
||||
*ptr = "true"
|
||||
return nil
|
||||
}
|
||||
if strings.ToLower(*ptr) == "no" {
|
||||
*ptr = "false"
|
||||
return nil
|
||||
}
|
||||
val, err := strconv.ParseBool(*ptr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("commandline option %s needs to be bool", myType.Tag.Get("lopt"))
|
||||
}
|
||||
*ptr = strconv.FormatBool(val)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
"",
|
||||
myType.Tag.Get("comment"))
|
||||
} else {
|
||||
baseCmd.PersistentFlags().StringVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
"",
|
||||
myType.Tag.Get("comment"))
|
||||
}
|
||||
baseCmd.PersistentFlags().Lookup(myType.Tag.Get("lopt")).NoOptDefVal = "true"
|
||||
case "IP":
|
||||
converters = append(converters, func() error {
|
||||
if !util.InSlice(GetUnsetVerbs(), *ptr) && *ptr != "" {
|
||||
ipval := net.ParseIP(*ptr)
|
||||
if ipval == nil {
|
||||
return fmt.Errorf("commandline option %s needs to be an IP address", myType.Tag.Get("lopt"))
|
||||
}
|
||||
*ptr = ipval.String()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
myType.Tag.Get("default"),
|
||||
myType.Tag.Get("comment"))
|
||||
} else {
|
||||
baseCmd.PersistentFlags().StringVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("default"),
|
||||
myType.Tag.Get("comment"))
|
||||
}
|
||||
case "IPMask":
|
||||
defaultConv := net.ParseIP(myType.Tag.Get("default")).DefaultMask()
|
||||
var valueRaw net.IPMask
|
||||
converters = append(converters, func() error {
|
||||
if valueRaw != nil {
|
||||
*ptr = valueRaw.String()
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("could not parse %s to IP", valueRaw.String())
|
||||
}
|
||||
})
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().IPMaskVarP(&valueRaw,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
defaultConv,
|
||||
myType.Tag.Get("comment"))
|
||||
} else {
|
||||
baseCmd.PersistentFlags().IPMaskVar(&valueRaw,
|
||||
myType.Tag.Get("lopt"),
|
||||
defaultConv,
|
||||
myType.Tag.Get("comment"))
|
||||
}
|
||||
case "MAC":
|
||||
converters = append(converters, func() error {
|
||||
if !util.InSlice(GetUnsetVerbs(), *ptr) && *ptr != "" {
|
||||
myMac, err := net.ParseMAC(*ptr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*ptr = myMac.String()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
"",
|
||||
myType.Tag.Get("comment"))
|
||||
} else {
|
||||
baseCmd.PersistentFlags().StringVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
"",
|
||||
myType.Tag.Get("comment"))
|
||||
}
|
||||
default:
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
myType.Tag.Get("default"),
|
||||
myType.Tag.Get("comment"))
|
||||
} else {
|
||||
baseCmd.PersistentFlags().StringVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("default"),
|
||||
myType.Tag.Get("comment"))
|
||||
}
|
||||
}
|
||||
} else if myType.Type == reflect.TypeOf([]string{}) {
|
||||
ptr := myVal.Addr().Interface().(*[]string)
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringSliceVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
[]string{myType.Tag.Get("default")},
|
||||
myType.Tag.Get("comment"))
|
||||
} else if !util.InSlice(excludeList, myType.Tag.Get("lopt")) {
|
||||
baseCmd.PersistentFlags().StringSliceVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
[]string{myType.Tag.Get("default")},
|
||||
myType.Tag.Get("comment"))
|
||||
|
||||
}
|
||||
} else if myType.Type == reflect.TypeOf(map[string]string{}) {
|
||||
ptr := myVal.Addr().Interface().(*map[string]string)
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringToStringVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
map[string]string{}, // empty default!
|
||||
myType.Tag.Get("comment"))
|
||||
} else if !util.InSlice(excludeList, myType.Tag.Get("lopt")) {
|
||||
baseCmd.PersistentFlags().StringToStringVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
map[string]string{}, // empty default!
|
||||
myType.Tag.Get("comment"))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return converters
|
||||
}
|
||||
@@ -10,6 +10,10 @@ import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func GetUnsetVerbs() []string {
|
||||
return []string{"UNSET", "DELETE", "UNDEF", "undef", "--", "nil", "0.0.0.0"}
|
||||
}
|
||||
|
||||
/**********
|
||||
*
|
||||
* Filters
|
||||
@@ -77,7 +81,7 @@ func (ent *Entry) Set(val string) {
|
||||
return
|
||||
}
|
||||
|
||||
if val == "UNDEF" || val == "DELETE" || val == "UNSET" || val == "--" || val == "nil" {
|
||||
if util.InSlice(GetUnsetVerbs(), val) {
|
||||
wwlog.Debug("Removing value for %v", *ent)
|
||||
ent.value = []string{""}
|
||||
} else {
|
||||
@@ -102,7 +106,7 @@ func (ent *Entry) SetSlice(val []string) {
|
||||
} else if len(val) == 1 && val[0] == "" { // check also for an "empty" slice
|
||||
return
|
||||
}
|
||||
if val[0] == "UNDEF" || val[0] == "DELETE" || val[0] == "UNSET" || val[0] == "--" {
|
||||
if util.InSlice(GetUnsetVerbs(), val[0]) {
|
||||
ent.value = []string{}
|
||||
} else {
|
||||
ent.value = val
|
||||
@@ -352,8 +356,10 @@ Create an empty node NodeConf
|
||||
*/
|
||||
func NewConf() (nodeconf NodeConf) {
|
||||
nodeconf.Ipmi = new(IpmiConf)
|
||||
nodeconf.Ipmi.Tags = map[string]string{}
|
||||
nodeconf.Kernel = new(KernelConf)
|
||||
nodeconf.NetDevs = make(map[string]*NetDevs)
|
||||
nodeconf.Tags = map[string]string{}
|
||||
return nodeconf
|
||||
}
|
||||
|
||||
@@ -362,11 +368,18 @@ Create an empty node NodeInfo
|
||||
*/
|
||||
func NewInfo() (nodeInfo NodeInfo) {
|
||||
nodeInfo.Ipmi = new(IpmiEntry)
|
||||
nodeInfo.Ipmi.Tags = map[string]*Entry{}
|
||||
nodeInfo.Kernel = new(KernelEntry)
|
||||
nodeInfo.NetDevs = make(map[string]*NetDevEntry)
|
||||
nodeInfo.Tags = make(map[string]*Entry)
|
||||
return nodeInfo
|
||||
}
|
||||
|
||||
func NewNetDevEntry() (netdev NetDevEntry) {
|
||||
netdev.Tags = make(map[string]*Entry)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Get a entry by its name
|
||||
*/
|
||||
|
||||
@@ -2,36 +2,351 @@ package node
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func NewTransformerTestNode() NodeYaml {
|
||||
var data = `
|
||||
nodeprofiles:
|
||||
default:
|
||||
comment: This profile is automatically included for each node
|
||||
ipmi:
|
||||
username: greg
|
||||
profile2:
|
||||
tags:
|
||||
foo: foo profile2
|
||||
comment: Comment profile2
|
||||
ipmi:
|
||||
tags:
|
||||
foo: foo ipmi profile
|
||||
nodes:
|
||||
test_node1:
|
||||
comment: Node Comment
|
||||
profiles:
|
||||
- default
|
||||
network devices:
|
||||
net0:
|
||||
device: eth1
|
||||
discoverable: true
|
||||
ipmi:
|
||||
username: chris
|
||||
tags:
|
||||
baar: baar node1
|
||||
test_node2:
|
||||
primary: net0
|
||||
profiles:
|
||||
- default
|
||||
- profile2
|
||||
network devices:
|
||||
net0:
|
||||
netmask: 1.1.1.1
|
||||
net1:
|
||||
ipaddr: 1.2.3.4
|
||||
tags:
|
||||
baar: baar node2
|
||||
test_node3:
|
||||
profiles:
|
||||
- profile2
|
||||
tags:
|
||||
foo: foo node3
|
||||
foobaar: foobaar node3
|
||||
ipmi:
|
||||
ipaddr: 1.1.1.1
|
||||
tags:
|
||||
foo: foo ipmi node3
|
||||
`
|
||||
var ret NodeYaml
|
||||
_ = yaml.Unmarshal([]byte(data), &ret)
|
||||
return ret
|
||||
}
|
||||
func Test_nodeYaml_SetFrom(t *testing.T) {
|
||||
c, _ := NewTestNode()
|
||||
singleNodeConf := c.Nodes["test_node"]
|
||||
singleNodeInfo := NewInfo()
|
||||
singleNodeInfo.SetFrom(singleNodeConf)
|
||||
tests := []struct {
|
||||
c := NewTransformerTestNode()
|
||||
nodes, _ := c.FindAllNodes()
|
||||
test_node1 := NewInfo()
|
||||
test_node2 := NewInfo()
|
||||
test_node3 := NewInfo()
|
||||
test_node4 := NewInfo()
|
||||
for _, n := range nodes {
|
||||
if n.Id.Get() == "test_node1" {
|
||||
test_node1 = n
|
||||
}
|
||||
if n.Id.Get() == "test_node2" {
|
||||
test_node2 = n
|
||||
}
|
||||
if n.Id.Get() == "test_node3" {
|
||||
test_node3 = n
|
||||
}
|
||||
}
|
||||
getByNametests := []struct {
|
||||
name string
|
||||
arg string
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{"Right comment", "Comment", "Node Comment", false},
|
||||
{"FieldName", "comment", "NodeComment", true},
|
||||
{"GetByName: FieldValue", "Comment", "Node Comment", false},
|
||||
{"GetByName: FieldName", "comment", "NodeComment", true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
for _, tt := range getByNametests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GetByName(&singleNodeInfo, tt.arg)
|
||||
got, err := GetByName(&test_node1, tt.arg)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetByName(%s,%s) error = %v, wantErr %v",
|
||||
reflect.TypeOf(singleNodeConf), tt.arg, err, tt.wantErr)
|
||||
reflect.TypeOf(test_node1), tt.arg, err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if (got != tt.want) != tt.wantErr {
|
||||
t.Errorf("GetByName(%s,%s) got = %v, want = %v",
|
||||
reflect.TypeOf(singleNodeConf), tt.arg, got, tt.want)
|
||||
reflect.TypeOf(test_node1), tt.arg, got, tt.want)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
t.Run("Get() comment", func(t *testing.T) {
|
||||
comment := test_node1.Comment.Get()
|
||||
if comment != "Node Comment" {
|
||||
t.Errorf("Get() returned wrong comment: %s", comment)
|
||||
}
|
||||
})
|
||||
t.Run("Get() profile comment", func(t *testing.T) {
|
||||
comment := test_node2.Comment.Get()
|
||||
if comment != "Comment profile2" {
|
||||
t.Errorf("Get() returned wrong comment: %s", comment)
|
||||
}
|
||||
})
|
||||
t.Run("Get() default ipxe", func(t *testing.T) {
|
||||
value := test_node1.Ipxe.Get()
|
||||
if value != "default" {
|
||||
t.Errorf("Get() returned wrong ipxe template: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("GetSlice() default profile", func(t *testing.T) {
|
||||
value := test_node1.Profiles.GetSlice()[0]
|
||||
if value != "default" {
|
||||
t.Errorf("GetSlice() returned wrong profile: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() default kernel args", func(t *testing.T) {
|
||||
value := test_node1.Kernel.Args.Get()
|
||||
if value != "quiet crashkernel=no vga=791 net.naming-scheme=v238" {
|
||||
t.Errorf("Get() returned wrong kernel args: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() default network mask", func(t *testing.T) {
|
||||
value := test_node1.NetDevs["net0"].Netmask.Get()
|
||||
if value != "255.255.255.0" {
|
||||
t.Errorf("Get() returned wrong default netmask: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() default network mask", func(t *testing.T) {
|
||||
value := test_node2.NetDevs["net0"].Netmask.Get()
|
||||
if value != "1.1.1.1" {
|
||||
t.Errorf("Get() returned wrong default netmask: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("GetB() primary for single network", func(t *testing.T) {
|
||||
value := test_node1.NetDevs["net0"].Primary.GetB()
|
||||
if !value {
|
||||
t.Errorf("GetB() returned wrong: %s", strconv.FormatBool(value))
|
||||
}
|
||||
})
|
||||
t.Run("GetB() for primary with two networks", func(t *testing.T) {
|
||||
value := test_node2.NetDevs["net0"].Primary.GetB()
|
||||
if !value {
|
||||
t.Errorf("GetB() returned wrong: %s", strconv.FormatBool(value))
|
||||
}
|
||||
})
|
||||
t.Run("GetB() for primary with two networks, get secondary network", func(t *testing.T) {
|
||||
value := test_node2.NetDevs["net1"].Primary.GetB()
|
||||
if value {
|
||||
t.Errorf("GetB() returned wrong: %s", strconv.FormatBool(value))
|
||||
}
|
||||
})
|
||||
t.Run("GetB() default discoverable", func(t *testing.T) {
|
||||
value := test_node1.Discoverable.GetB()
|
||||
if !value {
|
||||
t.Errorf("GetB() returned wrong: %s", strconv.FormatBool(value))
|
||||
}
|
||||
})
|
||||
t.Run("GetB() default discoverable", func(t *testing.T) {
|
||||
value := test_node2.Discoverable.GetB()
|
||||
if value {
|
||||
t.Errorf("GetB() returned wrong: %s", strconv.FormatBool(value))
|
||||
}
|
||||
})
|
||||
t.Run("Get() ipmi user from profile", func(t *testing.T) {
|
||||
value := test_node2.Ipmi.UserName.Get()
|
||||
if value != "greg" {
|
||||
t.Errorf("Get() returned wrong ipmi username: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() ipmi user from node", func(t *testing.T) {
|
||||
value := test_node1.Ipmi.UserName.Get()
|
||||
if value != "chris" {
|
||||
t.Errorf("Get() returned wrong ipmi username: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() tag foo from profile, node does not have this tag", func(t *testing.T) {
|
||||
value := test_node2.Tags["foo"].Get()
|
||||
if value != "foo profile2" {
|
||||
t.Errorf("Get() returned wrong tag for foo: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() tag baar from node, node tag map is not overwritten", func(t *testing.T) {
|
||||
value := test_node2.Tags["baar"].Get()
|
||||
if value != "baar node2" {
|
||||
t.Errorf("Get() returned wrong tag for foo: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() tag foo from node, tag present in profile", func(t *testing.T) {
|
||||
value := test_node3.Tags["foo"].Get()
|
||||
if value != "foo node3" {
|
||||
t.Errorf("Get() returned wrong tag for foo: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() tag foobaar from node", func(t *testing.T) {
|
||||
value := test_node3.Tags["foobaar"].Get()
|
||||
if value != "foobaar node3" {
|
||||
t.Errorf("Get() returned wrong tag for foo: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Get() ipmitag foo from profile, node does not have this tag", func(t *testing.T) {
|
||||
value := test_node3.Ipmi.Tags["foo"].Get()
|
||||
if value != "foo ipmi node3" {
|
||||
t.Errorf("Get() returned wrong tag for foo: %s", value)
|
||||
}
|
||||
})
|
||||
t.Run("Set() comment foo for empty node", func(t *testing.T) {
|
||||
test_node4.Comment.Set("foo")
|
||||
nodeConf := NewConf()
|
||||
nodeConf.GetFrom(test_node4)
|
||||
ymlByte, _ := yaml.Marshal(nodeConf)
|
||||
wanted := `comment: foo
|
||||
kernel: {}
|
||||
ipmi: {}
|
||||
`
|
||||
if !(wanted == string(ymlByte)) {
|
||||
t.Errorf("Got wrong yml, wanted:\n'%s'\nGot:\n'%s'", wanted, string(ymlByte))
|
||||
}
|
||||
// have to remove the comment for further tests, as vscode
|
||||
// can test single functions
|
||||
test_node4.Comment.Set("UNDEF")
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
ymlByte, _ = yaml.Marshal(nodeConf)
|
||||
wanted = `{}
|
||||
`
|
||||
if string(ymlByte) != wanted {
|
||||
t.Errorf("Couldn't unset comment:\n'%s'\nwanted:\n'%s'", string(ymlByte), wanted)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Set() ipmiuser foo for flattened empty node", func(t *testing.T) {
|
||||
test_node4.Ipmi.UserName.Set("foo")
|
||||
nodeConf := NewConf()
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
ymlByte, _ := yaml.Marshal(nodeConf)
|
||||
wanted := `ipmi:
|
||||
username: foo
|
||||
`
|
||||
if !(wanted == string(ymlByte)) {
|
||||
t.Errorf("Got wrong yml, wanted:\n'%s'\nGot:\n'%s'", wanted, string(ymlByte))
|
||||
}
|
||||
test_node4.Ipmi.Tags["foo"] = &Entry{}
|
||||
test_node4.Ipmi.Tags["foo"].Set("baar")
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
ymlByte, _ = yaml.Marshal(nodeConf)
|
||||
wanted = `ipmi:
|
||||
username: foo
|
||||
tags:
|
||||
foo: baar
|
||||
`
|
||||
if !(wanted == string(ymlByte)) {
|
||||
t.Errorf("Got wrong yml, wanted:\n'%s'\nGot:\n'%s'", wanted, string(ymlByte))
|
||||
}
|
||||
test_node4.Ipmi.UserName.Set("UNSET")
|
||||
delete(test_node4.Ipmi.Tags, "foo")
|
||||
})
|
||||
t.Run("Set() kernelargs foo for flattened empty node", func(t *testing.T) {
|
||||
test_node4.Kernel.Args.Set("foo")
|
||||
nodeConf := NewConf()
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
ymlByte, _ := yaml.Marshal(nodeConf)
|
||||
wanted := `kernel:
|
||||
args: foo
|
||||
`
|
||||
if !(wanted == string(ymlByte)) {
|
||||
t.Errorf("Got wrong yml, wanted:\n'%s'\nGot:\n'%s'", wanted, string(ymlByte))
|
||||
}
|
||||
test_node4.Kernel.Args.Set("--")
|
||||
})
|
||||
t.Run("Set() tag foo to bar for flattened empty node", func(t *testing.T) {
|
||||
test_node4.Tags["foo"] = &Entry{}
|
||||
test_node4.Tags["foo"].Set("baar")
|
||||
nodeConf := NewConf()
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
ymlByte, _ := yaml.Marshal(nodeConf)
|
||||
wanted := `tags:
|
||||
foo: baar
|
||||
`
|
||||
if !(wanted == string(ymlByte)) {
|
||||
t.Errorf("Got wrong yml, wanted:\n'%s'\nGot:\n'%s'", wanted, string(ymlByte))
|
||||
}
|
||||
delete(test_node4.Tags, "foo")
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
ymlByte, _ = yaml.Marshal(nodeConf)
|
||||
wanted = `{}
|
||||
`
|
||||
if string(ymlByte) != wanted {
|
||||
t.Errorf("Couldn't remove tag'%s'", string(ymlByte))
|
||||
}
|
||||
|
||||
})
|
||||
t.Run("Set() netdev foo with device name baar for flattened empty node", func(t *testing.T) {
|
||||
netdev := NewNetDevEntry()
|
||||
test_node4.NetDevs["foo"] = &netdev
|
||||
test_node4.NetDevs["foo"].Device.Set("baar")
|
||||
nodeConf := NewConf()
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
ymlByte, _ := yaml.Marshal(nodeConf)
|
||||
wanted := `network devices:
|
||||
foo:
|
||||
device: baar
|
||||
`
|
||||
if !(wanted == string(ymlByte)) {
|
||||
t.Errorf("Got wrong yml, wanted:\n'%s'\nGot:\n'%s'", wanted, string(ymlByte))
|
||||
}
|
||||
test_node4.NetDevs["foo"].Tags["netfoo"] = &Entry{}
|
||||
test_node4.NetDevs["foo"].Tags["netfoo"].Set("netbaar")
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
wanted = `network devices:
|
||||
foo:
|
||||
device: baar
|
||||
tags:
|
||||
netfoo: netbaar
|
||||
`
|
||||
ymlByte, _ = yaml.Marshal(nodeConf)
|
||||
if string(ymlByte) != wanted {
|
||||
t.Errorf("Couldn set nettag: '%s' got: '%s'", wanted, string(ymlByte))
|
||||
}
|
||||
|
||||
delete(test_node4.NetDevs, "foo")
|
||||
nodeConf.GetFrom(test_node4)
|
||||
nodeConf.Flatten()
|
||||
ymlByte, _ = yaml.Marshal(nodeConf)
|
||||
wanted = `{}
|
||||
`
|
||||
if string(ymlByte) != wanted {
|
||||
t.Errorf("Couldn't remove tag'%s'", string(ymlByte))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/util"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -194,102 +193,6 @@ func (nodeConf *NodeConf) getterFrom(nodeInfo NodeInfo,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Create cmd line flags from the NodeConf fields
|
||||
*/
|
||||
func (nodeConf *NodeConf) CreateFlags(baseCmd *cobra.Command, excludeList []string) {
|
||||
nodeInfoType := reflect.TypeOf(nodeConf)
|
||||
nodeInfoVal := reflect.ValueOf(nodeConf)
|
||||
// now iterate of every field
|
||||
for i := 0; i < nodeInfoVal.Elem().NumField(); i++ {
|
||||
if nodeInfoType.Elem().Field(i).Tag.Get("comment") != "" &&
|
||||
!util.InSlice(excludeList, nodeInfoType.Elem().Field(i).Tag.Get("lopt")) {
|
||||
field := nodeInfoVal.Elem().Field(i)
|
||||
createFlags(baseCmd, excludeList, nodeInfoType.Elem().Field(i), &field)
|
||||
} else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr {
|
||||
nestType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface())
|
||||
nestVal := reflect.ValueOf(nodeInfoVal.Elem().Field(i).Interface())
|
||||
for j := 0; j < nestType.Elem().NumField(); j++ {
|
||||
field := nestVal.Elem().Field(j)
|
||||
createFlags(baseCmd, excludeList, nestType.Elem().Field(j), &field)
|
||||
}
|
||||
} else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf(map[string]*NetDevs(nil)) {
|
||||
netMap := nodeInfoVal.Elem().Field(i).Interface().(map[string]*NetDevs)
|
||||
// add a default network so that it can hold values
|
||||
key := "default"
|
||||
if len(netMap) == 0 {
|
||||
netMap[key] = new(NetDevs)
|
||||
} else {
|
||||
for keyIt := range netMap {
|
||||
key = keyIt
|
||||
break
|
||||
}
|
||||
}
|
||||
netType := reflect.TypeOf(netMap[key])
|
||||
netVal := reflect.ValueOf(netMap[key])
|
||||
for j := 0; j < netType.Elem().NumField(); j++ {
|
||||
field := netVal.Elem().Field(j)
|
||||
createFlags(baseCmd, excludeList, netType.Elem().Field(j), &field)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Helper function to create the different PerisitantFlags() for different types.
|
||||
*/
|
||||
func createFlags(baseCmd *cobra.Command, excludeList []string,
|
||||
myType reflect.StructField, myVal *reflect.Value) {
|
||||
if myType.Tag.Get("lopt") != "" {
|
||||
if myType.Type.Kind() == reflect.String {
|
||||
ptr := myVal.Addr().Interface().(*string)
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
myType.Tag.Get("default"),
|
||||
myType.Tag.Get("comment"))
|
||||
} else if !util.InSlice(excludeList, myType.Tag.Get("lopt")) {
|
||||
baseCmd.PersistentFlags().StringVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("default"),
|
||||
myType.Tag.Get("comment"))
|
||||
|
||||
}
|
||||
} else if myType.Type == reflect.TypeOf([]string{}) {
|
||||
ptr := myVal.Addr().Interface().(*[]string)
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringSliceVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
[]string{myType.Tag.Get("default")},
|
||||
myType.Tag.Get("comment"))
|
||||
} else if !util.InSlice(excludeList, myType.Tag.Get("lopt")) {
|
||||
baseCmd.PersistentFlags().StringSliceVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
[]string{myType.Tag.Get("default")},
|
||||
myType.Tag.Get("comment"))
|
||||
|
||||
}
|
||||
} else if myType.Type == reflect.TypeOf(map[string]string{}) {
|
||||
ptr := myVal.Addr().Interface().(*map[string]string)
|
||||
if myType.Tag.Get("sopt") != "" {
|
||||
baseCmd.PersistentFlags().StringToStringVarP(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
myType.Tag.Get("sopt"),
|
||||
map[string]string{}, // empty default!
|
||||
myType.Tag.Get("comment"))
|
||||
} else if !util.InSlice(excludeList, myType.Tag.Get("lopt")) {
|
||||
baseCmd.PersistentFlags().StringToStringVar(ptr,
|
||||
myType.Tag.Get("lopt"),
|
||||
map[string]string{}, // empty default!
|
||||
myType.Tag.Get("comment"))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Populates all fields of NodeInfo with Set from the
|
||||
values of NodeConf.
|
||||
@@ -363,24 +266,28 @@ func (node *NodeInfo) setterFrom(n *NodeConf, nameArg 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())
|
||||
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 netstedInfoVal.Elem().Field(j).Type() == reflect.TypeOf(Entry{}) {
|
||||
setter(netstedInfoVal.Elem().Field(j).Addr().Interface().(*Entry), nestedVal.String(), nameArg)
|
||||
} else {
|
||||
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 netstedInfoVal.Elem().Field(j).IsNil() {
|
||||
newMap := make(map[string]*Entry)
|
||||
mapPtr := (netstedInfoVal.Elem().Field(j).Addr().Interface()).(*map[string](*Entry))
|
||||
*mapPtr = newMap
|
||||
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 {
|
||||
entr := new(Entry)
|
||||
setter(entr, val, nameArg)
|
||||
(netstedInfoVal.Elem().Field(j).Interface()).(map[string](*Entry))[key] = entr
|
||||
if entr, ok := tagMap[key]; ok {
|
||||
setter(entr, val, nameArg)
|
||||
} else {
|
||||
entr := new(Entry)
|
||||
tagMap[key] = entr
|
||||
setter(entr, val, nameArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,9 +295,17 @@ func (node *NodeInfo) setterFrom(n *NodeConf, nameArg 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 {
|
||||
entr := new(Entry)
|
||||
setter(entr, val, nameArg)
|
||||
(nodeInfoVal.Elem().Field(i).Interface()).(map[string](*Entry))[key] = entr
|
||||
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))
|
||||
|
||||
@@ -27,10 +27,11 @@ func (config *NodeYaml) FindByHwaddr(hwa string) (NodeInfo, error) {
|
||||
}
|
||||
|
||||
func (config *NodeYaml) FindByIpaddr(ipaddr string) (NodeInfo, error) {
|
||||
if net.ParseIP(ipaddr) == nil {
|
||||
if addr := net.ParseIP(ipaddr); addr == nil {
|
||||
return NodeInfo{}, errors.New("invalid IP:" + ipaddr)
|
||||
} else {
|
||||
ipaddr = addr.String()
|
||||
}
|
||||
|
||||
var ret NodeInfo
|
||||
|
||||
n, _ := config.FindAllNodes()
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func NewTestNode() (NodeYaml, error) {
|
||||
func NewUtilTestNode() (NodeYaml, error) {
|
||||
var data = `
|
||||
nodeprofiles:
|
||||
default:
|
||||
@@ -49,7 +49,7 @@ nodes:
|
||||
}
|
||||
|
||||
func Test_nodeYaml_FindByHwaddr(t *testing.T) {
|
||||
c, _ := NewTestNode()
|
||||
c, _ := NewUtilTestNode()
|
||||
//type fields struct {
|
||||
// NodeProfiles map[string]*NodeConf
|
||||
// Nodes map[string]*NodeConf
|
||||
@@ -90,7 +90,7 @@ func Test_nodeYaml_FindByHwaddr(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_nodeYaml_FindByIpaddr(t *testing.T) {
|
||||
c, _ := NewTestNode()
|
||||
c, _ := NewUtilTestNode()
|
||||
type args struct {
|
||||
ipaddr string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user