mvcli.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package mvcli
  15. import (
  16. "fmt"
  17. "strconv"
  18. "strings"
  19. "yunion.io/x/pkg/tristate"
  20. "yunion.io/x/pkg/util/stringutils"
  21. api "yunion.io/x/onecloud/pkg/apis/compute"
  22. "yunion.io/x/onecloud/pkg/baremetal/utils/raid"
  23. "yunion.io/x/onecloud/pkg/compute/baremetal"
  24. )
  25. type MarvelRaidPhyDev struct {
  26. *raid.RaidBasePhyDev
  27. slot int
  28. sn string
  29. }
  30. func NewMarvelRaidPhyDev(adapter int) *MarvelRaidPhyDev {
  31. b := raid.NewRaidBasePhyDev(baremetal.DISK_DRIVER_MARVELRAID)
  32. b.Adapter = adapter
  33. return &MarvelRaidPhyDev{
  34. RaidBasePhyDev: b,
  35. slot: -1,
  36. }
  37. }
  38. func (dev *MarvelRaidPhyDev) parseLine(line string) bool {
  39. key, val := stringutils.SplitKeyValue(line)
  40. if key == "" {
  41. return false
  42. }
  43. switch key {
  44. case "SSD Type":
  45. if strings.HasSuffix(val, "SSD") {
  46. dev.Rotate = tristate.True
  47. } else {
  48. dev.Rotate = tristate.False
  49. }
  50. case "PD ID":
  51. dev.slot, _ = strconv.Atoi(val)
  52. case "Size":
  53. dat := strings.Split(val, " ")
  54. size, _ := strconv.Atoi(dat[0])
  55. dev.Size = int64(size / 1024) // MB
  56. case "model":
  57. dev.Model = val
  58. case "Serial":
  59. dev.sn = val
  60. default:
  61. return false
  62. }
  63. return true
  64. }
  65. func (dev *MarvelRaidPhyDev) isComplete() bool {
  66. if !dev.RaidBasePhyDev.IsComplete() {
  67. return false
  68. }
  69. if dev.Size < 0 {
  70. return false
  71. }
  72. if dev.slot < 0 {
  73. return false
  74. }
  75. if dev.sn == "" {
  76. return false
  77. }
  78. return true
  79. }
  80. func (dev *MarvelRaidPhyDev) ToBaremetalStorage(idx int) *baremetal.BaremetalStorage {
  81. s := dev.RaidBasePhyDev.ToBaremetalStorage(idx)
  82. s.Slot = dev.slot
  83. return s
  84. }
  85. func GetSpecString(dev *baremetal.BaremetalStorage) string {
  86. return fmt.Sprintf("%d", dev.Slot)
  87. }
  88. type MarvelRaidAdaptor struct {
  89. index int
  90. raid *MarvelRaid
  91. devs []*MarvelRaidPhyDev
  92. }
  93. func NewMarvelRaidAdaptor(index int, raid *MarvelRaid) *MarvelRaidAdaptor {
  94. return &MarvelRaidAdaptor{
  95. index: index,
  96. raid: raid,
  97. devs: make([]*MarvelRaidPhyDev, 0),
  98. }
  99. }
  100. func (adapter *MarvelRaidAdaptor) GetIndex() int {
  101. return adapter.index
  102. }
  103. func (adapter *MarvelRaidAdaptor) ParsePhyDevs() error {
  104. cmd := GetCommand("info", "-o", "pd")
  105. ret, err := adapter.raid.term.Run(cmd)
  106. if err != nil {
  107. return fmt.Errorf("get physical device: %v", err)
  108. }
  109. return adapter.parsePhyDevs(ret)
  110. }
  111. func (adapter *MarvelRaidAdaptor) parsePhyDevs(lines []string) error {
  112. phyDev := NewMarvelRaidPhyDev(adapter.index)
  113. for _, line := range lines {
  114. if phyDev.parseLine(line) && phyDev.isComplete() {
  115. adapter.devs = append(adapter.devs, phyDev)
  116. phyDev = NewMarvelRaidPhyDev(adapter.index)
  117. }
  118. }
  119. return nil
  120. }
  121. func (adapter *MarvelRaidAdaptor) GetDevices() []*baremetal.BaremetalStorage {
  122. ret := []*baremetal.BaremetalStorage{}
  123. for idx, dev := range adapter.devs {
  124. ret = append(ret, dev.ToBaremetalStorage(idx))
  125. }
  126. return ret
  127. }
  128. func (adapter *MarvelRaidAdaptor) GetLogicVolumes() ([]*raid.RaidLogicalVolume, error) {
  129. cmd := GetCommand("info", "-o", "vd")
  130. ret, err := adapter.raid.term.Run(cmd)
  131. if err != nil {
  132. return nil, fmt.Errorf("getLogicVolumes: %v", err)
  133. }
  134. return adapter.parseLogicVolumes(ret)
  135. }
  136. func (adapter *MarvelRaidAdaptor) parseLogicVolumes(lines []string) ([]*raid.RaidLogicalVolume, error) {
  137. lvIdx := make([]*raid.RaidLogicalVolume, 0)
  138. usedDevs := make([]*raid.RaidLogicalVolume, 0)
  139. for _, line := range lines {
  140. key, val := stringutils.SplitKeyValue(line)
  141. if key != "" {
  142. if key == "id" {
  143. idx, err := strconv.Atoi(val)
  144. if err != nil {
  145. return nil, err
  146. }
  147. lvIdx = append(lvIdx, &raid.RaidLogicalVolume{
  148. Index: idx,
  149. Adapter: adapter.index,
  150. })
  151. } else if key == "PD RAID setup" {
  152. for _, d := range strings.Split(val, " ") {
  153. idx, err := strconv.Atoi(d)
  154. if err != nil {
  155. return nil, err
  156. }
  157. usedDevs = append(usedDevs, &raid.RaidLogicalVolume{
  158. Index: idx,
  159. Adapter: adapter.index,
  160. })
  161. }
  162. }
  163. }
  164. }
  165. if len(adapter.devs) < len(usedDevs) {
  166. return nil, fmt.Errorf("adapter %d current %d devs < usedDevs %d", adapter.index, len(adapter.devs), len(usedDevs))
  167. }
  168. return lvIdx, nil
  169. }
  170. func (adapter *MarvelRaidAdaptor) RemoveLogicVolumes() error {
  171. lvs, err := adapter.GetLogicVolumes()
  172. if err != nil {
  173. return fmt.Errorf("Failed to get logic volumes: %v", err)
  174. }
  175. for _, i := range raid.ReverseLogicalArray(lvs) {
  176. if err := adapter.removeLogicVolume(i.Index); err != nil {
  177. return fmt.Errorf("Remove %#v logical volume: %v", i, err)
  178. }
  179. }
  180. return nil
  181. }
  182. func (adapter *MarvelRaidAdaptor) removeLogicVolume(idx int) error {
  183. cmd := GetCommand("delete", "-o", "vd", "-i", fmt.Sprintf("%d", idx), "-f", "--waiveconfirmation")
  184. _, err := adapter.raid.term.Run(cmd)
  185. return err
  186. }
  187. func (adapter *MarvelRaidAdaptor) PreBuildRaid(confs []*api.BaremetalDiskConfig) error {
  188. return nil
  189. }
  190. func (adapter *MarvelRaidAdaptor) PostBuildRaid() error {
  191. return nil
  192. }
  193. func (adapter *MarvelRaidAdaptor) buildRaid(level string, devs []*baremetal.BaremetalStorage, _ *api.BaremetalDiskConfig) error {
  194. pds := []string{}
  195. for _, dev := range devs {
  196. pds = append(pds, fmt.Sprintf("%s", GetSpecString(dev)))
  197. }
  198. args := []string{"create", "-o", "vd", "-d", strings.Join(pds, ","), level, "--waiveconfirmation"}
  199. cmd := GetCommand(args...)
  200. _, err := adapter.raid.term.Run(cmd)
  201. return err
  202. }
  203. func (adapter *MarvelRaidAdaptor) BuildRaid0(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
  204. return adapter.buildRaid("-r0", devs, conf)
  205. }
  206. func (adapter *MarvelRaidAdaptor) BuildRaid1(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
  207. return adapter.buildRaid("-r1", devs, conf)
  208. }
  209. func (adapter *MarvelRaidAdaptor) BuildRaid5(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
  210. //return adapter.buildRaid("-r5", devs, conf)
  211. return fmt.Errorf("BuildRaid5 not impl")
  212. }
  213. func (adapter *MarvelRaidAdaptor) BuildRaid10(devs []*baremetal.BaremetalStorage, conf *api.BaremetalDiskConfig) error {
  214. return adapter.buildRaid("-r10", devs, conf)
  215. }
  216. func (adapter *MarvelRaidAdaptor) BuildNoneRaid(devs []*baremetal.BaremetalStorage) error {
  217. return fmt.Errorf("BuildNoneRaid not impl")
  218. }
  219. type MarvelRaid struct {
  220. term raid.IExecTerm
  221. adapters []*MarvelRaidAdaptor
  222. }
  223. func NewMarvelRaid(term raid.IExecTerm) raid.IRaidDriver {
  224. return &MarvelRaid{
  225. term: term,
  226. adapters: make([]*MarvelRaidAdaptor, 0),
  227. }
  228. }
  229. func (r *MarvelRaid) GetName() string {
  230. return baremetal.DISK_DRIVER_MARVELRAID
  231. }
  232. func GetCommand(args ...string) string {
  233. bin := "/opt/mvcli/mvcli"
  234. return raid.GetCommand(bin, args...)
  235. }
  236. func (r *MarvelRaid) ParsePhyDevs() error {
  237. cmd := GetCommand("info", "-o", "hba")
  238. ret, err := r.term.Run(cmd)
  239. if err != nil {
  240. return fmt.Errorf("Remote get info error: %v", err)
  241. }
  242. err = r.parseAdapters(ret)
  243. if err != nil {
  244. return fmt.Errorf("parse adapt error: %v", err)
  245. }
  246. if len(r.adapters) > 0 {
  247. return nil
  248. }
  249. return fmt.Errorf("Empty adapters")
  250. }
  251. func (r *MarvelRaid) parseAdapters(lines []string) error {
  252. for _, line := range lines {
  253. k, v := stringutils.SplitKeyValue(line)
  254. if k == "Adapter ID" {
  255. vi, err := strconv.Atoi(v)
  256. if err != nil {
  257. return err
  258. }
  259. adapter := NewMarvelRaidAdaptor(vi, r)
  260. r.adapters = append(r.adapters, adapter)
  261. }
  262. }
  263. for _, adp := range r.adapters {
  264. adp.ParsePhyDevs()
  265. }
  266. return nil
  267. }
  268. func (r *MarvelRaid) PreBuildRaid(_ []*api.BaremetalDiskConfig, _ int) error {
  269. return nil
  270. }
  271. func (r *MarvelRaid) GetAdapters() []raid.IRaidAdapter {
  272. ret := make([]raid.IRaidAdapter, 0)
  273. for _, a := range r.adapters {
  274. ret = append(ret, a)
  275. }
  276. return ret
  277. }
  278. func (r *MarvelRaid) CleanRaid() error {
  279. // pass
  280. return nil
  281. }
  282. func init() {
  283. raid.RegisterDriver(baremetal.DISK_DRIVER_MARVELRAID, NewMarvelRaid)
  284. }