mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
baremetal: raid driver abstract
This commit is contained in:
@@ -29,6 +29,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/detect_storages"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/disktool"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
|
||||
raiddrivers "yunion.io/x/onecloud/pkg/baremetal/utils/raid/drivers"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/dhcp"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/sshkeys"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
@@ -1177,15 +1178,33 @@ func (s *SBaremetalServer) DoDiskConfig(term *ssh.Client) error {
|
||||
}
|
||||
layouts, err := baremetal.CalculateLayout(confs, storages)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("CalculateLayout: %v", err)
|
||||
}
|
||||
diskConfs := baremetal.GroupLayoutResultsByDriverAdapter(layouts)
|
||||
for _, dConf := range diskConfs {
|
||||
driver := dConf.Driver
|
||||
raidDrv := raiddrivers.GetDriver(driver, term)
|
||||
if raidDrv != nil {
|
||||
if err := raidDrv.ParsePhyDevs(); err != nil {
|
||||
return fmt.Errorf("RaidDriver %s parse physical devices: %v", raidDrv.GetName(), err)
|
||||
}
|
||||
raidDrv.CleanRaid()
|
||||
}
|
||||
}
|
||||
|
||||
for _, dConf := range diskConfs {
|
||||
driver := dConf.Driver
|
||||
adapter := dConf.Adapter
|
||||
//TODO: build raid here
|
||||
log.Errorf("=== driver: %s, adapter: %d", driver, adapter)
|
||||
time.Sleep(10 * time.Second) // wait 10 seconds for raid status OK
|
||||
raidDrv := raiddrivers.GetDriver(driver, term)
|
||||
if raidDrv != nil {
|
||||
if err := raidDrv.ParsePhyDevs(); err != nil {
|
||||
return fmt.Errorf("RaidDriver %s parse physical devices: %v", raidDrv.GetName(), err)
|
||||
}
|
||||
if err := raiddrivers.BuildRaid(raidDrv, dConf.Configs, adapter); err != nil {
|
||||
return fmt.Errorf("Build %s raid failed: %v", raidDrv.GetName(), err)
|
||||
}
|
||||
time.Sleep(10 * time.Second) // wait 10 seconds for raid status OK
|
||||
}
|
||||
}
|
||||
|
||||
tool := disktool.NewSSHPartitionTool(term)
|
||||
@@ -1209,11 +1228,14 @@ func (s *SBaremetalServer) DoDiskConfig(term *ssh.Client) error {
|
||||
|
||||
func (s *SBaremetalServer) DoDiskUnconfig(term *ssh.Client) error {
|
||||
// tear down raid
|
||||
//driver := s.baremetal.GetStorageDriver()
|
||||
//util := raidutil.GetDriver(driver, term)
|
||||
//if util != nil {
|
||||
//}
|
||||
// TODO:
|
||||
driver := s.baremetal.GetStorageDriver()
|
||||
raidDrv := raiddrivers.GetDriver(driver, term)
|
||||
if raidDrv != nil {
|
||||
if err := raidDrv.ParsePhyDevs(); err != nil {
|
||||
return err
|
||||
}
|
||||
raidDrv.CleanRaid()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -7,30 +7,57 @@ import (
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid/drivers"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/types"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
"yunion.io/x/onecloud/pkg/util/sysutils"
|
||||
)
|
||||
|
||||
func GetRaidDevices(drv raid.IRaidDriver) []*baremetal.BaremetalStorage {
|
||||
devs := make([]*baremetal.BaremetalStorage, 0)
|
||||
for _, ada := range drv.GetAdapters() {
|
||||
devs = append(devs, ada.GetDevices()...)
|
||||
}
|
||||
return devs
|
||||
}
|
||||
|
||||
func GetRaidLogicVolumes(drv raid.IRaidDriver) ([]int, error) {
|
||||
lvs := []int{}
|
||||
for _, adapter := range drv.GetAdapters() {
|
||||
lv, err := adapter.GetLogicVolumes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lvs = append(lvs, lv...)
|
||||
}
|
||||
return lvs, nil
|
||||
}
|
||||
|
||||
func DetectStorageInfo(term *ssh.Client, wait bool) ([]*baremetal.BaremetalStorage, []*baremetal.BaremetalStorage, []*baremetal.BaremetalStorage, error) {
|
||||
raidDiskInfo := make([]*baremetal.BaremetalStorage, 0)
|
||||
lvDiskInfo := make([]int, 0)
|
||||
|
||||
raidDrivers := []string{}
|
||||
for _, drv := range []raid.IRaidDriver{} {
|
||||
if drv.ParsePhyDevs() {
|
||||
raidDiskInfo = append(raidDiskInfo, drv.GetPhyDevs()...)
|
||||
raidDrivers = append(raidDrivers, drv.GetName())
|
||||
for _, drv := range drivers.GetDrivers(term) {
|
||||
if err := drv.ParsePhyDevs(); err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("ParsePhyDevs: %v", err)
|
||||
}
|
||||
raidDiskInfo = append(raidDiskInfo, GetRaidDevices(drv)...)
|
||||
raidDrivers = append(raidDrivers, drv.GetName())
|
||||
}
|
||||
|
||||
for _, drv := range []raid.IRaidDriver{} {
|
||||
if drv.ParsePhyDevs() {
|
||||
raidDiskInfo = append(raidDiskInfo, drv.GetPhyDevs()...)
|
||||
lvDiskInfo = append(lvDiskInfo, drv.GetLogicVolumes()...)
|
||||
raidDrivers = append(raidDrivers, drv.GetName())
|
||||
for _, drv := range drivers.GetDrivers(term) {
|
||||
if err := drv.ParsePhyDevs(); err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("ParsePhyDevs: %v", err)
|
||||
}
|
||||
raidDiskInfo = append(raidDiskInfo, GetRaidDevices(drv)...)
|
||||
lvs, err := GetRaidLogicVolumes(drv)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("GetRaidLogicVolumes: %v", err)
|
||||
}
|
||||
lvDiskInfo = append(lvDiskInfo, lvs...)
|
||||
raidDrivers = append(raidDrivers, drv.GetName())
|
||||
}
|
||||
|
||||
log.Infof("Get Raid drivers: %v", raidDrivers)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package drivers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
_ "yunion.io/x/onecloud/pkg/baremetal/utils/raid/hpssactl"
|
||||
_ "yunion.io/x/onecloud/pkg/baremetal/utils/raid/megactl"
|
||||
_ "yunion.io/x/onecloud/pkg/baremetal/utils/raid/mvcli"
|
||||
_ "yunion.io/x/onecloud/pkg/baremetal/utils/raid/sas2iru"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
func GetDriver(name string, term *ssh.Client) raid.IRaidDriver {
|
||||
factory := raid.RaidDrivers[name]
|
||||
if factory == nil {
|
||||
return nil
|
||||
}
|
||||
return factory(term)
|
||||
}
|
||||
|
||||
func GetDrivers(term *ssh.Client) []raid.IRaidDriver {
|
||||
ret := []raid.IRaidDriver{}
|
||||
for _, factory := range raid.RaidDrivers {
|
||||
ret = append(ret, factory(term))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func BuildRaid(driver raid.IRaidDriver, confs []*baremetal.BaremetalDiskConfig, adapterIdx int) error {
|
||||
if err := driver.PreBuildRaid(confs, adapterIdx); err != nil {
|
||||
return fmt.Errorf("PreBuildRaid: %v", err)
|
||||
}
|
||||
var adapter raid.IRaidAdapter
|
||||
for _, tmp := range driver.GetAdapters() {
|
||||
if tmp.GetIndex() == adapterIdx {
|
||||
adapter = tmp
|
||||
break
|
||||
}
|
||||
}
|
||||
if adapter == nil {
|
||||
return fmt.Errorf("Not found adapter by index %d", adapterIdx)
|
||||
}
|
||||
if err := buildRaid(adapter, confs); err != nil {
|
||||
return fmt.Errorf("Driver %s, adapter %d build raid: %v", driver.GetName(), adapterIdx, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildRaid(adapter raid.IRaidAdapter, confs []*baremetal.BaremetalDiskConfig) error {
|
||||
if err := adapter.PreBuildRaid(confs); err != nil {
|
||||
return fmt.Errorf("PreBuildRaid: %v", err)
|
||||
}
|
||||
if err := adapter.RemoveLogicVolumes(); err != nil {
|
||||
return fmt.Errorf("RemoveLogicVolumes: %v", err)
|
||||
}
|
||||
devs := adapter.GetDevices()
|
||||
if len(devs) == 0 {
|
||||
// no disk to build
|
||||
return nil
|
||||
}
|
||||
|
||||
var selected []*baremetal.BaremetalStorage
|
||||
var nonDisks []*baremetal.BaremetalStorage
|
||||
left := devs
|
||||
|
||||
for _, conf := range confs {
|
||||
selected, left = baremetal.RetrieveStorages(conf, left)
|
||||
if len(selected) == 0 {
|
||||
return fmt.Errorf("No enough disks for config %#v", conf)
|
||||
}
|
||||
var err error
|
||||
switch conf.Conf {
|
||||
case baremetal.DISK_CONF_RAID5:
|
||||
err = adapter.BuildRaid5(selected, conf)
|
||||
case baremetal.DISK_CONF_RAID10:
|
||||
err = adapter.BuildRaid10(selected, conf)
|
||||
case baremetal.DISK_CONF_NONE:
|
||||
nonDisks = append(nonDisks, selected...)
|
||||
case baremetal.DISK_CONF_RAID0:
|
||||
err = adapter.BuildRaid0(selected, conf)
|
||||
case baremetal.DISK_CONF_RAID1:
|
||||
err = adapter.BuildRaid1(selected, conf)
|
||||
default:
|
||||
return fmt.Errorf("Unknown raid config %s", conf.Conf)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("Build raid %s: %v", conf.Conf, err)
|
||||
}
|
||||
if len(nonDisks) > 0 {
|
||||
if err := adapter.BuildNoneRaid(nonDisks, conf); err != nil {
|
||||
return fmt.Errorf("Build raw disks: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
package hpssactl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/util/stringutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/regutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type HPSARaidPhyDev struct {
|
||||
*raid.RaidBasePhyDev
|
||||
addr string
|
||||
}
|
||||
|
||||
func newHPSARaidPhyDev(addr string, adapter int, rotate bool) *HPSARaidPhyDev {
|
||||
b := raid.NewRaidBasePhyDev(baremetal.DISK_DRIVER_HPSARAID)
|
||||
b.Adapter = adapter
|
||||
return &HPSARaidPhyDev{
|
||||
RaidBasePhyDev: b,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
func (dev *HPSARaidPhyDev) ToBaremetalStorage() *baremetal.BaremetalStorage {
|
||||
s := dev.RaidBasePhyDev.ToBaremetalStorage()
|
||||
s.Addr = dev.addr
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (dev *HPSARaidPhyDev) parseLine(line string) bool {
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
switch key {
|
||||
case "Size":
|
||||
dat := strings.Split(val, " ")
|
||||
szStr, unitStr := dat[0], dat[1]
|
||||
var sz int64
|
||||
szF, err := strconv.ParseFloat(szStr, 64)
|
||||
if err != nil {
|
||||
log.Errorf("Parse size string %s: %v", szStr, err)
|
||||
return false
|
||||
}
|
||||
switch unitStr {
|
||||
case "GB":
|
||||
sz = int64(szF * 1000 * 1000 * 1000)
|
||||
case "TB":
|
||||
sz = int64(szF * 1000 * 1000 * 1000 * 1000)
|
||||
case "MB":
|
||||
sz = int64(szF * 1000 * 1000)
|
||||
default:
|
||||
log.Errorf("Unsupported unit: %s", unitStr)
|
||||
return false
|
||||
}
|
||||
dev.Size = sz / 1024 / 1024
|
||||
case "Model":
|
||||
dev.Model = strings.Join(regexp.MustCompile(`\s+`).Split(val, -1), " ")
|
||||
case "Status":
|
||||
dev.Status = val
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *HPSARaidPhyDev) isComplete() bool {
|
||||
if !dev.RaidBasePhyDev.IsComplete() {
|
||||
return false
|
||||
}
|
||||
if dev.Size < 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func GetSpecString(dev *baremetal.BaremetalStorage) string {
|
||||
return dev.Addr
|
||||
}
|
||||
|
||||
type HPSARaidAdaptor struct {
|
||||
index int
|
||||
raid *HPSARaid
|
||||
devs []*HPSARaidPhyDev
|
||||
}
|
||||
|
||||
func newHPSARaidAdaptor(index int, raid *HPSARaid) *HPSARaidAdaptor {
|
||||
return &HPSARaidAdaptor{
|
||||
index: index,
|
||||
raid: raid,
|
||||
}
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) GetIndex() int {
|
||||
return adapter.index
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) PreBuildRaid(confs []*baremetal.BaremetalDiskConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) ParsePhyDevs() error {
|
||||
parseByCmd := func(cmd string, isRotate bool) error {
|
||||
ret, err := adapter.raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
adapter.parsePhyDevs(ret, isRotate)
|
||||
return nil
|
||||
}
|
||||
cmd1 := GetCommand("controller", "slot=%d", fmt.Sprintf("%d", adapter.index), "ssdphysicaldrive", "all", "show", "detail")
|
||||
cmd2 := GetCommand("controller", "slot=%d", fmt.Sprintf("%d", adapter.index), "physicaldrive", "all", "show", "detail")
|
||||
var err error
|
||||
if err = parseByCmd(cmd1, false); err != nil {
|
||||
log.Errorf("parsePhyDevs by cmd %q: %v", cmd1, err)
|
||||
}
|
||||
if err = parseByCmd(cmd2, true); err != nil {
|
||||
log.Errorf("parsePhyDevs by cmd %q: %v", cmd1, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) parsePhyDevs(lines []string, isRotate bool) {
|
||||
var phydev *HPSARaidPhyDev
|
||||
for _, line := range lines {
|
||||
m := regutils2.SubGroupMatch(`physicaldrive\s+(?P<addr>\w+:\w+:\w)`, line)
|
||||
if len(m) != 0 {
|
||||
phydev = newHPSARaidPhyDev(m["addr"], adapter.index, isRotate)
|
||||
} else if phydev != nil && phydev.parseLine(line) && phydev.isComplete() {
|
||||
oldDev := adapter.getPhyDevByAddr(phydev.addr)
|
||||
if oldDev != nil {
|
||||
adapter.devs = append(adapter.devs, phydev)
|
||||
}
|
||||
phydev = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) getPhyDevByAddr(addr string) *HPSARaidPhyDev {
|
||||
for _, dev := range adapter.devs {
|
||||
if addr == dev.addr {
|
||||
return dev
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) GetDevices() []*baremetal.BaremetalStorage {
|
||||
ret := []*baremetal.BaremetalStorage{}
|
||||
for _, dev := range adapter.devs {
|
||||
ret = append(ret, dev.ToBaremetalStorage())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) conf2Params(conf *baremetal.BaremetalDiskConfig) []string {
|
||||
params := []string{}
|
||||
if conf.Direct != nil {
|
||||
if *(conf.Direct) {
|
||||
params = append(params, "caching=disable")
|
||||
} else {
|
||||
params = append(params, "caching=enable")
|
||||
}
|
||||
}
|
||||
if conf.Strip != nil {
|
||||
params = append(params, fmt.Sprintf("stripsize=%d", *(conf.Strip)))
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) getLastArray() (string, error) {
|
||||
cmd := GetCommand("controller", fmt.Sprintf("slot=%d", adapter.index), "logicaldrive", "all", "show")
|
||||
ret, err := adapter.raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var lastArray string
|
||||
for _, line := range ret {
|
||||
m := regutils2.SubGroupMatch(`array\s+(?P<idx>\w+)`, line)
|
||||
if len(m) > 0 {
|
||||
lastArray = m["idx"]
|
||||
return lastArray, nil
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) buildRaid(level string, devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
labels := []string{}
|
||||
for _, dev := range devs {
|
||||
labels = append(labels, fmt.Sprintf("%s", GetSpecString(dev)))
|
||||
}
|
||||
args := []string{
|
||||
"controller", fmt.Sprintf("slot=%d", adapter.GetIndex()),
|
||||
"create", "type=ld", fmt.Sprintf("drives=%s", strings.Join(labels, ",")),
|
||||
fmt.Sprintf("raid=%s", level),
|
||||
}
|
||||
if len(conf.Size) > 0 {
|
||||
args = append(args, fmt.Sprintf("size=%d", conf.Size[0]))
|
||||
}
|
||||
params := adapter.conf2Params(conf)
|
||||
args = append(args, params...)
|
||||
cmd := GetCommand(args...)
|
||||
_, err := adapter.raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(conf.Size) > 0 {
|
||||
array, err := adapter.getLastArray()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getLastArray: %v", err)
|
||||
}
|
||||
cmds := []string{}
|
||||
for _, sz := range conf.Size[1:] {
|
||||
args = []string{"controller", fmt.Sprintf("slot=%d", adapter.index),
|
||||
"array", array, "create", "type=ld",
|
||||
fmt.Sprintf("raid=%s", level),
|
||||
fmt.Sprintf("size=%d", sz),
|
||||
}
|
||||
args = append(args, params...)
|
||||
cmds = append(cmds, GetCommand(args...))
|
||||
}
|
||||
_, err = adapter.raid.term.Run(cmds...)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) BuildRaid0(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("0", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) BuildRaid1(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("1", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("5", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("10", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
for _, d := range devs {
|
||||
// WT|WB] [NORA|RA] [Direct|Cached] [CachedBadBBU|NoCachedBadBBU]
|
||||
useWT := true
|
||||
useDirect := true
|
||||
if err := adapter.buildRaid("0", []*baremetal.BaremetalStorage{d}, &baremetal.BaremetalDiskConfig{WT: &useWT, Direct: &useDirect}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) removeLogicVolume(idx int) error {
|
||||
cmd := GetCommand("controller", fmt.Sprintf("slot=%d", adapter.index, "logicaldrive",
|
||||
fmt.Sprintf("%d", idx), "delete", "forced",
|
||||
))
|
||||
_, err := adapter.raid.term.Run(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) GetLogicVolumes() ([]int, error) {
|
||||
cmd := GetCommand("controller", fmt.Sprintf("slot=%d", adapter.index), "logicaldrive", "all", "show")
|
||||
ret, err := adapter.raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adapter.parseLogicalVolumes(ret)
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) parseLogicalVolumes(lines []string) ([]int, error) {
|
||||
lvs := []int{}
|
||||
for _, line := range lines {
|
||||
m := regutils2.SubGroupMatch(`logicaldrive\s+(?P<addr>\w+)`, line)
|
||||
if len(m) > 0 {
|
||||
idxStr := m["addr"]
|
||||
idx, err := strconv.Atoi(idxStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s not int: %v", idxStr, err)
|
||||
}
|
||||
lvs = append(lvs, idx)
|
||||
}
|
||||
}
|
||||
return lvs, nil
|
||||
}
|
||||
|
||||
func (adapter *HPSARaidAdaptor) RemoveLogicVolumes() error {
|
||||
lvs, err := adapter.GetLogicVolumes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get logic volumes: %v", err)
|
||||
}
|
||||
for i := len(lvs) - 1; i >= 0; i-- {
|
||||
if err := adapter.removeLogicVolume(i); err != nil {
|
||||
return fmt.Errorf("Remove %d logical volume: %v", i, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type HPSARaid struct {
|
||||
term *ssh.Client
|
||||
adapters []*HPSARaidAdaptor
|
||||
}
|
||||
|
||||
func NewHPSARaid(term *ssh.Client) raid.IRaidDriver {
|
||||
return &HPSARaid{
|
||||
term: term,
|
||||
adapters: make([]*HPSARaidAdaptor, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HPSARaid) ParsePhyDevs() error {
|
||||
if !utils.IsInStringArray("hpsa", raid.GetModules(r.term)) {
|
||||
return fmt.Errorf("Not found hpsa module")
|
||||
}
|
||||
cmd := GetCommand("controller", "all", "show")
|
||||
ret, err := r.term.Run(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.parsePhyDevs(ret)
|
||||
}
|
||||
|
||||
func (r *HPSARaid) parsePhyDevs(lines []string) error {
|
||||
for _, line := range lines {
|
||||
m := regutils2.SubGroupMatch(`\s+Slot\s+(?P<idx>[0-9]+)\s+`, line)
|
||||
if len(m) > 0 {
|
||||
idxStr := m["idx"]
|
||||
idx, err := strconv.Atoi(idxStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
adapter := newHPSARaidAdaptor(idx, r)
|
||||
r.adapters = append(r.adapters, adapter)
|
||||
}
|
||||
}
|
||||
for _, a := range r.adapters {
|
||||
if err := a.ParsePhyDevs(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *HPSARaid) PreBuildRaid(_ []*baremetal.BaremetalDiskConfig, _ int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *HPSARaid) GetAdapters() []raid.IRaidAdapter {
|
||||
ret := make([]raid.IRaidAdapter, 0)
|
||||
for _, a := range r.adapters {
|
||||
ret = append(ret, a)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *HPSARaid) GetName() string {
|
||||
return baremetal.DISK_DRIVER_HPSARAID
|
||||
}
|
||||
|
||||
func (r *HPSARaid) CleanRaid() error {
|
||||
// pass
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetCommand(args ...string) string {
|
||||
bin := "/opt/hp/hpssacli/bld/hpssacli"
|
||||
return raid.GetCommand(bin, args...)
|
||||
}
|
||||
|
||||
func init() {
|
||||
raid.RegisterDriver(baremetal.DISK_DRIVER_HPSARAID, NewHPSARaid)
|
||||
}
|
||||
@@ -5,8 +5,24 @@ import (
|
||||
)
|
||||
|
||||
type IRaidDriver interface {
|
||||
ParsePhyDevs() bool
|
||||
GetPhyDevs() []*baremetal.BaremetalStorage
|
||||
GetLogicVolumes() []int
|
||||
ParsePhyDevs() error
|
||||
GetName() string
|
||||
GetAdapters() []IRaidAdapter
|
||||
PreBuildRaid(confs []*baremetal.BaremetalDiskConfig, adapterIdx int) error
|
||||
|
||||
CleanRaid() error
|
||||
}
|
||||
|
||||
type IRaidAdapter interface {
|
||||
GetIndex() int
|
||||
PreBuildRaid(confs []*baremetal.BaremetalDiskConfig) error
|
||||
GetLogicVolumes() ([]int, error)
|
||||
RemoveLogicVolumes() error
|
||||
GetDevices() []*baremetal.BaremetalStorage
|
||||
|
||||
BuildRaid0(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error
|
||||
BuildRaid1(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error
|
||||
BuildRaid5(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error
|
||||
BuildRaid10(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error
|
||||
BuildNoneRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package megactl
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -12,7 +11,7 @@ import (
|
||||
"yunion.io/x/pkg/util/stringutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
raiddrivers "yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
@@ -23,34 +22,42 @@ var (
|
||||
)
|
||||
|
||||
type MegaRaidPhyDev struct {
|
||||
*raiddrivers.RaidBasePhyDev
|
||||
|
||||
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,
|
||||
RaidBasePhyDev: raiddrivers.NewRaidBasePhyDev(baremetal.DISK_DRIVER_MEGARAID),
|
||||
enclosure: -1,
|
||||
slot: -1,
|
||||
minStripSize: -1,
|
||||
maxStripSize: -1,
|
||||
sector: -1,
|
||||
block: 512,
|
||||
}
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) GetSize() int {
|
||||
return dev.sector * dev.block / 1024 / 1024 // MB
|
||||
func (dev *MegaRaidPhyDev) ToBaremetalStorage() *baremetal.BaremetalStorage {
|
||||
s := dev.RaidBasePhyDev.ToBaremetalStorage()
|
||||
s.Enclosure = dev.enclosure
|
||||
s.Slot = dev.slot
|
||||
s.Size = dev.GetSize()
|
||||
s.MinStripSize = int64(dev.minStripSize)
|
||||
s.MaxStripSize = int64(dev.maxStripSize)
|
||||
s.Block = dev.block
|
||||
s.Sector = dev.sector
|
||||
return s
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) GetSize() int64 {
|
||||
return int64(dev.sector * dev.block / 1024 / 1024) // MB
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) parseLine(line string) bool {
|
||||
@@ -61,9 +68,9 @@ func (dev *MegaRaidPhyDev) parseLine(line string) bool {
|
||||
switch key {
|
||||
case "Media Type":
|
||||
if val == "Hard Disk Device" {
|
||||
dev.rotate = tristate.True
|
||||
dev.Rotate = tristate.True
|
||||
} else {
|
||||
dev.rotate = tristate.False
|
||||
dev.Rotate = tristate.False
|
||||
}
|
||||
case "Enclosure Device ID":
|
||||
enclosure, err := strconv.Atoi(val)
|
||||
@@ -91,14 +98,14 @@ func (dev *MegaRaidPhyDev) parseLine(line string) bool {
|
||||
dev.sector = 0
|
||||
}
|
||||
case "Inquiry Data":
|
||||
dev.model = strings.Join(regexp.MustCompile(`\s+`).Split(val, -1), " ")
|
||||
dev.Model = strings.Join(regexp.MustCompile(`\s+`).Split(val, -1), " ")
|
||||
case "Firmware state":
|
||||
if val == "JBOD" {
|
||||
dev.status = "jbod"
|
||||
dev.Status = "jbod"
|
||||
} else if strings.Contains(strings.ToLower(val), "online") {
|
||||
dev.status = "online"
|
||||
dev.Status = "online"
|
||||
} else {
|
||||
dev.status = "offline"
|
||||
dev.Status = "offline"
|
||||
}
|
||||
case "Logical Sector Size":
|
||||
block, err := strconv.Atoi(val)
|
||||
@@ -108,11 +115,13 @@ func (dev *MegaRaidPhyDev) parseLine(line string) bool {
|
||||
} else {
|
||||
dev.block = block
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) parseStripSize(lines []string) bool {
|
||||
func (dev *MegaRaidPhyDev) parseStripSize(lines []string) error {
|
||||
size2Int := func(sizeStr string) int {
|
||||
// TODO
|
||||
return -1
|
||||
@@ -125,11 +134,11 @@ func (dev *MegaRaidPhyDev) parseStripSize(lines []string) bool {
|
||||
dev.maxStripSize = size2Int(strings.Split(line, ": ")[1])
|
||||
}
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) isComplete() bool {
|
||||
if dev.model == "" {
|
||||
if !dev.RaidBasePhyDev.IsComplete() {
|
||||
return false
|
||||
}
|
||||
if dev.sector < 0 {
|
||||
@@ -141,31 +150,24 @@ func (dev *MegaRaidPhyDev) isComplete() bool {
|
||||
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"
|
||||
return dev.Status == "jbod"
|
||||
}
|
||||
|
||||
func (dev *MegaRaidPhyDev) String() string {
|
||||
if dev.enclosure < 0 {
|
||||
return fmt.Sprintf(":%d", dev.slot)
|
||||
func GetSpecString(dev *baremetal.BaremetalStorage) string {
|
||||
if dev.Enclosure < 0 {
|
||||
return fmt.Sprintf(":%d", dev.Slot)
|
||||
}
|
||||
return fmt.Sprintf("%d:%d", dev.enclosure, dev.slot)
|
||||
return fmt.Sprintf("%d:%d", dev.Enclosure, dev.Slot)
|
||||
}
|
||||
|
||||
type MegaRaidAdaptor struct {
|
||||
index int
|
||||
raid *MegaRaid
|
||||
devs []*baremetal.BaremetalStorage
|
||||
lvs []interface{}
|
||||
devs []*MegaRaidPhyDev
|
||||
}
|
||||
|
||||
func NewMegaRaidAdaptor(index int, raid *MegaRaid) *MegaRaidAdaptor {
|
||||
@@ -175,6 +177,10 @@ func NewMegaRaidAdaptor(index int, raid *MegaRaid) *MegaRaidAdaptor {
|
||||
}
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) GetIndex() int {
|
||||
return adapter.index
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) getTerm() *ssh.Client {
|
||||
return adapter.raid.term
|
||||
}
|
||||
@@ -184,21 +190,25 @@ func (adapter *MegaRaidAdaptor) remoteRun(cmds ...string) ([]string, error) {
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) AddPhyDev(dev *MegaRaidPhyDev) {
|
||||
dev.adapter = adapter.index
|
||||
dev.Adapter = adapter.index
|
||||
adapter.devs = append(adapter.devs, dev)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) GetPhyDevs() []*MegaRaidPhyDev {
|
||||
return adapter.devs
|
||||
func (adapter *MegaRaidAdaptor) GetDevices() []*baremetal.BaremetalStorage {
|
||||
ret := []*baremetal.BaremetalStorage{}
|
||||
for _, dev := range adapter.devs {
|
||||
ret = append(ret, dev.ToBaremetalStorage())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) getLogicVolumes() []int {
|
||||
func (adapter *MegaRaidAdaptor) GetLogicVolumes() ([]int, error) {
|
||||
cmd := GetCommand("-LDInfo", "-Lall", fmt.Sprintf("-a%d", adapter.index))
|
||||
ret, err := adapter.remoteRun(cmd)
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, fmt.Errorf("GetLogicVolumes error: %v", err)
|
||||
}
|
||||
return adapter.parseLogicVolumes(ret)
|
||||
return adapter.parseLogicVolumes(ret), nil
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) parseLogicVolumes(lines []string) []int {
|
||||
@@ -213,31 +223,9 @@ func (adapter *MegaRaidAdaptor) parseLogicVolumes(lines []string) []int {
|
||||
return lvIdx
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) BuildRaid(confs []*baremetal.BaremetalDiskConfig) bool {
|
||||
func (adapter *MegaRaidAdaptor) PreBuildRaid(confs []*baremetal.BaremetalDiskConfig) error {
|
||||
adapter.clearJBODDisks()
|
||||
if !adapter.removeLogicVolumes() {
|
||||
return false
|
||||
}
|
||||
if len(adapter.devs) == 0 {
|
||||
// no disk to build
|
||||
return true
|
||||
}
|
||||
var left []*baremetal.BaremetalStorage = adapter.devs
|
||||
var selected []*baremetal.BaremetalStorage
|
||||
for _, conf := range confs {
|
||||
selected, left = baremetal.RetrieveStorages(conf, left)
|
||||
if len(selected) == 0 {
|
||||
log.Errorf("No enough disks for config %#v", conf)
|
||||
return false
|
||||
}
|
||||
result := true
|
||||
switch conf.Conf {
|
||||
case baremetal.DISK_CONF_RAID5:
|
||||
result = adapter.buildRaid(selected, conf, "5")
|
||||
case baremetal.DISK_CONF_RAID10:
|
||||
result = adapter.buildRaid(selected, conf, "10")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) conf2ParamsStorcliSize(conf *baremetal.BaremetalDiskConfig) []string {
|
||||
@@ -329,35 +317,35 @@ func conf2Params(conf *baremetal.BaremetalDiskConfig) []string {
|
||||
return params
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _storcliBuildRaid0(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter._storcliBuildRaid(devs, conf, 0)
|
||||
func (adapter *MegaRaidAdaptor) storcliBuildRaid0(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.storcliBuildRaid(devs, conf, 0)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _megacliBuildRaid0(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter._megacliBuildRaid(devs, conf, 0)
|
||||
func (adapter *MegaRaidAdaptor) megacliBuildRaid0(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.megacliBuildRaid(devs, conf, 0)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _storcliBuildRaid1(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter._storcliBuildRaid(devs, conf, 1)
|
||||
func (adapter *MegaRaidAdaptor) storcliBuildRaid1(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.storcliBuildRaid(devs, conf, 1)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _megacliBuildRaid1(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter._megacliBuildRaid(devs, conf, 1)
|
||||
func (adapter *MegaRaidAdaptor) megacliBuildRaid1(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.megacliBuildRaid(devs, conf, 1)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _storcliBuildRaid5(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter._storcliBuildRaid(devs, conf, 5)
|
||||
func (adapter *MegaRaidAdaptor) storcliBuildRaid5(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.storcliBuildRaid(devs, conf, 5)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _megacliBuildRaid5(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter._megacliBuildRaid(devs, conf, 5)
|
||||
func (adapter *MegaRaidAdaptor) megacliBuildRaid5(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.megacliBuildRaid(devs, conf, 5)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _storcliBuildRaid10(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter._storcliBuildRaid(devs, conf, 10)
|
||||
func (adapter *MegaRaidAdaptor) storcliBuildRaid10(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.storcliBuildRaid(devs, conf, 10)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _megacliBuildRaid10(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
func (adapter *MegaRaidAdaptor) megacliBuildRaid10(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
if len(devs)%2 != 0 {
|
||||
return fmt.Errorf("Odd number of %d devs", len(devs))
|
||||
}
|
||||
@@ -365,26 +353,26 @@ func (adapter *MegaRaidAdaptor) _megacliBuildRaid10(devs []*baremtal.BaremetalSt
|
||||
params := []string{}
|
||||
for i := 0; i < devCnt; i++ {
|
||||
d1 := devs[i]
|
||||
d2 = devs[i+devCnt]
|
||||
params = append(params, fmt.Sprintf("-Array%d[%s,%s]", i, d1.String(), d2.String()))
|
||||
d2 := devs[i+devCnt]
|
||||
params = append(params, fmt.Sprintf("-Array%d[%s,%s]", i, GetSpecString(d1), GetSpecString(d2)))
|
||||
}
|
||||
args = []string{"-CfgSpanAdd", "-r10"}
|
||||
args := []string{"-CfgSpanAdd", "-r10"}
|
||||
args = append(args, params...)
|
||||
args = append(args, conf2Params(conf))
|
||||
args = append(args, conf2Params(conf)...)
|
||||
args = append(args, fmt.Sprintf("-a%d", adapter.index))
|
||||
cmd := GetCommand(args...)
|
||||
_, err := adapter.remoteRun(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _storcliBuildRaid(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig, level uint) error {
|
||||
func (adapter *MegaRaidAdaptor) storcliBuildRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig, level uint) error {
|
||||
args := []string{}
|
||||
args = append(args, fmt.Sprintf("/c%d", adapter.index))
|
||||
args = append(args, "add", "vd", fmt.Sprintf("type=r%d", level))
|
||||
args = append(args, adapter.conf2ParamsStorcliSize(conf)...)
|
||||
labels := []string{}
|
||||
for _, dev := range devs {
|
||||
labels = append(labels, dev.String())
|
||||
labels = append(labels, GetSpecString(dev))
|
||||
}
|
||||
args = append(args, fmt.Sprintf("drives=%s", strings.Join(labels, ",")))
|
||||
if level == 10 {
|
||||
@@ -397,10 +385,10 @@ func (adapter *MegaRaidAdaptor) _storcliBuildRaid(devs []*baremtal.BaremetalStor
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) _megacliBuildRaid(devs []*baremtal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig, level uint) error {
|
||||
func (adapter *MegaRaidAdaptor) megacliBuildRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig, level uint) error {
|
||||
labels := []string{}
|
||||
for _, dev := range devs {
|
||||
labels = append(labels, dev.String())
|
||||
labels = append(labels, GetSpecString(dev))
|
||||
}
|
||||
args := []string{"-CfgLdAdd", fmt.Sprintf("-r%d", level), fmt.Sprintf("[%s]", strings.Join(labels, ","))}
|
||||
args = append(args, conf2Params(conf)...)
|
||||
@@ -411,8 +399,39 @@ func (adapter *MegaRaidAdaptor) _megacliBuildRaid(devs []*baremtal.BaremetalStor
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) buildRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig, level string) bool {
|
||||
func cliBuildRaid(
|
||||
devs []*baremetal.BaremetalStorage,
|
||||
conf *baremetal.BaremetalDiskConfig,
|
||||
funcs ...func([]*baremetal.BaremetalStorage, *baremetal.BaremetalDiskConfig) error,
|
||||
) error {
|
||||
var err error
|
||||
for _, f := range funcs {
|
||||
err = f(devs, conf)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) BuildRaid0(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return cliBuildRaid(devs, conf, adapter.megacliBuildRaid0, adapter.storcliBuildRaid0)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) BuildRaid1(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return cliBuildRaid(devs, conf, adapter.megacliBuildRaid1, adapter.storcliBuildRaid1)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return cliBuildRaid(devs, conf, adapter.megacliBuildRaid5, adapter.storcliBuildRaid5)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return cliBuildRaid(devs, conf, adapter.megacliBuildRaid10, adapter.storcliBuildRaid10)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return cliBuildRaid(devs, conf, adapter.megacliBuildNoRaid, adapter.storcliBuildNoRaid)
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) storcliIsJBODEnabled() bool {
|
||||
@@ -460,7 +479,7 @@ func (adapter *MegaRaidAdaptor) storcliBuildJBOD(devs []*baremetal.BaremetalStor
|
||||
}
|
||||
cmds := []string{}
|
||||
for _, d := range devs {
|
||||
cmd := GetCommand2(fmt.Sprintf("/c%d/e%s/s%d", adapter.index, d.Enclosure, d.Slot))
|
||||
cmd := GetCommand2(fmt.Sprintf("/c%d/e%d/s%d", adapter.index, d.Enclosure, d.Slot))
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
log.Infof("storcliBuildJBOD cmds: %v", cmds)
|
||||
@@ -479,7 +498,7 @@ func (adapter *MegaRaidAdaptor) storcliBuildNoRaid(devs []*baremetal.BaremetalSt
|
||||
log.Errorf("Try build JBOD fail: %v", err)
|
||||
labels := []string{}
|
||||
for _, dev := range devs {
|
||||
labels = append(labels, dev.String())
|
||||
labels = append(labels, GetSpecString(dev))
|
||||
}
|
||||
args := []string{
|
||||
fmt.Sprintf("/c%d", adapter.index),
|
||||
@@ -493,15 +512,16 @@ func (adapter *MegaRaidAdaptor) storcliBuildNoRaid(devs []*baremetal.BaremetalSt
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) megacliBuildNoRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
err := adapter.megacliBuildJBOD()
|
||||
err := adapter.megacliBuildJBOD(devs)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
log.Errorf("Try build jbod fail: %v", err)
|
||||
cmds := []string{}
|
||||
for _, d := range devs {
|
||||
cmd = GetCommand("-CfgLdAdd", "-r0", fmt.Sprintf("[%s]", d.String()),
|
||||
for _, dev := range devs {
|
||||
cmd := GetCommand("-CfgLdAdd", "-r0", fmt.Sprintf("[%s]", GetSpecString(dev)),
|
||||
"WT", "NORA", "Direct", "NoCachedBadBBU", fmt.Sprintf("-a%d", adapter.index))
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
_, err = adapter.remoteRun(cmds...)
|
||||
return err
|
||||
@@ -552,16 +572,19 @@ func (adapter *MegaRaidAdaptor) megacliBuildJBOD(devs []*baremetal.BaremetalStor
|
||||
}
|
||||
devIds := []string{}
|
||||
for _, d := range devs {
|
||||
devIds = append(devIds, fmt.Sprintf("%s", d.String()))
|
||||
devIds = append(devIds, GetSpecString(d))
|
||||
}
|
||||
cmd = GetCommand("-PDMakeJBOD", fmt.Sprintf("-PhysDrv[%s]", strings.Join(devIds, ",")), fmt.Sprintf("-a%d", adapter.index))
|
||||
cmd := GetCommand("-PDMakeJBOD", fmt.Sprintf("-PhysDrv[%s]", strings.Join(devIds, ",")), fmt.Sprintf("-a%d", adapter.index))
|
||||
_, err := adapter.remoteRun(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *MegaRaidAdaptor) removeLogicVolumes() bool {
|
||||
func (adapter *MegaRaidAdaptor) RemoveLogicVolumes() error {
|
||||
cmds := []string{}
|
||||
lvIdx := adapter.getLogicVolumes()
|
||||
lvIdx, err := adapter.GetLogicVolumes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i := len(lvIdx) - 1; i >= 0; i-- {
|
||||
cmd := GetCommand("-CfgLdDel", fmt.Sprintf("-L%d", i), "-Force", fmt.Sprintf("-a%d", adapter.index))
|
||||
cmds = append(cmds, cmd)
|
||||
@@ -569,11 +592,11 @@ func (adapter *MegaRaidAdaptor) removeLogicVolumes() bool {
|
||||
if len(cmds) > 0 {
|
||||
_, err := adapter.remoteRun(cmds...)
|
||||
if err != nil {
|
||||
return false
|
||||
return err
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -591,7 +614,7 @@ def _storcli_clear_jbod_disks(self):
|
||||
func (adapter *MegaRaidAdaptor) megacliClearJBODDisks() error {
|
||||
devIds := []string{}
|
||||
for _, dev := range adapter.devs {
|
||||
devIds = append(devIds, dev.String())
|
||||
devIds = append(devIds, GetSpecString(dev.ToBaremetalStorage()))
|
||||
}
|
||||
cmd := GetCommand("-PDMakeGood", fmt.Sprintf("-PhysDrv[%s]", strings.Join(devIds, ",")), "-Force", fmt.Sprintf("-a%d", adapter.index))
|
||||
_, err := adapter.remoteRun(cmd)
|
||||
@@ -608,54 +631,45 @@ func (adapter *MegaRaidAdaptor) clearJBODDisks() {
|
||||
type MegaRaid struct {
|
||||
term *ssh.Client
|
||||
adapters []*MegaRaidAdaptor
|
||||
lv []interface{}
|
||||
PhyDevsCnt int
|
||||
Capacity int
|
||||
Capacity int64
|
||||
}
|
||||
|
||||
func NewMegaRaid(term *ssh.Client) raiddrivers.IRaidDriver {
|
||||
return &MegaRaid{
|
||||
term: term,
|
||||
adapters: make([]*MegaRaidAdaptor, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func GetCommand(args ...string) string {
|
||||
bin := "/opt/MegaRAID/MegaCli/MegaCli64"
|
||||
return raid.GetCommand(bin, args...)
|
||||
return raiddrivers.GetCommand(bin, args...)
|
||||
}
|
||||
|
||||
func GetCommand2(args ...string) string {
|
||||
bin := "/opt/MegaRAID/storcli/storcli64"
|
||||
return raid.GetCommand(bin, args...)
|
||||
return raiddrivers.GetCommand(bin, args...)
|
||||
}
|
||||
|
||||
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) GetName() string {
|
||||
return baremetal.DISK_DRIVER_MEGARAID
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) ParsePhyDevs() bool {
|
||||
if !utils.IsInStringArray("megaraid_sas", raid.GetModules()) {
|
||||
log.Warningf("Not found megaraid_sas module")
|
||||
return false
|
||||
func (raid *MegaRaid) ParsePhyDevs() error {
|
||||
if !utils.IsInStringArray("megaraid_sas", raiddrivers.GetModules(raid.term)) {
|
||||
return fmt.Errorf("Not found megaraid_sas module")
|
||||
}
|
||||
cmd := GetCommand("-PDList", "-aALL")
|
||||
ret, err := raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("List raid disk error: %v", err)
|
||||
return false
|
||||
return fmt.Errorf("List raid disk error: %v", err)
|
||||
}
|
||||
err := raid.parsePhyDevs(ret)
|
||||
err = raid.parsePhyDevs(ret)
|
||||
if err != nil {
|
||||
log.Errorf("parse physical disk device error: %v", err)
|
||||
return false
|
||||
return fmt.Errorf("parse physical disk device error: %v", err)
|
||||
}
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) parsePhyDevs(lines []string) error {
|
||||
@@ -684,30 +698,33 @@ func (raid *MegaRaid) parsePhyDevs(lines []string) error {
|
||||
phyDev = NewMegaRaidPhyDev()
|
||||
}
|
||||
}
|
||||
//map(self.add_phydev_strpsz, adapter.devs)
|
||||
for _, dev := range adapter.devs {
|
||||
if err := raid.addPhyDevStripSize(dev); err != nil {
|
||||
return fmt.Errorf("addPhyDevStripSize: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) addPhyDevStripSize(phyDev *MegaRaidPhyDev) bool {
|
||||
func (raid *MegaRaid) addPhyDevStripSize(phyDev *MegaRaidPhyDev) error {
|
||||
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 fmt.Errorf("addPhyDevStripSize error: %v", err)
|
||||
}
|
||||
return phyDev.parseStripSize(ret)
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) GetPhyDevs() []*MegaRaidPhyDev {
|
||||
/*func (raid *MegaRaid) GetPhyDevs() []*MegaRaidPhyDev {
|
||||
devs := make([]*MegaRaidPhyDev, 0)
|
||||
for _, ada := range raid.adapters {
|
||||
devs = append(devs, ada.GetPhyDevs()...)
|
||||
}
|
||||
return devs
|
||||
}
|
||||
}*/
|
||||
|
||||
//func (raid *MegaRaid) ParseLogicVolumes() bool {
|
||||
//cmd := GetCommand("-LDInfo", "-Lall", "-aALL")
|
||||
@@ -719,36 +736,38 @@ func (raid *MegaRaid) GetPhyDevs() []*MegaRaidPhyDev {
|
||||
//return true
|
||||
//}
|
||||
|
||||
func (raid *MegaRaid) CleanRaid() {
|
||||
func (raid *MegaRaid) CleanRaid() error {
|
||||
for _, adapter := range raid.adapters {
|
||||
adapter.clearJBODDisks()
|
||||
adapter.removeLogicVolumes()
|
||||
}
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) BuildRaid() {
|
||||
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) GetAdapter(index int) *MegaRaidAdaptor {
|
||||
for _, adapter := range raid.adapters {
|
||||
if adapter.index == index {
|
||||
return adapter
|
||||
}
|
||||
adapter.RemoveLogicVolumes()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) PreBuildRaid(_ []*baremetal.BaremetalDiskConfig, _ int) error {
|
||||
return raid.clearForeignState()
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) GetAdapters() []raiddrivers.IRaidAdapter {
|
||||
ret := make([]raiddrivers.IRaidAdapter, 0)
|
||||
for _, a := range raid.adapters {
|
||||
ret = append(ret, a)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) clearForeignState() error {
|
||||
cmd := GetCommand("-CfgForeign", "-Clear", "-aALL")
|
||||
_, err := raid.term.Run(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) RemoveLogicVolumes() {
|
||||
for _, adapter := range raid.adapters {
|
||||
adapter.removeLogicVolumes()
|
||||
adapter.RemoveLogicVolumes()
|
||||
}
|
||||
}
|
||||
|
||||
func (raid *MegaRaid) GetLogicVolumes() []int {
|
||||
lvs := []int{}
|
||||
for _, adapter := range raid.adapters {
|
||||
lvs = append(lvs, adapter.getLogicVolumes()...)
|
||||
}
|
||||
return lvs
|
||||
func init() {
|
||||
raiddrivers.RegisterDriver(baremetal.DISK_DRIVER_MEGARAID, NewMegaRaid)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/stringutils"
|
||||
|
||||
@@ -15,21 +14,17 @@ import (
|
||||
)
|
||||
|
||||
type MarvelRaidPhyDev struct {
|
||||
slot int
|
||||
adapter int
|
||||
model string
|
||||
rotate tristate.TriState
|
||||
sn string
|
||||
size int
|
||||
driver string
|
||||
*raid.RaidBasePhyDev
|
||||
slot int
|
||||
sn string
|
||||
}
|
||||
|
||||
func NewMarvelRaidPhyDev(adapter int) *MarvelRaidPhyDev {
|
||||
b := raid.NewRaidBasePhyDev(baremetal.DISK_DRIVER_MARVELRAID)
|
||||
b.Adapter = adapter
|
||||
return &MarvelRaidPhyDev{
|
||||
slot: -1,
|
||||
adapter: adapter,
|
||||
rotate: tristate.None,
|
||||
driver: baremetal.DISK_DRIVER_MARVELRAID,
|
||||
RaidBasePhyDev: b,
|
||||
slot: -1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,88 +36,205 @@ func (dev *MarvelRaidPhyDev) parseLine(line string) bool {
|
||||
switch key {
|
||||
case "SSD Type":
|
||||
if strings.HasSuffix(val, "SSD") {
|
||||
dev.rotate = tristate.True
|
||||
dev.Rotate = tristate.True
|
||||
} else {
|
||||
dev.rotate = tristate.False
|
||||
dev.Rotate = tristate.False
|
||||
}
|
||||
case "PD ID":
|
||||
dev.slot, _ = strconv.Atoi(val)
|
||||
case "Size":
|
||||
dat := strings.Split(val, " ")
|
||||
size, _ := strconv.Atoi(dat[0])
|
||||
dev.size = size / 1024 // MB
|
||||
dev.Size = int64(size / 1024) // MB
|
||||
case "model":
|
||||
dev.model = val
|
||||
dev.Model = val
|
||||
case "Serial":
|
||||
dev.sn = val
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *MarvelRaidPhyDev) isComplete() bool {
|
||||
if dev.model == "" {
|
||||
if !dev.RaidBasePhyDev.IsComplete() {
|
||||
return false
|
||||
}
|
||||
if dev.size < 0 {
|
||||
if dev.Size < 0 {
|
||||
return false
|
||||
}
|
||||
if dev.slot < 0 {
|
||||
return false
|
||||
}
|
||||
if dev.rotate.IsNone() {
|
||||
return false
|
||||
}
|
||||
if dev.sn == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *MarvelRaidPhyDev) String() string {
|
||||
return fmt.Sprintf("%d", dev.slot)
|
||||
func (dev *MarvelRaidPhyDev) ToBaremetalStorage() *baremetal.BaremetalStorage {
|
||||
s := dev.RaidBasePhyDev.ToBaremetalStorage()
|
||||
s.Slot = dev.slot
|
||||
return s
|
||||
}
|
||||
|
||||
func GetSpecString(dev *baremetal.BaremetalStorage) string {
|
||||
return fmt.Sprintf("%d", dev.Slot)
|
||||
}
|
||||
|
||||
type MarvelRaidAdaptor struct {
|
||||
index int
|
||||
raid *MarvelRaid
|
||||
devs []*baremetal.BaremetalStorage
|
||||
devs []*MarvelRaidPhyDev
|
||||
}
|
||||
|
||||
func NewMarvelRaidAdaptor(index int, raid *MarvelRaid) *MarvelRaidAdaptor {
|
||||
return &MarvelRaidAdaptor{
|
||||
index: index,
|
||||
raid: raid,
|
||||
devs: make([]*MarvelRaidPhyDev, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) ParsePhyDevs() bool {
|
||||
cmd := adapter.raid.GetCommand("info", "-o", "pd")
|
||||
func (adapter *MarvelRaidAdaptor) GetIndex() int {
|
||||
return adapter.index
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) ParsePhyDevs() error {
|
||||
cmd := GetCommand("info", "-o", "pd")
|
||||
ret, err := adapter.raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("get physical device: %v", err)
|
||||
return false
|
||||
return fmt.Errorf("get physical device: %v", err)
|
||||
}
|
||||
return adapter.parsePhyDevs(ret)
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) parsePhyDevs(lines []string) bool {
|
||||
func (adapter *MarvelRaidAdaptor) parsePhyDevs(lines []string) error {
|
||||
phyDev := NewMarvelRaidPhyDev(adapter.index)
|
||||
for _, line := range lines {
|
||||
if phyDev.parseLine(line) && phyDev.isComplete() {
|
||||
adapter.devs.append(phyDev)
|
||||
adapter.devs = append(adapter.devs, phyDev)
|
||||
phyDev = NewMarvelRaidPhyDev(adapter.index)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter) GetPhyDevs() []*MarvelRaidPhyDev {
|
||||
return adapter.devs
|
||||
func (adapter *MarvelRaidAdaptor) GetDevices() []*baremetal.BaremetalStorage {
|
||||
ret := []*baremetal.BaremetalStorage{}
|
||||
for _, dev := range adapter.devs {
|
||||
ret = append(ret, dev.ToBaremetalStorage())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) GetLogicVolumes() ([]int, error) {
|
||||
cmd := GetCommand("info", "-o", "vd")
|
||||
ret, err := adapter.raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getLogicVolumes: %v", err)
|
||||
}
|
||||
return adapter.parseLogicVolumes(ret)
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) parseLogicVolumes(lines []string) ([]int, error) {
|
||||
lvIdx := []int{}
|
||||
usedDevs := []int{}
|
||||
for _, line := range lines {
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key != "" {
|
||||
if key == "id" {
|
||||
idx, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lvIdx = append(lvIdx, idx)
|
||||
} else if key == "PD RAID setup" {
|
||||
for _, d := range strings.Split(val, " ") {
|
||||
idx, err := strconv.Atoi(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
usedDevs = append(usedDevs, idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(adapter.devs) < len(usedDevs) {
|
||||
return nil, fmt.Errorf("adapter %d current %d devs < usedDevs %d", adapter.index, len(adapter.devs), len(usedDevs))
|
||||
}
|
||||
return lvIdx, nil
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) RemoveLogicVolumes() error {
|
||||
lvs, err := adapter.GetLogicVolumes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to get logic volumes: %v", err)
|
||||
}
|
||||
for i := len(lvs) - 1; i >= 0; i-- {
|
||||
if err := adapter.removeLogicVolume(i); err != nil {
|
||||
return fmt.Errorf("Remove %d logical volume: %v", i, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) removeLogicVolume(idx int) error {
|
||||
cmd := GetCommand("delete", "-o", "vd", "-i", fmt.Sprintf("%d", idx), "-f", "--waiveconfirmation")
|
||||
_, err := adapter.raid.term.Run(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) PreBuildRaid(confs []*baremetal.BaremetalDiskConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) buildRaid(level string, devs []*baremetal.BaremetalStorage, _ *baremetal.BaremetalDiskConfig) error {
|
||||
pds := []string{}
|
||||
for _, dev := range devs {
|
||||
pds = append(pds, fmt.Sprintf("%s", GetSpecString(dev)))
|
||||
}
|
||||
args := []string{"create", "-o", "vd", "-d", strings.Join(pds, ","), level, "--waiveconfirmation"}
|
||||
cmd := GetCommand(args...)
|
||||
_, err := adapter.raid.term.Run(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) BuildRaid0(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("-r0", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) BuildRaid1(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("-r1", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
//return adapter.buildRaid("-r5", devs, conf)
|
||||
return fmt.Errorf("BuildRaid5 not impl")
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("-r10", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *MarvelRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return fmt.Errorf("BuildNoneRaid not impl")
|
||||
}
|
||||
|
||||
type MarvelRaid struct {
|
||||
term *ssh.Client
|
||||
adapters []*MarvelRaidAdaptor
|
||||
lv []interface{}
|
||||
}
|
||||
|
||||
func NewMarvelRaid(term *ssh.Client) raid.IRaidDriver {
|
||||
return &MarvelRaid{
|
||||
term: term,
|
||||
adapters: make([]*MarvelRaidAdaptor, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MarvelRaid) GetName() string {
|
||||
return baremetal.DISK_DRIVER_MARVELRAID
|
||||
}
|
||||
|
||||
func GetCommand(args ...string) string {
|
||||
@@ -130,22 +242,20 @@ func GetCommand(args ...string) string {
|
||||
return raid.GetCommand(bin, args...)
|
||||
}
|
||||
|
||||
func (r *MarvelRaid) ParsePhyDevs() bool {
|
||||
func (r *MarvelRaid) ParsePhyDevs() error {
|
||||
cmd := GetCommand("info", "-o", "hba")
|
||||
ret, err := r.term.Run(cmd)
|
||||
if err != nil {
|
||||
log.Errorf("Remote get info error: %v", err)
|
||||
return false
|
||||
return fmt.Errorf("Remote get info error: %v", err)
|
||||
}
|
||||
err = r.parseAdapters(ret)
|
||||
if err != nil {
|
||||
log.Errorf("parse adapt error: %v", err)
|
||||
return fmt.Errorf("parse adapt error: %v", err)
|
||||
}
|
||||
if len(r.adapters) > 0 {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
log.Errorf("Empty adapters")
|
||||
return false
|
||||
return fmt.Errorf("Empty adapters")
|
||||
}
|
||||
|
||||
func (r *MarvelRaid) parseAdapters(lines []string) error {
|
||||
@@ -165,3 +275,24 @@ func (r *MarvelRaid) parseAdapters(lines []string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *MarvelRaid) PreBuildRaid(_ []*baremetal.BaremetalDiskConfig, _ int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *MarvelRaid) GetAdapters() []raid.IRaidAdapter {
|
||||
ret := make([]raid.IRaidAdapter, 0)
|
||||
for _, a := range r.adapters {
|
||||
ret = append(ret, a)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *MarvelRaid) CleanRaid() error {
|
||||
// pass
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
raid.RegisterDriver(baremetal.DISK_DRIVER_MARVELRAID, NewMarvelRaid)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,87 @@ package raid
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type RaidDriverFactory func(term *ssh.Client) IRaidDriver
|
||||
|
||||
type sRaidDrivers map[string]RaidDriverFactory
|
||||
|
||||
var RaidDrivers sRaidDrivers
|
||||
|
||||
func init() {
|
||||
RaidDrivers = make(map[string]RaidDriverFactory)
|
||||
}
|
||||
|
||||
func GetCommand(bin string, args ...string) string {
|
||||
cmd := []string{bin}
|
||||
cmd = append(cmd, args...)
|
||||
return strings.Join(cmd, " ")
|
||||
}
|
||||
|
||||
func RegisterDriver(name string, drv RaidDriverFactory) {
|
||||
RaidDrivers[name] = drv
|
||||
}
|
||||
|
||||
type RaidBasePhyDev struct {
|
||||
Adapter int
|
||||
Size int64
|
||||
Model string
|
||||
Rotate tristate.TriState
|
||||
Status string
|
||||
Driver string
|
||||
}
|
||||
|
||||
func NewRaidBasePhyDev(driver string) *RaidBasePhyDev {
|
||||
return &RaidBasePhyDev{
|
||||
Size: -1,
|
||||
Rotate: tristate.None,
|
||||
Driver: driver,
|
||||
}
|
||||
}
|
||||
|
||||
func (dev *RaidBasePhyDev) IsComplete() bool {
|
||||
if dev.Model == "" {
|
||||
return false
|
||||
}
|
||||
if dev.Rotate.IsNone() {
|
||||
return false
|
||||
}
|
||||
if dev.Status == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *RaidBasePhyDev) ToBaremetalStorage() *baremetal.BaremetalStorage {
|
||||
return &baremetal.BaremetalStorage{
|
||||
Adapter: dev.Adapter,
|
||||
Status: dev.Status,
|
||||
Size: dev.Size,
|
||||
Model: dev.Model,
|
||||
Rotate: dev.Rotate.Bool(),
|
||||
Driver: dev.Driver,
|
||||
}
|
||||
}
|
||||
|
||||
func GetModules(term *ssh.Client) []string {
|
||||
ret := []string{}
|
||||
lines, err := 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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
package sas2iru
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/stringutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
type Mpt2SASRaidPhyDev struct {
|
||||
*raid.RaidBasePhyDev
|
||||
|
||||
enclosure int
|
||||
slot int
|
||||
sector int
|
||||
block int
|
||||
}
|
||||
|
||||
func newMpt2SASRaidPhyDev(adapter int) *Mpt2SASRaidPhyDev {
|
||||
b := raid.NewRaidBasePhyDev(baremetal.DISK_DRIVER_MARVELRAID)
|
||||
b.Adapter = adapter
|
||||
return &Mpt2SASRaidPhyDev{
|
||||
RaidBasePhyDev: b,
|
||||
slot: -1,
|
||||
enclosure: -1,
|
||||
block: -1,
|
||||
sector: -1,
|
||||
}
|
||||
}
|
||||
|
||||
func (dev *Mpt2SASRaidPhyDev) parseLine(line string) bool {
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
switch key {
|
||||
case "Drive Type":
|
||||
if strings.HasSuffix("_HDD", val) {
|
||||
dev.Rotate = tristate.True
|
||||
} else {
|
||||
dev.Rotate = tristate.False
|
||||
}
|
||||
case "Enclosure #":
|
||||
dev.enclosure, _ = strconv.Atoi(val)
|
||||
case "Slot #":
|
||||
dev.slot, _ = strconv.Atoi(val)
|
||||
case "Size (in MB)/(in sectors)":
|
||||
dat := strings.Split(val, "/")
|
||||
sz, _ := strconv.Atoi(dat[0])
|
||||
dev.Size = int64(sz)
|
||||
dev.sector, _ = strconv.Atoi(dat[1])
|
||||
dev.block = int(dev.Size * 1024 * 1024 / 7814037167)
|
||||
if dev.block > 4000 {
|
||||
dev.block = 4096
|
||||
} else {
|
||||
dev.block = 512
|
||||
}
|
||||
dev.Size = int64(dev.block * dev.sector / 1024 / 1024)
|
||||
case "Manufacturer", "Model Number", "Firmware Revision", "Serial No":
|
||||
if dev.Model == "" {
|
||||
dev.Model = val
|
||||
} else {
|
||||
dev.Model = fmt.Sprintf("%s %s", dev.Model, val)
|
||||
}
|
||||
case "State":
|
||||
if strings.Contains(strings.ToLower(val), "ready") {
|
||||
dev.Status = "online"
|
||||
} else {
|
||||
dev.Status = strings.ToLower(val)
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *Mpt2SASRaidPhyDev) isComplete() bool {
|
||||
if !dev.RaidBasePhyDev.IsComplete() {
|
||||
return false
|
||||
}
|
||||
if dev.Size < 0 {
|
||||
return false
|
||||
}
|
||||
if dev.slot < 0 {
|
||||
return false
|
||||
}
|
||||
if dev.sector < 0 {
|
||||
return false
|
||||
}
|
||||
if dev.block < 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *Mpt2SASRaidPhyDev) ToBaremetalStorage() *baremetal.BaremetalStorage {
|
||||
s := dev.RaidBasePhyDev.ToBaremetalStorage()
|
||||
s.Slot = dev.slot
|
||||
s.Enclosure = dev.enclosure
|
||||
s.Block = dev.block
|
||||
s.Sector = dev.sector
|
||||
return s
|
||||
}
|
||||
|
||||
func GetSpecString(dev *baremetal.BaremetalStorage) string {
|
||||
if dev.Enclosure < 0 {
|
||||
return fmt.Sprintf(":%d", dev.Slot)
|
||||
}
|
||||
return fmt.Sprintf("%d:%d", dev.Enclosure, dev.Slot)
|
||||
}
|
||||
|
||||
type Mpt2SASRaidAdaptor struct {
|
||||
index int
|
||||
raid *Mpt2SASRaid
|
||||
devs []*Mpt2SASRaidPhyDev
|
||||
}
|
||||
|
||||
func newMpt2SASRaidAdaptor(index int, raid *Mpt2SASRaid) *Mpt2SASRaidAdaptor {
|
||||
return &Mpt2SASRaidAdaptor{
|
||||
index: index,
|
||||
raid: raid,
|
||||
devs: make([]*Mpt2SASRaidPhyDev, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) GetIndex() int {
|
||||
return adapter.index
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) ParsePhyDevs() error {
|
||||
cmd := adapter.raid.GetCommand(fmt.Sprintf("%d", adapter.index), "DISPLAY")
|
||||
ret, err := adapter.raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get physical device: %v", err)
|
||||
}
|
||||
for _, l := range ret {
|
||||
if strings.Contains(l, "RAID Support") && strings.ToLower(strings.TrimSpace(l[strings.Index(l, ":")+1:])) == "no" {
|
||||
return fmt.Errorf("No raid support")
|
||||
}
|
||||
}
|
||||
return adapter.parsePhyDevs(ret)
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) parsePhyDevs(lines []string) error {
|
||||
dev := newMpt2SASRaidPhyDev(adapter.index)
|
||||
for _, l := range lines {
|
||||
if dev.parseLine(l) && dev.isComplete() {
|
||||
adapter.devs = append(adapter.devs, dev)
|
||||
dev = newMpt2SASRaidPhyDev(adapter.index)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) GetDevices() []*baremetal.BaremetalStorage {
|
||||
ret := []*baremetal.BaremetalStorage{}
|
||||
for _, dev := range adapter.devs {
|
||||
ret = append(ret, dev.ToBaremetalStorage())
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) GetLogicVolumes() ([]int, error) {
|
||||
cmd := adapter.raid.GetCommand(fmt.Sprintf("%d", adapter.index), "DISPLAY")
|
||||
ret, err := adapter.raid.term.Run(cmd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetLogicVolumes error: %v", err)
|
||||
}
|
||||
return adapter.parseLogicVolumes(ret)
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) parseLogicVolumes(lines []string) ([]int, error) {
|
||||
lvIdx := []int{}
|
||||
usedDevs := []int{}
|
||||
for _, line := range lines {
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key != "" && key == "Volume ID" {
|
||||
idx, _ := strconv.Atoi(val)
|
||||
lvIdx = append(lvIdx, idx)
|
||||
} else if regexp.MustCompile(`PHY\[\d+\] Enclosure#/Slot#`).MatchString(key) {
|
||||
idx, _ := strconv.Atoi(val)
|
||||
usedDevs = append(usedDevs, idx)
|
||||
}
|
||||
}
|
||||
if len(adapter.devs) < len(usedDevs) {
|
||||
return nil, fmt.Errorf("adapter current dev %d < usedDevs %d", len(adapter.devs), len(usedDevs))
|
||||
}
|
||||
for i := 0; i < len(adapter.devs)-len(usedDevs); i++ {
|
||||
lvIdx = append(lvIdx, -1)
|
||||
}
|
||||
return lvIdx, nil
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) rescanLV() error {
|
||||
var cmd string
|
||||
if adapter.raid.utility == "/opt/lsi/sas2ircu" {
|
||||
cmd = "/opt/lsi/rescan.sh mpt2sas"
|
||||
} else if adapter.raid.utility == "/opt/lsi/sas3ircu" {
|
||||
cmd = "/opt/lsi/rescan.sh mpt3sas"
|
||||
} else {
|
||||
return fmt.Errorf("Unsupport raid utility: %v", adapter.raid.utility)
|
||||
}
|
||||
_, err := adapter.raid.term.Run(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) setBootIR() error {
|
||||
lvs, err := adapter.GetLogicVolumes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(lvs) > 0 && lvs[0] > 0 {
|
||||
args := []string{fmt.Sprintf("%d", adapter.index), "BOOTIR", fmt.Sprintf("%d", lvs[0])}
|
||||
cmd := adapter.raid.GetCommand(args...)
|
||||
_, err := adapter.raid.term.Run(cmd)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) PreBuildRaid(confs []*baremetal.BaremetalDiskConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) buildRaid(level string, devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
if len(conf.Size) > 1 {
|
||||
return fmt.Errorf("Subdivide sub-size not supported")
|
||||
}
|
||||
args := []string{fmt.Sprintf("%d", adapter.index), "CREATE", level, "MAX"}
|
||||
labels := []string{}
|
||||
for _, dev := range devs {
|
||||
labels = append(labels, GetSpecString(dev))
|
||||
}
|
||||
args = append(args, labels...)
|
||||
args = append(args, "noprompt")
|
||||
_, err := adapter.raid.term.Run(adapter.raid.GetCommand(args...))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Build raid error: %v", err)
|
||||
}
|
||||
if err := adapter.setBootIR(); err != nil {
|
||||
return fmt.Errorf("setBootIR: %v", err)
|
||||
}
|
||||
if err := adapter.rescanLV(); err != nil {
|
||||
return fmt.Errorf("rescanLV: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) BuildRaid0(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("RAID0", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) BuildRaid1(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return adapter.buildRaid("RAID1", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return fmt.Errorf("Not impl")
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
if len(devs) > 10 {
|
||||
return fmt.Errorf("RAID10 supports no more than 10 disks")
|
||||
}
|
||||
return adapter.buildRaid("RAID10", devs, conf)
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage, conf *baremetal.BaremetalDiskConfig) error {
|
||||
return fmt.Errorf("Not impl")
|
||||
}
|
||||
|
||||
func (adapter *Mpt2SASRaidAdaptor) RemoveLogicVolumes() error {
|
||||
cmd := adapter.raid.GetCommand(fmt.Sprintf("%d", adapter.index), "DELETE", "noprompt")
|
||||
_, err := adapter.raid.term.Run(cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
type Mpt2SASRaid struct {
|
||||
term *ssh.Client
|
||||
utility string
|
||||
adapters []*Mpt2SASRaidAdaptor
|
||||
}
|
||||
|
||||
func NewMpt2SASRaid(term *ssh.Client) raid.IRaidDriver {
|
||||
return &Mpt2SASRaid{
|
||||
term: term,
|
||||
adapters: make([]*Mpt2SASRaidAdaptor, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Mpt2SASRaid) GetName() string {
|
||||
return baremetal.DISK_DRIVER_MPT2SAS
|
||||
}
|
||||
|
||||
func (r *Mpt2SASRaid) ParsePhyDevs() error {
|
||||
if r.modulePCIProbed("mpt2sas") {
|
||||
r.utility = "/opt/lsi/sas2ircu"
|
||||
} else if r.modulePCIProbed("mpt3sas") {
|
||||
r.utility = "/opt/lsi/sas3ircu"
|
||||
} else {
|
||||
return fmt.Errorf("Not probe mpt2sas or mpt3sas kernel module")
|
||||
}
|
||||
cmd := r.GetCommand("LIST")
|
||||
ret, err := r.term.Run(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.parseAdapters(ret)
|
||||
}
|
||||
|
||||
func (r *Mpt2SASRaid) parseAdapters(lines []string) error {
|
||||
for _, line := range lines {
|
||||
dat := regexp.MustCompile(`\s+`).Split(strings.TrimSpace(line), -1)
|
||||
if regexp.MustCompile(`\d+`).MatchString(dat[0]) {
|
||||
idx, _ := strconv.Atoi(dat[0])
|
||||
adapter := newMpt2SASRaidAdaptor(idx, r)
|
||||
r.adapters = append(r.adapters, adapter)
|
||||
}
|
||||
}
|
||||
for _, adapter := range r.adapters {
|
||||
if err := adapter.ParsePhyDevs(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Mpt2SASRaid) modulePCIProbed(mod string) bool {
|
||||
cmd := fmt.Sprintf("lspci -k | grep %s", mod)
|
||||
_, err := r.term.Run(cmd)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (r *Mpt2SASRaid) GetCommand(args ...string) string {
|
||||
return raid.GetCommand(r.utility, args...)
|
||||
}
|
||||
|
||||
func (r *Mpt2SASRaid) PreBuildRaid(_ []*baremetal.BaremetalDiskConfig, _ int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Mpt2SASRaid) GetAdapters() []raid.IRaidAdapter {
|
||||
ret := make([]raid.IRaidAdapter, 0)
|
||||
for _, a := range r.adapters {
|
||||
ret = append(ret, a)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *Mpt2SASRaid) CleanRaid() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
raid.RegisterDriver(baremetal.DISK_DRIVER_MPT2SAS, NewMpt2SASRaid)
|
||||
}
|
||||
@@ -89,6 +89,7 @@ type BaremetalStorage struct {
|
||||
MinStripSize int64 `json:"min_strip_size,omitempty"`
|
||||
MaxStripSize int64 `json:"max_strip_size,omitempty"`
|
||||
Index int64 `json:"index,omitempty"`
|
||||
Addr string `json:"addr,omitempty"`
|
||||
}
|
||||
|
||||
func (s BaremetalStorage) GetBlock() int {
|
||||
|
||||
Reference in New Issue
Block a user