feat(baremetal): adaptec raid driver

This commit is contained in:
Zexi Li
2021-09-13 22:02:10 +08:00
parent 4c3adeb328
commit f8822c745a
11 changed files with 1112 additions and 17 deletions
+1 -1
View File
@@ -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>"
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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 .
+8 -6
View File
@@ -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")
}
+650
View File
@@ -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")
}
+15
View File
@@ -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)
+1
View File
@@ -36,6 +36,7 @@ const (
MODULE_HPSA = "hpsa"
MODULE_MPT2SAS = "mpt2sas"
MODULE_MPT3SAS = "mpt3sas"
MODULE_AACRAID = "aacraid"
)
const (
+7 -6
View File
@@ -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