From 14b86a5e8e5fbd670070f6c333c6fa5252283209 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Wed, 13 Jul 2022 15:56:04 +0200 Subject: [PATCH] added profile set over API --- internal/app/wwctl/node/set/main.go | 8 +- internal/app/wwctl/node/set/root.go | 5 +- internal/app/wwctl/profile/set/main.go | 364 ++----------------------- internal/app/wwctl/profile/set/root.go | 95 ++----- internal/pkg/api/node/node.go | 22 +- internal/pkg/api/node/utils.go | 25 ++ internal/pkg/api/profile/profile.go | 109 ++++++++ 7 files changed, 188 insertions(+), 440 deletions(-) create mode 100644 internal/pkg/api/node/utils.go create mode 100644 internal/pkg/api/profile/profile.go diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index 24cb5dda..877c9c57 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -4,14 +4,14 @@ import ( "errors" "fmt" - "github.com/hpcng/warewulf/internal/pkg/api/node" + apinode "github.com/hpcng/warewulf/internal/pkg/api/node" "github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1" "github.com/hpcng/warewulf/internal/pkg/api/util" "github.com/spf13/cobra" ) func CobraRunE(cmd *cobra.Command, args []string) (err error) { - OptionStrMap, haveNetname := node.AddNetname(OptionStrMap) + OptionStrMap, haveNetname := apinode.AddNetname(OptionStrMap) if !haveNetname { return errors.New("a netname must be given for any network related configuration") } @@ -33,7 +33,7 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { var nodeCount uint // The checks run twice in the prompt case. // Avoiding putting in a blocking prompt in an API. - _, nodeCount, err = node.NodeSetParameterCheck(&set, false) + _, nodeCount, err = apinode.NodeSetParameterCheck(&set, false) if err != nil { return } @@ -42,5 +42,5 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { return } } - return node.NodeSet(&set) + return apinode.NodeSet(&set) } diff --git a/internal/app/wwctl/node/set/root.go b/internal/app/wwctl/node/set/root.go index f827b605..36a24063 100644 --- a/internal/app/wwctl/node/set/root.go +++ b/internal/app/wwctl/node/set/root.go @@ -37,17 +37,14 @@ var ( SetYes bool SetForce bool OptionStrMap map[string]*string - KernelStrMap map[string]*string ) func init() { - //var emptyNodeConf node.NodeConf - //var emptyKernelE node.KernelEntry + // init empty helper structs, so that we know what's inside myBase := node.CobraCommand{Command: baseCmd} var emptyNodeConf node.NodeConf emptyNodeConf.Kernel = new(node.KernelConf) emptyNodeConf.Ipmi = new(node.IpmiConf) - //emptyNodeConf.NetDevs = make(map[string]*node.NetDevs) OptionStrMap = myBase.CreateFlags(emptyNodeConf) baseCmd.PersistentFlags().StringVarP(&SetNetDevDel, "netdel", "D", "", "Delete the node's network device") diff --git a/internal/app/wwctl/profile/set/main.go b/internal/app/wwctl/profile/set/main.go index 6fec3326..e206c13f 100644 --- a/internal/app/wwctl/profile/set/main.go +++ b/internal/app/wwctl/profile/set/main.go @@ -2,352 +2,46 @@ package set import ( "fmt" - "os" - "strings" - "github.com/hpcng/warewulf/internal/pkg/node" - "github.com/hpcng/warewulf/internal/pkg/warewulfd" - "github.com/hpcng/warewulf/internal/pkg/wwlog" - "github.com/manifoldco/promptui" + apinode "github.com/hpcng/warewulf/internal/pkg/api/node" + apiprofile "github.com/hpcng/warewulf/internal/pkg/api/profile" + "github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1" + "github.com/hpcng/warewulf/internal/pkg/api/util" "github.com/pkg/errors" "github.com/spf13/cobra" ) -func CobraRunE(cmd *cobra.Command, args []string) error { - var err error +func CobraRunE(cmd *cobra.Command, args []string) (err error) { + OptionStrMap, haveNetname := apinode.AddNetname(OptionStrMap) + if !haveNetname { + return errors.New("a netname must be given for any network related configuration") + } + realMap := make(map[string]string) - nodeDB, err := node.New() - if err != nil { - wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) - os.Exit(1) + for key, val := range OptionStrMap { + realMap[key] = *val } - profiles, err := nodeDB.FindAllProfiles() - if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) + set := wwapiv1.NodeSetParameter{ + OptionsStrMap: realMap, + NetdevDelete: SetNetDevDel, + AllNodes: SetNodeAll, + Force: SetForce, + NodeNames: args, } - if SetAll { - fmt.Printf("\n*** WARNING: This command will modify all profiles! ***\n\n") - } else if len(args) > 0 { - profiles = node.FilterByName(profiles, args) - } else { - wwlog.Printf(wwlog.INFO, "No profile specified, selecting the 'default' profile\n") - profiles = node.FilterByName(profiles, []string{"default"}) - } - - if len(profiles) == 0 { - fmt.Printf("No profiles found\n") - os.Exit(1) - } - - for _, p := range profiles { - wwlog.Printf(wwlog.VERBOSE, "Modifying profile: %s\n", p.Id.Get()) - - if SetComment != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting comment to: %s\n", p.Id.Get(), SetComment) - p.Comment.Set(SetComment) - } - - if SetClusterName != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting cluster name to: %s\n", p.Id.Get(), SetClusterName) - p.ClusterName.Set(SetClusterName) - } - - if SetContainer != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Container name to: %s\n", p.Id.Get(), SetContainer) - p.ContainerName.Set(SetContainer) - } - - if SetInit != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting init command to: %s\n", p.Id.Get(), SetInit) - p.Init.Set(SetInit) - } - - if SetRoot != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting root to: %s\n", p.Id.Get(), SetRoot) - p.Root.Set(SetRoot) - } - - if SetAssetKey != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting asset key to: %s\n", p.Id.Get(), SetAssetKey) - p.AssetKey.Set(SetAssetKey) - } - - if SetKernelOverride != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Kernel override version to: %s\n", p.Id.Get(), SetKernelOverride) - p.Kernel.Override.Set(SetKernelOverride) - } - - if SetKernelArgs != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Kernel args to: %s\n", p.Id.Get(), SetKernelArgs) - p.Kernel.Args.Set(SetKernelArgs) - } - - if SetIpxe != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting iPXE template to: %s\n", p.Id.Get(), SetIpxe) - p.Ipxe.Set(SetIpxe) - } - - if len(SetRuntimeOverlay) != 0 { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting runtime overlay to: %s\n", p.Id.Get(), SetRuntimeOverlay) - p.RuntimeOverlay.SetSlice(SetRuntimeOverlay) - } - - if len(SetSystemOverlay) != 0 { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting system overlay to: %s\n", p.Id.Get(), SetSystemOverlay) - p.SystemOverlay.SetSlice(SetSystemOverlay) - } - - if SetIpmiNetmask != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI netmask to: %s\n", p.Id.Get(), SetIpmiNetmask) - p.Ipmi.Netmask.Set(SetIpmiNetmask) - } - - if SetIpmiPort != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI port to: %s\n", p.Id.Get(), SetIpmiPort) - p.Ipmi.Port.Set(SetIpmiPort) - } - - if SetIpmiGateway != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI gateway to: %s\n", p.Id.Get(), SetIpmiGateway) - p.Ipmi.Gateway.Set(SetIpmiGateway) - } - - if SetIpmiUsername != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI username to: %s\n", p.Id.Get(), SetIpmiUsername) - p.Ipmi.UserName.Set(SetIpmiUsername) - } - - if SetIpmiPassword != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI password to: %s\n", p.Id.Get(), SetIpmiPassword) - p.Ipmi.Password.Set(SetIpmiPassword) - } - - if SetIpmiInterface != "" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting IPMI interface to: %s\n", p.Id.Get(), SetIpmiInterface) - p.Ipmi.Interface.Set(SetIpmiInterface) - } - - if SetIpmiWrite == "yes" || SetNetOnBoot == "y" || SetNetOnBoot == "1" || SetNetOnBoot == "true" { - wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting Ipmiwrite to %s\n", p.Id.Get(), SetIpmiWrite) - p.Ipmi.Write.SetB(true) - } else { - wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting Ipmiwrite to %s\n", p.Id.Get(), SetIpmiWrite) - p.Ipmi.Write.SetB(false) - } - - if SetDiscoverable { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting all nodes to discoverable\n", p.Id.Get()) - p.Discoverable.SetB(true) - } - - if SetUndiscoverable { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting all nodes to undiscoverable\n", p.Id.Get()) - p.Discoverable.SetB(false) - } - - if SetNetName != "" { - if _, ok := p.NetDevs[SetNetName]; !ok { - var nd node.NetDevEntry - nd.Tags = make(map[string]*node.Entry) - p.NetDevs[SetNetName] = &nd - } - } - - if SetNetDev != "" { - if SetNetName == "" { - wwlog.Printf(wwlog.ERROR, "You must include the '--netname' option\n") - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Node: %s:%s, Setting net Device to: %s\n", p.Id.Get(), SetNetName, SetNetDev) - p.NetDevs[SetNetName].Device.Set(SetNetDev) - } - - if SetNetmask != "" { - if SetNetName == "" { - wwlog.Printf(wwlog.ERROR, "You must include the '--netname' option\n") - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Profile '%s': Setting netmask to: %s\n", p.Id.Get(), SetNetName) - p.NetDevs[SetNetName].Netmask.Set(SetNetmask) - } - - if SetGateway != "" { - if SetNetName == "" { - wwlog.Printf(wwlog.ERROR, "You must include the '--netname' option\n") - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Profile '%s': Setting gateway to: %s\n", p.Id.Get(), SetNetName) - p.NetDevs[SetNetName].Gateway.Set(SetGateway) - } - - if SetType != "" { - if SetNetName == "" { - wwlog.Printf(wwlog.ERROR, "You must include the '--netname' option\n") - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Profile '%s': Setting HW address to: %s:%s\n", p.Id.Get(), SetNetName, SetType) - p.NetDevs[SetNetName].Type.Set(SetType) - } - - if SetNetOnBoot != "" { - if SetNetName == "" { - wwlog.Printf(wwlog.ERROR, "You must include the '--netname' option\n") - os.Exit(1) - } - - if SetNetOnBoot == "yes" || SetNetOnBoot == "y" || SetNetOnBoot == "1" || SetNetOnBoot == "true" { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s:%s, Setting ONBOOT\n", p.Id.Get(), SetNetName) - p.NetDevs[SetNetName].OnBoot.SetB(true) - } else { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s:%s, Unsetting ONBOOT\n", p.Id.Get(), SetNetName) - p.NetDevs[SetNetName].OnBoot.SetB(false) - } - } - - if SetNetPrimary != "" { - if SetNetName == "" { - wwlog.Printf(wwlog.ERROR, "You must include the '--netname' option\n") - os.Exit(1) - } - - if SetNetPrimary == "yes" || SetNetPrimary == "y" || SetNetPrimary == "1" || SetNetPrimary == "true" { - - // Set all other networks to non-default - for _, n := range p.NetDevs { - n.Primary.SetB(false) - } - - wwlog.Printf(wwlog.VERBOSE, "Profile: %s:%s, Setting PRIMARY\n", p.Id.Get(), SetNetName) - p.NetDevs[SetNetName].Primary.SetB(true) - } else { - wwlog.Printf(wwlog.VERBOSE, "Profile: %s:%s, Unsetting PRIMARY\n", p.Id.Get(), SetNetName) - p.NetDevs[SetNetName].Primary.SetB(false) - } - } - - if SetNetDevDel { - if SetNetName == "" { - wwlog.Printf(wwlog.ERROR, "You must include the '--netname' option\n") - os.Exit(1) - } - - if _, ok := p.NetDevs[SetNetName]; !ok { - wwlog.Printf(wwlog.ERROR, "Profile '%s': network name doesn't exist: %s\n", p.Id.Get(), SetNetName) - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Profile %s: Deleting network: %s\n", p.Id.Get(), SetNetName) - delete(p.NetDevs, SetNetName) - } - - if len(SetTags) > 0 { - for _, t := range SetTags { - keyval := strings.SplitN(t, "=", 2) - key := keyval[0] - val := keyval[1] - - if _, ok := p.Tags[key]; !ok { - var nd node.Entry - p.Tags[key] = &nd - } - - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Setting Tag '%s'='%s'\n", p.Id.Get(), key, val) - p.Tags[key].Set(val) - } - } - if len(SetDelTags) > 0 { - for _, t := range SetDelTags { - keyval := strings.SplitN(t, "=", 1) - key := keyval[0] - - if _, ok := p.Tags[key]; !ok { - wwlog.Printf(wwlog.WARN, "Key does not exist: %s\n", key) - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Profile: %s, Deleting tag: %s\n", p.Id.Get(), key) - delete(p.Tags, key) - } - } - if len(SetNetTags) > 0 { - for _, t := range SetNetTags { - keyval := strings.SplitN(t, "=", 2) - key := keyval[0] - val := keyval[1] - if _, ok := p.NetDevs[SetNetName].Tags[key]; !ok { - var nd node.Entry - p.NetDevs[SetNetName].Tags[key] = &nd - } - - wwlog.Printf(wwlog.VERBOSE, "Profile: %s:%s, Setting NETTAG '%s'='%s'\n", p.Id.Get(), SetNetName, key, val) - p.NetDevs[SetNetName].Tags[key].Set(val) - } - - } - if len(SetNetDelTags) > 0 { - for _, t := range SetNetDelTags { - keyval := strings.SplitN(t, "=", 1) - key := keyval[0] - if _, ok := p.NetDevs[SetNetName].Tags[key]; !ok { - wwlog.Printf(wwlog.WARN, "Profile: %s,%s, Key %s does not exist\n", p.Id.Get(), SetNetName, key) - os.Exit(1) - } - - wwlog.Printf(wwlog.VERBOSE, "Profile: %s,%s Deleting NETTAG: %s\n", p.Id.Get(), SetNetName, key) - delete(p.NetDevs[SetNetName].Tags, key) - } - } - - err := nodeDB.ProfileUpdate(p) + if !SetYes { + var nodeCount uint + // The checks run twice in the prompt case. + // Avoiding putting in a blocking prompt in an API. + _, nodeCount, err = apiprofile.ProfileSetParameterCheck(&set, false) if err != nil { - wwlog.Printf(wwlog.ERROR, "%s\n", err) - os.Exit(1) + return + } + yes := util.ConfirmationPrompt(fmt.Sprintf("Are you sure you want to modify %d nodes(s)", nodeCount)) + if !yes { + return } } - - if len(profiles) > 0 { - if SetYes { - 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") - } - } else { - q := fmt.Sprintf("Are you sure you want to modify %d profile(s)", len(profiles)) - - prompt := promptui.Prompt{ - Label: q, - IsConfirm: true, - } - - result, _ := prompt.Run() - - if result == "y" || result == "yes" { - 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 daemon") - } - } - } - } else { - fmt.Printf("No profiles found\n") - } - - return nil + return apiprofile.ProfileSet(&set) } diff --git a/internal/app/wwctl/profile/set/root.go b/internal/app/wwctl/profile/set/root.go index e15d28d5..b1a62fd4 100644 --- a/internal/app/wwctl/profile/set/root.go +++ b/internal/app/wwctl/profile/set/root.go @@ -32,110 +32,51 @@ var ( return p_names, cobra.ShellCompDirectiveNoFileComp }, } - SetAll bool - SetYes bool - SetForce bool - SetComment string - SetContainer string - SetKernelOverride string - SetKernelArgs string - SetClusterName string - SetIpxe string - SetInitOverlay string - SetRuntimeOverlay []string - SetSystemOverlay []string - SetIpmiNetmask string - SetIpmiPort string - SetIpmiGateway string - SetIpmiUsername string - SetIpmiPassword string - SetIpmiInterface string - SetIpmiWrite string - SetNetName string - SetNetDev string - SetNetmask string - SetGateway string - SetType string - SetNetOnBoot string - SetNetPrimary string - SetNetDevDel bool - SetDiscoverable bool - SetUndiscoverable bool - SetInit string - SetRoot string - SetKey string - SetTags []string - SetDelTags []string - SetAssetKey string - SetNetTags []string - SetNetDelTags []string + SetNetDevDel string + SetNodeAll bool + SetYes bool + SetForce bool + OptionStrMap map[string]*string ) func init() { - baseCmd.PersistentFlags().StringVar(&SetComment, "comment", "", "Set a comment for this node") - baseCmd.PersistentFlags().StringVarP(&SetContainer, "container", "C", "", "Set the container (VNFS) for this node") + // init empty helper structs, so that we know what's inside + myBase := node.CobraCommand{Command: baseCmd} + var emptyNodeConf node.NodeConf + emptyNodeConf.Kernel = new(node.KernelConf) + emptyNodeConf.Ipmi = new(node.IpmiConf) + OptionStrMap = myBase.CreateFlags(emptyNodeConf) + + baseCmd.PersistentFlags().StringVarP(&SetNetDevDel, "netdel", "D", "", "Delete the node's network device") + baseCmd.PersistentFlags().BoolVarP(&SetNodeAll, "all", "a", false, "Set all nodes") + baseCmd.PersistentFlags().BoolVarP(&SetYes, "yes", "y", false, "Set 'yes' to all questions asked") + baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force configuration (even on error)") + // register the command line completions if err := baseCmd.RegisterFlagCompletionFunc("container", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { list, _ := container.ListSources() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) } - baseCmd.PersistentFlags().StringVarP(&SetKernelOverride, "kerneloverride", "K", "", "Set kernel override version for nodes") if err := baseCmd.RegisterFlagCompletionFunc("kerneloverride", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { list, _ := kernel.ListKernels() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) } - baseCmd.PersistentFlags().StringVarP(&SetKernelArgs, "kernelargs", "A", "", "Set Kernel argument for nodes") - baseCmd.PersistentFlags().StringVarP(&SetClusterName, "cluster", "c", "", "Set the node's cluster group") - baseCmd.PersistentFlags().StringVarP(&SetIpxe, "ipxe", "P", "", "Set the node's iPXE template name") - baseCmd.PersistentFlags().StringVarP(&SetInit, "init", "i", "", "Define the init process to boot the container") - baseCmd.PersistentFlags().StringVar(&SetRoot, "root", "", "Define the rootfs") - baseCmd.PersistentFlags().StringVar(&SetAssetKey, "assetkey", "", "Set the node's Asset tag (key)") - baseCmd.PersistentFlags().StringSliceVarP(&SetRuntimeOverlay, "runtime", "R", []string{}, "Set the node's runtime overlay") if err := baseCmd.RegisterFlagCompletionFunc("runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { list, _ := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) - } - baseCmd.PersistentFlags().StringSliceVarP(&SetSystemOverlay, "system", "S", []string{}, "Set the node's system overlay") - if err := baseCmd.RegisterFlagCompletionFunc("system", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if err := baseCmd.RegisterFlagCompletionFunc("wwinit", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { list, _ := overlay.FindOverlays() return list, cobra.ShellCompDirectiveNoFileComp }); err != nil { log.Println(err) } - baseCmd.PersistentFlags().StringVar(&SetIpmiNetmask, "ipminetmask", "", "Set the node's IPMI netmask") - baseCmd.PersistentFlags().StringVar(&SetIpmiPort, "ipmiport", "", "Set the node's IPMI port") - baseCmd.PersistentFlags().StringVar(&SetIpmiGateway, "ipmigateway", "", "Set the node's IPMI gateway") - baseCmd.PersistentFlags().StringVar(&SetIpmiUsername, "ipmiuser", "", "Set the node's IPMI username") - baseCmd.PersistentFlags().StringVar(&SetIpmiPassword, "ipmipass", "", "Set the node's IPMI password") - baseCmd.PersistentFlags().StringVar(&SetIpmiInterface, "ipmiinterface", "", "Set the node's IPMI interface (defaults to 'lan')") - baseCmd.PersistentFlags().StringVar(&SetIpmiWrite, "ipmiwrite", "", "Enable/disable the write of impi configuration (yes/no)") - baseCmd.PersistentFlags().StringVarP(&SetNetName, "netname", "n", "default", "Define the network name to configure") - baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "N", "", "Set the node's network device") - baseCmd.PersistentFlags().StringVar(&SetNetPrimary, "primary", "", "Enable/disable device as primary (yes/no)") - baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask") - baseCmd.PersistentFlags().StringVarP(&SetGateway, "gateway", "G", "", "Set the node's network device gateway") - baseCmd.PersistentFlags().StringVarP(&SetType, "type", "T", "", "Set the node's network device type") - baseCmd.PersistentFlags().StringVar(&SetNetOnBoot, "onboot", "", "Enable/disable device (yes/no)") - - baseCmd.PersistentFlags().BoolVar(&SetNetDevDel, "netdel", false, "Delete the node's network device") - baseCmd.PersistentFlags().StringSliceVar(&SetNetTags, "nettag", []string{}, "Define custom tag to network device (key=value)") - baseCmd.PersistentFlags().StringSliceVar(&SetNetDelTags, "netdeltag", []string{}, "Delete tag for network device") - - baseCmd.PersistentFlags().StringSliceVarP(&SetTags, "tag", "t", []string{}, "Define custom tag (key=value)") - baseCmd.PersistentFlags().StringSliceVar(&SetDelTags, "tagdel", []string{}, "Delete tag") - - baseCmd.PersistentFlags().BoolVarP(&SetAll, "all", "a", false, "Set all profiles") - baseCmd.PersistentFlags().BoolVarP(&SetForce, "force", "f", false, "Force configuration (even on error)") - baseCmd.PersistentFlags().BoolVarP(&SetYes, "yes", "y", false, "Set 'yes' to all questions asked") - baseCmd.PersistentFlags().BoolVar(&SetDiscoverable, "discoverable", false, "Make this node discoverable") - baseCmd.PersistentFlags().BoolVar(&SetUndiscoverable, "undiscoverable", false, "Remove the discoverable flag") } // GetRootCommand returns the root cobra.Command for the application. diff --git a/internal/pkg/api/node/node.go b/internal/pkg/api/node/node.go index aed8224e..5121528f 100644 --- a/internal/pkg/api/node/node.go +++ b/internal/pkg/api/node/node.go @@ -1,4 +1,4 @@ -package node +package apinode import ( "encoding/json" @@ -477,7 +477,7 @@ func NodeSet(set *wwapiv1.NodeSetParameter) (err error) { if err != nil { return } - return nodeDbSave(&nodeDB) + return DbSave(&nodeDB) } // NodeSetParameterCheck does error checking on NodeSetParameter. @@ -658,24 +658,6 @@ func checkNetNameRequired(netname string) (err error) { return } -// nodeDbSave persists the nodeDB to disk and restarts warewulfd. -// TODO: We will likely need locking around anything changing nodeDB -// or restarting warewulfd. Determine if the reason for restart is -// just to reinitialize warewulfd with the new nodeDB or if there is -// something more to it. -func nodeDbSave(nodeDB *node.NodeYaml) (err error) { - 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 -} - /* Add the netname to the options map, as its only known after the map command line options have been read out. diff --git a/internal/pkg/api/node/utils.go b/internal/pkg/api/node/utils.go new file mode 100644 index 00000000..e2643f77 --- /dev/null +++ b/internal/pkg/api/node/utils.go @@ -0,0 +1,25 @@ +package apinode + +import ( + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/warewulfd" + "github.com/pkg/errors" +) + +// nodeDbSave persists the nodeDB to disk and restarts warewulfd. +// TODO: We will likely need locking around anything changing nodeDB +// or restarting warewulfd. Determine if the reason for restart is +// just to reinitialize warewulfd with the new nodeDB or if there is +// something more to it. +func DbSave(nodeDB *node.NodeYaml) (err error) { + 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 +} diff --git a/internal/pkg/api/profile/profile.go b/internal/pkg/api/profile/profile.go new file mode 100644 index 00000000..ef4916a7 --- /dev/null +++ b/internal/pkg/api/profile/profile.go @@ -0,0 +1,109 @@ +package apiprofile + +import ( + "fmt" + "os" + + apinode "github.com/hpcng/warewulf/internal/pkg/api/node" + "github.com/hpcng/warewulf/internal/pkg/api/routes/wwapiv1" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/wwlog" +) + +// NodeSet is the wwapiv1 implmentation for updating node fields. +func ProfileSet(set *wwapiv1.NodeSetParameter) (err error) { + + if set == nil { + return fmt.Errorf("NodeAddParameter is nil") + } + + var nodeDB node.NodeYaml + nodeDB, _, err = ProfileSetParameterCheck(set, false) + if err != nil { + return + } + return apinode.DbSave(&nodeDB) +} + +// NodeSetParameterCheck does error checking on NodeSetParameter. +// Output to the console if console is true. +// TODO: Determine if the console switch does wwlog or not. +// - console may end up being textOutput? +func ProfileSetParameterCheck(set *wwapiv1.NodeSetParameter, console bool) (nodeDB node.NodeYaml, profileCount uint, err error) { + + if set == nil { + err = fmt.Errorf("Profile set parameter is nil") + if console { + fmt.Printf("%v\n", err) + return + } + } + + if set.NodeNames == nil { + err = fmt.Errorf("Profile set parameter: ProfileNames is nil") + if console { + fmt.Printf("%v\n", err) + return + } + } + + nodeDB, err = node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open configuration: %s\n", err) + return + } + + profiles, err := nodeDB.FindAllProfiles() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not get profile list: %s\n", err) + return + } + + // Note: This does not do expansion on the nodes. + + if set.AllNodes || (len(set.NodeNames) == 0 && len(profiles) > 0) { + if console { + fmt.Printf("\n*** WARNING: This command will modify all profiles! ***\n\n") + } + } else { + profiles = node.FilterByName(profiles, set.NodeNames) + } + + if len(profiles) == 0 { + if console { + fmt.Printf("No profiles found\n") + } + return + } + + for _, p := range profiles { + wwlog.Printf(wwlog.VERBOSE, "Evaluating profile: %s\n", p.Id.Get()) + for key, val := range set.OptionsStrMap { + if val != "" { + wwlog.Verbose("profile:%s setting %s to %s\n", p.Id.Get(), key, val) + p.SetField(key, val) + } + } + + if set.NetdevDelete != "" { + + if _, ok := p.NetDevs[set.NetdevDelete]; !ok { + err = fmt.Errorf("Network device name doesn't exist: %s", set.NetdevDelete) + wwlog.Printf(wwlog.ERROR, fmt.Sprintf("%v\n", err.Error())) + return + } + + wwlog.Printf(wwlog.VERBOSE, "Node: %s, Deleting network device: %s\n", p.Id.Get(), set.NetdevDelete) + delete(p.NetDevs, set.NetdevDelete) + } + + err := nodeDB.NodeUpdate(p) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + profileCount++ + } + return +}