Merge branch 'main' of github.com:ctrl-cmd/warewulf into main
This commit is contained in:
1
Makefile
1
Makefile
@@ -44,6 +44,7 @@ all: vendor warewulfd wwctl wwclient
|
|||||||
|
|
||||||
files: all
|
files: all
|
||||||
install -d -m 0755 /var/warewulf/
|
install -d -m 0755 /var/warewulf/
|
||||||
|
install -d -m 0755 /var/warewulf/chroot
|
||||||
install -d -m 0755 /etc/warewulf/
|
install -d -m 0755 /etc/warewulf/
|
||||||
install -d -m 0755 /etc/warewulf/ipxe
|
install -d -m 0755 /etc/warewulf/ipxe
|
||||||
install -d -m 0755 /var/lib/tftpboot/warewulf/ipxe/
|
install -d -m 0755 /var/lib/tftpboot/warewulf/ipxe/
|
||||||
|
|||||||
@@ -68,13 +68,19 @@
|
|||||||
# Fedora prerequisites
|
# Fedora prerequisites
|
||||||
sudo dnf -y install tftp-server tftp
|
sudo dnf -y install tftp-server tftp
|
||||||
sudo dnf -y install dhcp
|
sudo dnf -y install dhcp
|
||||||
|
sudo dnf -y install ipmitool
|
||||||
sudo dnf install singularity
|
sudo dnf install singularity
|
||||||
|
sudo dnf install gpgme-devel
|
||||||
|
sudo dnf install libassuan.x86_64 libassuan-devel.x86_64
|
||||||
|
|
||||||
# Centos prerequisites
|
# Centos prerequisites
|
||||||
sudo yum -y install tftp-server tftp
|
sudo yum -y install tftp-server tftp
|
||||||
sudo yum -y install dhcp
|
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 http://repo.ctrliq.com/packages/rhel7/ctrl-release.rpm
|
||||||
sudo yum install singularityplus
|
sudo yum install singularityplus
|
||||||
|
sudo yum install gpgme-devel
|
||||||
|
sudo yum install libassuan.x86_64 libassuan-devel.x86_64
|
||||||
|
|
||||||
# follow README.md instructions
|
# 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
|
package node
|
||||||
|
|
||||||
import (
|
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"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -11,14 +13,12 @@ var (
|
|||||||
Short: "Node management",
|
Short: "Node management",
|
||||||
Long: "Management of node settings and power management",
|
Long: "Management of node settings and power management",
|
||||||
}
|
}
|
||||||
test bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
baseCmd.PersistentFlags().BoolVarP(&test, "test", "t", false, "Testing.")
|
baseCmd.AddCommand(poweron.GetCommand())
|
||||||
|
baseCmd.AddCommand(poweroff.GetCommand())
|
||||||
baseCmd.AddCommand(power.GetCommand())
|
baseCmd.AddCommand(powerstatus.GetCommand())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootCommand returns the root cobra.Command for the application.
|
// GetRootCommand returns the root cobra.Command for the application.
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ type nodeGroup struct {
|
|||||||
RuntimeOverlay string `yaml:"runtime overlay""`
|
RuntimeOverlay string `yaml:"runtime overlay""`
|
||||||
DomainSuffix string `yaml:"domain suffix"`
|
DomainSuffix string `yaml:"domain suffix"`
|
||||||
KernelVersion string `yaml:"kernel version"`
|
KernelVersion string `yaml:"kernel version"`
|
||||||
KernelArgs string `yaml:"kernel args"`
|
KernelArgs string `yaml:"kernel args"`
|
||||||
Nodes map[string]nodeEntry
|
Nodes map[string]nodeEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ type nodeEntry struct {
|
|||||||
RuntimeOverlay string `yaml:"runtime overlay"`
|
RuntimeOverlay string `yaml:"runtime overlay"`
|
||||||
DomainSuffix string `yaml:"domain suffix"`
|
DomainSuffix string `yaml:"domain suffix"`
|
||||||
KernelVersion string `yaml:"kernel version"`
|
KernelVersion string `yaml:"kernel version"`
|
||||||
KernelArgs string `yaml:"kernel args"`
|
KernelArgs string `yaml:"kernel args"`
|
||||||
IpmiIpaddr string `yaml:"ipmi ipaddr"`
|
IpmiIpaddr string `yaml:"ipmi ipaddr"`
|
||||||
NetDevs map[string]netDevs
|
NetDevs map[string]netDevs
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,8 @@ type NodeInfo struct {
|
|||||||
SystemOverlay string
|
SystemOverlay string
|
||||||
RuntimeOverlay string
|
RuntimeOverlay string
|
||||||
KernelVersion string
|
KernelVersion string
|
||||||
KernelArgs string
|
KernelArgs string
|
||||||
|
IpmiIpaddr string
|
||||||
NetDevs map[string]netDevs
|
NetDevs map[string]netDevs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +101,7 @@ func FindAllNodes() ([]NodeInfo, error) {
|
|||||||
|
|
||||||
n.GroupName = groupname
|
n.GroupName = groupname
|
||||||
n.HostName = node.Hostname
|
n.HostName = node.Hostname
|
||||||
|
n.IpmiIpaddr = node.IpmiIpaddr
|
||||||
|
|
||||||
n.Vnfs = group.Vnfs
|
n.Vnfs = group.Vnfs
|
||||||
n.SystemOverlay = group.SystemOverlay
|
n.SystemOverlay = group.SystemOverlay
|
||||||
@@ -223,6 +225,26 @@ func SearchByName(search string) ([]NodeInfo, error) {
|
|||||||
return ret, nil
|
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) {
|
func FindAllVnfs() ([]string, error) {
|
||||||
var ret []string
|
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