164 lines
3.9 KiB
Go
164 lines
3.9 KiB
Go
// Copyright 2022 Listware
|
|
|
|
package ipmi
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"git.fg-tech.ru/listware/inventory-app/pkg/utils/driver"
|
|
)
|
|
|
|
// https://webcache.googleusercontent.com/search?q=cache:ohTuxLGBYaEJ:https://computercheese.blogspot.com/2014/03/&cd=2&hl=ru&ct=clnk&gl=ru
|
|
var (
|
|
// Tool \\
|
|
Tool = &tool{}
|
|
// Driver \\
|
|
Driver = driver.Driver("ipmi_si")
|
|
)
|
|
|
|
type tool struct{}
|
|
|
|
func (t *tool) MC() MC {
|
|
mc := &mgmtController{tool: t}
|
|
return mc
|
|
}
|
|
|
|
func (t *tool) exec(method string, args ...string) (*bytes.Buffer, error) {
|
|
a := []string{method}
|
|
a = append(a, args...)
|
|
c := exec.Command("ipmitool", a...)
|
|
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
|
|
c.Stdout = stdout
|
|
c.Stderr = stderr
|
|
if err := c.Run(); err != nil {
|
|
return nil, fmt.Errorf("%s: %w", stderr.String(), err)
|
|
}
|
|
return stdout, nil
|
|
}
|
|
|
|
// MC - management controller
|
|
type MC interface {
|
|
GUID() (string, error)
|
|
IP() (string, error)
|
|
Temp() ([4]int, error)
|
|
Reset() error // rtype: <warm|cold>
|
|
}
|
|
|
|
type mgmtController struct {
|
|
tool *tool
|
|
}
|
|
|
|
func (mc *mgmtController) GUIDOld() (s string, err error) {
|
|
bf, err := mc.tool.exec("mc", "guid")
|
|
if err != nil {
|
|
return
|
|
}
|
|
scanner := bufio.NewScanner(bf)
|
|
for scanner.Scan() {
|
|
txt := scanner.Text()
|
|
if strings.Contains(txt, "System GUID") {
|
|
kv := strings.Split(txt, ": ")
|
|
if len(kv) != 2 {
|
|
err = fmt.Errorf("failed to parse ipmitool output: %s", txt)
|
|
return
|
|
}
|
|
s = kv[1]
|
|
return
|
|
}
|
|
}
|
|
err = fmt.Errorf("failed to parse ipmitool output: %s", bf)
|
|
return
|
|
}
|
|
|
|
func (mc *mgmtController) GUID() (s string, err error) {
|
|
buf, err := mc.tool.exec("raw", "0x06", "0x037")
|
|
if err != nil {
|
|
return
|
|
}
|
|
rawString := normalize(buf.Bytes())
|
|
output := make([]string, 5)
|
|
output[0] = revert(rawString, 0, 7)
|
|
output[1] = revert(rawString, 1+7, 7+4)
|
|
output[2] = revert(rawString, 1+7+4, 7+4+4)
|
|
output[3] = string(rawString[1+7+4+4 : 1+7+4+4+4])
|
|
output[4] = string(rawString[1+7+4+4+4 : 1+7+4+4+4+12])
|
|
return strings.Join(output, "-"), err
|
|
}
|
|
|
|
func revert(r []byte, f, t int) (result string) {
|
|
for i := t; i >= f; i -= 2 {
|
|
result += string(r[i-1]) + string(r[i])
|
|
}
|
|
return
|
|
}
|
|
|
|
func normalize(src []byte) []byte {
|
|
str := strings.ReplaceAll(string(src), " ", "")
|
|
return []byte(strings.ReplaceAll(str, "\n", ""))
|
|
}
|
|
|
|
func (mc *mgmtController) IP() (s string, err error) {
|
|
buf, err := mc.tool.exec("raw", "0x0C", "0x02", "0x1", "0x3", "0x0", "0x0")
|
|
if err != nil {
|
|
return
|
|
}
|
|
rawString := normalize(buf.Bytes())
|
|
dst := make([]byte, hex.DecodedLen(len(rawString)))
|
|
if _, err = hex.Decode(dst, rawString); err != nil {
|
|
return
|
|
}
|
|
|
|
if dst[0] != 0x11 {
|
|
err = fmt.Errorf("bad code")
|
|
return
|
|
}
|
|
s = fmt.Sprintf("%d.%d.%d.%d", dst[1], dst[2], dst[3], dst[4])
|
|
return
|
|
}
|
|
|
|
func (mc *mgmtController) Reset() (err error) {
|
|
_, err = mc.tool.exec("mc", "reset", "cold")
|
|
return
|
|
}
|
|
|
|
// ipmitool -b 0x06 -t 0x2c raw 0x2e 0x4b 0x57 0x01 0x00 0x0f 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
|
|
// -b channel
|
|
// -t address
|
|
// header: 57 01 00
|
|
// cpus (2 из 4 Шт): 2c 2f ff ff
|
|
// mem (посмотри в IpmiTemperatureStats::SystemTopology::setChannels):
|
|
//
|
|
// 2d ff ff ff 2d ff ff ff 2d
|
|
// ff ff ff 2d ff ff ff 2d ff ff ff 2d ff ff ff 2e
|
|
// ff ff ff 2d ff ff ff ff ff ff ff ff ff ff ff ff
|
|
// ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
|
// ff ff ff ff ff ff ff
|
|
func (mc *mgmtController) Temp() (cpuTemp [4]int, err error) {
|
|
buf, err := mc.tool.exec("-b", "0x06", "-t", "0x2c", "raw", "0x2e", "0x4b", "0x57", "0x01", "0x00", "0x0f", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff")
|
|
if err != nil {
|
|
return
|
|
}
|
|
rawString := normalize(buf.Bytes())
|
|
dst := make([]byte, hex.DecodedLen(len(rawString)))
|
|
if _, err = hex.Decode(dst, rawString); err != nil {
|
|
return
|
|
}
|
|
|
|
if dst[0] != 0x57 || dst[1] != 0x01 || dst[2] != 0x00 {
|
|
err = fmt.Errorf("bad code")
|
|
return
|
|
}
|
|
|
|
cpuTemp[0] = int(dst[3])
|
|
cpuTemp[1] = int(dst[4])
|
|
cpuTemp[2] = int(dst[5])
|
|
cpuTemp[3] = int(dst[6])
|
|
|
|
return
|
|
}
|