cloudpods-baremetals.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  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 guestdrivers
  15. import (
  16. "context"
  17. "fmt"
  18. "path/filepath"
  19. "regexp"
  20. "time"
  21. "yunion.io/x/cloudmux/pkg/cloudprovider"
  22. "yunion.io/x/jsonutils"
  23. "yunion.io/x/log"
  24. "yunion.io/x/pkg/errors"
  25. "yunion.io/x/pkg/util/rbacscope"
  26. "yunion.io/x/pkg/utils"
  27. api "yunion.io/x/onecloud/pkg/apis/compute"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  31. "yunion.io/x/onecloud/pkg/compute/baremetal"
  32. "yunion.io/x/onecloud/pkg/compute/models"
  33. "yunion.io/x/onecloud/pkg/compute/options"
  34. "yunion.io/x/onecloud/pkg/httperrors"
  35. "yunion.io/x/onecloud/pkg/mcclient"
  36. "yunion.io/x/onecloud/pkg/mcclient/cloudpods"
  37. )
  38. type SCloudpodsBaremetalGuestDriver struct {
  39. SManagedVirtualizedGuestDriver
  40. }
  41. func init() {
  42. driver := SCloudpodsBaremetalGuestDriver{}
  43. models.RegisterGuestDriver(&driver)
  44. }
  45. func (self *SCloudpodsBaremetalGuestDriver) GetHypervisor() string {
  46. return api.HYPERVISOR_BAREMETAL
  47. }
  48. func (self *SCloudpodsBaremetalGuestDriver) GetProvider() string {
  49. return api.CLOUD_PROVIDER_CLOUDPODS
  50. }
  51. func (self *SCloudpodsBaremetalGuestDriver) GetInstanceCapability() cloudprovider.SInstanceCapability {
  52. return cloudprovider.SInstanceCapability{
  53. Hypervisor: self.GetHypervisor(),
  54. Provider: self.GetProvider(),
  55. }
  56. }
  57. func (self *SCloudpodsBaremetalGuestDriver) GetComputeQuotaKeys(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider, brand string) models.SComputeResourceKeys {
  58. keys := models.SComputeResourceKeys{}
  59. keys.SBaseProjectQuotaKeys = quotas.OwnerIdProjectQuotaKeys(scope, ownerId)
  60. keys.CloudEnv = api.CLOUD_ENV_PRIVATE_CLOUD
  61. keys.Provider = api.CLOUD_PROVIDER_CLOUDPODS
  62. keys.Brand = api.CLOUD_PROVIDER_CLOUDPODS
  63. keys.Hypervisor = api.HYPERVISOR_BAREMETAL
  64. return keys
  65. }
  66. func (self *SCloudpodsBaremetalGuestDriver) GetDefaultSysDiskBackend() string {
  67. return api.STORAGE_LOCAL
  68. }
  69. func (self *SCloudpodsBaremetalGuestDriver) GetMinimalSysDiskSizeGb() int {
  70. return options.Options.DefaultDiskSizeMB / 1024
  71. }
  72. func (self *SCloudpodsBaremetalGuestDriver) GetMaxSecurityGroupCount() int {
  73. //暂不支持绑定安全组
  74. return 0
  75. }
  76. func (self *SCloudpodsBaremetalGuestDriver) GetMaxVCpuCount() int {
  77. return 1024
  78. }
  79. func (self *SCloudpodsBaremetalGuestDriver) GetMaxVMemSizeGB() int {
  80. return 4096
  81. }
  82. func (self *SCloudpodsBaremetalGuestDriver) PrepareDiskRaidConfig(userCred mcclient.TokenCredential, host *models.SHost, confs []*api.BaremetalDiskConfig, disks []*api.DiskConfig) ([]*api.DiskConfig, error) {
  83. baremetalStorage := models.ConvertStorageInfo2BaremetalStorages(host.StorageInfo)
  84. if baremetalStorage == nil {
  85. return nil, fmt.Errorf("Convert storage info error")
  86. }
  87. if len(confs) == 0 {
  88. parsedConf, _ := baremetal.ParseDiskConfig("")
  89. confs = []*api.BaremetalDiskConfig{&parsedConf}
  90. }
  91. layouts, err := baremetal.CalculateLayout(confs, baremetalStorage)
  92. if err != nil {
  93. return nil, err
  94. }
  95. err = host.UpdateDiskConfig(userCred, layouts)
  96. if err != nil {
  97. return nil, err
  98. }
  99. allocable, extra := baremetal.CheckDisksAllocable(layouts, disks)
  100. if !allocable {
  101. return nil, fmt.Errorf("baremetal.CheckDisksAllocable not allocable")
  102. }
  103. return extra, nil
  104. }
  105. func (self *SCloudpodsBaremetalGuestDriver) GetRebuildRootStatus() ([]string, error) {
  106. return []string{api.VM_READY, api.VM_ADMIN}, nil
  107. }
  108. func (self *SCloudpodsBaremetalGuestDriver) GetChangeInstanceTypeStatus() ([]string, error) {
  109. return nil, httperrors.NewUnsupportOperationError("Cannot change config for baremtal")
  110. }
  111. func (self *SCloudpodsBaremetalGuestDriver) GetDeployStatus() ([]string, error) {
  112. return []string{api.VM_READY, api.VM_ADMIN}, nil
  113. }
  114. func (self *SCloudpodsBaremetalGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error {
  115. return httperrors.NewUnsupportOperationError("Cannot resize disk for baremtal")
  116. }
  117. func (self *SCloudpodsBaremetalGuestDriver) GetNamedNetworkConfiguration(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, netConfig *api.NetworkConfig) (*models.SNetwork, []models.SNicConfig, api.IPAllocationDirection, bool, error) {
  118. netifs, net, err := host.GetNetinterfacesWithIdAndCredential(netConfig.Network, userCred, netConfig.Reserved)
  119. if err != nil {
  120. return nil, nil, "", false, errors.Wrap(err, "get host netinterfaces")
  121. }
  122. if netifs != nil {
  123. nicCnt := 1
  124. if netConfig.RequireTeaming || netConfig.TryTeaming {
  125. nicCnt = 2
  126. }
  127. if len(netifs) < nicCnt {
  128. if netConfig.RequireTeaming {
  129. return net, nil, "", false, errors.Errorf("not enough network interfaces, want %d got %d", nicCnt, len(netifs))
  130. }
  131. nicCnt = len(netifs)
  132. }
  133. nicConfs := make([]models.SNicConfig, 0)
  134. for i := 0; i < nicCnt; i += 1 {
  135. nicConf := models.SNicConfig{
  136. Mac: netifs[i].Mac,
  137. Index: netifs[i].Index,
  138. Ifname: "",
  139. }
  140. nicConfs = append(nicConfs, nicConf)
  141. }
  142. reuseAddr := false
  143. hn := host.GetAttach2Network(netConfig.Network)
  144. if hn != nil && options.Options.BaremetalServerReuseHostIp {
  145. if (netConfig.Address == "" && netConfig.Address6 == "") || (netConfig.Address == hn.IpAddr && netConfig.Address6 == hn.Ip6Addr) {
  146. // try to reuse host network IP address
  147. netConfig.Address = hn.IpAddr
  148. netConfig.Address6 = hn.Ip6Addr
  149. reuseAddr = true
  150. }
  151. }
  152. return net, nicConfs, api.IPAllocationStepup, reuseAddr, nil
  153. }
  154. return net, nil, "", false, nil
  155. }
  156. func (self *SCloudpodsBaremetalGuestDriver) GetRandomNetworkTypes() []api.TNetworkType {
  157. return []api.TNetworkType{api.NETWORK_TYPE_BAREMETAL, api.NETWORK_TYPE_GUEST}
  158. }
  159. func (self *SCloudpodsBaremetalGuestDriver) Attach2RandomNetwork(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, host *models.SHost, netConfig *api.NetworkConfig, pendingUsage quotas.IQuota) ([]models.SGuestnetwork, error) {
  160. netifs := host.GetHostNetInterfaces()
  161. netsAvaiable := make([]models.SNetwork, 0)
  162. netifIndexs := make(map[string][]models.SNetInterface, 0)
  163. drv, err := guest.GetDriver()
  164. if err != nil {
  165. return nil, err
  166. }
  167. netTypes := drv.GetRandomNetworkTypes()
  168. if len(netConfig.NetType) > 0 {
  169. netTypes = []api.TNetworkType{netConfig.NetType}
  170. }
  171. var wirePattern *regexp.Regexp
  172. if len(netConfig.Wire) > 0 {
  173. wirePattern = regexp.MustCompile(netConfig.Wire)
  174. }
  175. for idx, netif := range netifs {
  176. if !netif.IsUsableServernic() {
  177. continue
  178. }
  179. wire := netif.GetWire()
  180. if wire == nil {
  181. continue
  182. }
  183. if wirePattern != nil && !wirePattern.MatchString(wire.Id) && !wirePattern.MatchString(wire.Name) {
  184. continue
  185. }
  186. var net *models.SNetwork
  187. if netConfig.Private {
  188. net, _ = wire.GetCandidatePrivateNetwork(ctx, userCred, userCred, models.NetworkManager.AllowScope(userCred), netConfig.Exit, netTypes)
  189. } else {
  190. net, _ = wire.GetCandidateAutoAllocNetwork(ctx, userCred, userCred, models.NetworkManager.AllowScope(userCred), netConfig.Exit, netTypes)
  191. }
  192. if net != nil {
  193. netsAvaiable = append(netsAvaiable, *net)
  194. if _, exist := netifIndexs[net.WireId]; !exist {
  195. netifIndexs[net.WireId] = make([]models.SNetInterface, 0)
  196. }
  197. netifIndexs[net.WireId] = append(netifIndexs[net.WireId], netifs[idx])
  198. }
  199. }
  200. if len(netsAvaiable) == 0 {
  201. return nil, fmt.Errorf("No appropriate host virtual network...")
  202. }
  203. net := models.ChooseCandidateNetworks(netsAvaiable, netConfig.Exit, netTypes)
  204. if net != nil {
  205. netifs := netifIndexs[net.WireId]
  206. nicConfs := make([]models.SNicConfig, 0)
  207. nicCnt := 1
  208. if netConfig.RequireTeaming || netConfig.TryTeaming {
  209. nicCnt = 2
  210. }
  211. if len(netifs) < nicCnt {
  212. if netConfig.RequireTeaming {
  213. return nil, fmt.Errorf("not enough network interfaces, want %d got %d", nicCnt, len(netifs))
  214. }
  215. nicCnt = len(netifs)
  216. }
  217. for i := 0; i < nicCnt; i += 1 {
  218. nicConf := models.SNicConfig{
  219. Mac: netifs[i].Mac,
  220. Index: netifs[i].Index,
  221. Ifname: "",
  222. }
  223. nicConfs = append(nicConfs, nicConf)
  224. }
  225. address := ""
  226. address6 := ""
  227. reuseAddr := false
  228. hn := host.GetAttach2Network(net.Id)
  229. if hn != nil && options.Options.BaremetalServerReuseHostIp {
  230. // try to reuse host network IP address
  231. address = hn.IpAddr
  232. address6 = hn.Ip6Addr
  233. reuseAddr = true
  234. }
  235. return guest.Attach2Network(ctx, userCred, models.Attach2NetworkArgs{
  236. Network: net,
  237. PendingUsage: pendingUsage,
  238. IpAddr: address,
  239. Ip6Addr: address6,
  240. NicDriver: netConfig.Driver,
  241. BwLimit: netConfig.BwLimit,
  242. Virtual: netConfig.Vip,
  243. TryReserved: false,
  244. AllocDir: api.IPAllocationStepup,
  245. RequireDesignatedIP: false,
  246. UseDesignatedIP: reuseAddr,
  247. NicConfs: nicConfs,
  248. IsDefault: netConfig.IsDefault,
  249. BillingType: netConfig.BillingType,
  250. ChargeType: netConfig.ChargeType,
  251. })
  252. }
  253. return nil, fmt.Errorf("No appropriate host virtual network...")
  254. }
  255. func (self *SCloudpodsBaremetalGuestDriver) GetStorageTypes() []string {
  256. return []string{
  257. api.STORAGE_BAREMETAL,
  258. }
  259. }
  260. func (self *SCloudpodsBaremetalGuestDriver) ChooseHostStorage(host *models.SHost, guest *models.SGuest, diskConfig *api.DiskConfig, storageIds []string) (*models.SStorage, error) {
  261. if len(storageIds) != 0 {
  262. return models.StorageManager.FetchStorageById(storageIds[0]), nil
  263. }
  264. bs := host.GetBaremetalstorage()
  265. if bs == nil {
  266. return nil, nil
  267. }
  268. return bs.GetStorage(), nil
  269. }
  270. func (self *SCloudpodsBaremetalGuestDriver) RequestGuestCreateAllDisks(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
  271. diskCat := guest.CategorizeDisks()
  272. var imageId string
  273. if diskCat.Root != nil {
  274. imageId = diskCat.Root.GetTemplateId()
  275. }
  276. if len(imageId) == 0 {
  277. task.ScheduleRun(nil)
  278. return nil
  279. }
  280. storage, _ := diskCat.Root.GetStorage()
  281. if storage == nil {
  282. return fmt.Errorf("no valid storage")
  283. }
  284. storageCache := storage.GetStoragecache()
  285. if storageCache == nil {
  286. return fmt.Errorf("no valid storage cache")
  287. }
  288. input := api.CacheImageInput{
  289. ImageId: imageId,
  290. Format: "qcow2",
  291. ParentTaskId: task.GetTaskId(),
  292. }
  293. return storageCache.StartImageCacheTask(ctx, task.GetUserCred(), input)
  294. }
  295. func (self *SCloudpodsBaremetalGuestDriver) NeedRequestGuestHotAddIso(ctx context.Context, guest *models.SGuest) bool {
  296. return true
  297. }
  298. func (self *SCloudpodsBaremetalGuestDriver) RequestGuestHotAddIso(ctx context.Context, guest *models.SGuest, path string, boot bool, task taskman.ITask) error {
  299. host, _ := guest.GetHost()
  300. return host.StartInsertIsoTask(ctx, task.GetUserCred(), filepath.Base(path), boot, task.GetTaskId())
  301. }
  302. func (self *SCloudpodsBaremetalGuestDriver) RequestGuestHotRemoveIso(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
  303. host, _ := guest.GetHost()
  304. return host.StartEjectIsoTask(ctx, task.GetUserCred(), task.GetTaskId())
  305. }
  306. func (self *SCloudpodsBaremetalGuestDriver) RequestGuestCreateInsertIso(ctx context.Context, imageId string, bootIndex *int8, task taskman.ITask, guest *models.SGuest) error {
  307. return guest.StartInsertIsoTask(ctx, 0, imageId, true, nil, guest.HostId, task.GetUserCred(), task.GetTaskId())
  308. }
  309. func (self *SCloudpodsBaremetalGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  310. if len(input.BaremetalDiskConfigs) != 0 {
  311. if err := baremetal.ValidateDiskConfigs(input.BaremetalDiskConfigs); err != nil {
  312. return nil, httperrors.NewInputParameterError("Invalid raid config: %v", err)
  313. }
  314. }
  315. return input, nil
  316. }
  317. func (self *SCloudpodsBaremetalGuestDriver) ValidateCreateDataOnHost(ctx context.Context, userCred mcclient.TokenCredential, bmName string, host *models.SHost, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  318. if host.HostType != api.HOST_TYPE_BAREMETAL || !host.IsBaremetal {
  319. return nil, httperrors.NewInputParameterError("Host %s is not a baremetal", bmName)
  320. }
  321. if !utils.IsInStringArray(host.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING, api.BAREMETAL_START_CONVERT}) {
  322. return nil, httperrors.NewInvalidStatusError("CloudpodsBaremetal %s is not ready", bmName)
  323. }
  324. if host.GetBaremetalServer() != nil {
  325. return nil, httperrors.NewInsufficientResourceError("CloudpodsBaremetal %s is occupied", bmName)
  326. }
  327. input.VmemSize = host.MemSize
  328. input.VcpuCount = int(host.CpuCount)
  329. return input, nil
  330. }
  331. func (self *SCloudpodsBaremetalGuestDriver) GetGuestVncInfo(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
  332. ret := &cloudprovider.ServerVncOutput{}
  333. ret.HostId = host.Id
  334. zone, _ := host.GetZone()
  335. ret.Zone = zone.Name
  336. return ret, nil
  337. }
  338. func (self *SCloudpodsBaremetalGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  339. config, err := guest.GetDeployConfigOnHost(ctx, task.GetUserCred(), host, task.GetParams())
  340. if err != nil {
  341. log.Errorf("GetDeployConfigOnHost error: %v", err)
  342. return err
  343. }
  344. val, _ := config.GetString("action")
  345. if len(val) == 0 {
  346. val = "deploy"
  347. }
  348. desc := cloudprovider.SManagedVMCreateConfig{}
  349. desc.Description = guest.Description
  350. // 账号必须在desc.GetConfig()之前设置,避免默认用户不能正常注入
  351. osInfo := struct {
  352. OsType string
  353. OsDistribution string
  354. ImageType string
  355. }{}
  356. config.Unmarshal(&osInfo, "desc")
  357. driver, err := guest.GetDriver()
  358. if err != nil {
  359. return errors.Wrapf(err, "GetDriver")
  360. }
  361. desc.Account = driver.GetDefaultAccount(osInfo.OsType, osInfo.OsDistribution, osInfo.ImageType)
  362. err = desc.GetConfig(config)
  363. if err != nil {
  364. return errors.Wrapf(err, "desc.GetConfig")
  365. }
  366. log.Debugf("%s baremetal config: %s", val, jsonutils.Marshal(desc).String())
  367. iHost, err := host.GetIHost(ctx)
  368. if err != nil {
  369. return err
  370. }
  371. switch val {
  372. case "create":
  373. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  374. h := iHost.(*cloudpods.SHost)
  375. opts := &api.ServerCreateInput{
  376. ServerConfigs: &api.ServerConfigs{},
  377. }
  378. task.GetParams().Unmarshal(&opts.BaremetalDiskConfigs, "baremetal_disk_configs")
  379. opts.Name = guest.Name
  380. opts.Hostname = guest.Hostname
  381. opts.Description = guest.Description
  382. opts.InstanceType = guest.InstanceType
  383. opts.VcpuCount = guest.VcpuCount
  384. opts.VmemSize = guest.VmemSize
  385. opts.Password = desc.Password
  386. opts.Metadata, _ = guest.GetAllUserMetadata()
  387. opts.UserData, _ = desc.GetUserData()
  388. opts.Hypervisor = api.HYPERVISOR_BAREMETAL
  389. networks := []*api.NetworkConfig{}
  390. if len(desc.ExternalNetworkId) > 0 {
  391. networks = append(networks, &api.NetworkConfig{
  392. Network: desc.ExternalNetworkId,
  393. Address: desc.IpAddr,
  394. })
  395. }
  396. disks := []*api.DiskConfig{}
  397. disks = append(disks, &api.DiskConfig{
  398. Index: 0,
  399. ImageId: desc.ExternalImageId,
  400. DiskType: api.DISK_TYPE_SYS,
  401. SizeMb: desc.SysDisk.SizeGB * 1024,
  402. Backend: desc.SysDisk.StorageType,
  403. Storage: desc.SysDisk.StorageExternalId,
  404. })
  405. for idx, disk := range desc.DataDisks {
  406. info := &api.DiskConfig{
  407. Index: idx + 1,
  408. DiskType: api.DISK_TYPE_DATA,
  409. SizeMb: -1,
  410. Backend: disk.StorageType,
  411. Storage: disk.StorageExternalId,
  412. }
  413. if disk.SizeGB > 0 {
  414. info.SizeMb = disk.SizeGB * 1024
  415. }
  416. disks = append(disks, info)
  417. }
  418. opts.Disks = disks
  419. opts.Networks = networks
  420. if len(desc.ProjectId) > 0 {
  421. opts.ProjectId = desc.ProjectId
  422. }
  423. log.Debugf("create baremetal params: %s", jsonutils.Marshal(opts))
  424. iVM, err := h.CreateBaremetalServer(opts)
  425. if err != nil {
  426. return nil, errors.Wrapf(err, "CreateBaremetalServer")
  427. }
  428. db.SetExternalId(guest, task.GetUserCred(), iVM.GetGlobalId())
  429. vmId := iVM.GetGlobalId()
  430. initialState := driver.GetGuestInitialStateAfterCreate()
  431. log.Debugf("VMcreated %s, wait status %s ...", vmId, initialState)
  432. err = cloudprovider.WaitStatusWithInstanceErrorCheck(iVM, initialState, time.Second*5, time.Second*1800, func() error {
  433. return iVM.GetError()
  434. })
  435. if err != nil {
  436. return nil, err
  437. }
  438. log.Debugf("VMcreated %s, and status is running", vmId)
  439. iVM, err = iHost.GetIVMById(vmId)
  440. if err != nil {
  441. return nil, errors.Wrapf(err, "GetIVMById(%s)", vmId)
  442. }
  443. data := fetchIVMinfo(desc, iVM, guest.Id, desc.Account, desc.Password, desc.PublicKey, "create")
  444. return data, nil
  445. })
  446. case "deploy":
  447. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  448. return self.SManagedVirtualizedGuestDriver.RemoteDeployGuestForDeploy(ctx, guest, iHost, task, desc)
  449. })
  450. case "rebuild":
  451. taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
  452. iVm, err := guest.GetIVM(ctx)
  453. if err != nil {
  454. return nil, errors.Wrapf(err, "GetIVM")
  455. }
  456. opts := &cloudprovider.SManagedVMRebuildRootConfig{
  457. Account: desc.Account,
  458. ImageId: desc.ExternalImageId,
  459. Password: desc.Password,
  460. PublicKey: desc.PublicKey,
  461. }
  462. _, err = iVm.RebuildRoot(ctx, opts)
  463. if err != nil {
  464. return nil, err
  465. }
  466. initialState := driver.GetGuestInitialStateAfterRebuild()
  467. err = cloudprovider.WaitStatus(iVm, initialState, time.Second*5, time.Hour*1)
  468. if err != nil {
  469. return nil, err
  470. }
  471. data := fetchIVMinfo(desc, iVm, guest.Id, desc.Account, desc.Password, desc.PublicKey, "rebuild")
  472. return data, nil
  473. })
  474. return nil
  475. default:
  476. return fmt.Errorf("Action %s not supported", val)
  477. }
  478. return nil
  479. }
  480. func (self *SCloudpodsBaremetalGuestDriver) CanKeepDetachDisk() bool {
  481. return false
  482. }
  483. func (self *SCloudpodsBaremetalGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  484. return task.ScheduleRun(nil)
  485. }
  486. func (self *SCloudpodsBaremetalGuestDriver) StartGuestDetachdiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  487. return fmt.Errorf("Cannot detach disk from a baremetal server")
  488. }
  489. func (self *SCloudpodsBaremetalGuestDriver) StartGuestAttachDiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  490. return fmt.Errorf("Cannot attach disk to a baremetal server")
  491. }
  492. func (self *SCloudpodsBaremetalGuestDriver) StartSuspendTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  493. return fmt.Errorf("Cannot suspend a baremetal server")
  494. }
  495. func (self *SCloudpodsBaremetalGuestDriver) StartResumeTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  496. return fmt.Errorf("Cannot resume a baremetal server")
  497. }
  498. func (self *SCloudpodsBaremetalGuestDriver) StartGuestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  499. return httperrors.NewUnsupportOperationError("Cannot save image for baremtal")
  500. }
  501. func (self *SCloudpodsBaremetalGuestDriver) StartGuestSaveGuestImage(ctx context.Context, userCred mcclient.TokenCredential,
  502. guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  503. return httperrors.NewUnsupportOperationError("Cannot save image for baremtal")
  504. }
  505. func (self *SCloudpodsBaremetalGuestDriver) StartGuestResetTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, isHard bool, parentTaskId string) error {
  506. task, err := taskman.TaskManager.NewTask(ctx, "BaremetalServerResetTask", guest, userCred, nil, "", parentTaskId, nil)
  507. if err != nil {
  508. return err
  509. }
  510. task.ScheduleRun(nil)
  511. return nil
  512. }
  513. func (self *SCloudpodsBaremetalGuestDriver) OnDeleteGuestFinalCleanup(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential) error {
  514. err := guest.DeleteAllDisksInDB(ctx, userCred)
  515. if err != nil {
  516. return err
  517. }
  518. baremetal, _ := guest.GetHost()
  519. if baremetal != nil {
  520. return baremetal.UpdateDiskConfig(userCred, nil)
  521. }
  522. return nil
  523. }
  524. func (self *SCloudpodsBaremetalGuestDriver) IsSupportGuestClone() bool {
  525. return false
  526. }
  527. func (self *SCloudpodsBaremetalGuestDriver) IsSupportCdrom(guest *models.SGuest) (bool, error) {
  528. host, _ := guest.GetHost()
  529. if host == nil {
  530. return false, errors.Wrap(httperrors.ErrNotFound, "no host")
  531. }
  532. ipmiInfo, err := host.GetIpmiInfo()
  533. if err != nil {
  534. return false, errors.Wrap(err, "host.GetIpmiInfo")
  535. }
  536. return ipmiInfo.CdromBoot, nil
  537. }
  538. func (self *SCloudpodsBaremetalGuestDriver) IsSupportFloppy(guest *models.SGuest) (bool, error) {
  539. return false, nil
  540. }