ipmitool.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package ipmitool
  15. import (
  16. "context"
  17. "fmt"
  18. "net"
  19. "strconv"
  20. "strings"
  21. "time"
  22. "yunion.io/x/log"
  23. "yunion.io/x/pkg/errors"
  24. "yunion.io/x/pkg/tristate"
  25. "yunion.io/x/pkg/util/stringutils"
  26. "yunion.io/x/pkg/utils"
  27. "yunion.io/x/onecloud/pkg/apis/compute"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/types"
  29. "yunion.io/x/onecloud/pkg/util/procutils"
  30. "yunion.io/x/onecloud/pkg/util/ssh"
  31. "yunion.io/x/onecloud/pkg/util/stringutils2"
  32. "yunion.io/x/onecloud/pkg/util/sysutils"
  33. )
  34. type IPMIParser struct{}
  35. func (parser *IPMIParser) GetDefaultTimeout() time.Duration {
  36. return 20 * time.Second
  37. }
  38. var (
  39. BOOTDEVS = []string{"pxe", "disk", "safe", "diag", "cdrom", "bios"}
  40. SOLOPTS = []string{"default", "skip", "enable"}
  41. )
  42. type Args []string
  43. func newArgs(args ...interface{}) Args {
  44. ret := make([]string, len(args))
  45. for i, arg := range args {
  46. ret[i] = fmt.Sprintf("%v", arg)
  47. }
  48. return ret
  49. }
  50. type IPMIExecutor interface {
  51. GetMode() string
  52. ExecuteCommand(args ...string) ([]string, error)
  53. }
  54. type SSHIPMI struct {
  55. IPMIParser
  56. sshClient *ssh.Client
  57. }
  58. func NewSSHIPMI(cli *ssh.Client) *SSHIPMI {
  59. return &SSHIPMI{
  60. sshClient: cli,
  61. }
  62. }
  63. func (ipmi *SSHIPMI) GetMode() string {
  64. return "ssh"
  65. }
  66. func (ipmi *SSHIPMI) GetCommand(args ...string) *procutils.Command {
  67. nArgs := []string{"-I", "open"}
  68. nArgs = append(nArgs, args...)
  69. return procutils.NewCommand("/usr/bin/ipmitool", nArgs...)
  70. }
  71. func (ipmi *SSHIPMI) ExecuteCommand(args ...string) ([]string, error) {
  72. cmd := ipmi.GetCommand(args...)
  73. log.Debugf("[SSHIPMI] execute command: %s", cmd)
  74. return ipmi.sshClient.Run(cmd.String())
  75. }
  76. type LanPlusIPMI struct {
  77. IPMIParser
  78. host string
  79. user string
  80. password string
  81. port int
  82. }
  83. func NewLanPlusIPMI(host, user, password string) *LanPlusIPMI {
  84. return NewLanPlusIPMIWithPort(host, user, password, 623)
  85. }
  86. func NewLanPlusIPMIWithPort(host, user, password string, port int) *LanPlusIPMI {
  87. return &LanPlusIPMI{
  88. host: host,
  89. user: user,
  90. password: password,
  91. port: port,
  92. }
  93. }
  94. func (ipmi *LanPlusIPMI) GetMode() string {
  95. return "rmcp"
  96. }
  97. func (ipmi *LanPlusIPMI) GetCommand(args ...string) (*procutils.Command, context.CancelFunc) {
  98. nArgs := []string{
  99. "-I", "lanplus", "-H", ipmi.host,
  100. "-p", fmt.Sprintf("%d", ipmi.port),
  101. "-U", ipmi.user,
  102. "-P", ipmi.password,
  103. }
  104. nArgs = append(nArgs, args...)
  105. ctx, cancel := context.WithTimeout(context.Background(), ipmi.GetDefaultTimeout())
  106. return procutils.NewCommandContext(ctx, "ipmitool", nArgs...), cancel
  107. }
  108. func (ipmi *LanPlusIPMI) ExecuteCommand(args ...string) ([]string, error) {
  109. cmd, cancel := ipmi.GetCommand(args...)
  110. defer cancel()
  111. log.Debugf("[LanPlusIPMI] execute command: %s", cmd.String())
  112. out, err := cmd.Output()
  113. if err != nil {
  114. return nil, err
  115. }
  116. return ssh.ParseOutput(out), nil
  117. }
  118. func GetSysGuid(exector IPMIExecutor) string {
  119. args := []string{"mc", "guid"}
  120. // args := []string{"raw", "0x06", "0x37"}
  121. lines, err := exector.ExecuteCommand(args...)
  122. if err != nil {
  123. // ignore error
  124. log.Errorf("mc guid error: %s", err)
  125. }
  126. for _, line := range lines {
  127. key, val := stringutils.SplitKeyValue(line)
  128. if key == "System GUID" {
  129. return sysutils.NormalizeUuid(val)
  130. }
  131. }
  132. return ""
  133. }
  134. func GetSysInfo(exector IPMIExecutor) (*types.SSystemInfo, error) {
  135. // TODO: do cache
  136. args := []string{"fru", "print", "0"}
  137. lines, err := exector.ExecuteCommand(args...)
  138. if err != nil {
  139. // ignore error
  140. log.Errorf("fru print 0 error: %s", err)
  141. }
  142. ret := make(map[string]string)
  143. keys := map[string]string{
  144. "manufacture": "Product Manufacturer",
  145. "model": "Product Name",
  146. "bmodel": "Board Product",
  147. "version": "Product Version",
  148. "sn": "Product Serial",
  149. "bsn": "Board Serial",
  150. }
  151. for _, line := range lines {
  152. key, val := stringutils.SplitKeyValue(line)
  153. if key != "" {
  154. for n, v := range keys {
  155. if _, ok := ret[n]; v == key && !ok {
  156. ret[n] = val
  157. }
  158. }
  159. }
  160. }
  161. _, snOk := ret["sn"]
  162. bsn, bsnOk := ret["bsn"]
  163. if !snOk && bsnOk {
  164. // no product serial
  165. ret["sn"] = bsn
  166. }
  167. info := types.SSystemInfo{}
  168. err = sysutils.DumpMapToObject(ret, &info)
  169. info.OemName = types.ManufactureOemName(info.Manufacture)
  170. return &info, err
  171. }
  172. /*func GetLanChannels(sysinfo *types.SSystemInfo) []int {
  173. return profiles.GetLanChannel(sysinfo)
  174. }
  175. func GetDefaultLanChannel(sysinfo *types.SSystemInfo) int {
  176. return GetLanChannels(sysinfo)[0]
  177. }
  178. func GetRootId(sysinfo *types.SSystemInfo) int {
  179. return profiles.GetRootId(sysinfo)
  180. }*/
  181. func GetLanConfig(exector IPMIExecutor, channel uint8) (*types.SIPMILanConfig, error) {
  182. args := newArgs("lan", "print", channel)
  183. lines, err := ExecuteCommands(exector, args)
  184. if err != nil {
  185. return nil, err
  186. }
  187. ret := new(types.SIPMILanConfig)
  188. for _, line := range lines {
  189. key, val := stringutils.SplitKeyValue(line)
  190. if key == "" {
  191. continue
  192. }
  193. switch key {
  194. case "IP Address Source":
  195. if val == "Static Address" {
  196. ret.IPSrc = "static"
  197. }
  198. case "IP Address":
  199. ret.IPAddr = val
  200. case "Subnet Mask":
  201. ret.Netmask = val
  202. case "MAC Address":
  203. ret.Mac, _ = net.ParseMAC(val)
  204. case "Default Gateway IP":
  205. ret.Gateway = val
  206. case "802.1q VLAN ID":
  207. vlanId, _ := strconv.ParseInt(val, 10, 64)
  208. ret.VlanId = int(vlanId)
  209. }
  210. }
  211. return ret, nil
  212. }
  213. func tryExecuteCommand(exector IPMIExecutor, args ...string) ([]string, error) {
  214. var err error
  215. var ret []string
  216. maxTries := 3
  217. for tried := 0; tried < maxTries; tried++ {
  218. ret, err = exector.ExecuteCommand(args...)
  219. if err == nil {
  220. return ret, nil
  221. }
  222. sleepTime := time.Second * (1 << uint(tried))
  223. log.Errorf("Execute args %v error: %v, sleep %s then try again", args, err, sleepTime)
  224. time.Sleep(sleepTime)
  225. }
  226. return ret, err
  227. }
  228. func ExecuteCommands(exector IPMIExecutor, args ...Args) ([]string, error) {
  229. results := make([]string, 0)
  230. for _, arg := range args {
  231. ret, err := tryExecuteCommand(exector, arg...)
  232. if err != nil {
  233. return nil, err
  234. }
  235. results = append(results, ret...)
  236. }
  237. return results, nil
  238. }
  239. func doActions(exector IPMIExecutor, actionName string, args ...Args) error {
  240. _, err := ExecuteCommands(exector, args...)
  241. if err != nil {
  242. return fmt.Errorf("Do %s action error: %v", actionName, err)
  243. }
  244. return nil
  245. }
  246. func SetLanDHCP(exector IPMIExecutor, lanChannel uint8) error {
  247. args := newArgs("lan", "set", lanChannel, "ipsrc", "dhcp")
  248. return doActions(exector, "set_lan_dhcp", args)
  249. }
  250. func SetLanStatic(
  251. exector IPMIExecutor,
  252. channel uint8,
  253. ip string,
  254. mask string,
  255. gateway string,
  256. ) error {
  257. // config, err := GetLanConfig(exector, channel)
  258. // if err != nil {
  259. // return err
  260. // }
  261. // var argss []Args
  262. // if config.IPAddr == ip && config.Netmask == mask && config.Gateway == gateway {
  263. argss := []Args{
  264. newArgs("lan", "set", channel, "ipsrc", "static"),
  265. newArgs("lan", "set", channel, "ipaddr", ip),
  266. newArgs("lan", "set", channel, "netmask", mask),
  267. newArgs("lan", "set", channel, "defgw", "ipaddr", gateway),
  268. }
  269. // } else {
  270. // argss = []Args{
  271. // newArgs("lan", "set", channel, "ipsrc", "static"),
  272. // newArgs("lan", "set", channel, "ipaddr", ip),
  273. // newArgs("lan", "set", channel, "netmask", mask),
  274. // newArgs("lan", "set", channel, "defgw", "ipaddr", gateway),
  275. // }
  276. // }
  277. return doActions(exector, "set_lan_static", argss...)
  278. }
  279. func SetLanStaticIP(exector IPMIExecutor, channel uint8, ip string) error {
  280. args := newArgs("lan", "set", channel, "ipaddr", ip)
  281. return doActions(exector, "set_lan_static_ip", args)
  282. }
  283. func setLanAccess(exector IPMIExecutor, channel uint8, access string) error {
  284. args := []Args{
  285. newArgs("lan", "set", channel, "access", access),
  286. // newArgs("lan", "set", channel, "auth", "ADMIN", "MD5"),
  287. }
  288. return doActions(exector, "set_lan_access", args...)
  289. }
  290. func EnableLanAccess(exector IPMIExecutor, channel uint8) error {
  291. return setLanAccess(exector, channel, "on")
  292. }
  293. func ListLanUsers(exector IPMIExecutor, channel uint8) ([]compute.IPMIUser, error) {
  294. args := newArgs("user", "list", channel)
  295. ret, err := ExecuteCommands(exector, args)
  296. if err != nil {
  297. return nil, errors.Wrapf(err, "list user at channel %d", channel)
  298. }
  299. return sysutils.ParseIPMIUser(ret), nil
  300. }
  301. func CreateOrSetAdminUser(exector IPMIExecutor, channel uint8, rootId int, username string, password string) error {
  302. users, err := ListLanUsers(exector, channel)
  303. if err != nil {
  304. return errors.Wrap(err, "List users")
  305. }
  306. if len(users) == 0 {
  307. return errors.Errorf("Empty users at channel %d", channel)
  308. }
  309. var foundUser *compute.IPMIUser = nil
  310. for _, user := range users {
  311. tmp := user
  312. if user.Name == username {
  313. foundUser = &tmp
  314. break
  315. }
  316. }
  317. if foundUser == nil {
  318. minEmptyUserId := -1
  319. for _, user := range users {
  320. if user.Name == "" {
  321. minEmptyUserId = user.Id
  322. break
  323. }
  324. }
  325. if minEmptyUserId == -1 {
  326. log.Warningf("Not found min empty user id, use root id %d to set", rootId)
  327. minEmptyUserId = rootId
  328. }
  329. return SetIdUserPasswd(exector, channel, minEmptyUserId, username, password)
  330. }
  331. return SetLanUserAdminPasswd(exector, channel, foundUser.Id, password)
  332. }
  333. func SetLanUserAdminPasswd(exector IPMIExecutor, channel uint8, id int, password string) error {
  334. var err error
  335. password, err = stringutils2.EscapeEchoString(password)
  336. if err != nil {
  337. return fmt.Errorf("EscapeEchoString for password: %s, error: %v", password, err)
  338. }
  339. args := []Args{
  340. newArgs("user", "enable", id),
  341. newArgs("user", "set", "password", id, fmt.Sprintf("\"%s\"", password)),
  342. newArgs("user", "priv", id, 4, channel),
  343. }
  344. err = doActions(exector, "set_lan_user_password", args...)
  345. if err != nil {
  346. return err
  347. }
  348. args = []Args{newArgs(
  349. "raw", "0x06", "0x43",
  350. fmt.Sprintf("0x%02x", 0xb0+channel),
  351. fmt.Sprintf("0x%02x", id), "0x04", "0x00")}
  352. err = doActions(exector, "set_lan_user_password2", args...)
  353. if err == nil {
  354. return nil
  355. }
  356. args = []Args{newArgs(
  357. "channel", "setaccess", channel,
  358. id, "link=on", "ipmi=on",
  359. "callin=on", "privilege=4",
  360. )}
  361. return doActions(exector, "set_lan_user_password3", args...)
  362. }
  363. func SetIdUserPasswd(exector IPMIExecutor, channel uint8, id int, user string, password string) error {
  364. args := newArgs("user", "set", "name", id, user)
  365. if err := doActions(exector, fmt.Sprintf("set_id%d_name", id), args); err != nil {
  366. return errors.Wrapf(err, "change root id %d to name %s", id, user)
  367. }
  368. return SetLanUserAdminPasswd(exector, channel, id, password)
  369. }
  370. func SetLanPasswd(exector IPMIExecutor, rootId int, password string) error {
  371. password, err := stringutils2.EscapeEchoString(password)
  372. if err != nil {
  373. return fmt.Errorf("EscapeEchoString for password: %v", err)
  374. }
  375. args := newArgs("user", "set", "password", rootId, fmt.Sprintf("\"%s\"", password))
  376. return doActions(exector, "set_lan_passwd", args)
  377. }
  378. func GetChassisPowerStatus(exector IPMIExecutor) (string, error) {
  379. args := newArgs("chassis", "power", "status")
  380. ret, err := ExecuteCommands(exector, args)
  381. if err != nil {
  382. return "", err
  383. }
  384. for _, line := range ret {
  385. if strings.Contains(line, "Chassis Power is") {
  386. data := strings.Split(line, " ")
  387. status := strings.ToLower(strings.TrimSpace(data[len(data)-1]))
  388. return status, nil
  389. }
  390. }
  391. return "", fmt.Errorf("Unknown chassis status")
  392. }
  393. func GetBootFlags(exector IPMIExecutor) (*types.SIPMIBootFlags, error) {
  394. args := newArgs("raw", "0x00", "0x09", "0x05", "0x00", "0x00")
  395. ret, err := ExecuteCommands(exector, args)
  396. if err != nil {
  397. return nil, err
  398. }
  399. bytes, err := HexStr2Bytes(ret[0])
  400. if err != nil {
  401. return nil, err
  402. }
  403. bootdevIdx := ((bytes[3] >> 2) & 0x0f) - 1
  404. bootdev := ""
  405. if bootdevIdx >= 0 && int(bootdevIdx) < len(BOOTDEVS) {
  406. bootdev = BOOTDEVS[bootdevIdx]
  407. }
  408. flags := &types.SIPMIBootFlags{
  409. Dev: bootdev,
  410. }
  411. solIdx := (bytes[4] & 0x03)
  412. if solIdx == 1 {
  413. sol := false
  414. flags.Sol = &sol
  415. } else if solIdx == 2 {
  416. sol := true
  417. flags.Sol = &sol
  418. }
  419. return flags, nil
  420. }
  421. func HexStr2Bytes(hs string) ([]int64, error) {
  422. b := []int64{}
  423. for _, x := range strings.Split(hs, " ") {
  424. intV, err := strconv.ParseInt(x, 16, 64)
  425. if err != nil {
  426. return nil, err
  427. }
  428. b = append(b, intV)
  429. }
  430. return b, nil
  431. }
  432. func GetACPIPowerStatus(exector IPMIExecutor) ([]int64, error) {
  433. args := newArgs("raw", "0x06", "0x07")
  434. ret, err := ExecuteCommands(exector, args)
  435. if err != nil {
  436. return nil, err
  437. }
  438. return HexStr2Bytes(ret[0])
  439. }
  440. func DoSoftShutdown(exector IPMIExecutor) error {
  441. args := newArgs("chassis", "power", "soft")
  442. return doActions(exector, "do_soft_shutdown", args)
  443. }
  444. func DoHardShutdown(exector IPMIExecutor) error {
  445. args := newArgs("chassis", "power", "off")
  446. return doActions(exector, "do_hard_shutdown", args)
  447. }
  448. func DoPowerOn(exector IPMIExecutor) error {
  449. args := newArgs("chassis", "power", "on")
  450. return doActions(exector, "do_power_on", args)
  451. }
  452. func DoPowerReset(exector IPMIExecutor) error {
  453. args := newArgs("chassis", "power", "reset")
  454. return doActions(exector, "do_power_reset", args)
  455. }
  456. func DoPowerCycle(exector IPMIExecutor) error {
  457. args := newArgs("chassis", "power", "cycle")
  458. return doActions(exector, "do_power_cycle", args)
  459. }
  460. func DoReboot(exector IPMIExecutor) error {
  461. maxTries := 10
  462. var status string
  463. var err error
  464. status, err = GetChassisPowerStatus(exector)
  465. if err != nil {
  466. log.Errorf("DoReboot get power status 1st: %v", err)
  467. }
  468. isValidStatus := func(s string) bool {
  469. return utils.IsInStringArray(s, []string{string(types.POWER_STATUS_ON), string(types.POWER_STATUS_OFF)})
  470. }
  471. for tried := 0; !isValidStatus(status) && tried <= maxTries; tried++ {
  472. time.Sleep(1 * time.Second)
  473. status, err = GetChassisPowerStatus(exector)
  474. if err != nil {
  475. log.Errorf("DoReboot %d tries to get power status: %v", tried, err)
  476. }
  477. }
  478. if !isValidStatus(status) {
  479. return fmt.Errorf("Unexpected power status: %q", status)
  480. }
  481. // do shutdown
  482. if status == string(types.POWER_STATUS_ON) {
  483. if err := DoHardShutdown(exector); err != nil {
  484. log.Errorf("DoHardShutdown: %v", err)
  485. }
  486. time.Sleep(1 * time.Second)
  487. for tried := 0; tried < maxTries; tried++ {
  488. status, err = GetChassisPowerStatus(exector)
  489. if err != nil {
  490. log.Errorf("DoReboot %d tries to get power status: %v", tried, err)
  491. }
  492. if status == string(types.POWER_STATUS_OFF) {
  493. break
  494. }
  495. time.Sleep(10 * time.Second)
  496. }
  497. }
  498. // do power on
  499. status, _ = GetChassisPowerStatus(exector)
  500. for tried := 0; status != string(types.POWER_STATUS_ON) && tried < maxTries; tried++ {
  501. if err := DoPowerOn(exector); err != nil {
  502. log.Errorf("DoReboot %d tries to power on: %v", tried, err)
  503. }
  504. time.Sleep(10 * time.Second)
  505. status, err = GetChassisPowerStatus(exector)
  506. if err != nil {
  507. log.Errorf("DoReboot %d tries to get power status: %v", tried, err)
  508. }
  509. }
  510. status, err = GetChassisPowerStatus(exector)
  511. if err != nil {
  512. return errors.Wrap(err, "Get power status after power on")
  513. }
  514. if status != string(types.POWER_STATUS_ON) {
  515. return errors.Errorf("do reboot fail to poweron, current status: %s", status)
  516. }
  517. return nil
  518. }
  519. func doRebootToFlag(exector IPMIExecutor, setFunc func(IPMIExecutor) error) error {
  520. err := setFunc(exector)
  521. if err != nil {
  522. return err
  523. }
  524. return DoReboot(exector)
  525. }
  526. func SetRebootToDisk(exector IPMIExecutor) error {
  527. return SetBootFlags(exector, "disk", tristate.True, true)
  528. }
  529. func DoRebootToDisk(exector IPMIExecutor) error {
  530. return doRebootToFlag(exector, SetRebootToDisk)
  531. }
  532. func SetRebootToPXE(exector IPMIExecutor) error {
  533. return SetBootFlagPXE(exector)
  534. }
  535. func DoRebootToPXE(exector IPMIExecutor) error {
  536. return doRebootToFlag(exector, SetRebootToPXE)
  537. }
  538. func SetRebootToBIOS(exector IPMIExecutor) error {
  539. return SetBootFlags(exector, "bios", tristate.True, false)
  540. }
  541. func DoRebootToBIOS(exector IPMIExecutor) error {
  542. return doRebootToFlag(exector, SetRebootToBIOS)
  543. }
  544. func SetBootFlagPXE(exector IPMIExecutor) error {
  545. return setBootFlagsV2(exector, "pxe")
  546. }
  547. func SetBootFlags(
  548. exector IPMIExecutor,
  549. bootdev string,
  550. sol tristate.TriState,
  551. enablePersistent bool,
  552. ) error {
  553. err := setBootFlagsV1(exector, bootdev, sol, enablePersistent)
  554. if err == nil {
  555. return nil
  556. }
  557. return setBootFlagsV2(exector, bootdev)
  558. }
  559. func setBootFlagsV1(
  560. exector IPMIExecutor,
  561. bootdev string,
  562. sol tristate.TriState,
  563. enablePersistent bool,
  564. ) error {
  565. cmd := []interface{}{"raw", "0x00", "0x08", "0x05"}
  566. bootdevIdx := 0
  567. if ok, idx := utils.InStringArray(bootdev, BOOTDEVS); ok {
  568. bootdevIdx = idx + 1
  569. } else {
  570. return fmt.Errorf("Illegal bootdev %s", bootdev)
  571. }
  572. valid := 0x80
  573. if enablePersistent {
  574. valid = valid + 0x40
  575. }
  576. solIdx := 0
  577. if !sol.IsNone() {
  578. if sol.IsTrue() {
  579. solIdx = 2
  580. } else {
  581. solIdx = 1
  582. }
  583. }
  584. for _, x := range []int{valid, bootdevIdx << 2, solIdx, 0, 0} {
  585. cmd = append(cmd, fmt.Sprintf("0x%02x", x))
  586. }
  587. return doActions(exector, "set_boot_flags_v1", newArgs(cmd...))
  588. }
  589. func setBootFlagsV2(exector IPMIExecutor, bootdev string) error {
  590. return doActions(
  591. exector,
  592. fmt.Sprintf("set_boot_flag_%s", bootdev),
  593. newArgs("chassis", "bootdev", bootdev),
  594. )
  595. }
  596. func GetIPMILanPort(exector IPMIExecutor) (string, error) {
  597. ret, err := ExecuteCommands(exector, newArgs("delloem", "lan", "get"))
  598. if err != nil {
  599. return "", err
  600. }
  601. return ret[1], nil
  602. }
  603. func SetDellIPMILanPortShared(exector IPMIExecutor) error {
  604. args1 := newArgs("delloem", "lan", "set", "shared")
  605. args2 := newArgs("delloem", "lan", "set", "shared", "with", "lom1")
  606. err2 := doActions(exector, "_dell_set_ipmi_lan_port_shared_02", args2)
  607. if err2 != nil {
  608. return doActions(exector, "_dell_set_ipmi_lan_port_shared_01", args1)
  609. }
  610. return nil
  611. }
  612. func SetHuaweiIPMILanPortShared(exector IPMIExecutor) error {
  613. args := []Args{
  614. newArgs(
  615. "raw", "0xc", "0x1", "0x1", "0xd7", "0xdb",
  616. "0x07", "0x00", "0x2",
  617. ),
  618. newArgs(
  619. "raw", "0x30", "0x93", "0xdb", "0x07", "0x00",
  620. "0x05", "0x0d", "0x0", "0x0", "0x1", "0x0",
  621. ),
  622. }
  623. return doActions(exector, "_huawei_set_ipmi_lan_port_shared", args...)
  624. }
  625. func SetIPMILanPortDedicated(exector IPMIExecutor) error {
  626. return doActions(
  627. exector,
  628. "set_ipmi_lan_port_dedicated",
  629. newArgs("delloem", "lan", "set", "dedicated"),
  630. )
  631. }
  632. func DoBMCReset(exector IPMIExecutor) error {
  633. return doActions(exector, "do_bmc_reset", newArgs("mc", "reset", "cold"))
  634. }