initial checkin of node IPMI power control
This commit is contained in:
@@ -68,13 +68,19 @@
|
||||
# Fedora prerequisites
|
||||
sudo dnf -y install tftp-server tftp
|
||||
sudo dnf -y install dhcp
|
||||
sudo dnf -y install ipmitool
|
||||
sudo dnf install singularity
|
||||
sudo dnf install gpgme-devel
|
||||
sudo dnf install libassuan.x86_64 libassuan-devel.x86_64
|
||||
|
||||
# Centos prerequisites
|
||||
sudo yum -y install tftp-server tftp
|
||||
sudo yum -y install dhcp
|
||||
sudo yum -y install ipmitool
|
||||
sudo yum install http://repo.ctrliq.com/packages/rhel7/ctrl-release.rpm
|
||||
sudo yum install singularityplus
|
||||
sudo yum install gpgme-devel
|
||||
sudo yum install libassuan.x86_64 libassuan-devel.x86_64
|
||||
|
||||
# follow README.md instructions
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package power
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
baseCmd = &cobra.Command{
|
||||
Use: "power",
|
||||
Short: "Node power management",
|
||||
Long: "Node Power management commands",
|
||||
RunE: CobraRunE,
|
||||
}
|
||||
test bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseCmd.PersistentFlags().BoolVarP(&test, "test", "t", false, "Testing.")
|
||||
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
return baseCmd
|
||||
}
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
fmt.Printf("Power: Hello World\n")
|
||||
return nil
|
||||
}
|
||||
58
internal/app/wwctl/node/poweroff/power.go
Normal file
58
internal/app/wwctl/node/poweroff/power.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package poweroff
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/assets"
|
||||
"github.com/hpcng/warewulf/internal/pkg/power"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
var returnErr error = nil
|
||||
|
||||
var nodeList []assets.NodeInfo
|
||||
|
||||
if len(args) >= 1 {
|
||||
//nodeList, _ = assets.SearchByName(args[0])
|
||||
nodeList, _ = assets.SearchByNameList(args)
|
||||
} else {
|
||||
wwlog.Printf(wwlog.ERROR, "No requested nodes\n")
|
||||
os.Exit(255)
|
||||
}
|
||||
|
||||
if len(nodeList) == 0 {
|
||||
wwlog.Printf(wwlog.ERROR, "No nodes found matching: '%s'\n", args[0])
|
||||
os.Exit(255)
|
||||
} else {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Found %d matching nodes for power command\n", len(nodeList))
|
||||
}
|
||||
|
||||
for _, node := range nodeList {
|
||||
|
||||
if node.IpmiIpaddr == "" {
|
||||
wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.HostName)
|
||||
continue
|
||||
}
|
||||
|
||||
ipmiCmd := power.IPMI{
|
||||
HostName: node.IpmiIpaddr,
|
||||
User: "ADMIN",
|
||||
Password: "ADMIN",
|
||||
AuthType: "MD5",
|
||||
}
|
||||
|
||||
out, err := ipmiCmd.PowerOff()
|
||||
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s: %s\n", node.HostName, out)
|
||||
returnErr = err
|
||||
continue
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.INFO, "%s: %s\n", node.HostName, out)
|
||||
}
|
||||
|
||||
return returnErr
|
||||
}
|
||||
19
internal/app/wwctl/node/poweroff/root.go
Normal file
19
internal/app/wwctl/node/poweroff/root.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package poweroff
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
powerCmd = &cobra.Command{
|
||||
Use: "poweroff",
|
||||
Short: "power off node(s)",
|
||||
Long: "turn power off for one or more nodes",
|
||||
RunE: CobraRunE,
|
||||
}
|
||||
)
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
return powerCmd
|
||||
}
|
||||
58
internal/app/wwctl/node/poweron/power.go
Normal file
58
internal/app/wwctl/node/poweron/power.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package poweron
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/assets"
|
||||
"github.com/hpcng/warewulf/internal/pkg/power"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
var returnErr error = nil
|
||||
|
||||
var nodeList []assets.NodeInfo
|
||||
|
||||
if len(args) >= 1 {
|
||||
//nodeList, _ = assets.SearchByName(args[0])
|
||||
nodeList, _ = assets.SearchByNameList(args)
|
||||
} else {
|
||||
wwlog.Printf(wwlog.ERROR, "No requested nodes\n")
|
||||
os.Exit(255)
|
||||
}
|
||||
|
||||
if len(nodeList) == 0 {
|
||||
wwlog.Printf(wwlog.ERROR, "No nodes found matching: '%s'\n", args[0])
|
||||
os.Exit(255)
|
||||
} else {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Found %d matching nodes for power command\n", len(nodeList))
|
||||
}
|
||||
|
||||
for _, node := range nodeList {
|
||||
|
||||
if node.IpmiIpaddr == "" {
|
||||
wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.HostName)
|
||||
continue
|
||||
}
|
||||
|
||||
ipmiCmd := power.IPMI{
|
||||
HostName: node.IpmiIpaddr,
|
||||
User: "ADMIN",
|
||||
Password: "ADMIN",
|
||||
AuthType: "MD5",
|
||||
}
|
||||
|
||||
out, err := ipmiCmd.PowerOn()
|
||||
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s: %s\n", node.HostName, out)
|
||||
returnErr = err
|
||||
continue
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.INFO, "%s: %s\n", node.HostName, out)
|
||||
}
|
||||
|
||||
return returnErr
|
||||
}
|
||||
19
internal/app/wwctl/node/poweron/root.go
Normal file
19
internal/app/wwctl/node/poweron/root.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package poweron
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
powerCmd = &cobra.Command{
|
||||
Use: "poweron",
|
||||
Short: "power on node(s)",
|
||||
Long: "turn power on for one or more nodes",
|
||||
RunE: CobraRunE,
|
||||
}
|
||||
)
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
return powerCmd
|
||||
}
|
||||
58
internal/app/wwctl/node/powerstatus/power.go
Normal file
58
internal/app/wwctl/node/powerstatus/power.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package powerstatus
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/pkg/assets"
|
||||
"github.com/hpcng/warewulf/internal/pkg/power"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
|
||||
var returnErr error = nil
|
||||
|
||||
var nodeList []assets.NodeInfo
|
||||
|
||||
if len(args) >= 1 {
|
||||
//nodeList, _ = assets.SearchByName(args[0])
|
||||
nodeList, _ = assets.SearchByNameList(args)
|
||||
} else {
|
||||
wwlog.Printf(wwlog.ERROR, "No requested nodes\n")
|
||||
os.Exit(255)
|
||||
}
|
||||
|
||||
if len(nodeList) == 0 {
|
||||
wwlog.Printf(wwlog.ERROR, "No nodes found matching: '%s'\n", args[0])
|
||||
os.Exit(255)
|
||||
} else {
|
||||
wwlog.Printf(wwlog.VERBOSE, "Found %d matching nodes for power command\n", len(nodeList))
|
||||
}
|
||||
|
||||
for _, node := range nodeList {
|
||||
|
||||
if node.IpmiIpaddr == "" {
|
||||
wwlog.Printf(wwlog.ERROR, "%s: No IPMI IP address\n", node.HostName)
|
||||
continue
|
||||
}
|
||||
|
||||
ipmiCmd := power.IPMI{
|
||||
HostName: node.IpmiIpaddr,
|
||||
User: "ADMIN",
|
||||
Password: "ADMIN",
|
||||
AuthType: "MD5",
|
||||
}
|
||||
|
||||
out, err := ipmiCmd.PowerStatus()
|
||||
|
||||
if err != nil {
|
||||
wwlog.Printf(wwlog.ERROR, "%s: %s\n", node.HostName, out)
|
||||
returnErr = err
|
||||
continue
|
||||
}
|
||||
|
||||
wwlog.Printf(wwlog.INFO, "%s: %s\n", node.HostName, out)
|
||||
}
|
||||
|
||||
return returnErr
|
||||
}
|
||||
19
internal/app/wwctl/node/powerstatus/root.go
Normal file
19
internal/app/wwctl/node/powerstatus/root.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package powerstatus
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
powerCmd = &cobra.Command{
|
||||
Use: "powerstatus",
|
||||
Short: "node power status",
|
||||
Long: "Get Node Power Status",
|
||||
RunE: CobraRunE,
|
||||
}
|
||||
)
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
return powerCmd
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/node/power"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/node/poweron"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/node/poweroff"
|
||||
"github.com/hpcng/warewulf/internal/app/wwctl/node/powerstatus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -11,14 +13,12 @@ var (
|
||||
Short: "Node management",
|
||||
Long: "Management of node settings and power management",
|
||||
}
|
||||
test bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
baseCmd.PersistentFlags().BoolVarP(&test, "test", "t", false, "Testing.")
|
||||
|
||||
baseCmd.AddCommand(power.GetCommand())
|
||||
|
||||
baseCmd.AddCommand(poweron.GetCommand())
|
||||
baseCmd.AddCommand(poweroff.GetCommand())
|
||||
baseCmd.AddCommand(powerstatus.GetCommand())
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
|
||||
@@ -73,6 +73,7 @@ type NodeInfo struct {
|
||||
RuntimeOverlay string
|
||||
KernelVersion string
|
||||
KernelArgs string
|
||||
IpmiIpaddr string
|
||||
NetDevs map[string]netDevs
|
||||
}
|
||||
|
||||
@@ -100,6 +101,7 @@ func FindAllNodes() ([]NodeInfo, error) {
|
||||
|
||||
n.GroupName = groupname
|
||||
n.HostName = node.Hostname
|
||||
n.IpmiIpaddr = node.IpmiIpaddr
|
||||
|
||||
n.Vnfs = group.Vnfs
|
||||
n.SystemOverlay = group.SystemOverlay
|
||||
@@ -223,6 +225,26 @@ func SearchByName(search string) ([]NodeInfo, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func SearchByNameList(searchList []string) ([]NodeInfo, error) {
|
||||
var ret []NodeInfo
|
||||
|
||||
nodeList, err := FindAllNodes()
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
for _, search := range searchList {
|
||||
for _, node := range nodeList {
|
||||
b, _ := regexp.MatchString(search, node.Fqdn)
|
||||
if b == true {
|
||||
ret = append(ret, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
/*
|
||||
func FindAllVnfs() ([]string, error) {
|
||||
var ret []string
|
||||
|
||||
49
internal/pkg/power/ipmitool.go
Normal file
49
internal/pkg/power/ipmitool.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package power
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type IPMI struct {
|
||||
HostName string
|
||||
User string
|
||||
Password string
|
||||
AuthType string
|
||||
}
|
||||
|
||||
func (ipmi IPMI) Command(ipmiArgs []string) ([]byte, error) {
|
||||
|
||||
var args []string
|
||||
|
||||
args = append(args, "-I", "lan", "-H", ipmi.HostName, "-U", ipmi.User, "-P", ipmi.Password)
|
||||
args = append(args, ipmiArgs...)
|
||||
ipmiCmd := exec.Command("/usr/bin/ipmitool", args...)
|
||||
return ipmiCmd.CombinedOutput()
|
||||
}
|
||||
|
||||
func (ipmi IPMI) PowerOn() (string, error) {
|
||||
|
||||
var args []string
|
||||
|
||||
args = append(args, "chassis", "power", "on")
|
||||
ipmiOut, err := ipmi.Command(args)
|
||||
return string(ipmiOut), err
|
||||
}
|
||||
|
||||
func (ipmi IPMI) PowerOff() (string, error) {
|
||||
|
||||
var args []string
|
||||
|
||||
args = append(args, "chassis", "power", "off")
|
||||
ipmiOut, err := ipmi.Command(args)
|
||||
return string(ipmiOut), err
|
||||
}
|
||||
|
||||
func (ipmi IPMI) PowerStatus() (string, error) {
|
||||
|
||||
var args []string
|
||||
|
||||
args = append(args, "chassis", "power", "status")
|
||||
ipmiOut, err := ipmi.Command(args)
|
||||
return string(ipmiOut), err
|
||||
}
|
||||
Reference in New Issue
Block a user