Merge pull request #540 from mslacken/node-edit

add edit command for direct edit of node entries
This commit is contained in:
Christian Goll
2022-10-13 10:17:00 +02:00
committed by GitHub
22 changed files with 1190 additions and 102 deletions

View File

@@ -0,0 +1,115 @@
package edit
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
apinode "github.com/hpcng/warewulf/internal/pkg/api/node"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
apiutil "github.com/hpcng/warewulf/internal/pkg/api/util"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
canWrite := apiutil.CanWriteConfig()
if !canWrite.CanWriteConfig {
wwlog.Error("Can't write to config exiting")
os.Exit(1)
}
editor := os.Getenv("EDITOR")
if editor == "" {
editor = "/bin/vi"
}
if len(args) == 0 {
args = append(args, ".*")
}
filterList := wwapiv1.NodeList{
Output: args,
}
nodeListMsg := apinode.FilteredNodes(&filterList)
nodeMap := make(map[string]*node.NodeConf)
// got proper yaml back
_ = yaml.Unmarshal([]byte(nodeListMsg.NodeConfMapYaml), nodeMap)
file, err := ioutil.TempFile("/tmp", "ww4NodeEdit*.yaml")
if err != nil {
wwlog.Error("Could not create temp file:%s \n", err)
}
defer os.Remove(file.Name())
nodeConf := node.NewConf()
yamlTemplate := nodeConf.UnmarshalConf([]string{"tagsdel", "default", "profiles"})
for {
_ = file.Truncate(0)
_, _ = file.Seek(0, 0)
if !NoHeader {
_, _ = file.WriteString("#nodename:\n# " + strings.Join(yamlTemplate, "\n# ") + "\n")
}
_, _ = file.WriteString(nodeListMsg.NodeConfMapYaml)
_, _ = file.Seek(0, 0)
hasher := sha256.New()
if _, err := io.Copy(hasher, file); err != nil {
wwlog.Error("Problems getting checksum of file %s\n", err)
}
sum1 := hex.EncodeToString(hasher.Sum(nil))
err = util.ExecInteractive(editor, file.Name())
if err != nil {
wwlog.Error("Editor process existed with non-zero\n")
os.Exit(1)
}
_, _ = file.Seek(0, 0)
hasher.Reset()
if _, err := io.Copy(hasher, file); err != nil {
wwlog.Error("Problems getting checksum of file %s\n", err)
}
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")
modifiedNodeMap := 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, 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 {
break
}
err = apinode.NodeDelete(&wwapiv1.NodeDeleteParameter{NodeNames: nodeList, Force: true})
if err != nil {
wwlog.Verbose("Problem deleting nodes before modification %s")
}
buffer, _ = yaml.Marshal(modifiedNodeMap)
err = apinode.NodeAddFromYaml(&wwapiv1.NodeYaml{NodeConfMapYaml: string(buffer)})
if err != nil {
wwlog.Error("Got following problem when writing back yaml: %s", err)
os.Exit(1)
}
break
} else {
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Got following error on parsing: %s, Retry", err))
if !yes {
break
}
}
} else {
break
}
}
return nil
}

View File

@@ -0,0 +1,39 @@
package edit
import (
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Use: "edit [OPTIONS] NODENAME",
Short: "Edit node(s) with editor",
Long: "This command opens an editor for the given nodes.",
RunE: CobraRunE,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
nodeDB, _ := node.New()
nodes, _ := nodeDB.FindAllNodes()
var node_names []string
for _, node := range nodes {
node_names = append(node_names, node.Id.Get())
}
return node_names, cobra.ShellCompDirectiveNoFileComp
},
}
NoHeader bool
)
func init() {
baseCmd.PersistentFlags().BoolVar(&NoHeader, "noheader", false, "Do not print header")
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -0,0 +1,26 @@
package export
import (
"fmt"
apinode "github.com/hpcng/warewulf/internal/pkg/api/node"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/spf13/cobra"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
args = append(args, ".*")
}
filterList := wwapiv1.NodeList{
Output: args,
}
nodeListMsg := apinode.FilteredNodes(&filterList)
/*
nodeMap := make(map[string]*node.NodeConf)
// got proper yaml back
_ = yaml.Unmarshal([]byte(nodeListMsg.NodeConfMapYaml), nodeMap)
*/
fmt.Println(nodeListMsg.NodeConfMapYaml)
return nil
}

View File

@@ -0,0 +1,38 @@
package export
import (
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Use: "export NODENAME",
Short: "Export nodes as yaml to stdout",
Long: "This command exports the given nodes as yaml to stdout.",
RunE: CobraRunE,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
nodeDB, _ := node.New()
nodes, _ := nodeDB.FindAllNodes()
var node_names []string
for _, node := range nodes {
node_names = append(node_names, node.Id.Get())
}
return node_names, cobra.ShellCompDirectiveNoFileComp
},
}
NoHeader bool
)
func init() {
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -0,0 +1,98 @@
package imprt
import (
"bytes"
"encoding/csv"
"fmt"
"io"
"os"
apinode "github.com/hpcng/warewulf/internal/pkg/api/node"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
apiutil "github.com/hpcng/warewulf/internal/pkg/api/util"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
file, err := os.Open(args[0])
if err != nil {
wwlog.Error("Could not open file:%s \n", err)
os.Exit(1)
}
defer file.Close()
importMap := make(map[string]*node.NodeConf)
buffer, err := io.ReadAll(file)
if err != nil {
wwlog.Error("Could not read:%s\n", err)
os.Exit(1)
}
if !ImportCVS {
err = yaml.Unmarshal(buffer, importMap)
if err == nil {
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Are you sure you want to modify %d nodes", len(importMap)))
if yes {
err = apinode.NodeAddFromYaml(&wwapiv1.NodeYaml{NodeConfMapYaml: string(buffer)})
if err != nil {
wwlog.Error("Got following problem when writing back yaml: %s", err)
os.Exit(1)
}
}
} else {
wwlog.Error("Could not parse import file")
}
} else {
// reading from buffer is a bit overshot
csvReader := csv.NewReader(bytes.NewReader(buffer))
records, err := csvReader.ReadAll()
if err != nil {
wwlog.Error("Could not parse %s: %s\n", args[0], err)
os.Exit(1)
}
if len(records) < 1 || len(records[0]) < 1 {
wwlog.Error("Did not find any data in %s\n", args[0])
os.Exit(1)
}
if !(records[0][0] == "node" || records[0][0] == "nodename") {
Usage()
os.Exit(1)
}
argsLen := len(records[0])
for i, line := range records[1:] {
if len(line) != argsLen {
wwlog.Error("Wrong number of fields in lube %u\n", i+1)
os.Exit(1)
}
for j := range line {
if j == 0 {
continue
}
if importMap[line[0]] == nil {
importMap[line[0]] = new(node.NodeConf)
}
ok := importMap[line[0]].SetLopt(records[0][j], line[j])
if !(ok) {
wwlog.Debug("Could not import %s\n", line[j])
}
}
}
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Are you sure you want to import %d nodes", len(importMap)))
if yes {
// create second buffer an marshall nodeMap to it
buffer, err = yaml.Marshal(importMap)
if err != nil {
wwlog.Error("Got following problem when creating yaml: %s", err)
}
err = apinode.NodeAddFromYaml(&wwapiv1.NodeYaml{NodeConfMapYaml: string(buffer)})
if err != nil {
wwlog.Error("Got following problem when writing back yaml: %s", err)
os.Exit(1)
}
}
}
return nil
}

View File

@@ -0,0 +1,35 @@
package imprt
import (
"fmt"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Use: "import [OPTIONS] NODENAME",
Short: "Import node(s) from yaml file",
Long: "This command imports all the nodes defined in a file. It will overwrite nodes with same name.",
RunE: CobraRunE,
Args: cobra.MinimumNArgs(1),
Aliases: []string{"import"},
}
ImportCVS bool
)
func init() {
baseCmd.PersistentFlags().BoolVarP(&ImportCVS, "cvs", "c", false, "Import CVS file")
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}
func Usage() {
fmt.Println(`The csv file must be structured in following way:
node,option1,option2,net.netname1.netopt
node01,value1,value2,net.netname1,netvalue`)
}

View File

@@ -4,6 +4,9 @@ import (
"github.com/hpcng/warewulf/internal/app/wwctl/node/add"
"github.com/hpcng/warewulf/internal/app/wwctl/node/console"
"github.com/hpcng/warewulf/internal/app/wwctl/node/delete"
"github.com/hpcng/warewulf/internal/app/wwctl/node/edit"
"github.com/hpcng/warewulf/internal/app/wwctl/node/export"
"github.com/hpcng/warewulf/internal/app/wwctl/node/imprt"
"github.com/hpcng/warewulf/internal/app/wwctl/node/list"
"github.com/hpcng/warewulf/internal/app/wwctl/node/sensors"
"github.com/hpcng/warewulf/internal/app/wwctl/node/set"
@@ -30,6 +33,9 @@ func init() {
baseCmd.AddCommand(delete.GetCommand())
baseCmd.AddCommand(console.GetCommand())
baseCmd.AddCommand(nodestatus.GetCommand())
baseCmd.AddCommand(edit.GetCommand())
baseCmd.AddCommand(imprt.GetCommand())
baseCmd.AddCommand(export.GetCommand())
}
// GetRootCommand returns the root cobra.Command for the application.

View File

@@ -1,15 +1,30 @@
package delete
import "github.com/spf13/cobra"
import (
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Use: "delete [OPTIONS] PROFILE",
Short: "Delete a node profile",
Long: "This command deletes the node PROFILE. You may use a pattern for PROFILE.",
RunE: CobraRunE,
Args: cobra.MinimumNArgs(1),
Use: "delete [OPTIONS] PROFILE",
Short: "Delete a node profile",
Long: "This command deletes the node PROFILE. You may use a pattern for PROFILE.",
RunE: CobraRunE,
Args: cobra.MinimumNArgs(1),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
nodeDB, _ := node.New()
profiles, _ := nodeDB.FindAllProfiles()
var p_names []string
for _, profile := range profiles {
p_names = append(p_names, profile.Id.Get())
}
return p_names, cobra.ShellCompDirectiveNoFileComp
},
}
SetYes bool
)

View File

@@ -0,0 +1,115 @@
package edit
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
apiprofile "github.com/hpcng/warewulf/internal/pkg/api/profile"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
apiutil "github.com/hpcng/warewulf/internal/pkg/api/util"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)
func CobraRunE(cmd *cobra.Command, args []string) error {
canWrite := apiutil.CanWriteConfig()
if !canWrite.CanWriteConfig {
wwlog.Error("Can't write to config exiting")
os.Exit(1)
}
editor := os.Getenv("EDITOR")
if editor == "" {
editor = "/bin/vi"
}
if len(args) == 0 {
args = append(args, ".*")
}
filterList := wwapiv1.NodeList{
Output: args,
}
profileListMsg := apiprofile.FilteredProfiles(&filterList)
profileMap := make(map[string]*node.NodeConf)
// got proper yaml back
_ = yaml.Unmarshal([]byte(profileListMsg.NodeConfMapYaml), profileMap)
file, err := ioutil.TempFile("/tmp", "ww4ProfileEdit*.yaml")
if err != nil {
wwlog.Error("Could not create temp file:%s \n", err)
}
defer os.Remove(file.Name())
nodeConf := node.NewConf()
yamlTemplate := nodeConf.UnmarshalConf([]string{"tagsdel"})
for {
_ = file.Truncate(0)
_, _ = file.Seek(0, 0)
if !NoHeader {
_, _ = file.WriteString("#profilename:\n# " + strings.Join(yamlTemplate, "\n# ") + "\n")
}
_, _ = file.WriteString(profileListMsg.NodeConfMapYaml)
_, _ = file.Seek(0, 0)
hasher := sha256.New()
if _, err := io.Copy(hasher, file); err != nil {
wwlog.Error("Problems getting checksum of file %s\n", err)
}
sum1 := hex.EncodeToString(hasher.Sum(nil))
err = util.ExecInteractive(editor, file.Name())
if err != nil {
wwlog.Error("Editor process existed with non-zero\n")
os.Exit(1)
}
_, _ = file.Seek(0, 0)
hasher.Reset()
if _, err := io.Copy(hasher, file); err != nil {
wwlog.Error("Problems getting checksum of file %s\n", err)
}
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")
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 {
break
}
err = apiprofile.ProfileDelete(&wwapiv1.NodeDeleteParameter{NodeNames: nodeList, Force: true})
if err != nil {
wwlog.Verbose("Problem deleting nodes before modification %s")
}
buffer, _ = yaml.Marshal(modifiedProfileMap)
err = apiprofile.ProfileAddFromYaml(&wwapiv1.NodeYaml{NodeConfMapYaml: string(buffer)})
if err != nil {
wwlog.Error("Got following problem when writing back yaml: %s", err)
os.Exit(1)
}
break
} else {
yes := apiutil.ConfirmationPrompt(fmt.Sprintf("Got following error on parsing: %s, Retry", err))
if !yes {
break
}
}
} else {
break
}
}
return nil
}

View File

@@ -0,0 +1,38 @@
package edit
import (
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/spf13/cobra"
)
var (
baseCmd = &cobra.Command{
DisableFlagsInUseLine: true,
Use: "edit [OPTIONS] NODENAME",
Short: "Edit node(s) with editor",
Long: "This command opens an editor for the given profiles.",
RunE: CobraRunE,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
nodeDB, _ := node.New()
profiles, _ := nodeDB.FindAllProfiles()
var p_names []string
for _, profile := range profiles {
p_names = append(p_names, profile.Id.Get())
}
return p_names, cobra.ShellCompDirectiveNoFileComp
},
}
NoHeader bool
)
func init() {
baseCmd.PersistentFlags().BoolVar(&NoHeader, "noheader", false, "Do not print header")
}
// GetRootCommand returns the root cobra.Command for the application.
func GetCommand() *cobra.Command {
return baseCmd
}

View File

@@ -3,6 +3,7 @@ package profile
import (
"github.com/hpcng/warewulf/internal/app/wwctl/profile/add"
"github.com/hpcng/warewulf/internal/app/wwctl/profile/delete"
"github.com/hpcng/warewulf/internal/app/wwctl/profile/edit"
"github.com/hpcng/warewulf/internal/app/wwctl/profile/list"
"github.com/hpcng/warewulf/internal/app/wwctl/profile/set"
"github.com/spf13/cobra"
@@ -23,6 +24,7 @@ func init() {
baseCmd.AddCommand(set.GetCommand())
baseCmd.AddCommand(add.GetCommand())
baseCmd.AddCommand(delete.GetCommand())
baseCmd.AddCommand(edit.GetCommand())
}
// GetRootCommand returns the root cobra.Command for the application.

View File

@@ -0,0 +1,70 @@
package apinode
import (
"os"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"
)
/*
Returns the nodes as a yaml string
*/
func FindAllNodeConfs() *wwapiv1.NodeYaml {
nodeDB, err := node.New()
if err != nil {
wwlog.Error("Could not open nodeDB: %s\n", err)
os.Exit(1)
}
nodeMap := nodeDB.Nodes
// ignore err as nodeDB should always be correct
buffer, _ := yaml.Marshal(nodeMap)
retVal := wwapiv1.NodeYaml{
NodeConfMapYaml: string(buffer),
}
return &retVal
}
/*
Returns filtered list of nodes
*/
func FilteredNodes(nodeList *wwapiv1.NodeList) *wwapiv1.NodeYaml {
nodeDB, err := node.New()
if err != nil {
wwlog.Error("Could not open nodeDB: %s\n", err)
os.Exit(1)
}
nodeMap := nodeDB.Nodes
nodeMap = node.FilterMapByName(nodeMap, nodeList.Output)
buffer, _ := yaml.Marshal(nodeMap)
retVal := wwapiv1.NodeYaml{
NodeConfMapYaml: string(buffer),
}
return &retVal
}
/*
Add nodes from yaml
*/
func NodeAddFromYaml(nodeList *wwapiv1.NodeYaml) (err error) {
nodeDB, err := node.New()
if err != nil {
return errors.Wrap(err, "Could not open NodeDB: %s\n")
}
nodeMap := make(map[string]*node.NodeConf)
err = yaml.Unmarshal([]byte(nodeList.NodeConfMapYaml), nodeMap)
if err != nil {
return errors.Wrap(err, "Could not unmarshall Yaml: %s\n")
}
for nodeName, node := range nodeMap {
nodeDB.Nodes[nodeName] = node
}
err = nodeDB.Persist()
if err != nil {
return errors.Wrap(err, "failed to persist nodedb")
}
return nil
}

View File

@@ -102,7 +102,7 @@ func NodeDelete(ndp *wwapiv1.NodeDeleteParameter) (err error) {
wwlog.Error("%s\n", err)
} else {
//count++
fmt.Printf("Deleting node: %s\n", n.Id.Print())
wwlog.Verbose("Deleting node: %s\n", n.Id.Print())
}
}

View File

@@ -0,0 +1,94 @@
package apiprofile
import (
"fmt"
"os"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/warewulfd"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/hpcng/warewulf/pkg/hostlist"
"github.com/pkg/errors"
)
// ProfileDelete adds profile deletion for management by Warewulf.
func ProfileDelete(ndp *wwapiv1.NodeDeleteParameter) (err error) {
var profileList []node.NodeInfo
profileList, err = ProfileDeleteParameterCheck(ndp, false)
if err != nil {
return
}
nodeDB, err := node.New()
if err != nil {
wwlog.Error("Failed to open node database: %s\n", err)
return
}
for _, p := range profileList {
err := nodeDB.DelProfile(p.Id.Get())
if err != nil {
wwlog.Error("%s\n", err)
} else {
//count++
wwlog.Verbose("Deleting node: %s\n", p.Id.Print())
}
}
err = nodeDB.Persist()
if err != nil {
return errors.Wrap(err, "failed to persist nodedb")
}
err = warewulfd.DaemonReload()
if err != nil {
return errors.Wrap(err, "failed to reload warewulf daemon")
}
return
}
// ProfileDeleteParameterCheck does error checking on ProfileDeleteParameter.
// Output to the console if console is true.
// Returns the profiles to delete.
func ProfileDeleteParameterCheck(ndp *wwapiv1.NodeDeleteParameter, console bool) (profileList []node.NodeInfo, err error) {
if ndp == nil {
err = fmt.Errorf("ProfileDeleteParameter is nil")
return
}
nodeDB, err := node.New()
if err != nil {
wwlog.Error("Failed to open node database: %s\n", err)
return
}
profiles, err := nodeDB.FindAllProfiles()
if err != nil {
wwlog.Error("Could not get node list: %s\n", err)
return
}
node_args := hostlist.Expand(ndp.NodeNames)
for _, r := range node_args {
var match bool
for _, p := range profiles {
if p.Id.Get() == r {
profileList = append(profileList, p)
match = true
}
}
if !match {
fmt.Fprintf(os.Stderr, "ERROR: No match for node: %s\n", r)
}
}
if len(profileList) == 0 {
fmt.Printf("No s found\n")
}
return
}

View File

@@ -0,0 +1,70 @@
package apiprofile
import (
"os"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"
)
/*
Returns the nodes as a yaml string
*/
func FindAllProfileConfs() *wwapiv1.NodeYaml {
nodeDB, err := node.New()
if err != nil {
wwlog.Error("Could not open nodeDB: %s\n", err)
os.Exit(1)
}
profileMap := nodeDB.NodeProfiles
// ignore err as nodeDB should always be correct
buffer, _ := yaml.Marshal(profileMap)
retVal := wwapiv1.NodeYaml{
NodeConfMapYaml: string(buffer),
}
return &retVal
}
/*
Returns filtered list of nodes
*/
func FilteredProfiles(profileList *wwapiv1.NodeList) *wwapiv1.NodeYaml {
nodeDB, err := node.New()
if err != nil {
wwlog.Error("Could not open nodeDB: %s\n", err)
os.Exit(1)
}
profileMap := nodeDB.NodeProfiles
profileMap = node.FilterMapByName(profileMap, profileList.Output)
buffer, _ := yaml.Marshal(profileMap)
retVal := wwapiv1.NodeYaml{
NodeConfMapYaml: string(buffer),
}
return &retVal
}
/*
Add profiles from yaml
*/
func ProfileAddFromYaml(nodeList *wwapiv1.NodeYaml) (err error) {
nodeDB, err := node.New()
if err != nil {
return errors.Wrap(err, "Could not open NodeDB: %s\n")
}
profileMap := make(map[string]*node.NodeConf)
err = yaml.Unmarshal([]byte(nodeList.NodeConfMapYaml), profileMap)
if err != nil {
return errors.Wrap(err, "Could not unmarshall Yaml: %s\n")
}
for profileName, profile := range profileMap {
nodeDB.NodeProfiles[profileName] = profile
}
err = nodeDB.Persist()
if err != nil {
return errors.Wrap(err, "failed to persist nodedb")
}
return nil
}

View File

@@ -91,7 +91,6 @@ message NetDev {
// NodeInfo contains details about a node managed by Warewulf/
message NodeInfo {
map<string, NodeField> Fields = 1;
map<string, NetDev> NetDevs = 23;
map<string, NodeField> Tags = 24;
map<string, NodeField> Keys = 25; // TODO: We may not need this. Tags may be it. Ask Greg.
@@ -126,6 +125,12 @@ message NodeAddParameter {
repeated string nodeNames = 10;
}
// NodeYaml is just the updated YAML config which will be added
// to nodes.conf (is resused for profile edit)
message NodeYaml {
string nodeConfMapYaml = 1;
}
// NodeDeleteParameter contains input for removing nodes from Warewulf
// management.
message NodeDeleteParameter {
@@ -167,6 +172,11 @@ message VersionResponse {
string warewulfVersion = 3;
}
// Check if config is writeable
message CanWriteConfig {
bool canWriteConfig = 1;
}
// WWApi defines the wwapid service web interface.
service WWApi {

View File

@@ -1026,6 +1026,55 @@ func (x *NodeAddParameter) GetNodeNames() []string {
return nil
}
// NodeYaml is just the updated YAML config which will be added
// to nodes.conf (is resused for profile edit)
type NodeYaml struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
NodeConfMapYaml string `protobuf:"bytes,1,opt,name=nodeConfMapYaml,proto3" json:"nodeConfMapYaml,omitempty"`
}
func (x *NodeYaml) Reset() {
*x = NodeYaml{}
if protoimpl.UnsafeEnabled {
mi := &file_routes_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NodeYaml) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeYaml) ProtoMessage() {}
func (x *NodeYaml) ProtoReflect() protoreflect.Message {
mi := &file_routes_proto_msgTypes[16]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NodeYaml.ProtoReflect.Descriptor instead.
func (*NodeYaml) Descriptor() ([]byte, []int) {
return file_routes_proto_rawDescGZIP(), []int{16}
}
func (x *NodeYaml) GetNodeConfMapYaml() string {
if x != nil {
return x.NodeConfMapYaml
}
return ""
}
// NodeDeleteParameter contains input for removing nodes from Warewulf
// management.
type NodeDeleteParameter struct {
@@ -1040,7 +1089,7 @@ type NodeDeleteParameter struct {
func (x *NodeDeleteParameter) Reset() {
*x = NodeDeleteParameter{}
if protoimpl.UnsafeEnabled {
mi := &file_routes_proto_msgTypes[16]
mi := &file_routes_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1053,7 +1102,7 @@ func (x *NodeDeleteParameter) String() string {
func (*NodeDeleteParameter) ProtoMessage() {}
func (x *NodeDeleteParameter) ProtoReflect() protoreflect.Message {
mi := &file_routes_proto_msgTypes[16]
mi := &file_routes_proto_msgTypes[17]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1066,7 +1115,7 @@ func (x *NodeDeleteParameter) ProtoReflect() protoreflect.Message {
// Deprecated: Use NodeDeleteParameter.ProtoReflect.Descriptor instead.
func (*NodeDeleteParameter) Descriptor() ([]byte, []int) {
return file_routes_proto_rawDescGZIP(), []int{16}
return file_routes_proto_rawDescGZIP(), []int{17}
}
func (x *NodeDeleteParameter) GetForce() bool {
@@ -1101,7 +1150,7 @@ type NodeSetParameter struct {
func (x *NodeSetParameter) Reset() {
*x = NodeSetParameter{}
if protoimpl.UnsafeEnabled {
mi := &file_routes_proto_msgTypes[17]
mi := &file_routes_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1114,7 +1163,7 @@ func (x *NodeSetParameter) String() string {
func (*NodeSetParameter) ProtoMessage() {}
func (x *NodeSetParameter) ProtoReflect() protoreflect.Message {
mi := &file_routes_proto_msgTypes[17]
mi := &file_routes_proto_msgTypes[18]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1127,7 +1176,7 @@ func (x *NodeSetParameter) ProtoReflect() protoreflect.Message {
// Deprecated: Use NodeSetParameter.ProtoReflect.Descriptor instead.
func (*NodeSetParameter) Descriptor() ([]byte, []int) {
return file_routes_proto_rawDescGZIP(), []int{17}
return file_routes_proto_rawDescGZIP(), []int{18}
}
func (x *NodeSetParameter) GetNodeConfYaml() string {
@@ -1188,7 +1237,7 @@ type NodeStatus struct {
func (x *NodeStatus) Reset() {
*x = NodeStatus{}
if protoimpl.UnsafeEnabled {
mi := &file_routes_proto_msgTypes[18]
mi := &file_routes_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1201,7 +1250,7 @@ func (x *NodeStatus) String() string {
func (*NodeStatus) ProtoMessage() {}
func (x *NodeStatus) ProtoReflect() protoreflect.Message {
mi := &file_routes_proto_msgTypes[18]
mi := &file_routes_proto_msgTypes[19]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1214,7 +1263,7 @@ func (x *NodeStatus) ProtoReflect() protoreflect.Message {
// Deprecated: Use NodeStatus.ProtoReflect.Descriptor instead.
func (*NodeStatus) Descriptor() ([]byte, []int) {
return file_routes_proto_rawDescGZIP(), []int{18}
return file_routes_proto_rawDescGZIP(), []int{19}
}
func (x *NodeStatus) GetNodeName() string {
@@ -1264,7 +1313,7 @@ type NodeStatusResponse struct {
func (x *NodeStatusResponse) Reset() {
*x = NodeStatusResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_routes_proto_msgTypes[19]
mi := &file_routes_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1277,7 +1326,7 @@ func (x *NodeStatusResponse) String() string {
func (*NodeStatusResponse) ProtoMessage() {}
func (x *NodeStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_routes_proto_msgTypes[19]
mi := &file_routes_proto_msgTypes[20]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1290,7 +1339,7 @@ func (x *NodeStatusResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use NodeStatusResponse.ProtoReflect.Descriptor instead.
func (*NodeStatusResponse) Descriptor() ([]byte, []int) {
return file_routes_proto_rawDescGZIP(), []int{19}
return file_routes_proto_rawDescGZIP(), []int{20}
}
func (x *NodeStatusResponse) GetNodeStatus() []*NodeStatus {
@@ -1314,7 +1363,7 @@ type VersionResponse struct {
func (x *VersionResponse) Reset() {
*x = VersionResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_routes_proto_msgTypes[20]
mi := &file_routes_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -1327,7 +1376,7 @@ func (x *VersionResponse) String() string {
func (*VersionResponse) ProtoMessage() {}
func (x *VersionResponse) ProtoReflect() protoreflect.Message {
mi := &file_routes_proto_msgTypes[20]
mi := &file_routes_proto_msgTypes[21]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -1340,7 +1389,7 @@ func (x *VersionResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use VersionResponse.ProtoReflect.Descriptor instead.
func (*VersionResponse) Descriptor() ([]byte, []int) {
return file_routes_proto_rawDescGZIP(), []int{20}
return file_routes_proto_rawDescGZIP(), []int{21}
}
func (x *VersionResponse) GetApiPrefix() string {
@@ -1364,6 +1413,54 @@ func (x *VersionResponse) GetWarewulfVersion() string {
return ""
}
// Check if config is writeable
type CanWriteConfig struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
CanWriteConfig bool `protobuf:"varint,1,opt,name=canWriteConfig,proto3" json:"canWriteConfig,omitempty"`
}
func (x *CanWriteConfig) Reset() {
*x = CanWriteConfig{}
if protoimpl.UnsafeEnabled {
mi := &file_routes_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CanWriteConfig) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CanWriteConfig) ProtoMessage() {}
func (x *CanWriteConfig) ProtoReflect() protoreflect.Message {
mi := &file_routes_proto_msgTypes[22]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CanWriteConfig.ProtoReflect.Descriptor instead.
func (*CanWriteConfig) Descriptor() ([]byte, []int) {
return file_routes_proto_rawDescGZIP(), []int{22}
}
func (x *CanWriteConfig) GetCanWriteConfig() bool {
if x != nil {
return x.CanWriteConfig
}
return false
}
var File_routes_proto protoreflect.FileDescriptor
var file_routes_proto_rawDesc = []byte{
@@ -1504,45 +1601,52 @@ var file_routes_proto_rawDesc = []byte{
0x6f, 0x6e, 0x66, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e,
0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x6e,
0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x49, 0x0a, 0x13, 0x4e, 0x6f, 0x64,
0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72,
0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61,
0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x4e,
0x61, 0x6d, 0x65, 0x73, 0x22, 0xc8, 0x01, 0x0a, 0x10, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x74,
0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x6e, 0x6f, 0x64,
0x65, 0x43, 0x6f, 0x6e, 0x66, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x1c, 0x0a,
0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0c, 0x6e,
0x65, 0x74, 0x64, 0x65, 0x76, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0c, 0x6e, 0x65, 0x74, 0x64, 0x65, 0x76, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12,
0x1a, 0x0a, 0x08, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x1b, 0x20, 0x01, 0x28,
0x08, 0x52, 0x08, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66,
0x6f, 0x72, 0x63, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63,
0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x27,
0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22,
0x86, 0x01, 0x0a, 0x0a, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a,
0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74,
0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65,
0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x73, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x70, 0x61, 0x64, 0x64, 0x72, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x61, 0x64, 0x64, 0x72, 0x12, 0x1a, 0x0a, 0x08,
0x6c, 0x61, 0x73, 0x74, 0x73, 0x65, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08,
0x6c, 0x61, 0x73, 0x74, 0x73, 0x65, 0x65, 0x6e, 0x22, 0x4a, 0x0a, 0x12, 0x4e, 0x6f, 0x64, 0x65,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34,
0x0a, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x14, 0x2e, 0x77, 0x77, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f,
0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x22, 0x79, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x70, 0x69, 0x50, 0x72,
0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x70, 0x69, 0x50,
0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x70, 0x69, 0x56, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x77, 0x61, 0x72, 0x65, 0x77, 0x75, 0x6c,
0x66, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
0x77, 0x61, 0x72, 0x65, 0x77, 0x75, 0x6c, 0x66, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32,
0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x34, 0x0a, 0x08, 0x4e, 0x6f, 0x64,
0x65, 0x59, 0x61, 0x6d, 0x6c, 0x12, 0x28, 0x0a, 0x0f, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e,
0x66, 0x4d, 0x61, 0x70, 0x59, 0x61, 0x6d, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f,
0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x4d, 0x61, 0x70, 0x59, 0x61, 0x6d, 0x6c, 0x22,
0x49, 0x0a, 0x13, 0x4e, 0x6f, 0x64, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x61, 0x72,
0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09,
0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
0x09, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xc8, 0x01, 0x0a, 0x10, 0x4e,
0x6f, 0x64, 0x65, 0x53, 0x65, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12,
0x22, 0x0a, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x59, 0x61, 0x6d, 0x6c, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x59,
0x61, 0x6d, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x12, 0x22, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x64, 0x65, 0x76, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6e, 0x65, 0x74, 0x64, 0x65, 0x76, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65,
0x73, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x6c, 0x6c, 0x4e, 0x6f, 0x64, 0x65,
0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08,
0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x4e,
0x61, 0x6d, 0x65, 0x73, 0x18, 0x27, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x6f, 0x64, 0x65,
0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x0a, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65,
0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x70,
0x61, 0x64, 0x64, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69, 0x70, 0x61, 0x64,
0x64, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x73, 0x65, 0x65, 0x6e, 0x18, 0x05,
0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x73, 0x65, 0x65, 0x6e, 0x22, 0x4a,
0x0a, 0x12, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x6e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x77, 0x77, 0x61, 0x70, 0x69,
0x2e, 0x76, 0x31, 0x2e, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0a,
0x6e, 0x6f, 0x64, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x79, 0x0a, 0x0f, 0x56, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a,
0x09, 0x61, 0x70, 0x69, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x61, 0x70, 0x69, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x61,
0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x61, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x77,
0x61, 0x72, 0x65, 0x77, 0x75, 0x6c, 0x66, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x77, 0x61, 0x72, 0x65, 0x77, 0x75, 0x6c, 0x66, 0x56, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x38, 0x0a, 0x0e, 0x43, 0x61, 0x6e, 0x57, 0x72, 0x69, 0x74,
0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x61, 0x6e, 0x57, 0x72,
0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
0x0e, 0x63, 0x61, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x32,
0xa6, 0x08, 0x0a, 0x05, 0x57, 0x57, 0x41, 0x70, 0x69, 0x12, 0x73, 0x0a, 0x0e, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x21, 0x2e, 0x77, 0x77,
0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
@@ -1628,7 +1732,7 @@ func file_routes_proto_rawDescGZIP() []byte {
}
var file_routes_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_routes_proto_msgTypes = make([]protoimpl.MessageInfo, 27)
var file_routes_proto_msgTypes = make([]protoimpl.MessageInfo, 29)
var file_routes_proto_goTypes = []interface{}{
(GetNodeList_ListType)(0), // 0: wwapi.v1.GetNodeList.ListType
(*ContainerBuildParameter)(nil), // 1: wwapi.v1.ContainerBuildParameter
@@ -1647,30 +1751,32 @@ var file_routes_proto_goTypes = []interface{}{
(*GetNodeList)(nil), // 14: wwapi.v1.GetNodeList
(*NodeList)(nil), // 15: wwapi.v1.NodeList
(*NodeAddParameter)(nil), // 16: wwapi.v1.NodeAddParameter
(*NodeDeleteParameter)(nil), // 17: wwapi.v1.NodeDeleteParameter
(*NodeSetParameter)(nil), // 18: wwapi.v1.NodeSetParameter
(*NodeStatus)(nil), // 19: wwapi.v1.NodeStatus
(*NodeStatusResponse)(nil), // 20: wwapi.v1.NodeStatusResponse
(*VersionResponse)(nil), // 21: wwapi.v1.VersionResponse
nil, // 22: wwapi.v1.NetDev.FieldEntry
nil, // 23: wwapi.v1.NetDev.TagsEntry
nil, // 24: wwapi.v1.NodeInfo.FieldsEntry
nil, // 25: wwapi.v1.NodeInfo.NetDevsEntry
nil, // 26: wwapi.v1.NodeInfo.TagsEntry
nil, // 27: wwapi.v1.NodeInfo.KeysEntry
(*empty.Empty)(nil), // 28: google.protobuf.Empty
(*NodeYaml)(nil), // 17: wwapi.v1.NodeYaml
(*NodeDeleteParameter)(nil), // 18: wwapi.v1.NodeDeleteParameter
(*NodeSetParameter)(nil), // 19: wwapi.v1.NodeSetParameter
(*NodeStatus)(nil), // 20: wwapi.v1.NodeStatus
(*NodeStatusResponse)(nil), // 21: wwapi.v1.NodeStatusResponse
(*VersionResponse)(nil), // 22: wwapi.v1.VersionResponse
(*CanWriteConfig)(nil), // 23: wwapi.v1.CanWriteConfig
nil, // 24: wwapi.v1.NetDev.FieldEntry
nil, // 25: wwapi.v1.NetDev.TagsEntry
nil, // 26: wwapi.v1.NodeInfo.FieldsEntry
nil, // 27: wwapi.v1.NodeInfo.NetDevsEntry
nil, // 28: wwapi.v1.NodeInfo.TagsEntry
nil, // 29: wwapi.v1.NodeInfo.KeysEntry
(*empty.Empty)(nil), // 30: google.protobuf.Empty
}
var file_routes_proto_depIdxs = []int32{
4, // 0: wwapi.v1.ContainerListResponse.containers:type_name -> wwapi.v1.ContainerInfo
22, // 1: wwapi.v1.NetDev.Field:type_name -> wwapi.v1.NetDev.FieldEntry
23, // 2: wwapi.v1.NetDev.Tags:type_name -> wwapi.v1.NetDev.TagsEntry
24, // 3: wwapi.v1.NodeInfo.Fields:type_name -> wwapi.v1.NodeInfo.FieldsEntry
25, // 4: wwapi.v1.NodeInfo.NetDevs:type_name -> wwapi.v1.NodeInfo.NetDevsEntry
26, // 5: wwapi.v1.NodeInfo.Tags:type_name -> wwapi.v1.NodeInfo.TagsEntry
27, // 6: wwapi.v1.NodeInfo.Keys:type_name -> wwapi.v1.NodeInfo.KeysEntry
24, // 1: wwapi.v1.NetDev.Field:type_name -> wwapi.v1.NetDev.FieldEntry
25, // 2: wwapi.v1.NetDev.Tags:type_name -> wwapi.v1.NetDev.TagsEntry
26, // 3: wwapi.v1.NodeInfo.Fields:type_name -> wwapi.v1.NodeInfo.FieldsEntry
27, // 4: wwapi.v1.NodeInfo.NetDevs:type_name -> wwapi.v1.NodeInfo.NetDevsEntry
28, // 5: wwapi.v1.NodeInfo.Tags:type_name -> wwapi.v1.NodeInfo.TagsEntry
29, // 6: wwapi.v1.NodeInfo.Keys:type_name -> wwapi.v1.NodeInfo.KeysEntry
12, // 7: wwapi.v1.NodeListResponse.nodes:type_name -> wwapi.v1.NodeInfo
0, // 8: wwapi.v1.GetNodeList.type:type_name -> wwapi.v1.GetNodeList.ListType
19, // 9: wwapi.v1.NodeStatusResponse.nodeStatus:type_name -> wwapi.v1.NodeStatus
20, // 9: wwapi.v1.NodeStatusResponse.nodeStatus:type_name -> wwapi.v1.NodeStatus
10, // 10: wwapi.v1.NetDev.FieldEntry.value:type_name -> wwapi.v1.NodeField
10, // 11: wwapi.v1.NetDev.TagsEntry.value:type_name -> wwapi.v1.NodeField
10, // 12: wwapi.v1.NodeInfo.FieldsEntry.value:type_name -> wwapi.v1.NodeField
@@ -1680,25 +1786,25 @@ var file_routes_proto_depIdxs = []int32{
1, // 16: wwapi.v1.WWApi.ContainerBuild:input_type -> wwapi.v1.ContainerBuildParameter
2, // 17: wwapi.v1.WWApi.ContainerDelete:input_type -> wwapi.v1.ContainerDeleteParameter
3, // 18: wwapi.v1.WWApi.ContainerImport:input_type -> wwapi.v1.ContainerImportParameter
28, // 19: wwapi.v1.WWApi.ContainerList:input_type -> google.protobuf.Empty
30, // 19: wwapi.v1.WWApi.ContainerList:input_type -> google.protobuf.Empty
6, // 20: wwapi.v1.WWApi.ContainerShow:input_type -> wwapi.v1.ContainerShowParameter
16, // 21: wwapi.v1.WWApi.NodeAdd:input_type -> wwapi.v1.NodeAddParameter
17, // 22: wwapi.v1.WWApi.NodeDelete:input_type -> wwapi.v1.NodeDeleteParameter
18, // 22: wwapi.v1.WWApi.NodeDelete:input_type -> wwapi.v1.NodeDeleteParameter
9, // 23: wwapi.v1.WWApi.NodeList:input_type -> wwapi.v1.NodeNames
18, // 24: wwapi.v1.WWApi.NodeSet:input_type -> wwapi.v1.NodeSetParameter
19, // 24: wwapi.v1.WWApi.NodeSet:input_type -> wwapi.v1.NodeSetParameter
9, // 25: wwapi.v1.WWApi.NodeStatus:input_type -> wwapi.v1.NodeNames
28, // 26: wwapi.v1.WWApi.Version:input_type -> google.protobuf.Empty
30, // 26: wwapi.v1.WWApi.Version:input_type -> google.protobuf.Empty
5, // 27: wwapi.v1.WWApi.ContainerBuild:output_type -> wwapi.v1.ContainerListResponse
28, // 28: wwapi.v1.WWApi.ContainerDelete:output_type -> google.protobuf.Empty
30, // 28: wwapi.v1.WWApi.ContainerDelete:output_type -> google.protobuf.Empty
5, // 29: wwapi.v1.WWApi.ContainerImport:output_type -> wwapi.v1.ContainerListResponse
5, // 30: wwapi.v1.WWApi.ContainerList:output_type -> wwapi.v1.ContainerListResponse
7, // 31: wwapi.v1.WWApi.ContainerShow:output_type -> wwapi.v1.ContainerShowResponse
13, // 32: wwapi.v1.WWApi.NodeAdd:output_type -> wwapi.v1.NodeListResponse
28, // 33: wwapi.v1.WWApi.NodeDelete:output_type -> google.protobuf.Empty
30, // 33: wwapi.v1.WWApi.NodeDelete:output_type -> google.protobuf.Empty
13, // 34: wwapi.v1.WWApi.NodeList:output_type -> wwapi.v1.NodeListResponse
13, // 35: wwapi.v1.WWApi.NodeSet:output_type -> wwapi.v1.NodeListResponse
20, // 36: wwapi.v1.WWApi.NodeStatus:output_type -> wwapi.v1.NodeStatusResponse
21, // 37: wwapi.v1.WWApi.Version:output_type -> wwapi.v1.VersionResponse
21, // 36: wwapi.v1.WWApi.NodeStatus:output_type -> wwapi.v1.NodeStatusResponse
22, // 37: wwapi.v1.WWApi.Version:output_type -> wwapi.v1.VersionResponse
27, // [27:38] is the sub-list for method output_type
16, // [16:27] is the sub-list for method input_type
16, // [16:16] is the sub-list for extension type_name
@@ -1905,7 +2011,7 @@ func file_routes_proto_init() {
}
}
file_routes_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NodeDeleteParameter); i {
switch v := v.(*NodeYaml); i {
case 0:
return &v.state
case 1:
@@ -1917,7 +2023,7 @@ func file_routes_proto_init() {
}
}
file_routes_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NodeSetParameter); i {
switch v := v.(*NodeDeleteParameter); i {
case 0:
return &v.state
case 1:
@@ -1929,7 +2035,7 @@ func file_routes_proto_init() {
}
}
file_routes_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NodeStatus); i {
switch v := v.(*NodeSetParameter); i {
case 0:
return &v.state
case 1:
@@ -1941,7 +2047,7 @@ func file_routes_proto_init() {
}
}
file_routes_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NodeStatusResponse); i {
switch v := v.(*NodeStatus); i {
case 0:
return &v.state
case 1:
@@ -1953,6 +2059,18 @@ func file_routes_proto_init() {
}
}
file_routes_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NodeStatusResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_routes_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*VersionResponse); i {
case 0:
return &v.state
@@ -1964,6 +2082,18 @@ func file_routes_proto_init() {
return nil
}
}
file_routes_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CanWriteConfig); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@@ -1971,7 +2101,7 @@ func file_routes_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_routes_proto_rawDesc,
NumEnums: 1,
NumMessages: 27,
NumMessages: 29,
NumExtensions: 0,
NumServices: 1,
},

View File

@@ -1,6 +1,11 @@
package util
import (
"syscall"
"github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/manifoldco/promptui"
)
@@ -18,4 +23,19 @@ func ConfirmationPrompt(label string) (yes bool) {
yes = true
}
return
}
}
/*
Simple check if the config can be written in case wwctl isn't run as root
*/
func CanWriteConfig() (canwrite *wwapiv1.CanWriteConfig) {
canwrite = new(wwapiv1.CanWriteConfig)
err := syscall.Access(node.ConfigFile, syscall.O_RDWR)
if err != nil {
wwlog.Warn("Couldn't open %s:%s", node.ConfigFile, err)
canwrite.CanWriteConfig = false
} else {
canwrite.CanWriteConfig = true
}
return canwrite
}

View File

@@ -3,7 +3,9 @@ package node
/******
* YAML data representations
******/
/*
Structure of which goes to disk
*/
type NodeYaml struct {
WWInternal int `yaml:"WW_INTERNAL"`
NodeProfiles map[string]*NodeConf
@@ -11,7 +13,7 @@ type NodeYaml struct {
}
/*
NodeConf is the datastructure which is stored on disk.
NodeConf is the datastructure describing a node and a profile which in disk format.
*/
type NodeConf struct {
Comment string `yaml:"comment,omitempty" lopt:"comment" comment:"Set arbitrary string comment"`
@@ -19,11 +21,11 @@ type NodeConf struct {
ContainerName string `yaml:"container name,omitempty" lopt:"container" sopt:"C" comment:"Set container name"`
Ipxe string `yaml:"ipxe template,omitempty" lopt:"ipxe" comment:"Set the iPXE template name"`
// Deprecated start
// Kernel settings here are deprecated and here for backward comptability
// Kernel settings here are deprecated and here for backward compatibility
KernelVersion string `yaml:"kernel version,omitempty"`
KernelOverride string `yaml:"kernel override,omitempty"`
KernelArgs string `yaml:"kernel args,omitempty"`
// Ipmi settings herer are deprecated and here for backward comptability
// Ipmi settings herer are deprecated and here for backward compatibility
IpmiUserName string `yaml:"ipmi username,omitempty"`
IpmiPassword string `yaml:"ipmi password,omitempty"`
IpmiIpaddr string `yaml:"ipmi ipaddr,omitempty"`

View File

@@ -26,8 +26,7 @@ func FilterByName(set []NodeInfo, searchList []string) []NodeInfo {
if len(searchList) > 0 {
for _, search := range searchList {
for _, entry := range set {
b, _ := regexp.MatchString("^"+search+"$", entry.Id.Get())
if b {
if match, _ := regexp.MatchString("^"+search+"$", entry.Id.Get()); match {
unique[entry.Id.Get()] = entry
}
}
@@ -42,6 +41,24 @@ func FilterByName(set []NodeInfo, searchList []string) []NodeInfo {
return ret
}
/*
Filter a given map of NodeConf against given regular expression.
*/
func FilterMapByName(inputMap map[string]*NodeConf, searchList []string) (retMap map[string]*NodeConf) {
retMap = map[string]*NodeConf{}
if len(searchList) > 0 {
for _, search := range searchList {
for name, nConf := range inputMap {
if match, _ := regexp.MatchString("^"+search+"$", name); match {
retMap[name] = nConf
}
}
}
}
return retMap
}
/**********
*
* Sets

View File

@@ -2,8 +2,10 @@ package node
import (
"reflect"
"strings"
"github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/wwlog"
"github.com/spf13/cobra"
)
@@ -186,6 +188,10 @@ 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)
@@ -520,3 +526,145 @@ func (netDev *NetDevEntry) setterFrom(netYaml *NetDevs, nameArg string,
}
}
}
/*
Create a string slice, where every element represents a yaml entry
*/
func (nodeConf *NodeConf) UnmarshalConf(excludeList []string) (lines []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("lopt") != "" {
if ymlStr, ok := getYamlString(nodeInfoType.Elem().Field(i), excludeList); ok {
lines = append(lines, ymlStr...)
}
} else if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.Ptr {
nestType := reflect.TypeOf(nodeInfoVal.Elem().Field(i).Interface())
if ymlStr, ok := getYamlString(nodeInfoType.Elem().Field(i), excludeList); ok {
lines = append(lines, ymlStr...)
}
for j := 0; j < nestType.Elem().NumField(); j++ {
if nestType.Elem().Field(j).Tag.Get("lopt") != "" &&
!util.InSlice(excludeList, nestType.Elem().Field(j).Tag.Get("lopt")) {
if ymlStr, ok := getYamlString(nestType.Elem().Field(j), excludeList); ok {
for _, str := range ymlStr {
lines = append(lines, " "+str)
}
}
}
}
} 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
}
}
if ymlStr, ok := getYamlString(nodeInfoType.Elem().Field(i), excludeList); ok {
lines = append(lines, ymlStr[0]+":", " "+key+":")
netType := reflect.TypeOf(netMap[key])
for j := 0; j < netType.Elem().NumField(); j++ {
if ymlStr, ok := getYamlString(netType.Elem().Field(j), excludeList); ok {
for _, str := range ymlStr {
lines = append(lines, " "+str)
}
}
} // lines
} // this
} //not
} //do
return lines
}
/*
Get the string of the yaml tag
*/
func getYamlString(myType reflect.StructField, excludeList []string) ([]string, bool) {
ymlStr := myType.Tag.Get("yaml")
if len(strings.Split(ymlStr, ",")) > 1 {
ymlStr = strings.Split(ymlStr, ",")[0]
}
if util.InSlice(excludeList, ymlStr) {
return []string{""}, false
} else if myType.Tag.Get("lopt") == "" && myType.Type.Kind() == reflect.String {
return []string{""}, false
}
if myType.Type.Kind() == reflect.String {
ymlStr += ": string"
return []string{ymlStr}, true
} else if myType.Type == reflect.TypeOf([]string{}) {
return []string{ymlStr + ":", " - string"}, true
} else if myType.Type == reflect.TypeOf(map[string]string{}) {
return []string{ymlStr + ":", " key: value"}, true
} else if myType.Type.Kind() == reflect.Ptr {
return []string{ymlStr + ":"}, true
}
return []string{ymlStr}, true
}
/*
Set the field of the NodeConf with the given lopt name, returns true if the
field was found. String slices must be comma separated. Network must have the form
net.$NETNAME.lopt or netname.$NETNAME.lopt
*/
func (nodeConf *NodeConf) SetLopt(lopt string, value string) (found bool) {
found = false
nodeInfoType := reflect.TypeOf(nodeConf)
nodeInfoVal := reflect.ValueOf(nodeConf)
// try to find the normal fields, networks come later
for i := 0; i < nodeInfoVal.Elem().NumField(); i++ {
//fmt.Println(nodeInfoType.Elem().Field(i).Tag.Get("lopt"), lopt)
if nodeInfoType.Elem().Field(i).Tag.Get("lopt") == lopt {
if nodeInfoType.Elem().Field(i).Type.Kind() == reflect.String {
wwlog.Verbose("Found lopt %s mapping to %s, setting to %s\n",
lopt, nodeInfoType.Elem().Field(i).Name, value)
confVal := nodeInfoVal.Elem().Field(i).Addr().Interface().(*string)
*confVal = value
found = true
} else if nodeInfoType.Elem().Field(i).Type == reflect.TypeOf([]string{}) {
wwlog.Verbose("Found lopt %s mapping to %s, setting to %s\n",
lopt, nodeInfoType.Elem().Field(i).Name, value)
confVal := nodeInfoVal.Elem().Field(i).Addr().Interface().(*[]string)
*confVal = strings.Split(value, ",")
found = true
}
}
}
// check network
loptSlice := strings.Split(lopt, ".")
wwlog.Debug("Trying to get network out of %s\n", loptSlice)
if !found && len(loptSlice) == 3 && (loptSlice[0] == "net" || loptSlice[0] == "network" || loptSlice[0] == "netname") {
if nodeConf.NetDevs == nil {
nodeConf.NetDevs = make(map[string]*NetDevs)
}
if nodeConf.NetDevs[loptSlice[1]] == nil {
nodeConf.NetDevs[loptSlice[1]] = new(NetDevs)
}
netInfoType := reflect.TypeOf(nodeConf.NetDevs[loptSlice[1]])
netInfoVal := reflect.ValueOf(nodeConf.NetDevs[loptSlice[1]])
for i := 0; i < netInfoVal.Elem().NumField(); i++ {
if netInfoType.Elem().Field(i).Tag.Get("lopt") == loptSlice[2] {
if netInfoType.Elem().Field(i).Type.Kind() == reflect.String {
wwlog.Verbose("Found lopt %s for network %s mapping to %s, setting to %s\n",
lopt, loptSlice[1], netInfoType.Elem().Field(i).Name, value)
confVal := netInfoVal.Elem().Field(i).Addr().Interface().(*string)
*confVal = value
found = true
} else if netInfoType.Elem().Field(i).Type == reflect.TypeOf([]string{}) {
wwlog.Verbose("Found lopt %s for network %s mapping to %s, setting to %s\n",
lopt, loptSlice[1], netInfoType.Elem().Field(i).Name, value)
confVal := netInfoVal.Elem().Field(i).Addr().Interface().(*[]string)
*confVal = strings.Split(value, ",")
found = true
}
}
}
}
return found
}

BIN
print_defaults Executable file

Binary file not shown.