check the yaml direclty after unmarshalling

This commit is contained in:
Christian Goll
2023-02-06 17:00:24 +01:00
parent 13bc378a6b
commit c14dd3c6d1
7 changed files with 176 additions and 31 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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 {

View File

@@ -0,0 +1,76 @@
package node
import (
"fmt"
"net/netip"
"reflect"
"strconv"
"strings"
)
/*
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 {
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 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"))
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 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++ {
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)
}
}
}
}
}
return nil
}
func checker(value string, valType string) (err error) {
if valType == "" || value == "" {
return nil
}
//wwlog.Debug("checker: %s is %s", value, valType)
switch valType {
case "":
return nil
case "bool":
if strings.ToLower(value) == "yes" {
return nil
}
if strings.ToLower(value) == "no" {
return nil
}
_, err = strconv.ParseBool(value)
return err
case "IP":
_, err = netip.ParseAddr(value)
return err
}
return nil
}

View File

@@ -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
@@ -165,6 +181,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 {

View File

@@ -13,7 +13,9 @@ import (
)
/*
Create cmd line flags from the NodeConf fields
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()) {
nodeInfoType := reflect.TypeOf(nodeConf)