baremetals.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  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. "strings"
  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/util/logclient"
  37. )
  38. type SBaremetalGuestDriver struct {
  39. SBaseGuestDriver
  40. }
  41. func init() {
  42. driver := SBaremetalGuestDriver{}
  43. models.RegisterGuestDriver(&driver)
  44. }
  45. func (self *SBaremetalGuestDriver) GetHypervisor() string {
  46. return api.HYPERVISOR_BAREMETAL
  47. }
  48. func (self *SBaremetalGuestDriver) GetProvider() string {
  49. return api.CLOUD_PROVIDER_ONECLOUD
  50. }
  51. func (self *SBaremetalGuestDriver) GetInstanceCapability() cloudprovider.SInstanceCapability {
  52. return cloudprovider.SInstanceCapability{
  53. Hypervisor: self.GetHypervisor(),
  54. Provider: self.GetProvider(),
  55. }
  56. }
  57. func (self *SBaremetalGuestDriver) 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_ON_PREMISE
  61. keys.Provider = api.CLOUD_PROVIDER_ONECLOUD
  62. keys.Brand = api.ONECLOUD_BRAND_ONECLOUD
  63. keys.Hypervisor = api.HYPERVISOR_BAREMETAL
  64. return keys
  65. }
  66. func (self *SBaremetalGuestDriver) GetDefaultSysDiskBackend() string {
  67. return api.STORAGE_LOCAL
  68. }
  69. func (self *SBaremetalGuestDriver) GetMinimalSysDiskSizeGb() int {
  70. return options.Options.DefaultDiskSizeMB / 1024
  71. }
  72. func (self *SBaremetalGuestDriver) GetMaxSecurityGroupCount() int {
  73. //暂不支持绑定安全组
  74. return 0
  75. }
  76. func (self *SBaremetalGuestDriver) GetMaxVCpuCount() int {
  77. return 1024
  78. }
  79. func (self *SBaremetalGuestDriver) GetMaxVMemSizeGB() int {
  80. return 4096
  81. }
  82. func (self *SBaremetalGuestDriver) 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 *SBaremetalGuestDriver) GetRebuildRootStatus() ([]string, error) {
  106. return []string{api.VM_READY, api.VM_ADMIN}, nil
  107. }
  108. func (self *SBaremetalGuestDriver) GetChangeInstanceTypeStatus() ([]string, error) {
  109. return nil, httperrors.NewUnsupportOperationError("Cannot change config for baremtal")
  110. }
  111. func (self *SBaremetalGuestDriver) GetDeployStatus() ([]string, error) {
  112. return []string{api.VM_READY, api.VM_ADMIN}, nil
  113. }
  114. func (self *SBaremetalGuestDriver) ValidateResizeDisk(guest *models.SGuest, disk *models.SDisk, storage *models.SStorage) error {
  115. return httperrors.NewUnsupportOperationError("Cannot resize disk for baremtal")
  116. }
  117. func (self *SBaremetalGuestDriver) 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 *SBaremetalGuestDriver) GetRandomNetworkTypes() []api.TNetworkType {
  157. return []api.TNetworkType{api.NETWORK_TYPE_BAREMETAL, api.NETWORK_TYPE_GUEST}
  158. }
  159. func (self *SBaremetalGuestDriver) 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{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 *SBaremetalGuestDriver) GetStorageTypes() []string {
  256. return []string{
  257. api.STORAGE_BAREMETAL,
  258. }
  259. }
  260. func (self *SBaremetalGuestDriver) 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 *SBaremetalGuestDriver) 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 *SBaremetalGuestDriver) NeedRequestGuestHotAddIso(ctx context.Context, guest *models.SGuest) bool {
  296. return true
  297. }
  298. func (self *SBaremetalGuestDriver) 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 *SBaremetalGuestDriver) 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 *SBaremetalGuestDriver) 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 *SBaremetalGuestDriver) RequestStartOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, userCred mcclient.TokenCredential, task taskman.ITask) error {
  310. desc := guest.GetJsonDescAtBaremetal(ctx, host)
  311. config := jsonutils.NewDict()
  312. config.Set("desc", jsonutils.Marshal(desc))
  313. params := task.GetParams()
  314. if params.Length() > 0 {
  315. config.Add(params, "params")
  316. }
  317. headers := task.GetTaskRequestHeader()
  318. url := fmt.Sprintf("/baremetals/%s/servers/%s/start", host.Id, guest.Id)
  319. _, err := host.BaremetalSyncRequest(ctx, "POST", url, headers, config)
  320. return err
  321. }
  322. func (self *SBaremetalGuestDriver) RequestStopGuestForDelete(ctx context.Context, guest *models.SGuest,
  323. host *models.SHost, task taskman.ITask) error {
  324. if host == nil {
  325. host, _ = guest.GetHost()
  326. }
  327. guestStatus, _ := task.GetParams().GetString("guest_status")
  328. overridePendingDelete := jsonutils.QueryBoolean(task.GetParams(), "override_pending_delete", false)
  329. purge := jsonutils.QueryBoolean(task.GetParams(), "purge", false)
  330. if host != nil && host.GetEnabled() &&
  331. (guestStatus == api.VM_RUNNING || strings.Index(guestStatus, "stop") >= 0) &&
  332. options.Options.EnablePendingDelete &&
  333. !guest.PendingDeleted &&
  334. !overridePendingDelete &&
  335. !purge {
  336. return guest.StartGuestStopTask(ctx, task.GetUserCred(), 0, true, false, task.GetTaskId())
  337. }
  338. if host != nil && !host.GetEnabled() && !purge {
  339. return errors.Errorf("fail to contact baremetal")
  340. }
  341. task.ScheduleRun(nil)
  342. return nil
  343. }
  344. func (self *SBaremetalGuestDriver) RequestStopOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask, syncStatus bool) error {
  345. body := jsonutils.NewDict()
  346. timeout, err := task.GetParams().Int("timeout")
  347. if err != nil {
  348. timeout = 30
  349. }
  350. if jsonutils.QueryBoolean(task.GetParams(), "is_force", false) || jsonutils.QueryBoolean(task.GetParams(), "reset", false) {
  351. timeout = 0
  352. }
  353. body.Set("timeout", jsonutils.NewInt(timeout))
  354. headers := task.GetTaskRequestHeader()
  355. url := fmt.Sprintf("/baremetals/%s/servers/%s/stop", host.Id, guest.Id)
  356. _, err = host.BaremetalSyncRequest(ctx, "POST", url, headers, body)
  357. return err
  358. }
  359. func (self *SBaremetalGuestDriver) StartGuestStopTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  360. task, err := taskman.TaskManager.NewTask(ctx, "GuestStopTask", guest, userCred, params, parentTaskId, "", nil)
  361. if err != nil {
  362. return err
  363. }
  364. return task.ScheduleRun(nil)
  365. }
  366. func (self *SBaremetalGuestDriver) RequestUndeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  367. url := fmt.Sprintf("/baremetals/%s/servers/%s", host.Id, guest.Id)
  368. headers := task.GetTaskRequestHeader()
  369. _, err := host.BaremetalSyncRequest(ctx, "DELETE", url, headers, nil)
  370. return err
  371. }
  372. func (self *SBaremetalGuestDriver) RequestSyncstatusOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, userCred mcclient.TokenCredential, task taskman.ITask) error {
  373. return errors.Wrap(httperrors.ErrNotSupported, "baremetal doesn't support RequestSyncstatusOnHost")
  374. }
  375. func (self *SBaremetalGuestDriver) StartGuestSyncstatusTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  376. return models.StartResourceSyncStatusTask(ctx, userCred, guest, "BaremetalServerSyncStatusTask", parentTaskId)
  377. }
  378. func (self *SBaremetalGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  379. if len(input.BaremetalDiskConfigs) != 0 {
  380. if err := baremetal.ValidateDiskConfigs(input.BaremetalDiskConfigs); err != nil {
  381. return nil, httperrors.NewInputParameterError("Invalid raid config: %v", err)
  382. }
  383. }
  384. if input.BaremetalRootDiskMatcher != nil {
  385. if err := baremetal.ValidateRootDiskMatcher(input.BaremetalRootDiskMatcher); err != nil {
  386. return nil, httperrors.NewInputParameterError("Invalid root disk matcher: %v", err)
  387. }
  388. }
  389. //if len(input.Disks) <= 0 {
  390. // return nil, httperrors.NewInputParameterError("Root disk must be present")
  391. //}
  392. //disk0 := input.Disks[0]
  393. //if disk0.ImageId == "" {
  394. // return nil, httperrors.NewInputParameterError("Root disk must have templete")
  395. //}
  396. return input, nil
  397. }
  398. func (self *SBaremetalGuestDriver) ValidateCreateDataOnHost(ctx context.Context, userCred mcclient.TokenCredential, bmName string, host *models.SHost, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  399. if host.HostType != api.HOST_TYPE_BAREMETAL || !host.IsBaremetal {
  400. return nil, httperrors.NewInputParameterError("Host %s is not a baremetal", bmName)
  401. }
  402. if !utils.IsInStringArray(host.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING, api.BAREMETAL_START_CONVERT}) {
  403. return nil, httperrors.NewInvalidStatusError("Baremetal %s is not ready", bmName)
  404. }
  405. if host.GetBaremetalServer() != nil {
  406. return nil, httperrors.NewInsufficientResourceError("Baremetal %s is occupied", bmName)
  407. }
  408. input.VmemSize = host.MemSize
  409. input.VcpuCount = int(host.CpuCount)
  410. return input, nil
  411. }
  412. func (self *SBaremetalGuestDriver) GetJsonDescAtHost(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, params *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
  413. desc := guest.GetJsonDescAtBaremetal(ctx, host)
  414. return jsonutils.Marshal(desc), nil
  415. }
  416. func (self *SBaremetalGuestDriver) GetGuestVncInfo(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, host *models.SHost, input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
  417. ret := &cloudprovider.ServerVncOutput{}
  418. ret.HostId = host.Id
  419. zone, _ := host.GetZone()
  420. ret.Zone = zone.Name
  421. return ret, nil
  422. }
  423. func (self *SBaremetalGuestDriver) RequestRebuildRootDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
  424. subtask, err := taskman.TaskManager.NewTask(ctx, "ManagedGuestRebuildRootTask", guest, task.GetUserCred(), task.GetParams(), task.GetTaskId(), "", nil)
  425. if err != nil {
  426. return err
  427. }
  428. subtask.ScheduleRun(nil)
  429. return nil
  430. }
  431. func (self *SBaremetalGuestDriver) PerformStart(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, data *jsonutils.JSONDict, parentTaskId string) error {
  432. return guest.StartGueststartTask(ctx, userCred, data, "")
  433. }
  434. func (self *SBaremetalGuestDriver) CheckDiskTemplateOnStorage(ctx context.Context, userCred mcclient.TokenCredential, imageId string, format string, storageId string, task taskman.ITask) error {
  435. task.ScheduleRun(nil)
  436. return nil
  437. }
  438. func (self *SBaremetalGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error {
  439. if data.Contains("disks") {
  440. disks, _ := data.GetArray("disks")
  441. for i := 0; i < len(disks); i++ {
  442. diskId, _ := disks[i].GetString("disk_id")
  443. iDisk, _ := models.DiskManager.FetchById(diskId)
  444. if iDisk == nil {
  445. return fmt.Errorf("OnGuestDeployTaskDataReceived fetch disk error")
  446. }
  447. disk := iDisk.(*models.SDisk)
  448. diskSize, _ := disks[i].Int("size")
  449. pciPath, _ := disks[i].GetString("pci_path")
  450. notes := fmt.Sprintf("%s=>%s", disk.Status, api.DISK_READY)
  451. _, err := db.Update(disk, func() error {
  452. if disk.DiskSize < int(diskSize) {
  453. disk.DiskSize = int(diskSize)
  454. }
  455. if len(pciPath) > 0 {
  456. disk.PCIPath = pciPath
  457. }
  458. disk.DiskFormat = "raw"
  459. disk.Status = api.DISK_READY
  460. return nil
  461. })
  462. if err != nil {
  463. return err
  464. }
  465. db.OpsLog.LogEvent(disk, db.ACT_UPDATE_STATUS, notes, task.GetUserCred())
  466. logclient.AddActionLogWithStartable(task, disk, logclient.ACT_VM_SYNC_STATUS, nil, task.GetUserCred(), false)
  467. db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(ctx), task.GetUserCred())
  468. if disks[i].Contains("dev") {
  469. dev, _ := disks[i].GetString("dev")
  470. disk.SetMetadata(ctx, "dev", dev, task.GetUserCred())
  471. }
  472. }
  473. }
  474. guest.SaveDeployInfo(ctx, task.GetUserCred(), data)
  475. return nil
  476. }
  477. func (self *SBaremetalGuestDriver) IsDisableImageCache(gst *models.SGuest) (bool, error) {
  478. host, err := gst.GetHost()
  479. if err != nil {
  480. return false, errors.Wrapf(err, "Get guest %s(%s) host", gst.GetName(), gst.GetId())
  481. }
  482. agent := host.GetAgent(api.AgentTypeBaremetal)
  483. if agent == nil {
  484. return false, errors.Wrapf(errors.ErrNotFound, "get host %s(%s) agent", host.GetName(), host.GetId())
  485. }
  486. return agent.DisableImageCache, nil
  487. }
  488. func (self *SBaremetalGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  489. config, err := guest.GetDeployConfigOnHost(ctx, task.GetUserCred(), host, task.GetParams())
  490. if err != nil {
  491. log.Errorf("GetDeployConfigOnHost error: %v", err)
  492. return err
  493. }
  494. val, _ := config.GetString("action")
  495. if len(val) == 0 {
  496. val = "deploy"
  497. }
  498. if val == "rebuild" && jsonutils.QueryBoolean(task.GetParams(), "auto_start", false) {
  499. config.Set("on_finish", jsonutils.NewString("restart"))
  500. } else if val == "deploy" && jsonutils.QueryBoolean(task.GetParams(), "restart", false) {
  501. config.Set("on_finish", jsonutils.NewString("shutdown"))
  502. }
  503. disableCache, err := self.IsDisableImageCache(guest)
  504. if err != nil {
  505. return errors.Wrap(err, "check IsDisableImageCache")
  506. }
  507. config.Set("disable_image_cache", jsonutils.NewBool(disableCache))
  508. url := fmt.Sprintf("/baremetals/%s/servers/%s/%s", host.Id, guest.Id, val)
  509. headers := task.GetTaskRequestHeader()
  510. _, err = host.BaremetalSyncRequest(ctx, "POST", url, headers, config)
  511. return err
  512. }
  513. func (self *SBaremetalGuestDriver) CanKeepDetachDisk() bool {
  514. return false
  515. }
  516. func (self *SBaremetalGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
  517. task.ScheduleRun(nil)
  518. return nil
  519. }
  520. func (self *SBaremetalGuestDriver) StartGuestDetachdiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  521. return fmt.Errorf("Cannot detach disk from a baremetal server")
  522. }
  523. func (self *SBaremetalGuestDriver) StartGuestAttachDiskTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  524. return fmt.Errorf("Cannot attach disk to a baremetal server")
  525. }
  526. func (self *SBaremetalGuestDriver) StartSuspendTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  527. return fmt.Errorf("Cannot suspend a baremetal server")
  528. }
  529. func (self *SBaremetalGuestDriver) StartResumeTask(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  530. return fmt.Errorf("Cannot resume a baremetal server")
  531. }
  532. func (self *SBaremetalGuestDriver) StartGuestSaveImage(ctx context.Context, userCred mcclient.TokenCredential, guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  533. return httperrors.NewUnsupportOperationError("Cannot save image for baremtal")
  534. }
  535. func (self *SBaremetalGuestDriver) StartGuestSaveGuestImage(ctx context.Context, userCred mcclient.TokenCredential,
  536. guest *models.SGuest, params *jsonutils.JSONDict, parentTaskId string) error {
  537. return httperrors.NewUnsupportOperationError("Cannot save image for baremtal")
  538. }
  539. func (self *SBaremetalGuestDriver) StartGuestResetTask(guest *models.SGuest, ctx context.Context, userCred mcclient.TokenCredential, isHard bool, parentTaskId string) error {
  540. task, err := taskman.TaskManager.NewTask(ctx, "BaremetalServerResetTask", guest, userCred, nil, "", parentTaskId, nil)
  541. if err != nil {
  542. return err
  543. }
  544. task.ScheduleRun(nil)
  545. return nil
  546. }
  547. func (self *SBaremetalGuestDriver) OnDeleteGuestFinalCleanup(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential) error {
  548. err := guest.DeleteAllDisksInDB(ctx, userCred)
  549. if err != nil {
  550. return err
  551. }
  552. baremetal, _ := guest.GetHost()
  553. if baremetal != nil {
  554. return baremetal.UpdateDiskConfig(userCred, nil)
  555. }
  556. return nil
  557. }
  558. func (self *SBaremetalGuestDriver) IsSupportGuestClone() bool {
  559. return false
  560. }
  561. func (self *SBaremetalGuestDriver) IsSupportCdrom(guest *models.SGuest) (bool, error) {
  562. host, _ := guest.GetHost()
  563. if host == nil {
  564. return false, errors.Wrap(httperrors.ErrNotFound, "no host")
  565. }
  566. ipmiInfo, err := host.GetIpmiInfo()
  567. if err != nil {
  568. return false, errors.Wrap(err, "host.GetIpmiInfo")
  569. }
  570. return ipmiInfo.CdromBoot, nil
  571. }
  572. func (self *SBaremetalGuestDriver) IsSupportFloppy(guest *models.SGuest) (bool, error) {
  573. return false, nil
  574. }