mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
baremetal: megactl
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/baremetal/profiles"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/sysutils"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/types"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/detect_storages"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
@@ -57,6 +58,7 @@ func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
|
||||
return err
|
||||
}
|
||||
// TODO: diskinfo
|
||||
raidDiskInfo, nonRaidDiskInfo, pcieDiskInfo := detect_storages.DetectStorageInfo(cli, true)
|
||||
|
||||
ipmiEnable, err := isIPMIEnable(cli)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
package detect_storages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/sysutils"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
func DetectStorageInfo(cli *ssh.Client, wait bool) (interface{}, error) {
|
||||
raidDiskInfo := nil
|
||||
|
||||
pcieRet, err := cli.Run("/lib/mos/lsdisk --pcie")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Fail to retrieve PCIE DISK info")
|
||||
}
|
||||
pcieDiskInfo := sysutils.ParsePCIEDiskInfo(pcieRet)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/stringutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/profiles"
|
||||
@@ -119,16 +120,6 @@ func (ipmi *LanPlusIPMI) ExecuteCommand(args ...string) ([]string, error) {
|
||||
return ssh.ParseOutput(out), nil
|
||||
}
|
||||
|
||||
func splitKeyValue(line string) (*string, *string) {
|
||||
pos := strings.Index(line, ":")
|
||||
if pos > 0 {
|
||||
key := strings.TrimSpace(line[:pos])
|
||||
val := strings.TrimSpace(line[pos+1:])
|
||||
return &key, &val
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func GetSysInfo(exector IPMIExecutor) (*types.IPMISystemInfo, error) {
|
||||
// TODO: do cache
|
||||
args := []string{"fru", "print", "0"}
|
||||
@@ -148,11 +139,11 @@ func GetSysInfo(exector IPMIExecutor) (*types.IPMISystemInfo, error) {
|
||||
}
|
||||
|
||||
for _, line := range lines {
|
||||
key, val := splitKeyValue(line)
|
||||
if key != nil {
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key != "" {
|
||||
for n, v := range keys {
|
||||
if _, ok := ret[n]; v == *key && !ok {
|
||||
ret[n] = *val
|
||||
if _, ok := ret[n]; v == key && !ok {
|
||||
ret[n] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,23 +179,23 @@ func GetLanConfig(exector IPMIExecutor, channel int) (*types.IPMILanConfig, erro
|
||||
}
|
||||
ret := new(types.IPMILanConfig)
|
||||
for _, line := range lines {
|
||||
key, val := splitKeyValue(line)
|
||||
if key == nil {
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
switch *key {
|
||||
switch key {
|
||||
case "IP Address Source":
|
||||
if *val == "Static Address" {
|
||||
if val == "Static Address" {
|
||||
ret.IPSrc = "static"
|
||||
}
|
||||
case "IP Address":
|
||||
ret.IPAddr = *val
|
||||
ret.IPAddr = val
|
||||
case "Subnet Mask":
|
||||
ret.Netmask = *val
|
||||
ret.Netmask = val
|
||||
case "MAC Address":
|
||||
ret.Mac, _ = net.ParseMAC(*val)
|
||||
ret.Mac, _ = net.ParseMAC(val)
|
||||
case "Default Gateway IP":
|
||||
ret.Gateway = *val
|
||||
ret.Gateway = val
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
package megactl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/stringutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
var (
|
||||
sizePattern = regexp.MustCompile(`(?P<sector>0x[0-9a-fA-F]+)`)
|
||||
adapterPatter = regexp.MustCompile(`^Adapter #(?P<idx>[0-9]+)`)
|
||||
)
|
||||
|
||||
type MegaRaidPhyDev struct {
|
||||
enclosure int
|
||||
slot int
|
||||
minStripSize int
|
||||
maxStripSize int
|
||||
model string
|
||||
rotate tristate.TriState
|
||||
adapter int
|
||||
status string
|
||||
driver string
|
||||
sector int
|
||||
block int
|
||||
}
|
||||
|
||||
func NewMegaRaidPhyDev() *MegaRaidPhyDev {
|
||||
return &MegaRaidPhyDev{
|
||||
enclosure: -1,
|
||||
slot: -1,
|
||||
minStripSize: -1,
|
||||
maxStripSize: -1,
|
||||
rotate: tristate.None,
|
||||
driver: baremetal.DISK_DRIVER_MEGARAID,
|
||||
sector: -1,
|
||||
block: 512,
|
||||
}
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) GetSize() int {
|
||||
return dev.sector * dev.block / 1024 / 1024 // MB
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) parseLine(line string) bool {
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
switch key {
|
||||
case "Media Type":
|
||||
if val == "Hard Disk Device" {
|
||||
dev.rotate = tristate.True
|
||||
} else {
|
||||
dev.rotate = tristate.False
|
||||
}
|
||||
case "Enclosure Device ID":
|
||||
enclosure, err := strconv.Atoi(val)
|
||||
if err == nil {
|
||||
dev.enclosure = enclosure
|
||||
}
|
||||
case "Slot Number":
|
||||
dev.slot, _ = strconv.Atoi(val)
|
||||
case "Coerced Size":
|
||||
matches := sizePattern.FindStringSubmatch(val)
|
||||
if len(matches) != 0 {
|
||||
paramsMap := make(map[string]string)
|
||||
for i, name := range sizePattern.SubexpNames() {
|
||||
if i > 0 && i <= len(matches) {
|
||||
paramsMap[name] = matches[i]
|
||||
}
|
||||
}
|
||||
sizeStr := paramsMap["sector"]
|
||||
sector, err := strconv.ParseInt(sizeStr, 16, 32)
|
||||
if err != nil {
|
||||
dev.sector = 0
|
||||
}
|
||||
dev.sector = int(sector)
|
||||
} else {
|
||||
dev.sector = 0
|
||||
}
|
||||
case "Inquiry Data":
|
||||
dev.model = strings.Join(regexp.MustCompile(`\s+`).Split(val, -1), " ")
|
||||
case "Firmware state":
|
||||
if val == "JBOD" {
|
||||
dev.status = "jbod"
|
||||
} else if strings.Contains(strings.ToLower(val), "online") {
|
||||
dev.status = "online"
|
||||
} else {
|
||||
dev.status = "offline"
|
||||
}
|
||||
case "Logical Sector Size":
|
||||
block, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
log.Errorf("parse logical sector size error: %v", err)
|
||||
dev.block = 512
|
||||
} else {
|
||||
dev.block = block
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) parseStripSize(lines []string) bool {
|
||||
size2Int := func(sizeStr string) int {
|
||||
// TODO
|
||||
return -1
|
||||
}
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "Min") {
|
||||
dev.minStripSize = size2Int(strings.Split(line, ": ")[1])
|
||||
}
|
||||
if strings.Contains(line, "Max") {
|
||||
dev.maxStripSize = size2Int(strings.Split(line, ": ")[1])
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) isComplete() bool {
|
||||
if dev.model == "" {
|
||||
return false
|
||||
}
|
||||
if dev.sector < 0 {
|
||||
return false
|
||||
}
|
||||
if dev.block < 0 {
|
||||
return false
|
||||
}
|
||||
if dev.slot < 0 {
|
||||
return false
|
||||
}
|
||||
if dev.rotate.IsNone() {
|
||||
return false
|
||||
}
|
||||
if dev.status == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) isJBOD() bool {
|
||||
return dev.status == "jbod"
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) String() string {
|
||||
if dev.enclosure < 0 {
|
||||
return fmt.Sprintf(":%d", dev.slot)
|
||||
}
|
||||
return fmt.Sprintf("%d:%d", dev.enclosure, dev.slot)
|
||||
}
|
||||
|
||||
type MegaRaidAdaptor struct {
|
||||
index int
|
||||
raid *MegaRaid
|
||||
devs []*MegaRaidPhyDev
|
||||
lvs []interface{}
|
||||
}
|
||||
|
||||
func NewMegaRaidAdaptor(index int, raid *MegaRaid) *MegaRaidAdaptor {
|
||||
return &MegaRaidAdaptor{
|
||||
index: index,
|
||||
raid: raid,
|
||||
}
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) AddPhyDev(dev *MegaRaidPhyDev) {
|
||||
dev.adapter = adapter.index
|
||||
adapter.devs = append(adapter.devs, dev)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) GetPhyDevs() []*MegaRaidPhyDev {
|
||||
return adapter.devs
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) getLogicVolumes() []int {
|
||||
cmd := GetCommand("-LDInfo", "-Lall", fmt.Sprintf("-a%d", adapter.index))
|
||||
ret, err := adapter.remoteRun(cmd)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return adapter.parseLogicVolumes(ret)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) parseLogicVolumes(lines []string) []int {
|
||||
lvIdx := []int{}
|
||||
for _, line := range lines {
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key != "" && key == "Virtual Drive" {
|
||||
idx, _ := strconv.Atoi(strings.Split(val, " ")[0])
|
||||
lvIdx = append(lvIdx, idx)
|
||||
}
|
||||
}
|
||||
return lvIdx
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) BuildRaid(confs interface{}) bool {
|
||||
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) getTerm() *ssh.Client {
|
||||
return adapter.raid.term
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) remoteRun(cmds ...string) ([]string, error) {
|
||||
return adapter.getTerm().Run(cmds...)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) megacliIsJBODEnabled() bool {
|
||||
cmd := GetCommand("-AdpGetProp", "-EnableJBOD", fmt.Sprintf("-a%d", adapter.index))
|
||||
pref := fmt.Sprintf("Adapter %d: JBOD: ", adapter.index)
|
||||
lines, err := adapter.remoteRun(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("megacliIsJBODEnabled error: %v", err)
|
||||
return false
|
||||
}
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, pref) {
|
||||
val := strings.ToLower(strings.TrimSpace(line[len(pref):]))
|
||||
if val == "disabled" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) megacliEnableJBOD(enable bool) bool {
|
||||
var val string = "0"
|
||||
if enable {
|
||||
val = "1"
|
||||
}
|
||||
cmd := GetCommand("-AdpSetProp", "-EnableJBOD", fmt.Sprintf("-%s", val), fmt.Sprintf("-a%d", adapter.index))
|
||||
_, err := adapter.remoteRun(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("enable jbod %v fail: %v", enable, err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) megacliClearJBODDisks() error {
|
||||
devIds := []string{}
|
||||
for _, dev := range adapter.devs {
|
||||
devIds = append(devIds, dev.String())
|
||||
}
|
||||
cmd := GetCommand("-PDMakeGood", fmt.Sprintf("-PhysDrv[%s]", strings.Join(devIds, ",")), "-Force", fmt.Sprintf("-a%d", adapter.index))
|
||||
_, err := adapter.remoteRun(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) clearJBODDisks() {
|
||||
adapter.megacliEnableJBOD(true)
|
||||
adapter.megacliEnableJBOD(false)
|
||||
adapter.megacliEnableJBOD(true)
|
||||
adapter.megacliEnableJBOD(false)
|
||||
}
|
||||
|
||||
type MegaRaid struct {
|
||||
term *ssh.Client
|
||||
adapters []*MegaRaidAdaptor
|
||||
lv []interface{}
|
||||
PhyDevsCnt int
|
||||
Capacity int
|
||||
}
|
||||
|
||||
func GetCommand(args ...string) string {
|
||||
bin := "/opt/MegaRAID/MegaCli/MegaCli64"
|
||||
cmd := []string{bin}
|
||||
cmd = append(cmd, args...)
|
||||
return strings.Join(cmd, " ")
|
||||
}
|
||||
|
||||
func GetCommand2(args ...string) string {
|
||||
bin := "/opt/MegaRAID/storcli/storcli64"
|
||||
cmd := []string{bin}
|
||||
cmd = append(cmd, args...)
|
||||
return strings.Join(cmd, " ")
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) GetModules() []string {
|
||||
ret := []string{}
|
||||
lines, err := raid.term.Run("/sbin/lsmod")
|
||||
if err != nil {
|
||||
log.Errorf("Remote lsmod error: %v", err)
|
||||
return ret
|
||||
}
|
||||
for _, line := range lines {
|
||||
mod := line[:strings.Index(line, " ")]
|
||||
if mod != "Module" {
|
||||
ret = append(ret, mod)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) ParsePhyDevs() bool {
|
||||
if !utils.IsInStringArray("megaraid_sas", raid.GetModules()) {
|
||||
log.Warningf("Not found megaraid_sas module")
|
||||
return false
|
||||
}
|
||||
cmd := GetCommand("-PDList", "-aALL")
|
||||
ret, err := raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("List raid disk error: %v", err)
|
||||
return false
|
||||
}
|
||||
err := raid.parsePhyDevs(ret)
|
||||
if err != nil {
|
||||
log.Errorf("parse physical disk device error: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) parsePhyDevs(lines []string) error {
|
||||
phyDev := NewMegaRaidPhyDev()
|
||||
var adapter *MegaRaidAdaptor
|
||||
for _, line := range lines {
|
||||
matches := adapterPatter.FindStringSubmatch(line)
|
||||
if len(matches) != 0 {
|
||||
paramsMap := make(map[string]string)
|
||||
for i, name := range sizePattern.SubexpNames() {
|
||||
if i > 0 && i <= len(matches) {
|
||||
paramsMap[name] = matches[i]
|
||||
}
|
||||
}
|
||||
adapterStr := paramsMap["idx"]
|
||||
adapterInt, _ := strconv.Atoi(adapterStr)
|
||||
adapter = NewMegaRaidAdaptor(adapterInt, raid)
|
||||
raid.adapters = append(raid.adapters, adapter)
|
||||
} else if phyDev.parseLine(line) && phyDev.isComplete() {
|
||||
if adapter == nil {
|
||||
return fmt.Errorf("Adapter is nil")
|
||||
}
|
||||
adapter.AddPhyDev(phyDev)
|
||||
raid.PhyDevsCnt += 1
|
||||
raid.Capacity += phyDev.GetSize()
|
||||
phyDev = NewMegaRaidPhyDev()
|
||||
}
|
||||
}
|
||||
//map(self.add_phydev_strpsz, adapter.devs)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) addPhyDevStripSize(phyDev *MegaRaidPhyDev) bool {
|
||||
grepCmd := []string{"grep", "-iE", "'^(Min|Max) Strip Size'"}
|
||||
args := []string{"-adpallinfo", "-aall", "|"}
|
||||
args = append(args, grepCmd...)
|
||||
cmd := GetCommand(args...)
|
||||
ret, err := raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("addPhyDevStripSize error: %v", err)
|
||||
return false
|
||||
}
|
||||
return phyDev.parseStripSize(ret)
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) GetPhyDevs() []*MegaRaidPhyDev {
|
||||
devs := make([]*MegaRaidPhyDev, 0)
|
||||
for _, ada := range raid.adapters {
|
||||
devs = append(devs, ada.GetPhyDevs()...)
|
||||
}
|
||||
return devs
|
||||
}
|
||||
Reference in New Issue
Block a user