guest_change_config_task.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  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 guest
  15. import (
  16. "context"
  17. "fmt"
  18. "time"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. api "yunion.io/x/onecloud/pkg/apis/compute"
  23. schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
  24. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
  29. "yunion.io/x/onecloud/pkg/compute/models"
  30. "yunion.io/x/onecloud/pkg/compute/options"
  31. taskutils "yunion.io/x/onecloud/pkg/compute/tasks/utils"
  32. "yunion.io/x/onecloud/pkg/util/logclient"
  33. )
  34. type GuestChangeConfigTask struct {
  35. taskutils.SSchedTask
  36. }
  37. func init() {
  38. taskman.RegisterTask(GuestChangeConfigTask{})
  39. }
  40. func (task *GuestChangeConfigTask) getChangeConfigSetting() (*api.ServerChangeConfigSettings, error) {
  41. confs := &api.ServerChangeConfigSettings{}
  42. err := task.Params.Unmarshal(confs)
  43. if err != nil {
  44. return nil, errors.Wrap(err, "unmarshal ServerChangeConfigSettings")
  45. }
  46. return confs, nil
  47. }
  48. func (task *GuestChangeConfigTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  49. taskutils.StartScheduleObjects(ctx, task, nil)
  50. }
  51. func (task *GuestChangeConfigTask) GetSchedParams() (*schedapi.ScheduleInput, error) {
  52. confs, err := task.getChangeConfigSetting()
  53. if err != nil {
  54. return nil, errors.Wrap(err, "getChangeConfigSetting")
  55. }
  56. schedInput := new(schedapi.ScheduleInput)
  57. err = confs.SchedDesc.Unmarshal(schedInput)
  58. if err != nil {
  59. return nil, errors.Wrap(err, "unmarshal sched_desc")
  60. }
  61. return schedInput, nil
  62. }
  63. func (task *GuestChangeConfigTask) OnStartSchedule(obj taskutils.IScheduleModel) {
  64. // do nothing
  65. }
  66. func (task *GuestChangeConfigTask) OnScheduleFailCallback(ctx context.Context, obj taskutils.IScheduleModel, reason jsonutils.JSONObject, index int) {
  67. // do nothing
  68. }
  69. func (task *GuestChangeConfigTask) OnScheduleFailed(ctx context.Context, reason jsonutils.JSONObject) {
  70. obj := task.GetObject()
  71. guest := obj.(*models.SGuest)
  72. task.markStageFailed(ctx, guest, reason)
  73. }
  74. func (task *GuestChangeConfigTask) SaveScheduleResult(ctx context.Context, obj taskutils.IScheduleModel, target *schedapi.CandidateResource, index int) {
  75. // must get object from task, because of obj is nil
  76. guest := task.GetObject().(*models.SGuest)
  77. task.Params.Set("sched_session_id", jsonutils.NewString(target.SessionId))
  78. confs, err := task.getChangeConfigSetting()
  79. if err != nil {
  80. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  81. return
  82. }
  83. if confs.ExtraCpuChanged() {
  84. _, err = db.Update(guest, func() error {
  85. if confs.ExtraCpuCount > 0 {
  86. guest.ExtraCpuCount = confs.ExtraCpuCount
  87. }
  88. return nil
  89. })
  90. if err != nil {
  91. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  92. return
  93. }
  94. }
  95. if len(target.CpuNumaPin) > 0 {
  96. task.Params.Set("cpu_numa_pin", jsonutils.Marshal(target.CpuNumaPin))
  97. }
  98. /*confs, err := task.getChangeConfigSetting()
  99. if err != nil {
  100. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  101. return
  102. }
  103. if len(confs.Create) > 0 {
  104. disks := make([]*api.DiskConfig, 0)
  105. err := task.Params.Unmarshal(&disks, "create")
  106. if err != nil {
  107. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  108. return
  109. }
  110. var resizeDisksCount = 0
  111. if task.Params.Contains("resize") {
  112. iResizeDisks, err := task.Params.Get("resize")
  113. if err != nil {
  114. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  115. return
  116. }
  117. resizeDisksCount = iResizeDisks.(*jsonutils.JSONArray).Length()
  118. }
  119. for i := 0; i < len(disks); i++ {
  120. disks[i].Storage = target.Disks[resizeDisksCount+i].StorageIds[0]
  121. }
  122. task.Params.Set("create", jsonutils.Marshal(disks))
  123. }*/
  124. task.SetStage("StartResizeDisks", nil)
  125. task.StartResizeDisks(ctx, guest, nil)
  126. }
  127. func (task *GuestChangeConfigTask) StartResizeDisks(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  128. confs, err := task.getChangeConfigSetting()
  129. if err != nil {
  130. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  131. return
  132. }
  133. if len(confs.Resize) > 0 {
  134. task.SetStage("OnDisksResizeComplete", nil)
  135. task.OnDisksResizeComplete(ctx, guest, data)
  136. } else {
  137. task.DoCreateDisksTask(ctx, guest)
  138. }
  139. }
  140. func (task *GuestChangeConfigTask) OnDisksResizeComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  141. guest := obj.(*models.SGuest)
  142. confs, err := task.getChangeConfigSetting()
  143. if err != nil {
  144. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  145. return
  146. }
  147. for i := 0; i < len(confs.Resize); i++ {
  148. diskId := confs.Resize[i].DiskId
  149. diskSizeMb := confs.Resize[i].SizeMb
  150. iDisk, err := models.DiskManager.FetchById(diskId)
  151. if err != nil {
  152. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("models.DiskManager.FetchById(%s) fail %s", diskId, err)))
  153. return
  154. }
  155. disk := iDisk.(*models.SDisk)
  156. if disk.DiskSize < diskSizeMb {
  157. var pendingUsage models.SQuota
  158. err = task.GetPendingUsage(&pendingUsage, 0)
  159. if err != nil {
  160. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("task.GetPendingUsage(&pendingUsage) fail %s", err)))
  161. return
  162. }
  163. err = guest.StartGuestDiskResizeTask(ctx, task.UserCred, disk.Id, int64(diskSizeMb), task.GetTaskId(), &pendingUsage)
  164. if err != nil {
  165. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("guest.StartGuestDiskResizeTask fail %s", err)))
  166. return
  167. }
  168. return
  169. }
  170. }
  171. task.DoCreateDisksTask(ctx, guest)
  172. }
  173. func (task *GuestChangeConfigTask) DoCreateDisksTask(ctx context.Context, guest *models.SGuest) {
  174. confs, err := task.getChangeConfigSetting()
  175. if err != nil {
  176. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  177. return
  178. }
  179. disks := confs.Create
  180. host, _ := guest.GetHost()
  181. err = guest.CreateDisksOnHost(ctx, task.UserCred, host, disks, nil, false, options.Options.UseServerTagsForDisk, nil, nil, false)
  182. if err != nil {
  183. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  184. return
  185. }
  186. task.SetStage("OnCreateDisksComplete", nil)
  187. guest.StartGuestCreateDiskTask(ctx, task.UserCred, disks, task.GetTaskId())
  188. }
  189. func (task *GuestChangeConfigTask) OnCreateDisksCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) {
  190. guest := obj.(*models.SGuest)
  191. task.markStageFailed(ctx, guest, err)
  192. }
  193. func (task *GuestChangeConfigTask) OnCreateDisksComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  194. guest := obj.(*models.SGuest)
  195. confs, err := task.getChangeConfigSetting()
  196. if err != nil {
  197. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  198. return
  199. }
  200. drv, err := guest.GetDriver()
  201. if err != nil {
  202. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  203. return
  204. }
  205. if confs.CpuChanged() || confs.MemChanged() || (drv.DoScheduleSKUFilter() && confs.InstanceTypeChanged()) {
  206. task.SetStage("OnGuestChangeCpuMemSpecComplete", nil)
  207. task.startGuestChangeCpuMemSpec(ctx, guest, confs.InstanceType, confs.VcpuCount, confs.CpuSockets, confs.VmemSize)
  208. } else {
  209. task.OnGuestChangeCpuMemSpecComplete(ctx, obj, data)
  210. }
  211. }
  212. func (task *GuestChangeConfigTask) startGuestChangeCpuMemSpec(ctx context.Context, guest *models.SGuest, instanceType string, vcpuCount, cpuSockets int, vmemSize int) {
  213. drv, err := guest.GetDriver()
  214. if err != nil {
  215. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  216. return
  217. }
  218. err = drv.RequestChangeVmConfig(ctx, guest, task, instanceType, int64(vcpuCount), int64(cpuSockets), int64(vmemSize))
  219. if err != nil {
  220. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  221. return
  222. }
  223. }
  224. func (task *GuestChangeConfigTask) OnGuestChangeCpuMemSpecComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  225. guest := obj.(*models.SGuest)
  226. confs, err := task.getChangeConfigSetting()
  227. if err != nil {
  228. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  229. return
  230. }
  231. if len(confs.InstanceType) == 0 {
  232. skus, err := models.ServerSkuManager.GetSkus(api.CLOUD_PROVIDER_ONECLOUD, confs.VcpuCount, confs.VmemSize)
  233. if err == nil && len(skus) > 0 {
  234. confs.InstanceType = skus[0].GetName()
  235. }
  236. }
  237. _, err = db.Update(guest, func() error {
  238. if confs.VcpuCount > 0 {
  239. guest.VcpuCount = confs.VcpuCount
  240. }
  241. if confs.CpuSockets > 0 {
  242. guest.CpuSockets = confs.CpuSockets
  243. }
  244. if confs.VmemSize > 0 {
  245. guest.VmemSize = confs.VmemSize
  246. }
  247. if len(confs.InstanceType) > 0 {
  248. guest.InstanceType = confs.InstanceType
  249. }
  250. return nil
  251. })
  252. if err != nil {
  253. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Update fail %s", err)))
  254. return
  255. }
  256. if task.Params.Contains("cpu_numa_pin") {
  257. cpuNumaPinSched := make([]schedapi.SCpuNumaPin, 0)
  258. task.Params.Unmarshal(&cpuNumaPinSched, "cpu_numa_pin")
  259. cpuNumaPinTarget := make([]api.SCpuNumaPin, 0)
  260. if data.Contains("cpu_numa_pin") {
  261. data.Unmarshal(&cpuNumaPinTarget, "cpu_numa_pin")
  262. }
  263. err = guest.UpdateCpuNumaPin(ctx, task.UserCred, cpuNumaPinSched, cpuNumaPinTarget)
  264. if err != nil {
  265. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Update cpu numa pin fail %s", err)))
  266. return
  267. }
  268. }
  269. changeConfigSpec := guest.GetShortDesc(ctx)
  270. if confs.VcpuCount > 0 && confs.AddedCpu() > 0 {
  271. changeConfigSpec.Set("add_cpu", jsonutils.NewInt(int64(confs.AddedCpu())))
  272. }
  273. if confs.VmemSize > 0 && confs.AddedMem() > 0 {
  274. changeConfigSpec.Set("add_mem", jsonutils.NewInt(int64(confs.AddedMem())))
  275. }
  276. if len(confs.InstanceType) > 0 {
  277. changeConfigSpec.Set("instance_type", jsonutils.NewString(confs.InstanceType))
  278. }
  279. db.OpsLog.LogEvent(guest, db.ACT_CHANGE_FLAVOR, changeConfigSpec.String(), task.UserCred)
  280. var pendingUsage models.SQuota
  281. err = task.GetPendingUsage(&pendingUsage, 0)
  282. if err != nil {
  283. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("GetPendingUsage %s", err)))
  284. return
  285. }
  286. var cancelUsage models.SQuota
  287. var reduceUsage models.SQuota
  288. if addCpu := confs.AddedCpu(); addCpu > 0 {
  289. cancelUsage.Cpu = addCpu
  290. }
  291. if addMem := confs.AddedMem(); addMem > 0 {
  292. cancelUsage.Memory = addMem
  293. }
  294. keys, err := guest.GetQuotaKeys()
  295. if err != nil {
  296. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("guest.GetQuotaKeys %s", err)))
  297. return
  298. }
  299. cancelUsage.SetKeys(keys)
  300. reduceUsage.SetKeys(keys)
  301. lockman.LockClass(ctx, guest.GetModelManager(), guest.ProjectId)
  302. defer lockman.ReleaseClass(ctx, guest.GetModelManager(), guest.ProjectId)
  303. if !cancelUsage.IsEmpty() {
  304. err = quotas.CancelPendingUsage(ctx, task.UserCred, &pendingUsage, &cancelUsage, true) // success
  305. if err != nil {
  306. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("CancelPendingUsage fail %s", err)))
  307. return
  308. }
  309. err = task.SetPendingUsage(&pendingUsage, 0)
  310. if err != nil {
  311. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("SetPendingUsage fail %s", err)))
  312. return
  313. }
  314. }
  315. if !reduceUsage.IsEmpty() {
  316. quotas.CancelUsages(ctx, task.UserCred, []db.IUsage{&reduceUsage})
  317. }
  318. task.OnGuestChangeCpuMemSpecFinish(ctx, guest)
  319. }
  320. func (task *GuestChangeConfigTask) OnGuestChangeCpuMemSpecCompleteFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  321. drv, err := guest.GetDriver()
  322. if err != nil {
  323. task.markStageFailed(ctx, guest, data)
  324. return
  325. }
  326. if err := drv.OnGuestChangeCpuMemFailed(ctx, guest, data.(*jsonutils.JSONDict), task); err != nil {
  327. log.Errorln(err)
  328. }
  329. task.markStageFailed(ctx, guest, data)
  330. }
  331. func (task *GuestChangeConfigTask) OnGuestChangeCpuMemSpecFinish(ctx context.Context, guest *models.SGuest) {
  332. models.HostManager.ClearSchedDescCache(guest.HostId)
  333. confs, err := task.getChangeConfigSetting()
  334. if err != nil {
  335. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  336. return
  337. }
  338. if len(confs.ResetTrafficLimits) > 0 {
  339. host, _ := guest.GetHost()
  340. // resetTraffics := []api.ServerNicTrafficLimit{}
  341. // task.Params.Unmarshal(&resetTraffics, "reset_traffic_limits")
  342. task.SetStage("OnGuestResetNicTraffics", nil)
  343. drv, err := guest.GetDriver()
  344. if err != nil {
  345. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  346. return
  347. }
  348. err = drv.RequestResetNicTrafficLimit(ctx, task, host, guest, confs.ResetTrafficLimits)
  349. if err != nil {
  350. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  351. return
  352. }
  353. } else {
  354. task.OnGuestResetNicTraffics(ctx, guest, nil)
  355. }
  356. }
  357. func (task *GuestChangeConfigTask) OnGuestResetNicTraffics(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  358. confs, err := task.getChangeConfigSetting()
  359. if err != nil {
  360. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  361. return
  362. }
  363. if len(confs.ResetTrafficLimits) > 0 {
  364. resetTraffics := confs.ResetTrafficLimits
  365. for i := range resetTraffics {
  366. input := resetTraffics[i]
  367. gn, _ := guest.GetGuestnetworkByMac(input.Mac)
  368. err := gn.UpdateBillingMode(ctx, task.UserCred, input)
  369. if err != nil {
  370. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("failed update guest nic traffic limit %s", err)))
  371. return
  372. }
  373. err = gn.UpdateNicTrafficUsed(ctx, guest, &api.SNicTrafficRecord{RxTraffic: 0, TxTraffic: 0}, time.Now(), true)
  374. if err != nil {
  375. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("failed update guest nic traffic used %s", err)))
  376. return
  377. }
  378. }
  379. }
  380. if len(confs.SetTrafficLimits) > 0 {
  381. host, _ := guest.GetHost()
  382. setTraffics := confs.SetTrafficLimits
  383. task.SetStage("OnGuestSetNicTraffics", nil)
  384. drv, err := guest.GetDriver()
  385. if err != nil {
  386. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  387. return
  388. }
  389. err = drv.RequestSetNicTrafficLimit(ctx, task, host, guest, setTraffics)
  390. if err != nil {
  391. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  392. return
  393. }
  394. } else {
  395. task.OnGuestSetNicTraffics(ctx, guest, nil)
  396. }
  397. }
  398. func (task *GuestChangeConfigTask) OnGuestSetNicTraffics(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  399. confs, err := task.getChangeConfigSetting()
  400. if err != nil {
  401. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  402. return
  403. }
  404. if len(confs.SetTrafficLimits) > 0 {
  405. setTraffics := confs.SetTrafficLimits
  406. for i := range setTraffics {
  407. input := setTraffics[i]
  408. gn, _ := guest.GetGuestnetworkByMac(input.Mac)
  409. err := gn.UpdateBillingMode(ctx, task.UserCred, input)
  410. if err != nil {
  411. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("failed update guest nic traffic limit %s", err)))
  412. return
  413. }
  414. }
  415. }
  416. task.SetStage("OnSyncConfigComplete", nil)
  417. err = guest.StartSyncTaskWithoutSyncstatus(ctx, task.UserCred, false, task.GetTaskId())
  418. if err != nil {
  419. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("StartSyncstatus fail %s", err)))
  420. return
  421. }
  422. }
  423. func (task *GuestChangeConfigTask) OnGuestResetNicTrafficsFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  424. task.markStageFailed(ctx, guest, data)
  425. }
  426. func (task *GuestChangeConfigTask) OnGuestSetNicTrafficsFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  427. task.markStageFailed(ctx, guest, data)
  428. }
  429. func (task *GuestChangeConfigTask) OnSyncConfigComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  430. guest := obj.(*models.SGuest)
  431. task.SetStage("OnSyncStatusComplete", nil)
  432. err := guest.StartSyncstatus(ctx, task.UserCred, task.GetTaskId())
  433. if err != nil {
  434. task.markStageFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("StartSyncstatus fail %s", err)))
  435. return
  436. }
  437. }
  438. func (task *GuestChangeConfigTask) OnSyncStatusComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  439. guest := obj.(*models.SGuest)
  440. if guest.Status == api.VM_READY && jsonutils.QueryBoolean(task.Params, "auto_start", false) {
  441. task.SetStage("OnGuestStartComplete", nil)
  442. drv, _ := guest.GetDriver()
  443. if err := drv.PerformStart(ctx, task.GetUserCred(), guest, nil, task.GetTaskId()); err != nil {
  444. task.OnGuestStartCompleteFailed(ctx, guest, jsonutils.NewString(err.Error()))
  445. return
  446. }
  447. } else {
  448. dt := jsonutils.NewDict()
  449. dt.Add(jsonutils.NewString(guest.Id), "id")
  450. task.SetStageComplete(ctx, dt)
  451. }
  452. confs, err := task.getChangeConfigSetting()
  453. if err != nil {
  454. task.markStageFailed(ctx, guest, jsonutils.NewString(err.Error()))
  455. return
  456. }
  457. notes := fmt.Sprintf("instance_type: %s => %s vcpu: %d => %d mem: %d => %d", confs.Old.InstanceType, confs.InstanceType, confs.Old.VcpuCount, confs.VcpuCount, confs.Old.VmemSize, confs.VmemSize)
  458. logclient.AddActionLogWithStartable(task, guest, logclient.ACT_VM_CHANGE_FLAVOR, notes, task.UserCred, true)
  459. guest.EventNotify(ctx, task.UserCred, notifyclient.ActionChangeConfig)
  460. }
  461. func (task *GuestChangeConfigTask) OnGuestStartComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  462. guest := obj.(*models.SGuest)
  463. dt := jsonutils.NewDict()
  464. dt.Add(jsonutils.NewString(guest.Id), "id")
  465. task.SetStageComplete(ctx, dt)
  466. }
  467. func (task *GuestChangeConfigTask) OnGuestStartCompleteFailed(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  468. task.SetStageFailed(ctx, data)
  469. }
  470. func (task *GuestChangeConfigTask) markStageFailed(ctx context.Context, guest *models.SGuest, reason jsonutils.JSONObject) {
  471. guest.SetStatus(ctx, task.UserCred, api.VM_CHANGE_FLAVOR_FAIL, reason.String())
  472. db.OpsLog.LogEvent(guest, db.ACT_CHANGE_FLAVOR_FAIL, reason, task.UserCred)
  473. logclient.AddActionLogWithStartable(task, guest, logclient.ACT_VM_CHANGE_FLAVOR, reason, task.UserCred, false)
  474. notifyclient.EventNotify(ctx, task.GetUserCred(), notifyclient.SEventNotifyParam{
  475. Obj: guest,
  476. Action: notifyclient.ActionChangeConfig,
  477. IsFail: true,
  478. })
  479. task.SetStageFailed(ctx, reason)
  480. }
  481. func (task *GuestChangeConfigTask) SetStageFailed(ctx context.Context, reason jsonutils.JSONObject) {
  482. guest := task.GetObject().(*models.SGuest)
  483. hostId := guest.HostId
  484. sessionId, _ := task.Params.GetString("sched_session_id")
  485. lockman.LockRawObject(ctx, models.HostManager.KeywordPlural(), hostId)
  486. defer lockman.ReleaseRawObject(ctx, models.HostManager.KeywordPlural(), hostId)
  487. models.HostManager.ClearSchedDescSessionCache(hostId, sessionId)
  488. task.SSchedTask.SetStageFailed(ctx, reason)
  489. }
  490. func (task *GuestChangeConfigTask) SetStageComplete(ctx context.Context, data *jsonutils.JSONDict) {
  491. guest := task.GetObject().(*models.SGuest)
  492. hostId := guest.HostId
  493. sessionId, _ := task.Params.GetString("sched_session_id")
  494. lockman.LockRawObject(ctx, models.HostManager.KeywordPlural(), hostId)
  495. defer lockman.ReleaseRawObject(ctx, models.HostManager.KeywordPlural(), hostId)
  496. models.HostManager.ClearSchedDescSessionCache(hostId, sessionId)
  497. task.SSchedTask.SetStageComplete(ctx, data)
  498. }