| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package megactl
- import (
- "fmt"
- "regexp"
- "strconv"
- "strings"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/tristate"
- "yunion.io/x/pkg/util/stringutils"
- "yunion.io/x/pkg/utils"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- "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/regutils2"
- )
- var (
- sizePattern = regexp.MustCompile(`(?P<sector>0x[0-9a-fA-F]+)`)
- adapterPatter = regexp.MustCompile(`^Adapter #(?P<idx>[0-9]+)`)
- )
- type MegaRaidPhyDev struct {
- *raiddrivers.RaidBasePhyDev
- enclosure int
- slot int
- minStripSize int
- maxStripSize int
- sector int64
- block int64
- }
- func NewMegaRaidPhyDev() *MegaRaidPhyDev {
- return &MegaRaidPhyDev{
- RaidBasePhyDev: raiddrivers.NewRaidBasePhyDev(baremetal.DISK_DRIVER_MEGARAID),
- enclosure: -1,
- slot: -1,
- minStripSize: -1,
- maxStripSize: -1,
- sector: -1,
- block: 512,
- }
- }
- func (dev *MegaRaidPhyDev) ToBaremetalStorage(index int) *baremetal.BaremetalStorage {
- s := dev.RaidBasePhyDev.ToBaremetalStorage(index)
- 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 dev.sector * dev.block / 1024 / 1024 // MB
- }
- func (dev *MegaRaidPhyDev) parseLine(line string) bool {
- key, val := stringutils.SplitKeyValue(line)
- if key == "" {
- return false
- }
- switch key {
- case "Media Type":
- if val == "Hard Disk Device" {
- dev.Rotate = tristate.True
- } else {
- dev.Rotate = tristate.False
- }
- case "Enclosure Device ID":
- enclosure, err := strconv.Atoi(val)
- if err == nil {
- dev.enclosure = enclosure
- }
- case "Slot Number":
- dev.slot, _ = strconv.Atoi(val)
- case "Coerced Size":
- sizeStr := regutils2.GetParams(sizePattern, val)["sector"]
- if len(sizeStr) != 0 {
- sizeStr = strings.Replace(sizeStr, "0x", "", -1)
- sector, err := strconv.ParseInt(sizeStr, 16, 64)
- if err != nil {
- log.Errorf("Parse sector %q to Int error: %v", sizeStr, err)
- }
- dev.sector = sector
- } else {
- dev.sector = 0
- }
- case "Inquiry Data":
- dev.Model = dev.convertModel(val)
- case "Firmware state":
- dev.Status = dev.convertState(val)
- case "Logical Sector Size":
- block, err := strconv.Atoi(val)
- if err != nil {
- log.Errorf("parse logical sector size error: %v", err)
- dev.block = 512
- } else if block > 0 {
- dev.block = int64(block)
- }
- default:
- return false
- }
- return true
- }
- func (dev *MegaRaidPhyDev) fillByStorcliPD(pd *StorcliPhysicalDrive) error {
- if pd.MediaType == "HDD" {
- dev.Rotate = tristate.True
- } else {
- dev.Rotate = tristate.False
- }
- eId, slotId := stringutils.SplitKeyValue(pd.EnclosureIdSlotNo)
- eIdInt, err := strconv.Atoi(eId)
- if err != nil {
- return errors.Errorf("Can't convert enclosureId %q", eId)
- }
- slotIdInt, err := strconv.Atoi(slotId)
- if err != nil {
- return errors.Errorf("Can't convert slotId %q", slotId)
- }
- dev.enclosure = eIdInt
- dev.slot = slotIdInt
- dev.Model = dev.convertModel(pd.Model)
- dev.Status = dev.convertState(pd.State)
- sector := strings.TrimSuffix(pd.SectorSize, "B")
- sectorInt, err := strconv.Atoi(sector)
- if err != nil {
- return errors.Errorf("Can't convert sector %q", pd.SectorSize)
- }
- // Use block not sector ...
- dev.block = int64(sectorInt)
- // parse size then fill block count
- sizeStrUnit := strings.Split(pd.Size, " ")
- if len(sizeStrUnit) != 2 {
- return errors.Errorf("Invalid size string %q", pd.Size)
- }
- sizeStr := sizeStrUnit[0]
- unit := sizeStrUnit[1]
- size, err := strconv.ParseFloat(sizeStr, 64)
- if err != nil {
- return errors.Errorf("Invalid size %q", sizeStr)
- }
- // convert size to Bytes
- switch unit {
- case "TB":
- size = size * 1024 * 1024 * 1024 * 1024
- case "GB":
- size = size * 1024 * 1024 * 1024
- case "MB":
- size = size * 1024 * 1024
- }
- blockCnt := int64(size) / int64(sectorInt)
- dev.sector = blockCnt
- return nil
- }
- func (dev *MegaRaidPhyDev) convertModel(val string) string {
- return strings.Join(regexp.MustCompile(`\s+`).Split(val, -1), " ")
- }
- func (dev *MegaRaidPhyDev) convertState(val string) string {
- state := val
- if val == "JBOD" {
- state = "jbod"
- } else if strings.Contains(strings.ToLower(val), "online") || utils.IsInStringArray(val, []string{"Onln"}) {
- state = "online"
- } else if val == "Rebuild" {
- state = "rebuild"
- } else if strings.Contains(strings.ToLower(val), "hotspare") {
- state = "hotspare"
- } else if strings.Contains(strings.ToLower(val), "copyback") {
- state = "copyback"
- } else if strings.Contains(strings.ToLower(val), "unconfigured(good)") {
- state = "unconfigured_good"
- } else {
- state = "offline"
- }
- return state
- }
- func (dev *MegaRaidPhyDev) isComplete() bool {
- if !dev.RaidBasePhyDev.IsComplete() {
- return false
- }
- if dev.sector < 0 {
- return false
- }
- if dev.block < 0 {
- return false
- }
- if dev.slot < 0 {
- return false
- }
- return true
- }
- func (dev *MegaRaidPhyDev) isJBOD() bool {
- return dev.Status == "jbod"
- }
- 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 MegaRaidAdaptor struct {
- index int
- storcliIndex int
- raid *MegaRaid
- devs []*MegaRaidPhyDev
- sn string
- name string
- busNumber string
- deviceNumber string
- funcNumber string
- // used by sg_map
- hostNum int
- //channelNum int
- minStripSize int
- maxStripSize int
- }
- func NewMegaRaidAdaptor(index int, raid *MegaRaid) (*MegaRaidAdaptor, error) {
- adapter := &MegaRaidAdaptor{
- index: index,
- storcliIndex: -1,
- raid: raid,
- }
- if err := adapter.fillInfo(); err != nil {
- return adapter, errors.Wrapf(err, "%d fill info", adapter.index)
- }
- return adapter, nil
- }
- func NewMegaRaidAdaptorByStorcli(storAda *StorcliAdaptor, raid *MegaRaid) (*MegaRaidAdaptor, error) {
- adapter := &MegaRaidAdaptor{
- index: storAda.Controller,
- storcliIndex: storAda.Controller,
- raid: raid,
- sn: storAda.sn,
- name: storAda.name,
- busNumber: storAda.busNumber,
- deviceNumber: storAda.deviceNumber,
- funcNumber: storAda.funcNumber,
- }
- if err := adapter.checkPciDevice(); err != nil {
- return nil, errors.Wrap(err, "checkPciDevice")
- }
- return adapter, nil
- }
- func (adapter MegaRaidAdaptor) key() string {
- return adapter.name + adapter.sn
- }
- /*
- Adapter: 0
- Product Name: MegaRAID 9560-8i 4GB
- Memory: 4096MB
- BBU: Absent
- Serial No: SKC4011564
- */
- func (adapter *MegaRaidAdaptor) fillInfo() error {
- size2Int := func(sizeStr string) int {
- sz, _ := strconv.ParseFloat(strings.Fields(sizeStr)[0], 32)
- szInt := int(sz)
- if strings.Contains(sizeStr, "KB") {
- return szInt
- }
- if strings.Contains(sizeStr, "MB") {
- return szInt * 1024
- }
- return -1
- }
- cmd := GetCommand("-CfgDsply", fmt.Sprintf("-a%d", adapter.index))
- ret, err := adapter.remoteRun(cmd)
- if err != nil {
- return errors.Wrap(err, "remote get SN")
- }
- for _, l := range ret {
- key, val := stringutils.SplitKeyValue(l)
- if len(key) == 0 {
- continue
- }
- switch key {
- case "Serial No":
- adapter.sn = val
- case "Product Name":
- adapter.name = val
- case "Strip Size":
- sz := size2Int(val)
- adapter.minStripSize = sz
- adapter.maxStripSize = sz
- case "Min Strip Size":
- adapter.minStripSize = size2Int(val)
- case "Max Strip Size":
- adapter.maxStripSize = size2Int(val)
- }
- }
- if len(adapter.key()) == 0 {
- return errors.Error("Not found Serial No and Product Name")
- }
- return adapter.fillPCIInfo()
- }
- func (adapter *MegaRaidAdaptor) fillPCIInfo() error {
- cmd := GetCommand("-adpgetpciinfo", fmt.Sprintf("-a%d", adapter.index))
- ret, err := adapter.remoteRun(cmd)
- if err != nil {
- return errors.Wrapf(err, "%d remote run get pci info", adapter.index)
- }
- for _, l := range ret {
- key, val := stringutils.SplitKeyValue(l)
- if len(key) == 0 {
- continue
- }
- switch key {
- case "Bus Number":
- if len(val) == 1 {
- val = fmt.Sprintf("0%s", val)
- }
- if len(val) != 2 {
- return errors.Errorf("Invalid bus number: %s", val)
- }
- adapter.busNumber = val
- case "Device Number":
- if len(val) == 1 {
- val = fmt.Sprintf("0%s", val)
- }
- if len(val) != 2 {
- return errors.Errorf("Invalid device number: %s", val)
- }
- adapter.deviceNumber = val
- case "Function Number":
- if len(val) != 1 {
- return errors.Errorf("Invalid function number: %s", val)
- }
- adapter.funcNumber = val
- }
- }
- if err := adapter.checkPciDevice(); err != nil {
- return errors.Wrap(err, "checkPciDevice")
- }
- return nil
- }
- func (adapter *MegaRaidAdaptor) checkPciDevice() error {
- pciDir := fmt.Sprintf("/sys/bus/pci/devices/0000:%s:%s.%s/", adapter.busNumber, adapter.deviceNumber, adapter.funcNumber)
- cmd := raiddrivers.GetCommand("ls", pciDir, "|", "grep", "host")
- ret, err := adapter.remoteRun(cmd)
- if err != nil {
- return errors.Wrapf(err, "find pci host number")
- }
- if len(ret) == 0 {
- return errors.Errorf("Not find pci host dir")
- }
- hostNumStr := ret[0]
- hostNum, err := strconv.Atoi(strings.TrimLeft(hostNumStr, "host"))
- if err != nil {
- return errors.Errorf("Invalid hostNum %s", hostNumStr)
- }
- adapter.hostNum = hostNum
- pciHostDir := fmt.Sprintf("%s%s/", pciDir, hostNumStr)
- // $ ls /sys/bus/pci/devices/0000:03:00.0/host0/ | grep target | head -n 1
- // target0:2:0
- targetCmd := raiddrivers.GetCommand("ls", pciHostDir, "|", "grep", "target", "|", "head", "-n", "1")
- ret, err = adapter.remoteRun(targetCmd)
- if err != nil {
- return errors.Wrapf(err, "find target %q", targetCmd)
- }
- if len(ret) == 0 {
- return errors.Errorf("Not find target dir")
- }
- //targetStr := ret[0]
- //parts := strings.Split(targetStr, ":")
- //if len(parts) != 3 {
- //// not build raid logical volume yet
- //log.Warningf("Cmd %q invalid target string %q, skip fill logical volume info", targetCmd, targetStr)
- //return nil
- //}
- //channelNum, err := strconv.Atoi(parts[1])
- //if err != nil {
- //return errors.Errorf("Invalid channel number %s", parts[1])
- //}
- //adapter.channelNum = channelNum
- return nil
- }
- func (adapter *MegaRaidAdaptor) GetIndex() int {
- return adapter.index
- }
- func (adapter *MegaRaidAdaptor) getTerm() raid.IExecTerm {
- return adapter.raid.term
- }
- func (adapter *MegaRaidAdaptor) remoteRun(cmds ...string) ([]string, error) {
- return adapter.getTerm().Run(cmds...)
- }
- func (adapter *MegaRaidAdaptor) AddPhyDev(dev *MegaRaidPhyDev) {
- dev.Adapter = adapter.index
- adapter.devs = append(adapter.devs, dev)
- }
- func (adapter *MegaRaidAdaptor) GetDevices() []*baremetal.BaremetalStorage {
- ret := []*baremetal.BaremetalStorage{}
- for idx, dev := range adapter.devs {
- ret = append(ret, dev.ToBaremetalStorage(idx))
- }
- return ret
- }
- func (adapter *MegaRaidAdaptor) GetLogicVolumes() ([]*raiddrivers.RaidLogicalVolume, error) {
- errs := make([]error, 0)
- megaLvs, megacliErr := adapter.getMegacliLogicVolumes()
- if megacliErr != nil {
- errs = append(errs, megacliErr)
- }
- storeLvs, storcliErr := adapter.getStorcliLogicVolums()
- if storcliErr != nil {
- errs = append(errs, storcliErr)
- }
- if len(megaLvs) > 0 {
- return megaLvs, nil
- }
- if len(storeLvs) > 0 {
- return storeLvs, nil
- }
- if len(errs) == 0 || megacliErr == nil || storcliErr == nil {
- // no error, no volume
- return []*raiddrivers.RaidLogicalVolume{}, nil
- }
- return nil, errors.NewAggregate(errs)
- }
- func (adapter *MegaRaidAdaptor) getMegacliLogicVolumes() ([]*raiddrivers.RaidLogicalVolume, error) {
- cmd := GetCommand("-LDInfo", "-Lall", fmt.Sprintf("-a%d", adapter.index))
- ret, err := adapter.remoteRun(cmd)
- if err != nil {
- return nil, errors.Wrapf(err, "remoteRun %s", cmd)
- }
- lvs, err := adapter.parseLogicVolumes(ret)
- if err != nil {
- return nil, errors.Wrap(err, "")
- }
- for i := range lvs {
- lvs[i].Driver = raiddrivers.RaidDriverToolMegacli64
- }
- return lvs, nil
- }
- func (adapter *MegaRaidAdaptor) getStorcliLogicVolums() ([]*raiddrivers.RaidLogicalVolume, error) {
- lvs, err := adapter.getStorcliLogicVolumsV2()
- if err != nil {
- return nil, err
- }
- ret := make([]*raiddrivers.RaidLogicalVolume, len(lvs))
- for i := range lvs {
- lv := lvs[i]
- ret[i] = &raiddrivers.RaidLogicalVolume{
- Index: lv.Index,
- Adapter: adapter.index,
- BlockDev: lv.GetOSDevice(),
- IsSSD: tristate.NewFromBool(lv.IsSSD()),
- Driver: raiddrivers.RaidDriverToolStorecli,
- }
- }
- return ret, nil
- }
- func (adapter *MegaRaidAdaptor) getStorcliLogicVolumsV2() ([]*StorcliLogicalVolume, error) {
- cmd := GetCommand2(fmt.Sprintf("/c%d/vall", adapter.index), "show", "all", "J")
- ret, err := adapter.remoteRun(cmd)
- if err != nil {
- return nil, fmt.Errorf("getStorcliLogicVolumsV2 error: %v", err)
- }
- output := strings.Join(ret, "\n")
- lvs, err := parseStorcliLVs(output)
- if err != nil {
- return nil, errors.Wrap(err, "parseStorcliLVs")
- }
- return lvs.GetLogicalVolumes(adapter.index)
- }
- var storcliLVRegexp = regexp.MustCompile(`^(?P<dg>\d+)\/(?P<vd>\d+)\s+(?P<type>RAID\d+).*`)
- func parseStorcliLogicalVolumes(adapter int, lines []string) ([]*raiddrivers.RaidLogicalVolume, error) {
- lvs := make([]*raiddrivers.RaidLogicalVolume, 0)
- for _, line := range lines {
- result := regutils2.GetParams(storcliLVRegexp, line)
- if len(result) == 0 {
- continue
- }
- idxStr, ok := result["vd"]
- if !ok {
- return nil, errors.Errorf("Not found virtual drive by line %q", line)
- }
- idx, _ := strconv.Atoi(idxStr)
- lvs = append(lvs, &raiddrivers.RaidLogicalVolume{
- Index: idx,
- Adapter: adapter,
- })
- }
- return lvs, nil
- }
- var logicalVolumeIdRegexp = regexp.MustCompile(`.*(Target Id: (?P<idx>[0-9]+))`)
- func (adapter *MegaRaidAdaptor) parseLogicVolumes(lines []string) ([]*raiddrivers.RaidLogicalVolume, error) {
- lvs := make([]*raiddrivers.RaidLogicalVolume, 0)
- for _, line := range lines {
- key, val := stringutils.SplitKeyValue(line)
- if key != "" && key == "Virtual Drive" {
- idxStr := regutils2.GetParams(logicalVolumeIdRegexp, val)["idx"]
- idx, err := strconv.Atoi(idxStr)
- if err != nil {
- return nil, errors.Errorf("index %q to int: %v", idxStr, err)
- }
- blockDev, err := getLogicVolumeDeviceById(adapter.hostNum, idx, adapter.getTerm())
- if err != nil {
- return nil, err
- }
- lvs = append(lvs, &raiddrivers.RaidLogicalVolume{
- Index: idx,
- Adapter: adapter.index,
- BlockDev: blockDev,
- })
- }
- }
- return lvs, nil
- }
- func getLogicVolumeDeviceById(hostNum, scsiId int, term raid.IExecTerm) (string, error) {
- items, err := raiddrivers.SGMap(term)
- if err != nil {
- return "", err
- }
- isMatch := func(item api.SGMapItem) bool {
- return item.HostNumber == hostNum && item.SCSIId == scsiId
- }
- for _, item := range items {
- if isMatch(item) {
- return item.LinuxDeviceName, nil
- }
- }
- return "", errors.Errorf("Not found SG item by id: %d:%d", hostNum, scsiId)
- }
- func (adapter *MegaRaidAdaptor) PreBuildRaid(confs []*api.BaremetalDiskConfig) error {
- adapter.clearJBODDisks()
- return nil
- }
- func (adapter *MegaRaidAdaptor) PostBuildRaid() error {
- // sync rotational of logical block device
- if err := adapter.storcliSyncBlockDeviceAttrs(); err != nil {
- log.Warningf("adapter %d storcliSyncBlockDeviceAttrs: %v", adapter.index, err)
- }
- return nil
- }
- func (adapter *MegaRaidAdaptor) storcliSyncBlockDeviceAttrs() error {
- lvs, err := adapter.getStorcliLogicVolumsV2()
- if err != nil {
- return errors.Wrap(err, "getStorcliLogicVolumsV2")
- }
- for _, lv := range lvs {
- if !lv.IsSSD() {
- continue
- }
- // e.g: echo 0 | tee /sys/block/sda/queue/rotational if logical volume is SSD
- cmd := fmt.Sprintf("echo 0 | tee %s", lv.GetSysBlockRotationalPath())
- if out, err := adapter.remoteRun(cmd); err != nil {
- return errors.Wrapf(err, "%s out %v", cmd, out)
- }
- }
- return nil
- }
- func conf2Params(conf *api.BaremetalDiskConfig) []string {
- params := []string{}
- if conf.WT != nil {
- if *conf.WT {
- params = append(params, "WT")
- } else {
- params = append(params, "WB")
- }
- }
- if conf.RA != nil {
- if *conf.RA {
- params = append(params, "RA")
- } else {
- params = append(params, "NORA")
- }
- }
- if conf.Direct != nil {
- if *conf.Direct {
- params = append(params, "Direct")
- } else {
- params = append(params, "Cached")
- }
- }
- if conf.Cachedbadbbu != nil {
- if *conf.Cachedbadbbu {
- params = append(params, "CachedBadBBU")
- } else {
- params = append(params, "NoCachedBadBBU")
- }
- }
- if conf.Strip != nil {
- params = append(params, fmt.Sprintf("-strpsz%d", *conf.Strip))
- }
- if len(conf.Size) > 0 {
- for _, sz := range conf.Size {
- params = append(params, fmt.Sprintf("-sz%d", sz))
- }
- }
- return params
- }
- func (adapter *MegaRaidAdaptor) storcliBuildRaid0(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return adapter.storcliBuildRaid(devs, conf, 0)
- }
- func (adapter *MegaRaidAdaptor) megacliBuildRaid0(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return adapter.megacliBuildRaid(devs, conf, 0)
- }
- func (adapter *MegaRaidAdaptor) storcliBuildRaid1(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return adapter.storcliBuildRaid(devs, conf, 1)
- }
- func (adapter *MegaRaidAdaptor) megacliBuildRaid1(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return adapter.megacliBuildRaid(devs, conf, 1)
- }
- func (adapter *MegaRaidAdaptor) storcliBuildRaid5(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return adapter.storcliBuildRaid(devs, conf, 5)
- }
- func (adapter *MegaRaidAdaptor) megacliBuildRaid5(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return adapter.megacliBuildRaid(devs, conf, 5)
- }
- func (adapter *MegaRaidAdaptor) storcliBuildRaid10(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return adapter.storcliBuildRaid(devs, conf, 10)
- }
- func (adapter *MegaRaidAdaptor) megacliBuildRaid10(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- if len(devs)%2 != 0 {
- return fmt.Errorf("Odd number of %d devs", len(devs))
- }
- devCnt := len(devs) / 2
- 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, GetSpecString(d1), GetSpecString(d2)))
- }
- args := []string{"-CfgSpanAdd", "-r10"}
- args = append(args, params...)
- 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 []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig, level uint) error {
- if err := storcliBuildRaid(
- adapter.GetStorcliCommand,
- adapter.getTerm(),
- devs, conf, level); err != nil {
- return err
- }
- return nil
- }
- func (adapter *MegaRaidAdaptor) megacliBuildRaid(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig, level uint) error {
- labels := []string{}
- for _, dev := range devs {
- labels = append(labels, GetSpecString(dev))
- }
- args := []string{"-CfgLdAdd", fmt.Sprintf("-r%d", level), fmt.Sprintf("[%s]", strings.Join(labels, ","))}
- args = append(args, conf2Params(conf)...)
- args = append(args, fmt.Sprintf("-a%d", adapter.index))
- cmd := GetCommand(args...)
- log.Infof("_megacliBuildRaid command: %s", cmd)
- _, err := adapter.remoteRun(cmd)
- return err
- }
- func cliBuildRaid(
- devs []*baremetal.BaremetalStorage,
- conf *api.BaremetalDiskConfig,
- funcs ...func([]*baremetal.BaremetalStorage, *api.BaremetalDiskConfig) error,
- ) error {
- var errs []error
- for _, f := range funcs {
- err := f(devs, conf)
- if err == nil {
- return nil
- }
- errs = append(errs, err)
- }
- return errors.NewAggregate(errs)
- }
- func (adapter *MegaRaidAdaptor) BuildRaid0(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return cliBuildRaid(devs, conf, adapter.megacliBuildRaid0, adapter.storcliBuildRaid0)
- }
- func (adapter *MegaRaidAdaptor) BuildRaid1(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return cliBuildRaid(devs, conf, adapter.megacliBuildRaid1, adapter.storcliBuildRaid1)
- }
- func (adapter *MegaRaidAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return cliBuildRaid(devs, conf, adapter.megacliBuildRaid5, adapter.storcliBuildRaid5)
- }
- func (adapter *MegaRaidAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
- return cliBuildRaid(devs, conf, adapter.megacliBuildRaid10, adapter.storcliBuildRaid10)
- }
- func (adapter *MegaRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage) error {
- return cliBuildRaid(devs, nil, adapter.megacliBuildNoRaid, adapter.storcliBuildNoRaid)
- }
- func (raid *MegaRaid) GetStorcliAdaptor() ([]*StorcliAdaptor, map[string]*StorcliAdaptor, error) {
- ret := make(map[string]*StorcliAdaptor)
- cmd := GetCommand2("/call", "show", "|", "grep", "-iE", `'^(Controller|Product Name|Serial Number|Bus Number|Device Number|Function Number)\s='`)
- lines, err := raid.term.Run(cmd)
- if err != nil {
- return nil, nil, errors.Wrap(err, "Get storcli adapter")
- }
- adapter := newStorcliAdaptor()
- list := make([]*StorcliAdaptor, 0)
- for _, l := range lines {
- adapter.parseLine(l)
- if adapter.isComplete() {
- ret[adapter.key()] = adapter
- list = append(list, adapter)
- adapter = newStorcliAdaptor()
- }
- }
- return list, ret, nil
- }
- func (adapter *MegaRaidAdaptor) storcliCtrlIndex() (int, error) {
- if adapter.storcliIndex >= 0 {
- return adapter.storcliIndex, nil
- }
- _, storcliAdaps, err := adapter.raid.GetStorcliAdaptor()
- if err != nil {
- return -1, errors.Wrap(err, "Get all Storcli adaptor")
- }
- storAdap, ok := storcliAdaps[adapter.key()]
- if !ok {
- return -1, errors.Errorf("Not found storcli adaptor by SN %q", adapter.key())
- }
- return storAdap.Controller, nil
- }
- func (adapter *MegaRaidAdaptor) GetStorcliCommand(args ...string) (string, error) {
- controllerIdx, err := adapter.storcliCtrlIndex()
- if err != nil {
- return "", errors.Errorf("Adapter %d get storcli controller index: %v", adapter.index, err)
- }
- nargs := []string{fmt.Sprintf("/c%d", controllerIdx)}
- nargs = append(nargs, args...)
- return GetCommand2(nargs...), nil
- }
- func (adapter *MegaRaidAdaptor) storcliIsJBODEnabled() bool {
- return storcliIsJBODEnabled(adapter.GetStorcliCommand, adapter.getTerm())
- }
- func (adapter *MegaRaidAdaptor) storcliEnableJBOD(enable bool) bool {
- val := "off"
- if enable {
- val = "on"
- }
- cmd, err := adapter.GetStorcliCommand("set", fmt.Sprintf("jbod=%s", val), "force")
- if err != nil {
- log.Errorf("get storcli controller cmd: %v", err)
- return false
- }
- _, err = adapter.remoteRun(cmd)
- if err != nil {
- log.Errorf("EnableJBOD %v fail: %v", enable, err)
- return false
- }
- return true
- }
- func (adapter *MegaRaidAdaptor) storcliBuildJBOD(devs []*baremetal.BaremetalStorage) error {
- return storcliBuildJBOD(adapter.GetStorcliCommand, adapter.getTerm(), devs)
- }
- func (adapter *MegaRaidAdaptor) storcliBuildNoRaid(devs []*baremetal.BaremetalStorage, _ *api.BaremetalDiskConfig) error {
- return storcliBuildNoRaid(adapter.GetStorcliCommand, adapter.getTerm(), devs)
- }
- func (adapter *MegaRaidAdaptor) megacliBuildNoRaid(devs []*baremetal.BaremetalStorage, _ *api.BaremetalDiskConfig) error {
- err := adapter.megacliBuildJBOD(devs)
- if err == nil {
- return nil
- }
- log.Errorf("Try megacli build jbod fail: %v", err)
- cmds := []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
- }
- func (adapter *MegaRaidAdaptor) megacliIsJBODEnabled() bool {
- cmd := GetCommand("-AdpGetProp", "-EnableJBOD", fmt.Sprintf("-a%d", adapter.index))
- pref := fmt.Sprintf("Adapter %d: JBOD: ", adapter.index)
- lines, err := adapter.remoteRun(cmd)
- if err != nil {
- log.Errorf("megacliIsJBODEnabled error: %v", err)
- return false
- }
- for _, line := range lines {
- if strings.HasPrefix(line, pref) {
- val := strings.ToLower(strings.TrimSpace(line[len(pref):]))
- if val == "disabled" {
- return false
- }
- return true
- }
- }
- return false
- }
- func (adapter *MegaRaidAdaptor) megacliEnableJBOD(enable bool) bool {
- var val string = "0"
- if enable {
- val = "1"
- }
- cmd := GetCommand("-AdpSetProp", "-EnableJBOD", fmt.Sprintf("-%s", val), fmt.Sprintf("-a%d", adapter.index))
- _, err := adapter.remoteRun(cmd)
- if err != nil {
- log.Errorf("enable jbod %v fail: %v", enable, err)
- return false
- }
- return true
- }
- func (adapter *MegaRaidAdaptor) megacliBuildJBOD(devs []*baremetal.BaremetalStorage) error {
- if !adapter.megacliIsJBODEnabled() {
- adapter.megacliEnableJBOD(true)
- adapter.megacliEnableJBOD(false)
- adapter.megacliEnableJBOD(true)
- }
- if !adapter.megacliIsJBODEnabled() {
- return fmt.Errorf("JBOD not supported")
- }
- // try clear jbod disk of devices
- if err := adapter.megacliClearJBODDisks(devs); err != nil {
- log.Warningf("try clear megaraid jbod disks before make jbod: %s", err)
- }
- devIds := []string{}
- for _, d := range devs {
- devIds = append(devIds, GetSpecString(d))
- }
- 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() error {
- lvIdx, err := adapter.GetLogicVolumes()
- if err != nil {
- return errors.Wrap(err, "GetLogicVolumes")
- }
- if len(lvIdx) == 0 {
- log.Infof("RemoveLogicVolumes: no logical volume to delete!")
- return nil
- }
- errs := make([]error, 0)
- lvIdx = raiddrivers.ReverseLogicalArray(lvIdx)
- for i := range lvIdx {
- lv := lvIdx[i]
- switch lv.Driver {
- case raiddrivers.RaidDriverToolMegacli64:
- cmd := GetCommand("-CfgLdDel", fmt.Sprintf("-L%d", lv.Index), "-Force", fmt.Sprintf("-a%d", adapter.index))
- _, err := adapter.remoteRun(cmd)
- if err != nil {
- errs = append(errs, err)
- }
- case raiddrivers.RaidDriverToolStorecli:
- cmd := GetCommand2(fmt.Sprintf("/c%d/v%d", adapter.index, lv.Index), "delete", "force")
- _, err := adapter.remoteRun(cmd)
- if err != nil {
- errs = append(errs, err)
- }
- }
- }
- if len(errs) > 0 {
- return errors.NewAggregate(errs)
- }
- return nil
- }
- func (adapter *MegaRaidAdaptor) storcliClearJBODDisks() error {
- return storcliClearJBODDisks(
- adapter.GetStorcliCommand, adapter.getTerm(),
- adapter.devs,
- )
- }
- func (adapter *MegaRaidAdaptor) megacliClearJBODDisks(devs []*baremetal.BaremetalStorage) error {
- devIds := []string{}
- for _, dev := range devs {
- devIds = append(devIds, GetSpecString(dev))
- }
- errs := make([]error, 0)
- for _, devId := range devIds {
- cmd := GetCommand("-PDMakeGood", "-PhysDrv", fmt.Sprintf("'[%s]'", devId), "-Force", fmt.Sprintf("-a%d", adapter.index))
- if _, err := adapter.remoteRun(cmd); err != nil {
- err = errors.Wrapf(err, "PDMakeGood megacli cmd %v", cmd)
- errs = append(errs, err)
- }
- }
- return errors.NewAggregate(errs)
- }
- func (adapter *MegaRaidAdaptor) megacliClearAllJBODDisks() error {
- allDevs := make([]*baremetal.BaremetalStorage, 0)
- for idx, dev := range adapter.devs {
- allDevs = append(allDevs, dev.ToBaremetalStorage(idx))
- }
- return adapter.megacliClearJBODDisks(allDevs)
- }
- func (adapter *MegaRaidAdaptor) clearJBODDisks() {
- if err := adapter.megacliClearAllJBODDisks(); err != nil {
- log.Errorf("megacliClearAllJBODDisks error: %v", err)
- log.Infof("try storcliClearJBODDisks")
- if err := adapter.storcliClearJBODDisks(); err != nil {
- log.Errorf("storcliClearJBODDisks error: %v", err)
- }
- }
- adapter.megacliEnableJBOD(true)
- adapter.megacliEnableJBOD(false)
- adapter.megacliEnableJBOD(true)
- adapter.megacliEnableJBOD(false)
- }
- type MegaRaid struct {
- term raid.IExecTerm
- adapters []*MegaRaidAdaptor
- PhyDevsCnt int
- Capacity int64
- }
- func NewMegaRaid(term raid.IExecTerm) raiddrivers.IRaidDriver {
- return &MegaRaid{
- term: term,
- adapters: make([]*MegaRaidAdaptor, 0),
- }
- }
- func GetCommand(args ...string) string {
- bin := "/opt/MegaRAID/MegaCli/MegaCli64"
- return raiddrivers.GetCommand(bin, args...)
- }
- func GetCommand2(args ...string) string {
- bin := "/opt/MegaRAID/storcli/storcli64"
- return raiddrivers.GetCommand(bin, args...)
- }
- func (raid *MegaRaid) GetName() string {
- return baremetal.DISK_DRIVER_MEGARAID
- }
- func (raid *MegaRaid) ParsePhyDevs() error {
- if !utils.IsInStringArray(raiddrivers.MODULE_MEGARAID, raiddrivers.GetModules(raid.term)) {
- return fmt.Errorf("Not found megaraid_sas module")
- }
- if err := raid.parsePhyDevsUseMegacli(); err == nil {
- return nil
- } else {
- // try use storecli parse physical devices
- if err := raid.parsePhyDevsUseStorcli(); err != nil {
- return errors.Wrap(err, "parsePhyDevsUseStorcli")
- }
- }
- return nil
- }
- func (raid *MegaRaid) parsePhyDevsUseMegacli() error {
- cmd := GetCommand("-PDList", "-aALL")
- ret, err := raid.term.Run(cmd)
- if err != nil {
- return fmt.Errorf("List raid disk error: %v", err)
- }
- if raiddrivers.Debug {
- log.Debugf("-PDList -aALL: %s", ret)
- }
- err = raid.parsePhyDevs(ret)
- if err != nil {
- return fmt.Errorf("parse physical disk device error: %v", err)
- }
- return nil
- }
- func (raid *MegaRaid) parsePhyDevsUseStorcli() error {
- adapters, _, err := raid.GetStorcliAdaptor()
- if err != nil {
- return errors.Wrap(err, "Get storcli adapter")
- }
- raid.adapters = make([]*MegaRaidAdaptor, 0)
- for _, ada := range adapters {
- megaAda, err := NewMegaRaidAdaptorByStorcli(ada, raid)
- if err != nil {
- return errors.Wrap(err, "NewMegaRaidAdaptorByStorcli")
- }
- devs, err := ada.getMegaPhyDevs(GetCommand2, raid.term)
- if err != nil {
- return errors.Wrapf(err, "get storcli %d mega PDs", ada.Controller)
- }
- for i := range devs {
- megaAda.AddPhyDev(devs[i])
- }
- raid.adapters = append(raid.adapters, megaAda)
- }
- return nil
- }
- func (raid *MegaRaid) parsePhyDevs(lines []string) error {
- phyDev := NewMegaRaidPhyDev()
- var adapter *MegaRaidAdaptor
- var err error
- for _, line := range lines {
- adapterStr := regutils2.GetParams(adapterPatter, line)["idx"]
- if adapterStr != "" {
- adapterInt, _ := strconv.Atoi(adapterStr)
- adapter, err = NewMegaRaidAdaptor(adapterInt, raid)
- if err != nil {
- return errors.Wrapf(err, "New raid adapter %d", adapterInt)
- }
- raid.adapters = append(raid.adapters, adapter)
- } else if phyDev.parseLine(line) && phyDev.isComplete() {
- if adapter == nil {
- return fmt.Errorf("Adapter is nil")
- }
- adapter.AddPhyDev(phyDev)
- raid.PhyDevsCnt += 1
- raid.Capacity += phyDev.GetSize()
- phyDev = NewMegaRaidPhyDev()
- }
- }
- for _, adapter := range raid.adapters {
- if err := adapter.addPhyDevsStripSize(); err != nil {
- log.Errorf("Adapter %d fill phsical devices strip size: %v", adapter.GetIndex(), err)
- }
- }
- return nil
- }
- func (adapter *MegaRaidAdaptor) addPhyDevsStripSize() error {
- for _, dev := range adapter.devs {
- dev.minStripSize = adapter.minStripSize
- dev.maxStripSize = adapter.maxStripSize
- }
- return nil
- }
- func (raid *MegaRaid) CleanRaid() error {
- for _, adapter := range raid.adapters {
- adapter.clearJBODDisks()
- adapter.RemoveLogicVolumes()
- }
- return nil
- }
- func (raid *MegaRaid) PreBuildRaid(_ []*api.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 {
- errs := make([]error, 0)
- cmd := GetCommand("-CfgForeign", "-Clear", "-aALL")
- _, err := raid.term.Run(cmd)
- if err != nil {
- errs = append(errs, err)
- cmd2 := GetCommand2("/call/fall", "delete")
- if _, err := raid.term.Run(cmd2); err == nil {
- return nil
- } else {
- errs = append(errs, err)
- }
- }
- return errors.NewAggregate(errs)
- }
- func (raid *MegaRaid) RemoveLogicVolumes() {
- for _, adapter := range raid.adapters {
- adapter.RemoveLogicVolumes()
- }
- }
|