mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
feat(baremetal): adaptec raid driver
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/baremetal-base:v0.3.2
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/baremetal-base:v0.3.3
|
||||
|
||||
MAINTAINER "Zexi Li <lizexi@yunionyun.com>"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
FROM --platform=linux/amd64 registry.cn-beijing.aliyuncs.com/yunionio/centos-build:1.1-4 as build
|
||||
RUN yum install -y https://iso.yunion.cn/vm-images/baremetal-pxerom-1.1.0-21080303.x86_64.rpm
|
||||
#RUN yum install -y http://192.168.122.112:8083/baremetal-pxerom-1.1.0-21080303.x86_64.rpm
|
||||
RUN yum install -y https://iso.yunion.cn/vm-images/baremetal-pxerom-1.1.0-21092209.x86_64.rpm
|
||||
#RUN yum install -y http://192.168.23.50:8083/baremetal-pxerom-1.1.0-21092209.x86_64.rpm
|
||||
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/onecloud-base:v0.3.5
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ climc-base:
|
||||
docker buildx build --platform linux/arm64,linux/amd64 --push \
|
||||
-t registry.cn-beijing.aliyuncs.com/yunionio/climc-base:$(CLIMC_BASE_VERSION) -f ./Dockerfile.climc-base .
|
||||
|
||||
BAREMETAL_BASE_VERSION = v0.3.2
|
||||
BAREMETAL_BASE_VERSION = v0.3.3
|
||||
|
||||
baremetal-base:
|
||||
$(DOCKER_BUILDX)/baremetal-base:$(BAREMETAL_BASE_VERSION) -f ./Dockerfile.baremetal-base .
|
||||
|
||||
@@ -29,12 +29,13 @@ const (
|
||||
|
||||
DEFAULT_DISK_TYPE = DISK_TYPE_ROTATE
|
||||
|
||||
DISK_DRIVER_MEGARAID = "MegaRaid"
|
||||
DISK_DRIVER_LINUX = "Linux"
|
||||
DISK_DRIVER_HPSARAID = "HPSARaid"
|
||||
DISK_DRIVER_MPT2SAS = "Mpt2SAS"
|
||||
DISK_DRIVER_MARVELRAID = "MarvelRaid"
|
||||
DISK_DRIVER_PCIE = "PCIE"
|
||||
DISK_DRIVER_MEGARAID = "MegaRaid"
|
||||
DISK_DRIVER_LINUX = "Linux"
|
||||
DISK_DRIVER_HPSARAID = "HPSARaid"
|
||||
DISK_DRIVER_MPT2SAS = "Mpt2SAS"
|
||||
DISK_DRIVER_MARVELRAID = "MarvelRaid"
|
||||
DISK_DRIVER_ADAPTECRAID = "AdaptecRaid"
|
||||
DISK_DRIVER_PCIE = "PCIE"
|
||||
|
||||
HDD_DISK_SPEC_TYPE = "HDD"
|
||||
SSD_DISK_SPEC_TYPE = "SSD"
|
||||
@@ -60,6 +61,7 @@ var (
|
||||
DISK_DRIVER_HPSARAID,
|
||||
DISK_DRIVER_MPT2SAS,
|
||||
DISK_DRIVER_MARVELRAID,
|
||||
DISK_DRIVER_ADAPTECRAID,
|
||||
)
|
||||
|
||||
DISK_DRIVERS = sets.NewString(
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
@@ -91,7 +92,7 @@ func DetectStorageInfo(term raid.IExecTerm, wait bool) ([]*baremetal.BaremetalSt
|
||||
break
|
||||
}
|
||||
}
|
||||
log.Infof("RaidDiskInfo: %#v, NonRaidSCSIDiskInfo: %#v, PCIEDiskInfo: %#v", raidDiskInfo, nonRaidDiskInfo, pcieDiskInfo)
|
||||
log.Infof("RaidDiskInfo: %s, NonRaidSCSIDiskInfo: %s, PCIEDiskInfo: %s", jsonutils.Marshal(raidDiskInfo), jsonutils.Marshal(nonRaidDiskInfo), jsonutils.Marshal(pcieDiskInfo))
|
||||
if len(nonRaidDiskInfo) < len(lvDiskInfo) {
|
||||
return nil, nil, nil, fmt.Errorf("Fail to retrieve disk info")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,650 @@
|
||||
// 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 adaptec
|
||||
|
||||
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"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
"yunion.io/x/onecloud/pkg/compute/baremetal"
|
||||
"yunion.io/x/onecloud/pkg/util/regutils2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
raid.RegisterDriver(api.DISK_DRIVER_ADAPTECRAID, NewAdaptecRaid)
|
||||
}
|
||||
|
||||
const (
|
||||
ControllerModeRaidExposeRaw = "RAID (Expose RAW)"
|
||||
ControllerModeRaidHideRaw = "RAID (Hide RAW)"
|
||||
ControllerModeMixed = "Mixed"
|
||||
)
|
||||
|
||||
type AdaptecRaid struct {
|
||||
term raid.IExecTerm
|
||||
adapters []*AdaptecRaidAdaptor
|
||||
}
|
||||
|
||||
func NewAdaptecRaid(term raid.IExecTerm) raid.IRaidDriver {
|
||||
return &AdaptecRaid{
|
||||
term: term,
|
||||
adapters: make([]*AdaptecRaidAdaptor, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func GetCommand(args ...string) string {
|
||||
bin := "/opt/adaptec/arcconf"
|
||||
return raid.GetCommand(bin, args...)
|
||||
}
|
||||
|
||||
func (raid *AdaptecRaid) GetName() string {
|
||||
return baremetal.DISK_DRIVER_ADAPTECRAID
|
||||
}
|
||||
|
||||
func (r *AdaptecRaid) ParsePhyDevs() error {
|
||||
cmd := GetCommand("LIST")
|
||||
ret, err := r.term.Run(cmd)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "list controllers")
|
||||
}
|
||||
if err := r.parsePhyDevs(ret); err != nil {
|
||||
return errors.Wrap(err, "parse physical device")
|
||||
}
|
||||
if len(r.adapters) == 0 {
|
||||
return errors.Errorf("Not found adaptec raid controller")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (raid *AdaptecRaid) CleanRaid() error {
|
||||
for _, ada := range raid.adapters {
|
||||
ada.removeJBODDisks()
|
||||
ada.RemoveLogicVolumes()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *AdaptecRaid) GetAdapters() []raid.IRaidAdapter {
|
||||
ret := make([]raid.IRaidAdapter, 0)
|
||||
for _, a := range r.adapters {
|
||||
ret = append(ret, a)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *AdaptecRaid) PreBuildRaid(confs []*api.BaremetalDiskConfig, adapterIdx int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
adaptorIDPatter = regexp.MustCompile(`Controller (?P<idx>[0-9]+):`)
|
||||
)
|
||||
|
||||
func getAdaptorIndex(line string) int {
|
||||
adapStr := regutils2.GetParams(adaptorIDPatter, line)["idx"]
|
||||
if adapStr == "" {
|
||||
return -1
|
||||
}
|
||||
adapInt, err := strconv.Atoi(adapStr)
|
||||
if err != nil {
|
||||
log.Errorf("Parse adapator string %q id error: %v", line, err)
|
||||
return -1
|
||||
}
|
||||
return adapInt
|
||||
}
|
||||
|
||||
func (raid *AdaptecRaid) parsePhyDevs(lines []string) error {
|
||||
for _, line := range lines {
|
||||
index := getAdaptorIndex(line)
|
||||
if index == -1 {
|
||||
continue
|
||||
}
|
||||
ada, err := NewAdaptecRaidAdaptor(index, raid)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "New raid adaptor %d", index)
|
||||
}
|
||||
raid.adapters = append(raid.adapters, ada)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AdaptecRaidAdaptor struct {
|
||||
*adaptorInfo
|
||||
|
||||
index int
|
||||
raid *AdaptecRaid
|
||||
devs []*AdaptecRaidPhyDev
|
||||
}
|
||||
|
||||
var (
|
||||
_ raid.IRaidAdapter = new(AdaptecRaidAdaptor)
|
||||
)
|
||||
|
||||
func NewAdaptecRaidAdaptor(index int, raid *AdaptecRaid) (*AdaptecRaidAdaptor, error) {
|
||||
adaptor := AdaptecRaidAdaptor{
|
||||
index: index,
|
||||
raid: raid,
|
||||
}
|
||||
if err := adaptor.fillInfo(); err != nil {
|
||||
return nil, errors.Wrapf(err, "fill adaptor %d info", adaptor.index)
|
||||
}
|
||||
if err := adaptor.fillDevices(); err != nil {
|
||||
return nil, errors.Wrap(err, "fill physical devices")
|
||||
}
|
||||
/*
|
||||
* if !adaptor.isRaidHideRawMode() {
|
||||
* if err := adaptor.setControllerModeRaidHideRaw(); err != nil {
|
||||
* return nil, errors.Wrap(err, "set controller mode to raid hide raw")
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
return &adaptor, nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) GetIndex() int {
|
||||
return ada.index
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) PreBuildRaid(confs []*api.BaremetalDiskConfig) error {
|
||||
// set to raid expose raw mode or mixed mode
|
||||
if !ada.isRaidExposeRawMode() && !ada.isMixedMode() {
|
||||
err := func() error {
|
||||
errs := []error{}
|
||||
if err := ada.setControllerModeRaidExposeRaw(); err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
if err := ada.setControllerModeMixed(); err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return errors.NewAggregate(errs)
|
||||
}()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "set raid to expose raw or mixed mode")
|
||||
}
|
||||
}
|
||||
if err := ada.removeJBODDisks(); err != nil {
|
||||
log.Warningf("remove all JBOD disks: %v", err)
|
||||
}
|
||||
// uninitialize all device to ready state
|
||||
if err := ada.uninitializeAllDevice(); err != nil {
|
||||
// return errors.Wrap(err, "uninitialize all devices")
|
||||
log.Warningf("uninitializeAllDevice error: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) getInitializeCmd(args ...string) string {
|
||||
newArgs := []string{"TASK", "START", fmt.Sprintf("%d", ada.GetIndex()), "DEVICE"}
|
||||
newArgs = append(newArgs, args...)
|
||||
newArgs = append(newArgs, "INITIALIZE", "noprompt")
|
||||
return GetCommand(newArgs...)
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) initializeDevice(channel string, id string) error {
|
||||
cmd := ada.getInitializeCmd(channel, id)
|
||||
_, err := ada.remoteRun(fmt.Sprintf("initialize device %s:%s", channel, id), cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) initializeAllDevice() error {
|
||||
cmd := ada.getInitializeCmd("ALL")
|
||||
_, err := ada.remoteRun("initialize all device", cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) uninitializeDevice(channel string, id string) error {
|
||||
cmd := ada.getUninitializeCmd(channel, id)
|
||||
_, err := ada.remoteRun(fmt.Sprintf("uninitialize device %s:%s", channel, id), cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) getUninitializeCmd(args ...string) string {
|
||||
newArgs := []string{"TASK", "START", fmt.Sprintf("%d", ada.GetIndex()), "DEVICE"}
|
||||
newArgs = append(newArgs, args...)
|
||||
newArgs = append(newArgs, "UNINITIALIZE", "noprompt")
|
||||
return GetCommand(newArgs...)
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) uninitializeAllDevice() error {
|
||||
cmd := ada.getUninitializeCmd("ALL")
|
||||
_, err := ada.remoteRun("uninitialize all devices", cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) getTerm() raid.IExecTerm {
|
||||
return ada.raid.term
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) remoteRun(hint string, cmd string) ([]string, error) {
|
||||
out, err := ada.getTerm().Run(cmd)
|
||||
if err != nil {
|
||||
return out, errors.Wrapf(err, "%q, out: %v", hint, out)
|
||||
}
|
||||
log.Debugf("remote run cmd %s %q successfully: %v", hint, cmd, out)
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) fillInfo() error {
|
||||
cmd := GetCommand("GETCONFIG", fmt.Sprintf("%d", ada.index), "AD")
|
||||
ret, err := ada.remoteRun("get AD config", cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := getAdaptorInfo(ret)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get adaptor info")
|
||||
}
|
||||
ada.adaptorInfo = info
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) fillDevices() error {
|
||||
cmd := GetCommand("GETCONFIG", fmt.Sprintf("%d", ada.index), "PD")
|
||||
ret, err := ada.remoteRun("get PD config", cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
devs := getPhyDevices(ada.GetIndex(), ret)
|
||||
ada.devs = append(ada.devs, devs...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPhyDevices(adapter int, lines []string) []*AdaptecRaidPhyDev {
|
||||
dev := newPhyDev(adapter)
|
||||
devs := make([]*AdaptecRaidPhyDev, 0)
|
||||
for _, line := range lines {
|
||||
if dev.parseLine(line) && dev.isComplete() {
|
||||
tmpDev := dev
|
||||
devs = append(devs, tmpDev)
|
||||
dev = newPhyDev(adapter)
|
||||
}
|
||||
}
|
||||
return devs
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) getChannelId(storage *baremetal.BaremetalStorage) (string, string, error) {
|
||||
if storage.Addr == "" {
|
||||
return "", "", errors.Errorf("storage %#v addr is empty", storage)
|
||||
}
|
||||
parts := strings.Split(storage.Addr, ":")
|
||||
if len(parts) != 2 {
|
||||
return "", "", errors.Errorf("invalid storage %#v addr %q", storage, storage.Addr)
|
||||
}
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) getCreateCmd(args ...string) string {
|
||||
newArgs := []string{"CREATE", fmt.Sprintf("%d", ada.GetIndex())}
|
||||
newArgs = append(newArgs, args...)
|
||||
return GetCommand(newArgs...)
|
||||
}
|
||||
|
||||
// setControllerMode change adapter controller's mode
|
||||
// Controller Modes : 0 - RAID: Expose RAW
|
||||
// : 1 - Auto Volume Mode
|
||||
// : 2 - HBA Mode
|
||||
// : 3 - RAID: Hide RAW
|
||||
// : 4 - Simple Volume Mode
|
||||
// : 5 - Mixed
|
||||
func (ada *AdaptecRaidAdaptor) setControllerMode(mode int) error {
|
||||
cmd := GetCommand("SETCONTROLLERMODE", fmt.Sprintf("%d", ada.GetIndex()), fmt.Sprintf("%d", mode), "noprompt")
|
||||
if _, err := ada.remoteRun(fmt.Sprintf("set controller mode to %d", mode), cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) setControllerModeRaidExposeRaw() error {
|
||||
if err := ada.setControllerMode(0); err != nil {
|
||||
return errors.Wrap(err, "mode raid expose raw")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) setControllerModeRaidHideRaw() error {
|
||||
if err := ada.setControllerMode(3); err != nil {
|
||||
return errors.Wrap(err, "mode raid hide raw")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) setControllerModeMixed() error {
|
||||
if err := ada.setControllerMode(5); err != nil {
|
||||
return errors.Wrap(err, "mode mixed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) buildJBOD(dev *baremetal.BaremetalStorage) error {
|
||||
channel, id, err := ada.getChannelId(dev)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get channel and id")
|
||||
}
|
||||
cmd := ada.getCreateCmd("JBOD", channel, id, "noprompt")
|
||||
if out, err := ada.remoteRun("create JBOD", cmd); err != nil {
|
||||
return errors.Wrapf(err, "run cmd %q, out: %q", cmd, out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) buildNonRaid(dev *baremetal.BaremetalStorage) error {
|
||||
// try build JBOD firstly
|
||||
if err := ada.buildJBOD(dev); err != nil {
|
||||
log.Warningf("try build JBOD error: %v", err)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
// just uninitialize device when build JBOD fail
|
||||
channel, id, err := ada.getChannelId(dev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ada.uninitializeDevice(channel, id); err != nil {
|
||||
return errors.Wrapf(err, "uninitialize device %v when build jbod fail", dev)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage) error {
|
||||
for _, dev := range devs {
|
||||
if err := ada.buildNonRaid(dev); err != nil {
|
||||
return errors.Wrap(err, "build nonraid")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) getBuildRaidCmd(level int, devs []*baremetal.BaremetalStorage) (string, error) {
|
||||
if len(devs) == 0 {
|
||||
return "", errors.Errorf("devices is empty")
|
||||
}
|
||||
args := []string{"LOGICALDRIVE", "MAX", fmt.Sprintf("%d", level)}
|
||||
chIds := []string{}
|
||||
for _, dev := range devs {
|
||||
ch, id, err := ada.getChannelId(dev)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "get device %v channel id", dev)
|
||||
}
|
||||
chIds = append(chIds, ch, id)
|
||||
}
|
||||
args = append(args, chIds...)
|
||||
cmd := ada.getCreateCmd(args...)
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) buildRaid(level int, devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
|
||||
// initialize each devs
|
||||
for _, dev := range devs {
|
||||
channel, id, err := ada.getChannelId(dev)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "get device %v channel id", dev)
|
||||
}
|
||||
if err := ada.initializeDevice(channel, id); err != nil {
|
||||
// return errors.Wrapf(err, "initialize device")
|
||||
log.Warningf("initialize device error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: support config to build raid params
|
||||
cmd, err := ada.getBuildRaidCmd(level, devs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = ada.remoteRun(fmt.Sprintf("build raid %d", level), cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) BuildRaid0(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
|
||||
return ada.buildRaid(0, devs, conf)
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) BuildRaid1(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
|
||||
return ada.buildRaid(1, devs, conf)
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
|
||||
return ada.buildRaid(5, devs, conf)
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
|
||||
return ada.buildRaid(10, devs, conf)
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) GetDevices() []*baremetal.BaremetalStorage {
|
||||
ret := []*baremetal.BaremetalStorage{}
|
||||
for idx, dev := range ada.devs {
|
||||
ret = append(ret, dev.ToBaremetalStorage(idx))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) GetLogicVolumes() ([]*raid.RaidLogicalVolume, error) {
|
||||
cmd := GetCommand("GETCONFIG", fmt.Sprintf("%d", ada.index), "LD")
|
||||
ret, err := ada.remoteRun("get logic volumes", cmd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Get logic volumes error: %v", err)
|
||||
}
|
||||
return getLogicalVolumes(ada.index, ret)
|
||||
}
|
||||
|
||||
func getLogicalVolumes(adapter int, lines []string) ([]*raid.RaidLogicalVolume, error) {
|
||||
lvs := make([]*raid.RaidLogicalVolume, 0)
|
||||
for _, line := range lines {
|
||||
m := regutils2.SubGroupMatch(`Logical Device number\s+(?P<idx>\d+)`, line)
|
||||
if len(m) > 0 {
|
||||
idxStr := m["idx"]
|
||||
idx, err := strconv.Atoi(idxStr)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("%s index str is not digit: %v", idxStr, err)
|
||||
}
|
||||
lvs = append(lvs, &raid.RaidLogicalVolume{
|
||||
Index: idx,
|
||||
Adapter: adapter,
|
||||
})
|
||||
}
|
||||
}
|
||||
return lvs, nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) removeJBODDisks() error {
|
||||
cmd := GetCommand("DELETE", fmt.Sprintf("%d", ada.index), "JBOD", "ALL", "noprompt")
|
||||
out, err := ada.remoteRun("delete JBOD disks", cmd)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "delete all JBOD output: %q", out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ada *AdaptecRaidAdaptor) RemoveLogicVolumes() error {
|
||||
lvs, err := ada.GetLogicVolumes()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get logic volumes")
|
||||
}
|
||||
if len(lvs) == 0 {
|
||||
return nil
|
||||
}
|
||||
cmd := GetCommand("DELETE", fmt.Sprintf("%d", ada.index), "LOGICALDRIVE", "ALL", "noprompt")
|
||||
out, err := ada.remoteRun("delete logical volumes", cmd)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "delete all logicaldrive output: %q", out)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type adaptorInfo struct {
|
||||
status string
|
||||
mode string
|
||||
name string
|
||||
sn string
|
||||
wwn string
|
||||
slot string
|
||||
}
|
||||
|
||||
func (ada *adaptorInfo) key() string {
|
||||
return ada.name + ada.sn
|
||||
}
|
||||
|
||||
func (ada *adaptorInfo) isRaidExposeRawMode() bool {
|
||||
return ada.mode == ControllerModeRaidExposeRaw
|
||||
}
|
||||
|
||||
func (ada *adaptorInfo) isRaidHideRawMode() bool {
|
||||
return ada.mode == ControllerModeRaidHideRaw
|
||||
}
|
||||
|
||||
func (ada *adaptorInfo) isMixedMode() bool {
|
||||
return ada.mode == ControllerModeMixed
|
||||
}
|
||||
|
||||
func getAdaptorInfo(lines []string) (*adaptorInfo, error) {
|
||||
ada := new(adaptorInfo)
|
||||
for _, l := range lines {
|
||||
key, val := stringutils.SplitKeyValue(l)
|
||||
if len(key) == 0 {
|
||||
continue
|
||||
}
|
||||
switch key {
|
||||
case "Controller Status":
|
||||
ada.status = val
|
||||
case "Controller Mode":
|
||||
ada.mode = val
|
||||
case "Controller Model":
|
||||
ada.name = val
|
||||
case "Controller Serial Number":
|
||||
ada.sn = val
|
||||
case "Controller World Wide Name":
|
||||
ada.wwn = val
|
||||
case "Physical Slot":
|
||||
ada.slot = val
|
||||
}
|
||||
}
|
||||
if len(ada.key()) == 0 {
|
||||
return nil, errors.Errorf("Not found SN and model name")
|
||||
}
|
||||
return ada, nil
|
||||
}
|
||||
|
||||
type AdaptecRaidPhyDev struct {
|
||||
*raid.RaidBasePhyDev
|
||||
// channelId and deviceId is parsed by Reported Channel,Device(T:L)
|
||||
// e.g.: Reported Channel,Device(T:L) : 0,6(6:0)
|
||||
channelId string
|
||||
deviceId string
|
||||
}
|
||||
|
||||
func newPhyDev(adapter int) *AdaptecRaidPhyDev {
|
||||
dev := &AdaptecRaidPhyDev{
|
||||
RaidBasePhyDev: raid.NewRaidBasePhyDev(api.DISK_DRIVER_ADAPTECRAID),
|
||||
}
|
||||
dev.Adapter = adapter
|
||||
return dev
|
||||
}
|
||||
|
||||
func (dev *AdaptecRaidPhyDev) isComplete() bool {
|
||||
if !dev.RaidBasePhyDev.IsComplete() {
|
||||
return false
|
||||
}
|
||||
if dev.channelId == "" || dev.deviceId == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (dev *AdaptecRaidPhyDev) ToBaremetalStorage(index int) *baremetal.BaremetalStorage {
|
||||
s := dev.RaidBasePhyDev.ToBaremetalStorage(index)
|
||||
s.Addr = fmt.Sprintf("%s:%s", dev.channelId, dev.deviceId)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
var (
|
||||
channelDeviceRegexp = regexp.MustCompile(`Reported Channel,Device\(T:L\).*(?P<channel>\d+),(?P<device>\d+)\(\d+:\d+\)`)
|
||||
)
|
||||
|
||||
func (dev *AdaptecRaidPhyDev) parseLine(line string) bool {
|
||||
chanDevMatch := regutils2.GetParams(channelDeviceRegexp, line)
|
||||
if len(chanDevMatch) != 0 {
|
||||
channelId := chanDevMatch["channel"]
|
||||
deviceId := chanDevMatch["device"]
|
||||
dev.channelId = channelId
|
||||
dev.deviceId = deviceId
|
||||
return true
|
||||
}
|
||||
key, val := stringutils.SplitKeyValue(line)
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
switch key {
|
||||
case "Total Size":
|
||||
dat := strings.Split(val, " ")
|
||||
szStr, unitStr := dat[0], dat[1]
|
||||
var sz int64
|
||||
szInt, err := strconv.Atoi(szStr)
|
||||
if err != nil {
|
||||
log.Errorf("Parse size string %s: %v", szStr, err)
|
||||
return false
|
||||
}
|
||||
switch unitStr {
|
||||
case "GB":
|
||||
sz = int64(szInt * 1000 * 1000 * 100)
|
||||
case "TB":
|
||||
sz = int64(szInt * 1000 * 1000 * 1000 * 1000)
|
||||
case "MB":
|
||||
sz = int64(szInt * 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 "State":
|
||||
dev.Status = val
|
||||
case "SSD":
|
||||
if val == "No" {
|
||||
dev.Rotate = tristate.True
|
||||
} else {
|
||||
dev.Rotate = tristate.False
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
// 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 adaptec
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_getAdaptorIndex(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args string
|
||||
want int
|
||||
}{
|
||||
{
|
||||
name: "Controllers found: 1",
|
||||
args: "Controllers found: 1",
|
||||
want: -1,
|
||||
},
|
||||
{
|
||||
name: " Controller 1: : Optimal, Slot 4, RAID (Expose RAW), Adaptec ASR8805, 6A2263667CA, 50000D1701B47780",
|
||||
args: " Controller 1: : Optimal, Slot 4, RAID (Expose RAW), Adaptec ASR8805, 6A2263667CA, 50000D1701B47780",
|
||||
want: 1,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getAdaptorIndex(tt.args); got != tt.want {
|
||||
t.Errorf("getAdaptorIndex() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getAdaptorInfo(t *testing.T) {
|
||||
input := `Controllers found: 1
|
||||
----------------------------------------------------------------------
|
||||
Controller information
|
||||
----------------------------------------------------------------------
|
||||
Controller Status : Optimal
|
||||
Controller Mode : RAID (Expose RAW)
|
||||
Channel description : SAS/SATA
|
||||
Controller Model : Adaptec ASR8805
|
||||
Controller Serial Number : 6A2263667CA
|
||||
Controller World Wide Name : 50000D1701B47780
|
||||
Controller Alarm : Disabled
|
||||
Physical Slot : 4
|
||||
Temperature : 42 C/ 107 F (Normal)
|
||||
Installed memory : 1024 MB
|
||||
Host bus type : PCIe
|
||||
Host bus speed : 8000 MHz
|
||||
Host bus link width : 8 bit(s)/link(s)
|
||||
Global task priority : High
|
||||
Performance Mode : Default/Dynamic
|
||||
PCI Device ID : 653
|
||||
Stayawake period : Disabled
|
||||
Spinup limit internal drives : 0
|
||||
Spinup limit external drives : 0
|
||||
Defunct disk drive count : 0
|
||||
NCQ status : Enabled
|
||||
Statistics data collection mode : Disabled
|
||||
Monitor Log Severity Level : Informational
|
||||
Global Max SAS Phy Link Rate : 12 Gbps
|
||||
Verify Write Setting : Not Applicable
|
||||
Save Custom Defaults Setting : Disabled
|
||||
Smart Poll : Enabled
|
||||
Error Tunable Profile : Normal
|
||||
--------------------------------------------------------
|
||||
Cache Properties
|
||||
--------------------------------------------------------
|
||||
Controller Cache Preservation : Disabled
|
||||
Global Physical Device Write Cache Policy: Drive Specific
|
||||
--------------------------------------------------------
|
||||
RAID Properties
|
||||
--------------------------------------------------------
|
||||
Logical devices/Failed/Degraded : 0/0/0
|
||||
Copyback : Disabled
|
||||
Automatic Failover : Enabled
|
||||
Background consistency check : Disabled
|
||||
Background consistency check period : 0
|
||||
--------------------------------------------------------
|
||||
Controller BIOS Setting Information
|
||||
--------------------------------------------------------
|
||||
Runtime BIOS : Enabled
|
||||
Array BBS Support : Disabled
|
||||
Physical Drives Displayed during POST : Disabled
|
||||
Backplane Mode : IBPI
|
||||
BIOS Halt on Missing Drive Count : 255
|
||||
--------------------------------------------------------
|
||||
Controller Version Information
|
||||
--------------------------------------------------------
|
||||
BIOS : 7.18-0 (33556)
|
||||
Firmware : 7.18-0 (33556)
|
||||
Driver : 1.2-1 (50983)
|
||||
Boot Flash : 7.18-0 (33556)
|
||||
CPLD (Load version/ Flash version) : 8/ 11
|
||||
SEEPROM (Load version/ Flash version) : 1/ 1
|
||||
FCT Custom Init String Version : 0x0
|
||||
|
||||
--------------------------------------------------------
|
||||
Controller Cache Backup Unit Information
|
||||
--------------------------------------------------------
|
||||
|
||||
Overall Backup Unit Status : Not Present
|
||||
--------------------------------------------------------
|
||||
Connector information
|
||||
|
||||
--------------------------------------------------------
|
||||
Connector #0
|
||||
Connector Name : CN0
|
||||
|
||||
--------------------------------------
|
||||
Lane Information
|
||||
--------------------------------------
|
||||
Lane #0
|
||||
Channel ID : 0
|
||||
Device ID : 0
|
||||
SAS Address : 50000D1701B47780
|
||||
PHY Identifier : 3
|
||||
-----------------------------------
|
||||
Lane SAS Phy Information
|
||||
-----------------------------------
|
||||
SAS Address : 50000D1701B47780
|
||||
|
||||
Lane #1
|
||||
Channel ID : 0
|
||||
Device ID : 1
|
||||
SAS Address : 50000D1701B47780
|
||||
PHY Identifier : 2
|
||||
-----------------------------------
|
||||
Lane SAS Phy Information
|
||||
-----------------------------------
|
||||
SAS Address : 50000D1701B47780
|
||||
|
||||
Lane #2
|
||||
Channel ID : 0
|
||||
Device ID : 2
|
||||
SAS Address : 50000D1701B47780
|
||||
PHY Identifier : 0
|
||||
-----------------------------------
|
||||
Lane SAS Phy Information
|
||||
-----------------------------------
|
||||
SAS Address : 50000D1701B47780
|
||||
|
||||
Lane #3
|
||||
Channel ID : 0
|
||||
Device ID : 3
|
||||
SAS Address : 50000D1701B47780
|
||||
PHY Identifier : 1
|
||||
-----------------------------------
|
||||
Lane SAS Phy Information
|
||||
-----------------------------------
|
||||
SAS Address : 50000D1701B47780
|
||||
|
||||
|
||||
Connector #1
|
||||
Connector Name : CN1
|
||||
|
||||
--------------------------------------
|
||||
Lane Information
|
||||
--------------------------------------
|
||||
Lane #0
|
||||
Channel ID : 0
|
||||
Device ID : 4
|
||||
SAS Address : 50000D1701B47780
|
||||
PHY Identifier : 5
|
||||
-----------------------------------
|
||||
Lane SAS Phy Information
|
||||
-----------------------------------
|
||||
SAS Address : 50000D1701B47780
|
||||
|
||||
Lane #1
|
||||
Channel ID : 0
|
||||
Device ID : 5
|
||||
SAS Address : 50000D1701B47780
|
||||
PHY Identifier : 6
|
||||
-----------------------------------
|
||||
Lane SAS Phy Information
|
||||
-----------------------------------
|
||||
SAS Address : 50000D1701B47780
|
||||
|
||||
Lane #2
|
||||
Channel ID : 0
|
||||
Device ID : 6
|
||||
SAS Address : 50000D1701B47780
|
||||
PHY Identifier : 4
|
||||
-----------------------------------
|
||||
Lane SAS Phy Information
|
||||
-----------------------------------
|
||||
SAS Address : 50000D1701B47780
|
||||
Attached PHY Identifier : 0
|
||||
Attached SAS Address : 5000C50077893141
|
||||
Negotiated Logical Link Rate : PHY enabled - 6 Gbps
|
||||
|
||||
Lane #3
|
||||
Channel ID : 0
|
||||
Device ID : 7
|
||||
SAS Address : 50000D1701B47780
|
||||
PHY Identifier : 7
|
||||
-----------------------------------
|
||||
Lane SAS Phy Information
|
||||
-----------------------------------
|
||||
SAS Address : 50000D1701B47780
|
||||
Attached PHY Identifier : 0
|
||||
Attached SAS Address : 50000395B839D9AE
|
||||
Negotiated Logical Link Rate : PHY enabled - 6 Gbps
|
||||
|
||||
|
||||
|
||||
|
||||
Command completed successfully.`
|
||||
lines := strings.Split(input, "\n")
|
||||
info, err := getAdaptorInfo(lines)
|
||||
if err != nil {
|
||||
t.Errorf("getAdaptorInfo: %v", err)
|
||||
}
|
||||
assert := assert.New(t)
|
||||
assert.Equal("Optimal", info.status)
|
||||
assert.Equal("RAID (Expose RAW)", info.mode)
|
||||
assert.Equal(true, info.isRaidExposeRawMode(), "should be raid expose raw mode")
|
||||
assert.Equal("Adaptec ASR8805", info.name)
|
||||
assert.Equal("6A2263667CA", info.sn)
|
||||
assert.Equal("50000D1701B47780", info.wwn)
|
||||
assert.Equal("4", info.slot)
|
||||
}
|
||||
|
||||
func Test_getPhyDevices(t *testing.T) {
|
||||
input := `Controllers found: 1
|
||||
----------------------------------------------------------------------
|
||||
Physical Device information
|
||||
----------------------------------------------------------------------
|
||||
Device #0
|
||||
Device is a Hard drive
|
||||
State : Online
|
||||
Block Size : 512 Bytes
|
||||
Supported : Yes
|
||||
Programmed Max Speed : SAS 6.0 Gb/s
|
||||
Transfer Speed : SAS 6.0 Gb/s
|
||||
Reported Channel,Device(T:L) : 0,6(6:0)
|
||||
Reported Location : Connector 1, Device 2
|
||||
Vendor : SEAGATE
|
||||
Model : ST300MM0006
|
||||
Firmware : LS0A
|
||||
Serial number : S0K30A4N
|
||||
World-wide name : 5000C50077893140
|
||||
Reserved Size : 415982 KB
|
||||
Used Size : 285696 MB
|
||||
Unused Size : 64 KB
|
||||
Total Size : 286102 MB
|
||||
Write Cache : Disabled (write-through)
|
||||
FRU : None
|
||||
S.M.A.R.T. : No
|
||||
S.M.A.R.T. warnings : 0
|
||||
Power State : Full rpm
|
||||
Supported Power States : Full rpm,Powered off
|
||||
SSD : No
|
||||
Temperature : 34 C/ 93 F
|
||||
----------------------------------------------------------------
|
||||
Device Phy Information
|
||||
----------------------------------------------------------------
|
||||
Phy #0
|
||||
PHY Identifier : 0
|
||||
SAS Address : 5000C50077893141
|
||||
Attached PHY Identifier : 4
|
||||
Attached SAS Address : 50000D1701B47780
|
||||
Phy #1
|
||||
PHY Identifier : 1
|
||||
SAS Address : 5000C50077893142
|
||||
----------------------------------------------------------------
|
||||
Runtime Error Counters
|
||||
----------------------------------------------------------------
|
||||
Hardware Error Count : 0
|
||||
Medium Error Count : 0
|
||||
Parity Error Count : 0
|
||||
Link Failure Count : 0
|
||||
Aborted Command Count : 0
|
||||
SMART Warning Count : 0
|
||||
|
||||
Device #1
|
||||
Device is a Hard drive
|
||||
State : Online
|
||||
Block Size : 512 Bytes
|
||||
Supported : Yes
|
||||
Programmed Max Speed : SAS 6.0 Gb/s
|
||||
Transfer Speed : SAS 6.0 Gb/s
|
||||
Reported Channel,Device(T:L) : 0,7(7:0)
|
||||
Reported Location : Connector 1, Device 3
|
||||
Vendor : TOSHIBA
|
||||
Model : AL13SEB300
|
||||
Firmware : DE0D
|
||||
Serial number : 84T0A31SFRD6
|
||||
World-wide name : 50000395B839D9AC
|
||||
Reserved Size : 415982 KB
|
||||
Used Size : 285696 MB
|
||||
Unused Size : 64 KB
|
||||
Total Size : 286102 MB
|
||||
Write Cache : Disabled (write-through)
|
||||
FRU : None
|
||||
S.M.A.R.T. : No
|
||||
S.M.A.R.T. warnings : 0
|
||||
Power State : Full rpm
|
||||
Supported Power States : Full rpm,Powered off
|
||||
SSD : No
|
||||
Temperature : 33 C/ 91 F
|
||||
----------------------------------------------------------------
|
||||
Device Phy Information
|
||||
----------------------------------------------------------------
|
||||
Phy #0
|
||||
PHY Identifier : 0
|
||||
SAS Address : 50000395B839D9AE
|
||||
Attached PHY Identifier : 7
|
||||
Attached SAS Address : 50000D1701B47780
|
||||
Phy #1
|
||||
PHY Identifier : 1
|
||||
SAS Address : 50000395B839D9AF
|
||||
----------------------------------------------------------------
|
||||
Runtime Error Counters
|
||||
----------------------------------------------------------------
|
||||
Hardware Error Count : 0
|
||||
Medium Error Count : 0
|
||||
Parity Error Count : 0
|
||||
Link Failure Count : 0
|
||||
Aborted Command Count : 0
|
||||
SMART Warning Count : 0
|
||||
|
||||
|
||||
|
||||
Command completed successfully.`
|
||||
lines := strings.Split(input, "\n")
|
||||
devs := getPhyDevices(1, lines)
|
||||
assert := assert.New(t)
|
||||
assert.Equal(2, len(devs), "physical devices should be 2")
|
||||
dev1 := devs[0]
|
||||
assert.Equal("0", dev1.channelId)
|
||||
assert.Equal("6", dev1.deviceId)
|
||||
assert.Equal("Online", dev1.Status)
|
||||
assert.Equal("ST300MM0006", dev1.Model)
|
||||
assert.Equal(true, dev1.Rotate.Bool())
|
||||
|
||||
dev2 := devs[1]
|
||||
assert.Equal("0", dev2.channelId)
|
||||
assert.Equal("7", dev2.deviceId)
|
||||
assert.Equal("Online", dev2.Status)
|
||||
assert.Equal("AL13SEB300", dev2.Model)
|
||||
assert.Equal(true, dev2.Rotate.Bool())
|
||||
}
|
||||
|
||||
func Test_getLogicalVolums(t *testing.T) {
|
||||
input := `Controllers found: 1
|
||||
----------------------------------------------------------------------
|
||||
Logical device information
|
||||
----------------------------------------------------------------------
|
||||
Logical Device number 0
|
||||
Logical Device name : LogicalDrv 0
|
||||
Block Size of member drives : 512 Bytes
|
||||
RAID level : 1
|
||||
Unique Identifier : 7D30DCD4
|
||||
Status of Logical Device : Optimal
|
||||
Additional details : Quick initialized
|
||||
Size : 285686 MB
|
||||
Parity space : 285696 MB
|
||||
Interface Type : Serial Attached SCSI
|
||||
Device Type : HDD
|
||||
Read-cache setting : Enabled
|
||||
Read-cache status : On
|
||||
Write-cache setting : Enabled
|
||||
Write-cache status : On
|
||||
Partitioned : No
|
||||
Protected by Hot-Spare : No
|
||||
Bootable : Yes
|
||||
Failed stripes : No
|
||||
Power settings : Disabled
|
||||
--------------------------------------------------------
|
||||
Logical Device segment information
|
||||
--------------------------------------------------------
|
||||
Segment 0 : Present (286102MB, SAS, HDD, Connector:1, Device:2) S0K30A4N
|
||||
Segment 1 : Present (286102MB, SAS, HDD, Connector:1, Device:3) 84T0A31SFRD6
|
||||
|
||||
|
||||
|
||||
Command completed successfully.`
|
||||
lines := strings.Split(input, "\n")
|
||||
lvs, err := getLogicalVolumes(1, lines)
|
||||
if err != nil {
|
||||
t.Errorf("getLogicalVolumes: %v", err)
|
||||
}
|
||||
assert := assert.New(t)
|
||||
assert.Equal(1, len(lvs), "logical volume len should be 1")
|
||||
lv := lvs[0]
|
||||
assert.Equal(1, lv.Adapter)
|
||||
assert.Equal(0, lv.Index)
|
||||
|
||||
inputNoLV := `Controllers found: 1
|
||||
----------------------------------------------------------------------
|
||||
Logical device information
|
||||
----------------------------------------------------------------------
|
||||
No logical devices configured
|
||||
|
||||
|
||||
Command completed successfully.`
|
||||
lines = strings.Split(inputNoLV, "\n")
|
||||
lvs, err = getLogicalVolumes(1, lines)
|
||||
if err != nil {
|
||||
t.Errorf("getLogicalVolumes: %v", err)
|
||||
}
|
||||
assert.Equal(0, len(lvs), "logical volume len should be 0")
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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 adaptec // import "yunion.io/x/onecloud/pkg/baremetal/utils/raid/adaptec"
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/baremetal/utils/raid"
|
||||
_ "yunion.io/x/onecloud/pkg/baremetal/utils/raid/adaptec"
|
||||
_ "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"
|
||||
@@ -64,6 +65,8 @@ func GetDriverByKernelModule(module string, term raid.IExecTerm) (raid.IRaidDriv
|
||||
name = baremetal.DISK_DRIVER_HPSARAID
|
||||
case raid.MODULE_MPT2SAS, raid.MODULE_MPT3SAS:
|
||||
name = baremetal.DISK_DRIVER_MPT2SAS
|
||||
case raid.MODULE_AACRAID:
|
||||
name = baremetal.DISK_DRIVER_ADAPTECRAID
|
||||
}
|
||||
if name == "" {
|
||||
return nil, errors.Errorf("Not support module %q", module)
|
||||
|
||||
@@ -36,6 +36,7 @@ const (
|
||||
MODULE_HPSA = "hpsa"
|
||||
MODULE_MPT2SAS = "mpt2sas"
|
||||
MODULE_MPT3SAS = "mpt3sas"
|
||||
MODULE_AACRAID = "aacraid"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -35,12 +35,13 @@ const (
|
||||
|
||||
DEFAULT_DISK_TYPE = api.DEFAULT_DISK_TYPE
|
||||
|
||||
DISK_DRIVER_MEGARAID = api.DISK_DRIVER_MEGARAID
|
||||
DISK_DRIVER_LINUX = api.DISK_DRIVER_LINUX
|
||||
DISK_DRIVER_HPSARAID = api.DISK_DRIVER_HPSARAID
|
||||
DISK_DRIVER_MPT2SAS = api.DISK_DRIVER_MPT2SAS
|
||||
DISK_DRIVER_MARVELRAID = api.DISK_DRIVER_MARVELRAID
|
||||
DISK_DRIVER_PCIE = api.DISK_DRIVER_PCIE
|
||||
DISK_DRIVER_MEGARAID = api.DISK_DRIVER_MEGARAID
|
||||
DISK_DRIVER_LINUX = api.DISK_DRIVER_LINUX
|
||||
DISK_DRIVER_HPSARAID = api.DISK_DRIVER_HPSARAID
|
||||
DISK_DRIVER_MPT2SAS = api.DISK_DRIVER_MPT2SAS
|
||||
DISK_DRIVER_MARVELRAID = api.DISK_DRIVER_MARVELRAID
|
||||
DISK_DRIVER_ADAPTECRAID = api.DISK_DRIVER_ADAPTECRAID
|
||||
DISK_DRIVER_PCIE = api.DISK_DRIVER_PCIE
|
||||
|
||||
HDD_DISK_SPEC_TYPE = api.HDD_DISK_SPEC_TYPE
|
||||
SSD_DISK_SPEC_TYPE = api.SSD_DISK_SPEC_TYPE
|
||||
|
||||
Reference in New Issue
Block a user