diff --git a/pkg/baremetal/utils/raid/megactl/megactl.go b/pkg/baremetal/utils/raid/megactl/megactl.go index 2330b0290d..5adbdd70b7 100644 --- a/pkg/baremetal/utils/raid/megactl/megactl.go +++ b/pkg/baremetal/utils/raid/megactl/megactl.go @@ -444,16 +444,25 @@ func (adapter *MegaRaidAdaptor) GetDevices() []*baremetal.BaremetalStorage { } func (adapter *MegaRaidAdaptor) GetLogicVolumes() ([]*raiddrivers.RaidLogicalVolume, error) { - lvs, err := adapter.getMegacliLogicVolumes() - if err == nil { - return lvs, nil - } - errs := []error{err} - if lvs, err := adapter.getStorcliLogicVolums(); err == nil { - return lvs, nil - } else { + errs := make([]error, 0) + megaLvs, err := adapter.getMegacliLogicVolumes() + if err != nil { errs = append(errs, err) } + storeLvs, err := adapter.getStorcliLogicVolums() + if err != nil { + errs = append(errs, err) + } + if len(megaLvs) > 0 { + return megaLvs, nil + } + if len(storeLvs) > 0 { + return storeLvs, nil + } + if len(errs) == 0 { + // no error, no volume + return []*raiddrivers.RaidLogicalVolume{}, nil + } return nil, errors.NewAggregate(errs) } @@ -461,24 +470,18 @@ func (adapter *MegaRaidAdaptor) getMegacliLogicVolumes() ([]*raiddrivers.RaidLog cmd := GetCommand("-LDInfo", "-Lall", fmt.Sprintf("-a%d", adapter.index)) ret, err := adapter.remoteRun(cmd) if err != nil { - return nil, fmt.Errorf("getMegacliLogicVolumes error: %v", err) + return nil, errors.Wrapf(err, "remoteRun %s", cmd) } - return adapter.parseLogicVolumes(ret) + 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) { -// cmd := GetCommand2(fmt.Sprintf("/c%d/vall", adapter.index), "show") -// ret, err := adapter.remoteRun(cmd) -// if err != nil { -// return nil, fmt.Errorf("getStorcliLogicVolums error: %v", err) -// } -// lvs, err := parseStorcliLogicalVolumes(adapter.index, ret) -// if err != nil { -// return nil, err -// } -// return lvs, nil -// } - func (adapter *MegaRaidAdaptor) getStorcliLogicVolums() ([]*raiddrivers.RaidLogicalVolume, error) { lvs, err := adapter.getStorcliLogicVolumsV2() if err != nil { @@ -488,10 +491,11 @@ func (adapter *MegaRaidAdaptor) getStorcliLogicVolums() ([]*raiddrivers.RaidLogi for i := range lvs { lv := lvs[i] ret[i] = &raiddrivers.RaidLogicalVolume{ - Index: i, + Index: lv.Index, Adapter: adapter.index, BlockDev: lv.GetOSDevice(), IsSSD: tristate.NewFromBool(lv.IsSSD()), + Driver: raiddrivers.RaidDriverToolStorecli, } } return ret, nil @@ -905,21 +909,34 @@ func (adapter *MegaRaidAdaptor) megacliBuildJBOD(devs []*baremetal.BaremetalStor func (adapter *MegaRaidAdaptor) RemoveLogicVolumes() error { lvIdx, err := adapter.GetLogicVolumes() if err != nil { - return err + return errors.Wrap(err, "GetLogicVolumes") } - for _, i := range raiddrivers.ReverseLogicalArray(lvIdx) { - cmd := GetCommand("-CfgLdDel", fmt.Sprintf("-L%d", i.Index), "-Force", fmt.Sprintf("-a%d", adapter.index)) - _, err := adapter.remoteRun(cmd) - if err == nil { - continue - } - errs := []error{err} - cmd = GetCommand2(fmt.Sprintf("/c%d/v%d", adapter.index, i.Index), "delete", "force") - if _, err := adapter.remoteRun(cmd); err != nil { - errs = append(errs, err) - return errors.NewAggregate(errs) + 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 } diff --git a/pkg/baremetal/utils/raid/megactl/storcli.go b/pkg/baremetal/utils/raid/megactl/storcli.go index 539397bac4..807f17f64c 100644 --- a/pkg/baremetal/utils/raid/megactl/storcli.go +++ b/pkg/baremetal/utils/raid/megactl/storcli.go @@ -22,6 +22,7 @@ import ( "strings" "yunion.io/x/jsonutils" + "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/baremetal/utils/raid" @@ -279,6 +280,50 @@ type StorcliLogicalVolume struct { Index int } +func fetchLvInfo(data *jsonutils.JSONDict, keyIdx string, vIdx int) (*StorcliLogicalVolume, error) { + lvObj, err := data.Get(keyIdx) + if err != nil { + return nil, errors.Wrapf(err, "Get %s", keyIdx) + } + + // parse PDs + pdKey := fmt.Sprintf("PDs for VD %d", vIdx) + if !data.Contains(pdKey) { + return nil, nil + } + + lvArr := make([]*StorcliLogicalVolume, 0) + if err := lvObj.Unmarshal(&lvArr); err != nil { + return nil, errors.Wrapf(err, "Unmarshal %s to StorcliLogicalVolume", lvObj) + } + lv := lvArr[0] + lv.Index = vIdx + lv.Name = keyIdx + pdObj, err := data.Get(pdKey) + if err != nil { + return nil, errors.Wrapf(err, "Get %s", pdKey) + } + pds := make([]*StorcliLogicalVolumePD, 0) + if err := pdObj.Unmarshal(&pds); err != nil { + return nil, errors.Wrapf(err, "Unmarshal %s to PDs", pdObj) + } + lv.PDs = pds + + // parse Properties + ppKey := fmt.Sprintf("VD%d Properties", vIdx) + ppObj, err := data.Get(ppKey) + if err != nil { + return nil, errors.Wrapf(err, "Get %s", ppKey) + } + props := new(StorcliLogicalVolumeProperties) + if err := ppObj.Unmarshal(props); err != nil { + return nil, errors.Wrapf(err, "Unmarshal %s to Properties", ppObj) + } + lv.Properties = props + + return lv, nil +} + func (lvs *StorcliLogicalVolumes) GetLogicalVolumes(controller int) ([]*StorcliLogicalVolume, error) { data, err := lvs.responseData(controller) if err != nil { @@ -287,55 +332,29 @@ func (lvs *StorcliLogicalVolumes) GetLogicalVolumes(controller int) ([]*StorcliL } return nil, errors.Wrap(err, "responseData") } - vIdx := 0 result := make([]*StorcliLogicalVolume, 0) - for { - // find volumes of controller - keyIdx := fmt.Sprintf("/c%d/v%d", controller, vIdx) - if !data.Contains(keyIdx) { - break + dataMap, err := data.GetMap() + if err != nil { + return nil, errors.Wrap(err, "response data get map") + } + vdPrefix := fmt.Sprintf("/c%d/v", controller) + for k := range dataMap { + if strings.HasPrefix(k, vdPrefix) { + // find a LV like cXvXXX + vIdx, err := strconv.ParseInt(k[len(vdPrefix):], 10, 64) + if err != nil { + log.Errorf("key %s not a valid LV key: %s", k, err) + continue + } + lv, err := fetchLvInfo(data, k, int(vIdx)) + if err != nil { + log.Errorf("fetchLvInfo %s failed %s", k, err) + continue + } + if lv != nil { + result = append(result, lv) + } } - lvObj, err := data.Get(keyIdx) - if err != nil { - return nil, errors.Wrapf(err, "Get %s", keyIdx) - } - - // parse PDs - pdKey := fmt.Sprintf("PDs for VD %d", vIdx) - if !data.Contains(pdKey) { - break - } - lvArr := make([]*StorcliLogicalVolume, 0) - if err := lvObj.Unmarshal(&lvArr); err != nil { - return nil, errors.Wrapf(err, "Unmarshal %s to StorcliLogicalVolume", lvObj) - } - lv := lvArr[0] - lv.Index = vIdx - lv.Name = keyIdx - pdObj, err := data.Get(pdKey) - if err != nil { - return nil, errors.Wrapf(err, "Get %s", pdKey) - } - pds := make([]*StorcliLogicalVolumePD, 0) - if err := pdObj.Unmarshal(&pds); err != nil { - return nil, errors.Wrapf(err, "Unmarshal %s to PDs", pdObj) - } - lv.PDs = pds - - // parse Properties - ppKey := fmt.Sprintf("VD%d Properties", vIdx) - ppObj, err := data.Get(ppKey) - if err != nil { - return nil, errors.Wrapf(err, "Get %s", ppKey) - } - props := new(StorcliLogicalVolumeProperties) - if err := ppObj.Unmarshal(props); err != nil { - return nil, errors.Wrapf(err, "Unmarshal %s to Properties", ppObj) - } - lv.Properties = props - - result = append(result, lv) - vIdx++ } return result, nil } diff --git a/pkg/baremetal/utils/raid/megactl/storcli_test.go b/pkg/baremetal/utils/raid/megactl/storcli_test.go index 5b7abfc2e1..c06072cba2 100644 --- a/pkg/baremetal/utils/raid/megactl/storcli_test.go +++ b/pkg/baremetal/utils/raid/megactl/storcli_test.go @@ -656,12 +656,18 @@ func TestStorcliLogicalVolumes_GetLogicalVolumes(t *testing.T) { assert := assert.New(t) assert.Equal(7, len(lvs), "Should 7 logical volumes") - first2SDDs := lvs[0].PDs - assert.Equal("SSD", first2SDDs[0].Med) - assert.Equal("446.625 GB", first2SDDs[0].Size) - assert.Equal("SSD", first2SDDs[1].Med) - assert.Equal("446.625 GB", first2SDDs[1].Size) - assert.Equal(true, lvs[0].IsSSD()) - assert.Equal("/dev/sda", lvs[0].Properties.DeviceName) - assert.Equal("/dev/sdg", lvs[6].Properties.DeviceName) + for i := range lvs { + switch lvs[i].Index { + case 0: + first2SDDs := lvs[i].PDs + assert.Equal("SSD", first2SDDs[0].Med) + assert.Equal("446.625 GB", first2SDDs[0].Size) + assert.Equal("SSD", first2SDDs[1].Med) + assert.Equal("446.625 GB", first2SDDs[1].Size) + assert.Equal(true, lvs[i].IsSSD()) + assert.Equal("/dev/sda", lvs[i].Properties.DeviceName) + case 6: + assert.Equal("/dev/sdg", lvs[i].Properties.DeviceName) + } + } } diff --git a/pkg/baremetal/utils/raid/raid.go b/pkg/baremetal/utils/raid/raid.go index db5571e347..3a3b2af6af 100644 --- a/pkg/baremetal/utils/raid/raid.go +++ b/pkg/baremetal/utils/raid/raid.go @@ -137,11 +137,20 @@ func ReverseLogicalArray(input []*RaidLogicalVolume) []*RaidLogicalVolume { return s } +type TRaidDriverToolType string + +const ( + RaidDriverToolMegacli64 = TRaidDriverToolType("megacli64") + RaidDriverToolStorecli = TRaidDriverToolType("storecli") +) + type RaidLogicalVolume struct { Index int Adapter int BlockDev string IsSSD tristate.TriState + + Driver TRaidDriverToolType } func SGMap(term IExecTerm) ([]compute.SGMapItem, error) {