From e171eae8588f02322eed606d2dddd00d5f3846e2 Mon Sep 17 00:00:00 2001 From: "Michael L. Young" Date: Tue, 24 Aug 2021 12:47:22 -0400 Subject: [PATCH 1/2] Clean up typos from copy and paste --- internal/app/wwctl/node/console/power.go | 2 +- internal/app/wwctl/node/delete/main.go | 2 +- internal/app/wwctl/node/list/main.go | 2 +- internal/app/wwctl/node/ready/main.go | 2 +- internal/app/wwctl/node/sensors/power.go | 2 +- internal/app/wwctl/node/set/main.go | 2 +- internal/app/wwctl/overlay/build/main.go | 4 ++-- internal/app/wwctl/overlay/chmod/main.go | 2 +- internal/app/wwctl/overlay/create/main.go | 2 +- internal/app/wwctl/overlay/delete/main.go | 2 +- internal/app/wwctl/overlay/edit/main.go | 2 +- internal/app/wwctl/overlay/imprt/main.go | 2 +- internal/app/wwctl/overlay/mkdir/main.go | 2 +- internal/app/wwctl/power/cycle/power.go | 2 +- internal/app/wwctl/power/off/power.go | 2 +- internal/app/wwctl/power/on/power.go | 2 +- internal/app/wwctl/power/status/power.go | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/internal/app/wwctl/node/console/power.go b/internal/app/wwctl/node/console/power.go index 29d7e993..1cbe7e1b 100644 --- a/internal/app/wwctl/node/console/power.go +++ b/internal/app/wwctl/node/console/power.go @@ -21,7 +21,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/node/delete/main.go b/internal/app/wwctl/node/delete/main.go index e7c7ef65..5183042c 100644 --- a/internal/app/wwctl/node/delete/main.go +++ b/internal/app/wwctl/node/delete/main.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index fcb40985..bdc9ceaf 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/node/ready/main.go b/internal/app/wwctl/node/ready/main.go index 2df4b33d..e5c62606 100644 --- a/internal/app/wwctl/node/ready/main.go +++ b/internal/app/wwctl/node/ready/main.go @@ -23,7 +23,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/node/sensors/power.go b/internal/app/wwctl/node/sensors/power.go index 2f684ff1..e962de9e 100644 --- a/internal/app/wwctl/node/sensors/power.go +++ b/internal/app/wwctl/node/sensors/power.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/node/set/main.go b/internal/app/wwctl/node/set/main.go index 29e0ad3c..8875beb5 100644 --- a/internal/app/wwctl/node/set/main.go +++ b/internal/app/wwctl/node/set/main.go @@ -26,7 +26,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/overlay/build/main.go b/internal/app/wwctl/overlay/build/main.go index 61a843eb..599b1a11 100644 --- a/internal/app/wwctl/overlay/build/main.go +++ b/internal/app/wwctl/overlay/build/main.go @@ -21,7 +21,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { if len(args) > 0 && BuildAll == false { nodes, err := n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } @@ -36,7 +36,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { var err error updateNodes, err = n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } } diff --git a/internal/app/wwctl/overlay/chmod/main.go b/internal/app/wwctl/overlay/chmod/main.go index b59d7755..33cddb9b 100644 --- a/internal/app/wwctl/overlay/chmod/main.go +++ b/internal/app/wwctl/overlay/chmod/main.go @@ -57,7 +57,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/overlay/create/main.go b/internal/app/wwctl/overlay/create/main.go index 407e6b34..fc79aac9 100644 --- a/internal/app/wwctl/overlay/create/main.go +++ b/internal/app/wwctl/overlay/create/main.go @@ -40,7 +40,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get nodeList: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/overlay/delete/main.go b/internal/app/wwctl/overlay/delete/main.go index bc8856dd..e1494e67 100644 --- a/internal/app/wwctl/overlay/delete/main.go +++ b/internal/app/wwctl/overlay/delete/main.go @@ -103,7 +103,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/overlay/edit/main.go b/internal/app/wwctl/overlay/edit/main.go index 6a5fd136..74328107 100644 --- a/internal/app/wwctl/overlay/edit/main.go +++ b/internal/app/wwctl/overlay/edit/main.go @@ -104,7 +104,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/overlay/imprt/main.go b/internal/app/wwctl/overlay/imprt/main.go index bf16d30a..c3cdf124 100644 --- a/internal/app/wwctl/overlay/imprt/main.go +++ b/internal/app/wwctl/overlay/imprt/main.go @@ -53,7 +53,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/overlay/mkdir/main.go b/internal/app/wwctl/overlay/mkdir/main.go index af1e30fe..f5e85a64 100644 --- a/internal/app/wwctl/overlay/mkdir/main.go +++ b/internal/app/wwctl/overlay/mkdir/main.go @@ -49,7 +49,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := n.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/power/cycle/power.go b/internal/app/wwctl/power/cycle/power.go index b798fb84..4d12b8c8 100644 --- a/internal/app/wwctl/power/cycle/power.go +++ b/internal/app/wwctl/power/cycle/power.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/power/off/power.go b/internal/app/wwctl/power/off/power.go index e499ab4f..168d18a7 100644 --- a/internal/app/wwctl/power/off/power.go +++ b/internal/app/wwctl/power/off/power.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/power/on/power.go b/internal/app/wwctl/power/on/power.go index abab8e0c..4cbc1b14 100644 --- a/internal/app/wwctl/power/on/power.go +++ b/internal/app/wwctl/power/on/power.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } diff --git a/internal/app/wwctl/power/status/power.go b/internal/app/wwctl/power/status/power.go index d162105d..b65039fe 100644 --- a/internal/app/wwctl/power/status/power.go +++ b/internal/app/wwctl/power/status/power.go @@ -22,7 +22,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { nodes, err := nodeDB.FindAllNodes() if err != nil { - wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + wwlog.Printf(wwlog.ERROR, "Could not get node list: %s\n", err) os.Exit(1) } From a9fcf5e74983546a366e50d908b95db98e322947 Mon Sep 17 00:00:00 2001 From: "Michael L. Young" Date: Wed, 25 Aug 2021 08:23:22 -0400 Subject: [PATCH 2/2] Add IPMI Power Commands, Soft And Reset --- internal/app/wwctl/power/reset/power.go | 95 +++++++++++++++++++++++++ internal/app/wwctl/power/reset/root.go | 19 +++++ internal/app/wwctl/power/root.go | 4 ++ internal/app/wwctl/power/soft/power.go | 95 +++++++++++++++++++++++++ internal/app/wwctl/power/soft/root.go | 19 +++++ internal/pkg/power/ipmitool.go | 8 +++ internal/pkg/power/power.go | 12 ++++ 7 files changed, 252 insertions(+) create mode 100644 internal/app/wwctl/power/reset/power.go create mode 100644 internal/app/wwctl/power/reset/root.go create mode 100644 internal/app/wwctl/power/soft/power.go create mode 100644 internal/app/wwctl/power/soft/root.go diff --git a/internal/app/wwctl/power/reset/power.go b/internal/app/wwctl/power/reset/power.go new file mode 100644 index 00000000..3b538202 --- /dev/null +++ b/internal/app/wwctl/power/reset/power.go @@ -0,0 +1,95 @@ +package powerreset + +import ( + "fmt" + "os" + + "github.com/hpcng/warewulf/internal/pkg/batch" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/power" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + var returnErr error = nil + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } + + if len(args) > 0 { + nodes = node.FilterByName(nodes, args) + } else { + cmd.Usage() + os.Exit(1) + } + + if len(nodes) == 0 { + fmt.Printf("No nodes found\n") + os.Exit(1) + } + + batchpool := batch.New(50) + jobcount := len(nodes) + results := make(chan power.IPMI, jobcount) + + for _, node := range nodes { + + if node.IpmiIpaddr.Get() == "" { + wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.Id.Get()) + continue + } + var ipmiInterface = "lan" + if node.IpmiInterface.Get() != "" { + ipmiInterface = node.IpmiInterface.Get() + } + var ipmiPort = "623" + if node.IpmiPort.Get() != "" { + ipmiPort = node.IpmiPort.Get() + } + ipmiCmd := power.IPMI{ + NodeName: node.Id.Get(), + HostName: node.IpmiIpaddr.Get(), + Port: ipmiPort, + User: node.IpmiUserName.Get(), + Password: node.IpmiPassword.Get(), + Interface: ipmiInterface, + AuthType: "MD5", + } + + batchpool.Submit(func() { + ipmiCmd.PowerReset() + results <- ipmiCmd + }) + + } + + batchpool.Run() + + close(results) + + for result := range results { + + out, err := result.Result() + + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s: %s\n", result.NodeName, out) + returnErr = err + continue + } + + fmt.Printf("%s: %s\n", result.NodeName, out) + + } + + return returnErr +} diff --git a/internal/app/wwctl/power/reset/root.go b/internal/app/wwctl/power/reset/root.go new file mode 100644 index 00000000..a55d780d --- /dev/null +++ b/internal/app/wwctl/power/reset/root.go @@ -0,0 +1,19 @@ +package powerreset + +import ( + "github.com/spf13/cobra" +) + +var ( + powerCmd = &cobra.Command{ + Use: "reset", + Short: "Issue a reset to the given node(s)", + Long: "This command will issue a reset to the given set of nodes.", + RunE: CobraRunE, + } +) + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return powerCmd +} diff --git a/internal/app/wwctl/power/root.go b/internal/app/wwctl/power/root.go index 7ef3dbde..c7a9e7ad 100644 --- a/internal/app/wwctl/power/root.go +++ b/internal/app/wwctl/power/root.go @@ -4,6 +4,8 @@ import ( powercycle "github.com/hpcng/warewulf/internal/app/wwctl/power/cycle" poweroff "github.com/hpcng/warewulf/internal/app/wwctl/power/off" poweron "github.com/hpcng/warewulf/internal/app/wwctl/power/on" + powerreset "github.com/hpcng/warewulf/internal/app/wwctl/power/reset" + powersoft "github.com/hpcng/warewulf/internal/app/wwctl/power/soft" powerstatus "github.com/hpcng/warewulf/internal/app/wwctl/power/status" "github.com/spf13/cobra" ) @@ -23,6 +25,8 @@ func init() { baseCmd.AddCommand(powercycle.GetCommand()) baseCmd.AddCommand(poweroff.GetCommand()) baseCmd.AddCommand(poweron.GetCommand()) + baseCmd.AddCommand(powerreset.GetCommand()) + baseCmd.AddCommand(powersoft.GetCommand()) baseCmd.AddCommand(powerstatus.GetCommand()) } diff --git a/internal/app/wwctl/power/soft/power.go b/internal/app/wwctl/power/soft/power.go new file mode 100644 index 00000000..2a2193fb --- /dev/null +++ b/internal/app/wwctl/power/soft/power.go @@ -0,0 +1,95 @@ +package powersoft + +import ( + "fmt" + "os" + + "github.com/hpcng/warewulf/internal/pkg/batch" + "github.com/hpcng/warewulf/internal/pkg/node" + "github.com/hpcng/warewulf/internal/pkg/power" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + var returnErr error = nil + + nodeDB, err := node.New() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Could not open node configuration: %s\n", err) + os.Exit(1) + } + + nodes, err := nodeDB.FindAllNodes() + if err != nil { + wwlog.Printf(wwlog.ERROR, "Cloud not get nodeList: %s\n", err) + os.Exit(1) + } + + if len(args) > 0 { + nodes = node.FilterByName(nodes, args) + } else { + cmd.Usage() + os.Exit(1) + } + + if len(nodes) == 0 { + fmt.Printf("No nodes found\n") + os.Exit(1) + } + + batchpool := batch.New(50) + jobcount := len(nodes) + results := make(chan power.IPMI, jobcount) + + for _, node := range nodes { + + if node.IpmiIpaddr.Get() == "" { + wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.Id.Get()) + continue + } + var ipmiInterface = "lan" + if node.IpmiInterface.Get() != "" { + ipmiInterface = node.IpmiInterface.Get() + } + var ipmiPort = "623" + if node.IpmiPort.Get() != "" { + ipmiPort = node.IpmiPort.Get() + } + ipmiCmd := power.IPMI{ + NodeName: node.Id.Get(), + HostName: node.IpmiIpaddr.Get(), + Port: ipmiPort, + User: node.IpmiUserName.Get(), + Password: node.IpmiPassword.Get(), + Interface: ipmiInterface, + AuthType: "MD5", + } + + batchpool.Submit(func() { + ipmiCmd.PowerSoft() + results <- ipmiCmd + }) + + } + + batchpool.Run() + + close(results) + + for result := range results { + + out, err := result.Result() + + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s: %s\n", result.NodeName, out) + returnErr = err + continue + } + + fmt.Printf("%s: %s\n", result.NodeName, out) + + } + + return returnErr +} diff --git a/internal/app/wwctl/power/soft/root.go b/internal/app/wwctl/power/soft/root.go new file mode 100644 index 00000000..41813cb6 --- /dev/null +++ b/internal/app/wwctl/power/soft/root.go @@ -0,0 +1,19 @@ +package powersoft + +import ( + "github.com/spf13/cobra" +) + +var ( + powerCmd = &cobra.Command{ + Use: "soft", + Short: "Gracefully shuts down the given node(s)", + Long: "This command will gracefully shutdown the given set of nodes.", + RunE: CobraRunE, + } +) + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return powerCmd +} diff --git a/internal/pkg/power/ipmitool.go b/internal/pkg/power/ipmitool.go index b9e489b0..dcf33e66 100644 --- a/internal/pkg/power/ipmitool.go +++ b/internal/pkg/power/ipmitool.go @@ -95,6 +95,14 @@ func (ipmi *IPMI) PowerCycle() (string, error) { return ipmi.IPMICommand("chassis", "power", "cycle") } +func (ipmi *IPMI) PowerReset() (string, error) { + return ipmi.IPMICommand("chassis", "power", "reset") +} + +func (ipmi *IPMI) PowerSoft() (string, error) { + return ipmi.IPMICommand("chassis", "power", "soft") +} + func (ipmi *IPMI) PowerStatus() (string, error) { return ipmi.IPMICommand("chassis", "power", "status") } diff --git a/internal/pkg/power/power.go b/internal/pkg/power/power.go index 10bd60fc..2faa3e67 100644 --- a/internal/pkg/power/power.go +++ b/internal/pkg/power/power.go @@ -14,6 +14,18 @@ type PowerOffInterface interface { PowerOff() (result string, err error) } +type PowerResetInterface interface { + PowerReset() (result string, err error) +} + +type PowerSoftInterface interface { + PowerSoft() (result string, err error) +} + +type PowerCycleInterface interface { + PowerCycle() (result string, err error) +} + type PowerStatusInterface interface { PowerStatus() (result string, err error) }