137 lines
2.9 KiB
Go
137 lines
2.9 KiB
Go
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"
|
|
)
|
|
|
|
type IPMIResult struct {
|
|
err error
|
|
out string
|
|
}
|
|
|
|
type IPMI struct {
|
|
node.IpmiConf
|
|
ShowOnly bool
|
|
Cmd string
|
|
result IPMIResult
|
|
}
|
|
|
|
func (ipmi *IPMI) Result() (string, error) {
|
|
return ipmi.result.out, ipmi.result.err
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
func (ipmi *IPMI) Command() ([]byte, error) {
|
|
cmdStr, err := ipmi.getStr()
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
if ipmi.ShowOnly {
|
|
return []byte(cmdStr), nil
|
|
}
|
|
ipmiCmd := exec.Command(cmdStr)
|
|
return ipmiCmd.CombinedOutput()
|
|
}
|
|
|
|
func (ipmi *IPMI) InteractiveCommand() (err error) {
|
|
cmdStr, err := ipmi.getStr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ipmiCmd := exec.Command(cmdStr)
|
|
ipmiCmd.Stdout = os.Stdout
|
|
ipmiCmd.Stdin = os.Stdin
|
|
ipmiCmd.Stderr = os.Stderr
|
|
return ipmiCmd.Run()
|
|
}
|
|
|
|
func (ipmi *IPMI) IPMIInteractiveCommand(cmd string) error {
|
|
ipmi.Cmd = cmd
|
|
return ipmi.InteractiveCommand()
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
/*
|
|
Just define meta commands here, implementation is in the template
|
|
*/
|
|
|
|
func (ipmi *IPMI) PowerOn() (string, error) {
|
|
return ipmi.IPMICommand("PowerOn")
|
|
}
|
|
|
|
func (ipmi *IPMI) PowerOff() (string, error) {
|
|
return ipmi.IPMICommand("PowerOff")
|
|
}
|
|
|
|
func (ipmi *IPMI) PowerCycle() (string, error) {
|
|
return ipmi.IPMICommand("PowerCycle")
|
|
}
|
|
|
|
func (ipmi *IPMI) PowerReset() (string, error) {
|
|
return ipmi.IPMICommand("PowerReset")
|
|
}
|
|
|
|
func (ipmi *IPMI) PowerSoft() (string, error) {
|
|
return ipmi.IPMICommand("PowerSoft")
|
|
}
|
|
|
|
func (ipmi *IPMI) PowerStatus() (string, error) {
|
|
return ipmi.IPMICommand("PowerStatus")
|
|
}
|
|
|
|
func (ipmi *IPMI) SDRList() (string, error) {
|
|
return ipmi.IPMICommand("SDRList")
|
|
}
|
|
|
|
func (ipmi *IPMI) SensorList() (string, error) {
|
|
return ipmi.IPMICommand("SensorList")
|
|
}
|
|
|
|
func (ipmi *IPMI) Console() error {
|
|
return ipmi.IPMIInteractiveCommand("Console")
|
|
}
|