baremetal: raid driver abstract

This commit is contained in:
Zexi Li
2019-01-10 20:00:46 +08:00
parent 2658734573
commit 986e22c5fa
10 changed files with 1362 additions and 222 deletions
+31 -9
View File
@@ -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)
}
+19 -3
View File
@@ -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
}
+180 -161
View File
@@ -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)
}
+171 -40
View File
@@ -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)
}
+77
View File
@@ -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
}
+363
View File
@@ -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)
}
+1
View File
@@ -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 {