diff --git a/build/docker/Dockerfile.baremetal-agent b/build/docker/Dockerfile.baremetal-agent index eb45a50990..4989be72fd 100644 --- a/build/docker/Dockerfile.baremetal-agent +++ b/build/docker/Dockerfile.baremetal-agent @@ -1,4 +1,4 @@ -FROM registry.cn-beijing.aliyuncs.com/yunionio/baremetal-base:v0.3.3-2-grub +FROM registry.cn-beijing.aliyuncs.com/yunionio/baremetal-base:v0.3.3-2-grub-test MAINTAINER "Zexi Li " diff --git a/build/docker/Dockerfile.baremetal-base b/build/docker/Dockerfile.baremetal-base index 472c4c7caa..b4f38ae53b 100644 --- a/build/docker/Dockerfile.baremetal-base +++ b/build/docker/Dockerfile.baremetal-base @@ -1,7 +1,7 @@ #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-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/yunionos:v0.1.1 as yunionos +FROM registry.cn-beijing.aliyuncs.com/yunionio/yunionos:v0.1.1-test as yunionos FROM centos:8 as grub-stage diff --git a/build/docker/Makefile b/build/docker/Makefile index d030d567b8..61bb76579b 100644 --- a/build/docker/Makefile +++ b/build/docker/Makefile @@ -27,7 +27,7 @@ WEBCONSOLE_BASE_VERSION = v0.2-1 webconsole-base: $(DOCKER_BUILDX)/webconsole-base:$(WEBCONSOLE_BASE_VERSION) -f ./Dockerfile.webconsole-base . -BAREMETAL_BASE_VERSION = v0.3.3-2-grub +BAREMETAL_BASE_VERSION = v0.3.3-2-grub-test baremetal-base: $(DOCKER_BUILDX)/baremetal-base:$(BAREMETAL_BASE_VERSION) -f ./Dockerfile.baremetal-base . diff --git a/pkg/baremetal/utils/raid/megactl/driver.go b/pkg/baremetal/utils/raid/megactl/driver.go new file mode 100644 index 0000000000..8df315550b --- /dev/null +++ b/pkg/baremetal/utils/raid/megactl/driver.go @@ -0,0 +1,184 @@ +// 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 ( + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/baremetal/utils/raid" + "yunion.io/x/onecloud/pkg/compute/baremetal" +) + +func init() { + raid.RegisterDriver(baremetal.DISK_DRIVER_MEGARAID, newRaid) +} + +type iDriver interface { + GetName() string + GetAdapterConstructCmd() string + NewAdaptor(term raid.IExecTerm) iAdaptor + ClearForeignState(term raid.IExecTerm) error +} + +type iAdaptor interface { + ParseLine(line string) + IsComplete() bool + Key() string + GetPhyDevs() ([]*MegaRaidPhyDev, error) + ClearJBODDisks(devs []*MegaRaidPhyDev) + + GetIndex() int + GetLogicVolumes() ([]*raid.RaidLogicalVolume, error) + RemoveLogicVolumes() error + BuildRaid0(devs []*baremetal.BaremetalStorage, conf *compute.BaremetalDiskConfig) error + BuildRaid1(devs []*baremetal.BaremetalStorage, conf *compute.BaremetalDiskConfig) error + BuildRaid5(devs []*baremetal.BaremetalStorage, conf *compute.BaremetalDiskConfig) error + BuildRaid10(devs []*baremetal.BaremetalStorage, conf *compute.BaremetalDiskConfig) error + BuildNoneRaid(devs []*baremetal.BaremetalStorage) error +} + +type sRaid struct { + driver iDriver + term raid.IExecTerm + adaptors []*sRaidAdaptor + phyDevsCnt int +} + +func newRaid(term raid.IExecTerm) raid.IRaidDriver { + perccliDrv := &sRaid{ + driver: newPerccliDriver(), + term: term, + adaptors: make([]*sRaidAdaptor, 0), + } + if err := perccliDrv.ParsePhyDevs(); err == nil && perccliDrv.phyDevsCnt > 0 { + log.Infof("Use perccli driver, found %d pds", perccliDrv.phyDevsCnt) + return perccliDrv + } else { + log.Warningf("perccli driver parse physical devices error: %v, %d pds, fallback to old megactl and storcli driver", err, perccliDrv.phyDevsCnt) + return NewMegaRaid(term) + } +} + +func (r *sRaid) GetName() string { + return baremetal.DISK_DRIVER_MEGARAID +} + +type sRaidAdaptor struct { + iAdaptor + + raid *sRaid + devs []*MegaRaidPhyDev + sn string + name string + busNumber string + deviceNumber string + funcNumber string + // used by sg_map + hostNum int + //channelNum int +} + +func newRaidAdaptor(baseAda iAdaptor, raid *sRaid) *sRaidAdaptor { + return &sRaidAdaptor{ + iAdaptor: baseAda, + raid: raid, + devs: make([]*MegaRaidPhyDev, 0), + } +} + +func (a *sRaidAdaptor) AddPhyDev(dev *MegaRaidPhyDev) { + a.devs = append(a.devs, dev) +} + +func (r *sRaid) ParsePhyDevs() error { + adaptors, _, err := r.getAdaptor() + r.phyDevsCnt = 0 + if err != nil { + return errors.Wrapf(err, "Get %q adaptor", r.driver.GetName()) + } + r.adaptors = make([]*sRaidAdaptor, 0) + for _, ada := range adaptors { + devs, err := ada.GetPhyDevs() + if err != nil { + return errors.Wrap(err, "Get %q adaptor physical devices") + } + nAda := newRaidAdaptor(ada, r) + for i := range devs { + nAda.AddPhyDev(devs[i]) + r.phyDevsCnt++ + } + r.adaptors = append(r.adaptors, nAda) + } + return nil +} + +func (r *sRaid) getAdaptor() ([]iAdaptor, map[string]iAdaptor, error) { + ret := make(map[string]iAdaptor) + cmd := r.driver.GetAdapterConstructCmd() + lines, err := r.term.Run(cmd) + if err != nil { + return nil, nil, errors.Wrap(err, "Get storcli adapter") + } + adaptor := r.driver.NewAdaptor(r.term) + list := make([]iAdaptor, 0) + for _, l := range lines { + adaptor.ParseLine(l) + if adaptor.IsComplete() { + ret[adaptor.Key()] = adaptor + list = append(list, adaptor) + adaptor = r.driver.NewAdaptor(r.term) + } + } + return list, ret, nil +} + +func (r *sRaid) PreBuildRaid(_ []*compute.BaremetalDiskConfig, _ int) error { + return r.driver.ClearForeignState(r.term) +} + +func (r *sRaid) GetAdapters() []raid.IRaidAdapter { + ret := make([]raid.IRaidAdapter, len(r.adaptors)) + for i := range r.adaptors { + ret[i] = r.adaptors[i] + } + return ret +} + +func (r *sRaidAdaptor) PreBuildRaid(_ []*compute.BaremetalDiskConfig) error { + r.ClearJBODDisks() + return nil +} + +func (r *sRaidAdaptor) ClearJBODDisks() { + r.iAdaptor.ClearJBODDisks(r.devs) +} + +func (r *sRaidAdaptor) GetDevices() []*baremetal.BaremetalStorage { + ret := []*baremetal.BaremetalStorage{} + for idx, dev := range r.devs { + ret = append(ret, dev.ToBaremetalStorage(idx)) + } + return ret +} + +func (r *sRaid) CleanRaid() error { + for _, ada := range r.adaptors { + ada.ClearJBODDisks() + ada.RemoveLogicVolumes() + } + return nil +} diff --git a/pkg/baremetal/utils/raid/megactl/helper.go b/pkg/baremetal/utils/raid/megactl/helper.go new file mode 100644 index 0000000000..730e494638 --- /dev/null +++ b/pkg/baremetal/utils/raid/megactl/helper.go @@ -0,0 +1,227 @@ +// 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" + "strings" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/baremetal/utils/raid" + "yunion.io/x/onecloud/pkg/compute/baremetal" +) + +func storcliIsJBODEnabled( + getCmd func(args ...string) (string, error), + term raid.IExecTerm, +) bool { + cmd, err := getCmd("show", "jbod") + if err != nil { + log.Errorf("get storcli controller cmd: %v", err) + return false + } + lines, err := term.Run(cmd) + if err != nil { + log.Errorf("storcliIsJBODEnabled error: %s", err) + return false + } + for _, line := range lines { + line = strings.ToLower(line) + if strings.HasPrefix(line, "jbod") { + data := strings.Split(line, " ") + if strings.TrimSpace(data[len(data)-1]) == "on" { + return true + } + return false + } + } + return false +} + +func storcliEnableJBOD( + getCmd func(args ...string) (string, error), + term raid.IExecTerm, + enable bool) bool { + val := "off" + if enable { + val = "on" + } + cmd, err := getCmd("set", fmt.Sprintf("jbod=%s", val), "force") + if err != nil { + log.Errorf("get storcli controller cmd: %v", err) + return false + } + _, err = term.Run(cmd) + if err != nil { + log.Errorf("EnableJBOD %v fail: %v", enable, err) + return false + } + return true +} + +func storcliBuildJBOD( + getCmd func(args ...string) (string, error), + term raid.IExecTerm, + devs []*baremetal.BaremetalStorage) error { + if !storcliIsJBODEnabled(getCmd, term) { + storcliEnableJBOD(getCmd, term, true) + storcliEnableJBOD(getCmd, term, false) + storcliEnableJBOD(getCmd, term, true) + } + if !storcliIsJBODEnabled(getCmd, term) { + return fmt.Errorf("JBOD not supported") + } + cmds := []string{} + for _, d := range devs { + // cmd := GetCommand2(fmt.Sprintf("/c%d/e%d/s%d", adapter.storcliIndex, d.Enclosure, d.Slot)) + cmd, err := getCmd() + if err != nil { + return errors.Wrapf(err, "getCmd for dev %#v", d) + } + cmd = fmt.Sprintf("%s/e%d/s%d", d.Enclosure, d.Slot) + cmds = append(cmds, cmd) + } + log.Infof("storcliBuildJBOD cmds: %v", cmds) + _, err := term.Run(cmds...) + if err != nil { + return err + } + return nil +} + +func storcliBuildNoRaid( + getCmd func(args ...string) (string, error), + term raid.IExecTerm, + devs []*baremetal.BaremetalStorage) error { + err := storcliBuildJBOD(getCmd, term, devs) + if err == nil { + return nil + } + log.Errorf("Try storcli build JBOD fail: %v", err) + labels := []string{} + for _, dev := range devs { + labels = append(labels, GetSpecString(dev)) + } + args := []string{ + "add", "vd", "each", "type=raid0", + fmt.Sprintf("drives=%s", strings.Join(labels, ",")), + "wt", "nora", "direct", + } + cmd, err := getCmd(args...) + if err != nil { + return errors.Wrapf(err, "build none raid") + } + _, err = term.Run(cmd) + return err +} + +func storcliClearJBODDisks( + getCmd func(args ...string) (string, error), + term raid.IExecTerm, + devs []*MegaRaidPhyDev, +) error { + errs := make([]error, 0) + for _, dev := range devs { + cmd, err := getCmd() + if err != nil { + return errors.Wrap(err, "get cmd error") + } + cmd = fmt.Sprintf("%s/e%d/s%d set good force", cmd, dev.enclosure, dev.slot) + if _, err := term.Run(cmd); err != nil { + err = errors.Wrapf(err, "Set PD good storcli cmd %v", cmd) + errs = append(errs, err) + } + } + return errors.NewAggregate(errs) +} + +func storcliBuildRaid( + getCmd func(args ...string) (string, error), + term raid.IExecTerm, + devs []*baremetal.BaremetalStorage, + conf *api.BaremetalDiskConfig, + level uint, +) error { + args := []string{} + args = append(args, "add", "vd", fmt.Sprintf("type=r%d", level)) + args = append(args, conf2ParamsStorcliSize(conf)...) + labels := []string{} + for _, dev := range devs { + labels = append(labels, GetSpecString(dev)) + } + args = append(args, fmt.Sprintf("drives=%s", strings.Join(labels, ","))) + if level == 10 { + args = append(args, "PDperArray=2") + } + args = append(args, conf2ParamsStorcli(conf)...) + cmd, err := getCmd(args...) + if err != nil { + return errors.Wrapf(err, "build raid %d", level) + } + log.Infof("_storcliBuildRaid command: %s", cmd) + _, err = term.Run(cmd) + return err +} + +func conf2ParamsStorcliSize(conf *api.BaremetalDiskConfig) []string { + params := []string{} + szStr := []string{} + if len(conf.Size) > 0 { + for _, sz := range conf.Size { + szStr = append(szStr, fmt.Sprintf("%dMB", sz)) + } + params = append(params, fmt.Sprintf("Size=%s", strings.Join(szStr, ","))) + } + return params +} + +func conf2ParamsStorcli(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("Strip=%d", *conf.Strip)) + } + return params +} diff --git a/pkg/baremetal/utils/raid/megactl/megactl.go b/pkg/baremetal/utils/raid/megactl/megactl.go index 1818234e82..7e6d5563ff 100644 --- a/pkg/baremetal/utils/raid/megactl/megactl.go +++ b/pkg/baremetal/utils/raid/megactl/megactl.go @@ -543,54 +543,6 @@ func (adapter *MegaRaidAdaptor) PreBuildRaid(confs []*api.BaremetalDiskConfig) e return nil } -func (adapter *MegaRaidAdaptor) conf2ParamsStorcliSize(conf *api.BaremetalDiskConfig) []string { - params := []string{} - szStr := []string{} - if len(conf.Size) > 0 { - for _, sz := range conf.Size { - szStr = append(szStr, fmt.Sprintf("%dMB", sz)) - } - params = append(params, fmt.Sprintf("Size=%s", strings.Join(szStr, ","))) - } - return params -} - -func (adapter *MegaRaidAdaptor) conf2ParamsStorcli(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("Strip=%d", *conf.Strip)) - } - return params -} - func conf2Params(conf *api.BaremetalDiskConfig) []string { params := []string{} if conf.WT != nil { @@ -681,25 +633,10 @@ func (adapter *MegaRaidAdaptor) megacliBuildRaid10(devs []*baremetal.BaremetalSt } func (adapter *MegaRaidAdaptor) storcliBuildRaid(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig, level uint) error { - args := []string{} - args = append(args, "add", "vd", fmt.Sprintf("type=r%d", level)) - args = append(args, adapter.conf2ParamsStorcliSize(conf)...) - labels := []string{} - for _, dev := range devs { - labels = append(labels, GetSpecString(dev)) - } - args = append(args, fmt.Sprintf("drives=%s", strings.Join(labels, ","))) - if level == 10 { - args = append(args, "PDperArray=2") - } - args = append(args, adapter.conf2ParamsStorcli(conf)...) - cmd, err := adapter.GetStorcliCommand(args...) - if err != nil { - return errors.Wrapf(err, "build raid %d", level) - } - log.Infof("_storcliBuildRaid command: %s", cmd) - _, err = adapter.remoteRun(cmd) - return err + return storcliBuildRaid( + adapter.GetStorcliCommand, + adapter.getTerm(), + devs, conf, level) } func (adapter *MegaRaidAdaptor) megacliBuildRaid(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig, level uint) error { @@ -897,9 +834,10 @@ func parseStorcliControllers(jsonStr string) (*StorcliControllersInfo, error) { return info, nil } -func (a *StorcliAdaptor) getPhyDevs(raid *MegaRaid) ([]*StorcliPhysicalDrive, error) { - cmd := GetCommand2(fmt.Sprintf("/c%d/eall/sall show J", a.Controller)) - lines, err := raid.term.Run(cmd) +func (a *StorcliAdaptor) getPhyDevs(getCmd func(...string) string, term raid.IExecTerm) ([]*StorcliPhysicalDrive, error) { + cmd := getCmd(fmt.Sprintf("/c%d/eall/sall show J", a.Controller)) + log.Errorf("----term %#v, cmd: %q", term, cmd) + lines, err := term.Run(cmd) if err != nil { return nil, errors.Wrap(err, "Get storcli PDList json output") } @@ -914,8 +852,8 @@ func (a *StorcliAdaptor) getPhyDevs(raid *MegaRaid) ([]*StorcliPhysicalDrive, er return info.Controllers[0].ResponseData.Info, nil } -func (a *StorcliAdaptor) getMegaPhyDevs(raid *MegaRaid) ([]*MegaRaidPhyDev, error) { - pdList, err := a.getPhyDevs(raid) +func (a *StorcliAdaptor) getMegaPhyDevs(getCmd func(...string) string, term raid.IExecTerm) ([]*MegaRaidPhyDev, error) { + pdList, err := a.getPhyDevs(getCmd, term) if err != nil { return nil, errors.Wrap(err, "storcli getPhyDevs") } @@ -976,27 +914,7 @@ func (adapter *MegaRaidAdaptor) GetStorcliCommand(args ...string) (string, error } func (adapter *MegaRaidAdaptor) storcliIsJBODEnabled() bool { - cmd, err := adapter.GetStorcliCommand("show", "jbod") - if err != nil { - log.Errorf("get storcli controller cmd: %v", err) - return false - } - lines, err := adapter.remoteRun(cmd) - if err != nil { - log.Errorf("storcliIsJBODEnabled error: %s", err) - return false - } - for _, line := range lines { - line = strings.ToLower(line) - if strings.HasPrefix(line, "jbod") { - data := strings.Split(line, " ") - if strings.TrimSpace(data[len(data)-1]) == "on" { - return true - } - return false - } - } - return false + return storcliIsJBODEnabled(adapter.GetStorcliCommand, adapter.getTerm()) } func (adapter *MegaRaidAdaptor) storcliEnableJBOD(enable bool) bool { @@ -1018,48 +936,11 @@ func (adapter *MegaRaidAdaptor) storcliEnableJBOD(enable bool) bool { } func (adapter *MegaRaidAdaptor) storcliBuildJBOD(devs []*baremetal.BaremetalStorage) error { - if !adapter.storcliIsJBODEnabled() { - adapter.storcliEnableJBOD(true) - adapter.storcliEnableJBOD(false) - adapter.storcliEnableJBOD(true) - } - if !adapter.storcliIsJBODEnabled() { - return fmt.Errorf("JBOD not supported") - } - cmds := []string{} - for _, d := range devs { - cmd := GetCommand2(fmt.Sprintf("/c%d/e%d/s%d", adapter.storcliIndex, d.Enclosure, d.Slot)) - cmds = append(cmds, cmd) - } - log.Infof("storcliBuildJBOD cmds: %v", cmds) - _, err := adapter.remoteRun(cmds...) - if err != nil { - return err - } - return nil + return storcliBuildJBOD(adapter.GetStorcliCommand, adapter.getTerm(), devs) } func (adapter *MegaRaidAdaptor) storcliBuildNoRaid(devs []*baremetal.BaremetalStorage, _ *api.BaremetalDiskConfig) error { - err := adapter.storcliBuildJBOD(devs) - if err == nil { - return nil - } - log.Errorf("Try storcli build JBOD fail: %v", err) - labels := []string{} - for _, dev := range devs { - labels = append(labels, GetSpecString(dev)) - } - args := []string{ - "add", "vd", "each", "type=raid0", - fmt.Sprintf("drives=%s", strings.Join(labels, ",")), - "wt", "nora", "direct", - } - cmd, err := adapter.GetStorcliCommand(args...) - if err != nil { - return errors.Wrapf(err, "build none raid") - } - _, err = adapter.remoteRun(cmd) - return err + return storcliBuildNoRaid(adapter.GetStorcliCommand, adapter.getTerm(), devs) } func (adapter *MegaRaidAdaptor) megacliBuildNoRaid(devs []*baremetal.BaremetalStorage, _ *api.BaremetalDiskConfig) error { @@ -1152,15 +1033,10 @@ func (adapter *MegaRaidAdaptor) RemoveLogicVolumes() error { } func (adapter *MegaRaidAdaptor) storcliClearJBODDisks() error { - errs := make([]error, 0) - for _, dev := range adapter.devs { - cmd := GetCommand2(fmt.Sprintf("/c%d/e%d/s%d", adapter.index, dev.enclosure, dev.slot), "set", "good", "force") - if _, err := adapter.remoteRun(cmd); err != nil { - err = errors.Wrapf(err, "Set PD good storcli cmd %v", cmd) - errs = append(errs, err) - } - } - return errors.NewAggregate(errs) + return storcliClearJBODDisks( + adapter.GetStorcliCommand, adapter.getTerm(), + adapter.devs, + ) } func (adapter *MegaRaidAdaptor) megacliClearJBODDisks() error { @@ -1263,7 +1139,7 @@ func (raid *MegaRaid) parsePhyDevsUseStorcli() error { if err != nil { return errors.Wrap(err, "NewMegaRaidAdaptorByStorcli") } - devs, err := ada.getMegaPhyDevs(raid) + devs, err := ada.getMegaPhyDevs(GetCommand2, raid.term) if err != nil { return errors.Wrapf(err, "get storcli %d mega PDs", ada.Controller) } @@ -1364,7 +1240,3 @@ func (raid *MegaRaid) RemoveLogicVolumes() { adapter.RemoveLogicVolumes() } } - -func init() { - raiddrivers.RegisterDriver(baremetal.DISK_DRIVER_MEGARAID, NewMegaRaid) -} diff --git a/pkg/baremetal/utils/raid/megactl/perccli.go b/pkg/baremetal/utils/raid/megactl/perccli.go new file mode 100644 index 0000000000..3926da9411 --- /dev/null +++ b/pkg/baremetal/utils/raid/megactl/perccli.go @@ -0,0 +1,169 @@ +// 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" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/baremetal/utils/raid" + "yunion.io/x/onecloud/pkg/compute/baremetal" +) + +var ( + _ iDriver = new(perccliDriver) +) + +type perccliDriver struct{} + +func newPerccliDriver() iDriver { + return new(perccliDriver) +} + +func (_ *perccliDriver) GetName() string { + return "MegaRAID_Perccli" +} + +func (_ *perccliDriver) GetAdapterConstructCmd() string { + return getPerccliCmd("/call", "show", "|", "grep", "-iE", `'^(Controller|Product Name|Serial Number|Bus Number|Device Number|Function Number)\s='`) +} + +func (_ *perccliDriver) NewAdaptor(term raid.IExecTerm) iAdaptor { + return newPerccliAdaptor(term) +} + +func (_ *perccliDriver) ClearForeignState(term raid.IExecTerm) error { + cmd := getPerccliCmd("/call/fall", "delete") + if _, err := term.Run(cmd); err != nil { + return err + } + return nil +} + +func getPerccliCmd(args ...string) string { + bin := "/opt/MegaRAID/perccli/perccli" + return raid.GetCommand(bin, args...) +} + +type PerccliAdaptor struct { + *StorcliAdaptor + term raid.IExecTerm +} + +func newPerccliAdaptor(term raid.IExecTerm) *PerccliAdaptor { + return &PerccliAdaptor{ + StorcliAdaptor: newStorcliAdaptor(), + term: term, + } +} + +func (a *PerccliAdaptor) ParseLine(line string) { + a.StorcliAdaptor.parseLine(line) +} + +func (a *PerccliAdaptor) IsComplete() bool { + return a.isComplete() +} + +func (a *PerccliAdaptor) Key() string { + return a.key() +} + +func (a *PerccliAdaptor) GetPhyDevs() ([]*MegaRaidPhyDev, error) { + return a.getMegaPhyDevs(a.getCmd, a.term) +} + +func (a *PerccliAdaptor) ClearJBODDisks(devs []*MegaRaidPhyDev) { + storcliClearJBODDisks(a.getAdaptorCmd, a.term, devs) +} + +func (a *PerccliAdaptor) GetIndex() int { + return a.Controller +} + +func (a *PerccliAdaptor) getCmd(args ...string) string { + return getPerccliCmd(args...) +} + +func (a *PerccliAdaptor) getAdaptorCmd(args ...string) (string, error) { + nargs := []string{fmt.Sprintf("/c%d", a.GetIndex())} + nargs = append(nargs, args...) + return a.getCmd(nargs...), nil +} + +func (a *PerccliAdaptor) GetLogicVolumes() ([]*raid.RaidLogicalVolume, error) { + cmd := a.getCmd(fmt.Sprintf("/c%d/vall", a.GetIndex()), "show") + ret, err := a.term.Run(cmd) + if err != nil { + return nil, errors.Wrap(err, "Get perccli logical volumes") + } + return parseStorcliLogicalVolumes(a.GetIndex(), ret) +} + +func (a *PerccliAdaptor) RemoveLogicVolumes() error { + lvIdx, err := a.GetLogicVolumes() + if err != nil { + return errors.Wrap(err, "GetLogicVolumes") + } + for _, i := range raid.ReverseLogicalArray(lvIdx) { + cmd := a.getCmd(fmt.Sprintf("/c%d/v%d", a.GetIndex(), i.Index), "delete", "force") + if _, err := a.term.Run(cmd); err != nil { + return errors.Wrapf(err, "remove adaptor %d lv %d", a.GetIndex(), i.Index) + } + } + return nil +} + +func (a *PerccliAdaptor) BuildRaid0(devs []*baremetal.BaremetalStorage, conf *compute.BaremetalDiskConfig) error { + return cliBuildRaid(devs, conf, func(bs []*baremetal.BaremetalStorage, bdc *compute.BaremetalDiskConfig) error { + return storcliBuildRaid(a.getAdaptorCmd, a.term, devs, conf, 0) + }) +} + +func (a *PerccliAdaptor) BuildRaid1(devs []*baremetal.BaremetalStorage, conf *compute.BaremetalDiskConfig) error { + return cliBuildRaid(devs, conf, func(bs []*baremetal.BaremetalStorage, bdc *compute.BaremetalDiskConfig) error { + return storcliBuildRaid(a.getAdaptorCmd, a.term, devs, conf, 1) + }) +} + +func (a *PerccliAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, conf *compute.BaremetalDiskConfig) error { + return cliBuildRaid(devs, conf, func(bs []*baremetal.BaremetalStorage, bdc *compute.BaremetalDiskConfig) error { + return storcliBuildRaid(a.getAdaptorCmd, a.term, devs, conf, 5) + }) +} + +func (a *PerccliAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *compute.BaremetalDiskConfig) error { + return cliBuildRaid(devs, conf, func(bs []*baremetal.BaremetalStorage, bdc *compute.BaremetalDiskConfig) error { + return storcliBuildRaid(a.getAdaptorCmd, a.term, devs, conf, 10) + }) +} + +func (a *PerccliAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage) error { + return cliBuildRaid(devs, nil, func(bs []*baremetal.BaremetalStorage, bdc *compute.BaremetalDiskConfig) error { + return storcliBuildNoRaid(a.getAdaptorCmd, a.term, devs) + }) +} + +type PerccliPhyDev struct { + *StorcliPhysicalDrive +} + +func NewPerccliPhyDev(base *StorcliPhysicalDrive) *PerccliPhyDev { + return &PerccliPhyDev{ + StorcliPhysicalDrive: base, + } +}