bougou / go-ipmi Goto Github PK
View Code? Open in Web Editor NEWIPMI library in pure Go
License: Apache License 2.0
IPMI library in pure Go
License: Apache License 2.0
Hi, I'd like to ask you how to set the next time the server starts pxe, and reset the power through the lanplus mode
Hi, when I use local mode client in one of my devices, I get this error:
`
Device ID : 1
Device Revision : 1
Firmware Revision : 1.0
IPMI Version : 2.0
Manufacturer ID : 7154 (0x1bf2)
Manufacturer Name : Unknown
Product ID : 1 (0x0001)
Product Name : 0x01
Device Available : yes
Provides Device SDRs : no
Additional Device Support :
Chassis Device
FRU Inventory Device
SEL Device
SDR Repo Device
Sensor Device
Aux Firmware Rev Info :
0x00
0x00
0x00
0x00
panic: GetSELEntry failed, err: openSendRequest failed, err: failed to read from syscall conn: i/o timeout
goroutine 1 [running]:
main.main()
`
Device info:
CPU: Intel(R) Atom(TM) x7835RE
Memory: 8GB
The function calling chain is:
client.GetSELEntries(0) --> c.GetSELInfo() --> c.Exchange(request, response) --> c.exchangeOpen(request, response) --> c.openSendRequest(request) --> open.SendCommand(c.openipmi.file, req) --> conn.Read(readMsgFunc)
By the way, if I use lanplus mode to the this device, this error will not happen
Hello there, and thanks again for implementing sensor readings in #15!
I use the sensor readings to monitor my home server temps over IPMI, you can see the code here. Most of the time, it works flawlessly, but after running for a while, I occasionally see this behavior:
Basically, the data looks good, and then it alternates between the failure ParseSDR failed, err: sdr data must be longer than 5
and returning a value of -124
. When I manually run:
ipmitool -I lanplus -H <ip> -U <user> -P <pass> sensor get 'Ambient Temp'
I get the correct output of Sensor Reading : 30 (+/- 1) degrees C
It seems like something is getting out of sync, perhaps with the long-lived connection I'm creating. I saw this behavior once before, maybe after the same amount of time, but I don't have logs for the last time I saw this. This time, the monitoring was running for ~87 hours and 41 minutes before showing the wrong readings.
Any ideas?
When I use ipmitools command, 50 concurrent requests can return all,
but I use this package 23 concurrent request has one timeout.
The result:
The code:
`package main
import (
"bytes"
"errors"
"fmt"
"github.com/bougou/go-ipmi"
"os/exec"
"sync"
"sync/atomic"
"time"
)
var total atomic.Int32
func main() {
var wg sync.WaitGroup
ip := "xxxxxxx"
port := 623
username := "xxxxx"
password := "xxxxx"
for i := 0; i < 23; i++ {
wg.Add(1)
getResultFromIPMI(ip, port, username, password, &wg)
//getCmdOut()
}
wg.Wait()
}
func getCmdOut() {
cmd := "./ipmitool -I lanplus -H xxxxxx -U xxxxx -P xxxxxxx fru"
cmd2 := exec.Command("sh", "-c", cmd)
var out bytes.Buffer
var stderr bytes.Buffer
cmd2.Stdout = &out
cmd2.Stderr = &stderr
err := cmd2.Run()
if err != nil {
fmt.Println(errors.New(fmt.Sprint(err) + ": " + stderr.String()))
return
}
fmt.Println(out.String())
total.Add(1)
fmt.Println("total:", total)
}
// 走ipmi协议取数据
func getResultFromIPMI(ip string, port int, username, password string, wg *sync.WaitGroup) ([][]interface{}, error) {
defer wg.Done()
client, err := connectIPMI(ip, port, username, password) //连接ipmi
if err != nil {
return nil, err
}
defer client.Close()
//从ipmi协议取数据
var arr [][]interface{}
arr, err = fru(client) //取sensor类型数据
if err != nil {
return nil, err
}
fmt.Println(arr)
return arr, nil
}
// 连接ipmi
func connectIPMI(ip string, port int, username string, password string) (*ipmi.Client, error) {
var c *ipmi.Client
var err error
//没有,重新连接
c, err = ipmi.NewClient(ip, port, username, password)
if err != nil {
fmt.Println(err)
return nil, err
}
c.WithInterface("lanplus")
c.WithTimeout(30 * time.Second)
if err = c.Connect(); err != nil { //TODO 有时候很慢,有时候很快
fmt.Println(err)
return nil, err
}
c.Interface = "lanplus"
//defer c.Close() //连接缓存就不用关闭了
return c, nil
}
// 取fru类型数据
func fru(client *ipmi.Client) ([][]interface{}, error) {
res, err := client.GetFRUs() //2秒
if err != nil {
return nil, err
}
arr := make([][]interface{}, len(res), len(res))
for index, value := range res {
item := make([]interface{}, 1, 1)
item[0] = value.String()
arr[index] = item
}
return arr, nil
}
`
hi bougou:
the situation is the outbound ip address can't access directly, so I need access it by a proxy (squid).
but this library looks not support send request via a proxy.
Hi 您好,我想请教下怎么去设置服务器 下次启动pxe ,并且reset 电源 通过lanplus 模式
Hey, thx for your lib, it's awesome.
Looks like ChassisControlHardwareRest is supposed to invoke Hard Reset, but the name is a little bit confusing.
Could you pls tell me if you are going to change it?
Hello,
This is a cool project. Thank you for spending the time maintaining it.
I'm not sure if the project is for me yet, but I'm evaluating it, and in doing so ran into an error. Mostly for your information, but if you have ideas, that's great too.
Test code
package main
import (
"fmt"
"log"
"github.com/bougou/go-ipmi"
)
func GetIPMI() error {
client, err := ipmi.NewOpenClient()
if err != nil {
return err
}
if err := client.Connect(); err != nil {
return err
}
res, err := client.GetDeviceID()
if err != nil {
return err
}
fmt.Println(res.Format())
fmt.Println("Getting sensors")
sensors, err := client.GetSensors()
if err != nil {
return err
}
fmt.Println("got sensors")
for _, sensor := range sensors {
fmt.Println(sensor.Name, sensor.Value, sensor.SensorUnit)
}
return nil
}
func main() {
if err := GetIPMI(); err != nil {
log.Fatal(err)
}
}
Running Linux on a Dell PowerEdge R730xd as root, this is the output of the above app:
Device ID : 32
Device Revision : 1
Firmware Revision : 2.82
IPMI Version : 2.0
Manufacturer ID : 674 (0x2a2)
Manufacturer Name : Dell
Product ID : 256 (0x0100)
Product Name : 0x100
Device Available : yes
Provides Device SDRs : yes
Additional Device Support :
Chassis Device
Bridge Device
IPMB Event Receiver
FRU Inventory Device
SEL Device
SDR Repo Device
Sensor Device
Aux Firmware Rev Info :
0x00
0x04
0x52
0x52
Getting sensors
2023/02/16 22:50:55 GetSensorFromSDR failed, err: setSensorThreshold failed, err: GetSensorThresholds for sensor 0x6a failed, err: ipmiRes CompletaionCode (0xcd) is not normal: Command illegal for specified sensor or record type
Hello, I would like to run local mode client in Windows, but I use NewOpenClient failed to create session.
How can I create a valid client?
When i execute command ipmi-go lan print 1
, that is a error:
error: GetLanConfig failed, err: get lan config param (Destination Addresses) failed, err: the data for param (Destination Addresses) is too short, input (13), required (18)
i find the relative code like this.
// cmd_get_lan_config_params.go
case LanParam_AlertDestinationAddress:
lanConfig.AlertDestinationAddress = AlertDestinationAddress{
SetSelector: paramData[0],
AddressFormat: (paramData[1] & 0xf0) >> 4,
IP4UseBackupGateway: isBit0Set(paramData[2]),
IP4IP: net.IP(paramData[3:7]),
IP4MAC: net.HardwareAddr(paramData[7:12]),
IP6IP: net.IP(paramData[2:18]),
}
var LanParams = []LanParam{
// types_lan_params.go
...
{Selector: LanParam_AlertDestinationAddress, DataSize: 18, Name: "Destination Addresses"},
...
}
So why need to check this size.
func (b BmcClient) BmcClient() (clients []*ipmi.Client, err error) {
clients = make([]*ipmi.Client, 0)
if len(b.Hosts) == 0 {
return nil, errors.New("not found host")
}
for _, host := range b.Hosts {
client, err := ipmi.NewClient(host.IP, host.Port, host.Username, host.Password)
if err != nil {
return nil, err
}
switch b.Protocol {
case "lan":
client.Interface = ipmi.InterfaceLan
case "lanplus":
client.Interface = ipmi.InterfaceLanplus
case "open":
client.Interface = ipmi.InterfaceOpen
default:
return nil, fmt.Errorf("not protocol type %s", b.Protocol)
}
if err := client.Connect(); err != nil {
return nil, err
}
clients = append(clients, client)
}
return clients, nil
}
rakp1 failed, err: unpack session setup response failed, err: unpacked data is too short
两个要求
When attempting to pull fru data from older systems, the fru request fails with
GetFRUAreaChassis failed, err: ReadFRUDataAll failed, err: ReadFRUData failed, err: ipmiRes CompletaionCode (0xca) is not normal: Cannot return number of requested data bytes
ipmitool loops through until it succeeds with a lower value
Ipmitool reference https://github.com/ipmitool/ipmitool/blob/master/lib/ipmi_fru.c#L740
When attempting to use this on windows compilation will fail here:
https://github.com/bougou/go-ipmi/blob/main/open/ioctl.go#L88
This should ideally be gated to linux platforms (along with the ipmi dev file code)
Everything works fine after removing this on windows
Hi, I want to get the mac address
by GetLanConfigParams()
, but it returns null.
func main() {
host := "172.16.253.17"
port := 623
username := "Admin"
password := "Admin"
client, err := ipmi.NewClient(host, port, username, password)
if err != nil {
panic(err)
}
client.WithInterface(ipmi.InterfaceLanplus)
if err := client.Connect(); err != nil {
panic(err)
}
res, err := client.GetLanConfigParams(1, ipmi.LanParamSelector(5))
if err != nil {
panic(err)
}
fmt.Println(res.Format())
}
using ipmitools
can get it successfuly
root@master1:~# ipmitool -I lanplus -H 172.16.253.17 -U Admin -P Admin lan print 1
Set in Progress : Set Complete
Auth Type Support : NONE MD2 MD5 PASSWORD
Auth Type Enable : Callback : MD2 MD5 PASSWORD
: User : MD2 MD5 PASSWORD
: Operator : MD2 MD5 PASSWORD
: Admin : MD2 MD5 PASSWORD
: OEM : MD2 MD5 PASSWORD
IP Address Source : Static Address
IP Address : 172.16.253.17
Subnet Mask : 255.255.255.0
MAC Address : 7c:c2:55:51:8e:5e
SNMP Community String : public
IP Header : TTL=0x00 Flags=0x00 Precedence=0x00 TOS=0x00
BMC ARP Control : ARP Responses Enabled, Gratuitous ARP Disabled
Default Gateway IP : 172.16.253.254
Default Gateway MAC : 00:00:00:00:00:00
Backup Gateway IP : 0.0.0.0
Backup Gateway MAC : 00:00:00:00:00:00
802.1q VLAN ID : Disabled
802.1q VLAN Priority : 0
RMCP+ Cipher Suites : 1,2,3,6,7,8,11,12
Cipher Suite Priv Max : XaaaXXaaaXXaaXX
: X=Cipher Suite Unused
: c=CALLBACK
: u=USER
: o=OPERATOR
: a=ADMIN
: O=OEM
Bad Password Threshold : 3
Invalid password disable: yes
Attempt Count Reset Int.: 300
User Lockout Interval : 300
I found two phenomena and need your help. Would you like to help me?
1、every time when I connect, then getSensors is unstable:
Sometimes, I can get the data that I want.
Sometimes, I can't get data and return an error:
Get Channel Authentication Capabilities failed, err: client udp exchange msg failed, err: read from conn failed, err: read udp 10.128.6.107:50132->10.128.9.201:623: i/o timeout
sometimes, I got another error:
GetSDRs failed, err: ParseSDR failed, err: sdr data must be longer than 5
2、 when I connect one time, use this connect to getSensors more times,
I can get data in minutes,
if I don't get data in minutes, then I use before conn to get data, then I got an error:
GetSDR for recordID (0x0) failed, err: client udp exchange msg failed, err: read from conn failed, err: read udp 10.128.6.107:52088->10.128.9.201:623: i/o timeout
I guess connect may be expired? If I guess right, how does set connect never be expired?
https://github.com/bougou/go-ipmi/blob/main/cmd_get_sensors.go#L162
当 GetSensorReading 返回错误时,函数会提前返回。此时 sensor.readingUnavailable 为默认值 false,并且没有从 readingRes 获取到 sensor 的 value。因为没有获取成功数据,预期调用 sensor.ReadingStr 应该返回 N/A,但由于 sensor.readingUnavailable 为默认值 false,导致返回了 0 值。
Hi there, and thanks for making this package!
The TL;DR is that Sensor Reading
doesn't appear to be implemented, or I'm using it wrong. The rest of this issue is just explanation, but I think the real problem is that I was confusing Sensor Reading
with Nominal Reading
. Currently, Sensor Reading is hardcoded to zero, and I think this is the value I really want here. Are there any plans to implement this? If not, I'm happy to give it a shot and contribute a PR, any pointers would be appreciated.
I've been using this to access IPMI on Dell M610 blade servers in this project, specifically here. One thing I've noticed is that result of sdr.Full.ConvertReading(sdr.Full.NominalReadingRaw)
never changes, and the results of running the equivalent ipmitool
command produce different output. For example:
ipmitool -I lanplus -H <ip> -U <user> -P <pass> sensor get 'Ambient Temp'
produces:
Locating sensor record...
Sensor ID : Ambient Temp (0x8)
Entity ID : 7.1
Sensor Type (Threshold) : Temperature
Sensor Reading : 21 (+/- 1) degrees C
Status : ok
Lower Non-Recoverable : na
Lower Critical : 3.000
Lower Non-Critical : 8.000
Upper Non-Critical : 42.000
Upper Critical : 47.000
Upper Non-Recoverable : na
Positive Hysteresis : 1.000
Negative Hysteresis : 1.000
Assertions Enabled : lnc- lcr- unc+ ucr+
Deassertions Enabled : lnc- lnc+ lcr+ unc+ ucr+
A (hopefully) equivalent invocation in Go:
sdr, err := ic.GetSDRBySensorName("Ambient Temp")
if err != nil { ... }
fmt.Println(sdr.Full.String())
This produces:
Sensor ID : Ambient Temp (0x08)
Generator : 0x20
Entity ID : 7.1 (system board)
Sensor Type (threshold) : Temperature (0x01)
Sensor Reading : 0 (+/- 2) degrees C
Sensor Initialization :
Settable : false
Scanning : true
Events : true
Hysteresis : true
Sensor Type : true
Default State:
Event Generation : enabled
Scanning : enabled
Sensor Capabilities :
Auto Re-arm : yes(auto)
Hysteresis Support : ReadableSettable
Threshold Access : ReadableSettable
Ev Message Control : Per-threshold
Mask :
Readable Thresholds : unc ucr lnc lcr
Settable Thresholds : unc ucr lnc lcr
Threshold Read Mask : unc ucr lnc lcr
Assertions Enabled :
Deassertions Enabled:
Nominal Reading : 0x97/23.000
Normal Minimum : 0x8b/11.000
Normal Maximum : 0xc5/69.000
Lower Non-Recoverable : unspecified
Lower Critical : 0x83/3.000
Lower Non-Critical : 0x88/8.000
Upper Non-Critical : 0xaa/42.000
Upper Critical : 0xaf/47.000
Upper Non-Recoverable : unspecified
Positive Hysteresis : 0x01/-127.000
Negative Hysteresis : 0x01/-127.000
Minimum sensor range : unspecified
Maximum sensor range : unspecified
SensorDirection : 0
LinearizationFunc : linear(0)
Reading Factors : M: (1), T: (2), B: (-128), A: (194), A_Exp: (0), R_Exp: (0), B_Exp: (0)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.