use ipmitool created from template file
Signed-off-by: Christian Goll <cgoll@suse.com>
This commit is contained in:
committed by
Jonathon Anderson
parent
10ea0ac78d
commit
4597fdfaa9
2
Makefile
2
Makefile
@@ -116,10 +116,12 @@ install: build docs
|
||||
install -d -m 0755 $(DESTDIR)$(IPXESOURCE)
|
||||
install -d -m 0755 $(DESTDIR)$(DATADIR)/warewulf
|
||||
# wwctl genconfig to get the compiled in paths to warewulf.conf
|
||||
install -d -m 0755 $(DESTDIR)$(WWDATADIR)/bmc
|
||||
test -f $(DESTDIR)$(WWCONFIGDIR)/warewulf.conf || ./wwctl --warewulfconf etc/warewulf.conf genconfig warewulfconf print> $(DESTDIR)$(WWCONFIGDIR)/warewulf.conf
|
||||
test -f $(DESTDIR)$(WWCONFIGDIR)/nodes.conf || install -m 0644 etc/nodes.conf $(DESTDIR)$(WWCONFIGDIR)
|
||||
for f in etc/examples/*.ww; do install -m 0644 $$f $(DESTDIR)$(WWCONFIGDIR)/examples/; done
|
||||
for f in etc/ipxe/*.ipxe; do install -m 0644 $$f $(DESTDIR)$(WWCONFIGDIR)/ipxe/; done
|
||||
for f in lib/warewulf/bmc/*.tmpl; do install -m 0644 $$f $(DESTDIR)$(WWDATADIR)/bmc; done
|
||||
install -m 0644 etc/grub/grub.cfg.ww $(DESTDIR)$(WWCONFIGDIR)/grub/grub.cfg.ww
|
||||
install -m 0644 etc/grub/chainload.ww $(DESTDIR)$(WWOVERLAYDIR)/host/rootfs$(TFTPDIR)/warewulf/grub.cfg.ww
|
||||
install -m 0644 etc/logrotate.d/warewulfd.conf $(DESTDIR)$(LOGROTATEDIR)/warewulfd.conf
|
||||
|
||||
@@ -12,36 +12,37 @@ import (
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
)
|
||||
|
||||
func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
var returnErr error = nil
|
||||
func CobraRunE(vars *variables) func(cmd *cobra.Command, args []string) (err error) {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
var returnErr error = nil
|
||||
|
||||
nodeDB, err := node.New()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not open node configuration: %s", err)
|
||||
}
|
||||
nodeDB, err := node.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := nodeDB.FindAllNodes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get node list: %s", err)
|
||||
}
|
||||
nodes, err := nodeDB.FindAllNodes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
nodes = node.FilterNodeListByName(nodes, hostlist.Expand(args))
|
||||
} else {
|
||||
//nolint:errcheck
|
||||
cmd.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
if len(args) > 0 {
|
||||
nodes = node.FilterByName(nodes, hostlist.Expand(args))
|
||||
} else {
|
||||
//nolint:errcheck
|
||||
cmd.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(nodes) == 0 {
|
||||
return fmt.Errorf("no nodes found")
|
||||
}
|
||||
|
||||
batchpool := batch.New(50)
|
||||
jobcount := len(nodes)
|
||||
results := make(chan power.IPMI, jobcount)
|
||||
batchpool := batch.New(50)
|
||||
jobcount := len(nodes)
|
||||
results := make(chan power.IPMI, jobcount)
|
||||
|
||||
for _, n := range nodes {
|
||||
for _, n := range nodes {
|
||||
|
||||
if node.Ipmi.Ipaddr.IsUnspecified() {
|
||||
wwlog.Error("%s: No IPMI IP address", node.Id())
|
||||
@@ -56,25 +57,26 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
|
||||
results <- ipmiCmd
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
batchpool.Run()
|
||||
|
||||
close(results)
|
||||
|
||||
for result := range results {
|
||||
|
||||
out, err := result.Result()
|
||||
|
||||
if err != nil {
|
||||
wwlog.Error("%s: %s", result.Ipaddr, out)
|
||||
returnErr = err
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("%s: %s\n", result.Ipaddr, out)
|
||||
batchpool.Run()
|
||||
|
||||
close(results)
|
||||
|
||||
for result := range results {
|
||||
|
||||
out, err := result.Result()
|
||||
|
||||
if err != nil {
|
||||
wwlog.Error("%s: %s", result.Ipaddr, out)
|
||||
returnErr = err
|
||||
continue
|
||||
}
|
||||
|
||||
wwlog.Info("%s: %s\n", result.Ipaddr, out)
|
||||
|
||||
}
|
||||
|
||||
return returnErr
|
||||
}
|
||||
|
||||
return returnErr
|
||||
}
|
||||
|
||||
@@ -5,13 +5,19 @@ import (
|
||||
"github.com/warewulf/warewulf/internal/pkg/node"
|
||||
)
|
||||
|
||||
var (
|
||||
powerCmd = &cobra.Command{
|
||||
type variables struct {
|
||||
Showcmd bool
|
||||
}
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
vars := variables{}
|
||||
powerCmd := &cobra.Command{
|
||||
DisableFlagsInUseLine: true,
|
||||
Use: "status [OPTIONS] [PATTERN ...]",
|
||||
Short: "Show power status for the given node(s)",
|
||||
Long: "This command displays the power status of a set of nodes specified by PATTERN.",
|
||||
RunE: CobraRunE,
|
||||
RunE: CobraRunE(&vars),
|
||||
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
if len(args) != 0 {
|
||||
return nil, cobra.ShellCompDirectiveNoFileComp
|
||||
@@ -26,9 +32,6 @@ var (
|
||||
return node_names, cobra.ShellCompDirectiveNoFileComp
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// GetRootCommand returns the root cobra.Command for the application.
|
||||
func GetCommand() *cobra.Command {
|
||||
powerCmd.PersistentFlags().BoolVarP(&vars.Showcmd, "show", "s", false, "only show command which will be executed")
|
||||
return powerCmd
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package power
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
warewulfconf "github.com/hpcng/warewulf/internal/pkg/config"
|
||||
"github.com/hpcng/warewulf/internal/pkg/wwlog"
|
||||
|
||||
"github.com/hpcng/warewulf/internal/pkg/node"
|
||||
)
|
||||
|
||||
@@ -15,109 +23,114 @@ type IPMIResult struct {
|
||||
|
||||
type IPMI struct {
|
||||
node.IpmiConf
|
||||
result IPMIResult
|
||||
ShowOnly bool
|
||||
Cmd string
|
||||
result IPMIResult
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) Result() (string, error) {
|
||||
return ipmi.result.out, ipmi.result.err
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) Command(ipmiArgs []string) ([]byte, error) {
|
||||
func (ipmi *IPMI) getStr() (cmdStr string, err error) {
|
||||
if ipmi.BmcTemplate == "" {
|
||||
ipmi.BmcTemplate = "ipmitool.tmpl"
|
||||
}
|
||||
conf := warewulfconf.Get()
|
||||
fbuf, err := os.ReadFile(path.Join(conf.Paths.Datadir, "bmc", ipmi.BmcTemplate))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("couldn't find the template which defines the ipmi/redfish command: %s", err)
|
||||
}
|
||||
cmdTmpl, err := template.New("bmc command").Parse(string(fbuf))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var tbuffer bytes.Buffer
|
||||
err = cmdTmpl.Execute(&tbuffer, *ipmi)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
rg := regexp.MustCompile(`(\r\n?|\n){2,}`)
|
||||
cmdStr = rg.ReplaceAllString(tbuffer.String(), " ")
|
||||
wwlog.Debug("bmc string is: %s", strings.TrimSpace(cmdStr))
|
||||
return strings.TrimSpace(cmdStr), nil
|
||||
|
||||
var args []string
|
||||
}
|
||||
|
||||
if ipmi.Interface == "" {
|
||||
ipmi.Interface = "lan"
|
||||
func (ipmi *IPMI) Command() ([]byte, error) {
|
||||
cmdStr, err := ipmi.getStr()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
if ipmi.Port == "" {
|
||||
ipmi.Port = "623"
|
||||
if ipmi.ShowOnly {
|
||||
return []byte(cmdStr), nil
|
||||
}
|
||||
if ipmi.EscapeChar == "" {
|
||||
ipmi.EscapeChar = "~"
|
||||
}
|
||||
args = append(args, "-I", ipmi.Interface, "-H", ipmi.Ipaddr, "-p", ipmi.Port, "-U", ipmi.UserName, "-P", ipmi.Password, "-e", ipmi.EscapeChar)
|
||||
args = append(args, ipmiArgs...)
|
||||
ipmiCmd := exec.Command("ipmitool", args...)
|
||||
ipmiCmd := exec.Command(cmdStr)
|
||||
return ipmiCmd.CombinedOutput()
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) InteractiveCommand(ipmiArgs []string) error {
|
||||
|
||||
var args []string
|
||||
|
||||
if ipmi.Interface == "" {
|
||||
ipmi.Interface = "lan"
|
||||
func (ipmi *IPMI) InteractiveCommand() (err error) {
|
||||
cmdStr, err := ipmi.getStr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ipmi.Port == "" {
|
||||
ipmi.Port = "623"
|
||||
}
|
||||
if ipmi.EscapeChar == "" {
|
||||
ipmi.EscapeChar = "~"
|
||||
}
|
||||
args = append(args, "-I", ipmi.Interface, "-H", ipmi.Ipaddr, "-p", ipmi.Port, "-U", ipmi.UserName, "-P", ipmi.Password, "-e", ipmi.EscapeChar)
|
||||
args = append(args, ipmiArgs...)
|
||||
ipmiCmd := exec.Command("ipmitool", args...)
|
||||
ipmiCmd := exec.Command(cmdStr)
|
||||
ipmiCmd.Stdout = os.Stdout
|
||||
ipmiCmd.Stdin = os.Stdin
|
||||
ipmiCmd.Stderr = os.Stderr
|
||||
return ipmiCmd.Run()
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) IPMIInteractiveCommand(args ...string) error {
|
||||
return ipmi.InteractiveCommand(args)
|
||||
func (ipmi *IPMI) IPMIInteractiveCommand(cmd string) error {
|
||||
ipmi.Cmd = cmd
|
||||
return ipmi.InteractiveCommand()
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) IPMICommand(args ...string) (string, error) {
|
||||
ipmiOut, err := ipmi.Command(args)
|
||||
func (ipmi *IPMI) IPMICommand(cmd string) (string, error) {
|
||||
ipmi.Cmd = cmd
|
||||
ipmiOut, err := ipmi.Command()
|
||||
ipmi.result.out = strings.TrimSpace(string(ipmiOut))
|
||||
ipmi.result.err = err
|
||||
return ipmi.result.out, ipmi.result.err
|
||||
|
||||
}
|
||||
|
||||
//func (ipmi IPMI) PowerOn() (string, error) {
|
||||
//
|
||||
// var args []string
|
||||
//
|
||||
// args = append(args, "chassis", "power", "on")
|
||||
// ipmiOut, err := ipmi.Command(args)
|
||||
// ipmi.result.out = string(ipmiOut)
|
||||
// ipmi.result.err = err
|
||||
// return ipmi.result.out, ipmi.result.err
|
||||
//}
|
||||
/*
|
||||
Just define meta commands here, implementation is in the template
|
||||
*/
|
||||
|
||||
func (ipmi *IPMI) PowerOn() (string, error) {
|
||||
return ipmi.IPMICommand("chassis", "power", "on")
|
||||
return ipmi.IPMICommand("PowerOn")
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) PowerOff() (string, error) {
|
||||
return ipmi.IPMICommand("chassis", "power", "off")
|
||||
return ipmi.IPMICommand("PowerOff")
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) PowerCycle() (string, error) {
|
||||
return ipmi.IPMICommand("chassis", "power", "cycle")
|
||||
return ipmi.IPMICommand("PowerCycle")
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) PowerReset() (string, error) {
|
||||
return ipmi.IPMICommand("chassis", "power", "reset")
|
||||
return ipmi.IPMICommand("PowerReset")
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) PowerSoft() (string, error) {
|
||||
return ipmi.IPMICommand("chassis", "power", "soft")
|
||||
return ipmi.IPMICommand("PowerSoft")
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) PowerStatus() (string, error) {
|
||||
return ipmi.IPMICommand("chassis", "power", "status")
|
||||
return ipmi.IPMICommand("PowerStatus")
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) SDRList() (string, error) {
|
||||
return ipmi.IPMICommand("sdr", "list")
|
||||
return ipmi.IPMICommand("SDRList")
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) SensorList() (string, error) {
|
||||
return ipmi.IPMICommand("sensor", "list")
|
||||
return ipmi.IPMICommand("SensorList")
|
||||
}
|
||||
|
||||
func (ipmi *IPMI) Console() error {
|
||||
return ipmi.IPMIInteractiveCommand("sol", "activate")
|
||||
return ipmi.IPMIInteractiveCommand("Console")
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package power
|
||||
|
||||
type PowerOnInterface interface {
|
||||
PowerOn() (result string, err error)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
19
lib/warewulf/bmc/ipmitool.tmpl
Normal file
19
lib/warewulf/bmc/ipmitool.tmpl
Normal file
@@ -0,0 +1,19 @@
|
||||
{{/* used command to access the ipmi interface of the nodes */}}
|
||||
{{- $escapechar := "~" }}
|
||||
{{- $port := "623" }}
|
||||
{{- $interface := "lan" }}
|
||||
{{- $args := "" }}
|
||||
{{- if .EscapeChar }} $escapechar = .EscapeChar {{ end }}
|
||||
{{- if .Port }} {{ $port = .Port }} {{ end }}
|
||||
{{- if .Interface }} {{ $interface = .Interface }} {{ end }}
|
||||
{{- if eq .Cmd "PowerOn" }} {{ $args = "chassis power on" }} {{ end }}
|
||||
{{- if eq .Cmd "PowerOff" }} {{ $args = "chassis power off" }} {{ end }}
|
||||
{{- if eq .Cmd "PowerCycle" }} {{ $args = "chassis power cycle" }} {{ end }}
|
||||
{{- if eq .Cmd "PowerReset" }} {{ $args = "chassis power reset" }} {{ end }}
|
||||
{{- if eq .Cmd "PowerSoft" }} {{ $args = "chassis power soft" }} {{ end }}
|
||||
{{- if eq .Cmd "PowerStatus" }} {{ $args = "chassis power status" }} {{ end }}
|
||||
{{- if eq .Cmd "SDRList" }} {{ $args = "sdr list" }} {{ end }}
|
||||
{{- if eq .Cmd "SensorList" }} {{ $args = "sensor list" }} {{ end }}
|
||||
{{- if eq .Cmd "Console" }} {{ $args = "sol activate" }} {{ end }}
|
||||
{{- $cmd := printf "ipmitool -I %s -H %s -p %s -U %s -P %s -e %s %s" $interface .Ipaddr $port .UserName .Password $escapechar $args }}
|
||||
{{ $cmd }}
|
||||
Reference in New Issue
Block a user