guest_backup_tasks.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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. "yunion.io/x/jsonutils"
  19. "yunion.io/x/pkg/utils"
  20. api "yunion.io/x/onecloud/pkg/apis/compute"
  21. schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
  22. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  23. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  24. "yunion.io/x/onecloud/pkg/compute/models"
  25. taskutils "yunion.io/x/onecloud/pkg/compute/tasks/utils"
  26. "yunion.io/x/onecloud/pkg/util/logclient"
  27. )
  28. type GuestSwitchToBackupTask struct {
  29. SGuestBaseTask
  30. }
  31. /*
  32. 0. ensure master guest stopped
  33. 1. stop backup guest
  34. 2. switch guest master host to backup host
  35. 3. start guest with new master
  36. */
  37. func (task *GuestSwitchToBackupTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  38. guest := obj.(*models.SGuest)
  39. host, _ := guest.GetHost()
  40. task.Params.Set("is_force", jsonutils.JSONTrue)
  41. task.SetStage("OnEnsureMasterGuestStoped", nil)
  42. drv, err := guest.GetDriver()
  43. if err != nil {
  44. task.OnEnsureMasterGuestStoped(ctx, guest, nil)
  45. }
  46. err = drv.RequestStopOnHost(ctx, guest, host, task, true)
  47. if err != nil {
  48. // In case of master host crash
  49. task.OnEnsureMasterGuestStoped(ctx, guest, nil)
  50. }
  51. }
  52. func (task *GuestSwitchToBackupTask) OnEnsureMasterGuestStoped(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  53. backupHost := models.HostManager.FetchHostById(guest.BackupHostId)
  54. task.Params.Set("is_force", jsonutils.JSONTrue)
  55. task.SetStage("OnBackupGuestStoped", nil)
  56. drv, err := guest.GetDriver()
  57. if err != nil {
  58. task.OnFail(ctx, guest, jsonutils.NewString(err.Error()))
  59. return
  60. }
  61. err = drv.RequestStopOnHost(ctx, guest, backupHost, task, true)
  62. if err != nil {
  63. task.OnFail(ctx, guest, jsonutils.NewString(err.Error()))
  64. }
  65. }
  66. func (task *GuestSwitchToBackupTask) OnBackupGuestStoped(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  67. disks, err := guest.GetDisks()
  68. if err != nil {
  69. task.OnFail(ctx, guest, jsonutils.NewString(err.Error()))
  70. return
  71. }
  72. for i := 0; i < len(disks); i++ {
  73. disk := disks[i]
  74. err := disk.SwitchToBackup(task.UserCred)
  75. if err != nil {
  76. if i > 0 {
  77. for j := 0; j < i; j++ {
  78. disk = disks[j]
  79. disk.SwitchToBackup(task.UserCred)
  80. }
  81. }
  82. task.OnFail(ctx, guest, jsonutils.NewString(fmt.Sprintf("Switch to backup disk error: %s", err)))
  83. return
  84. }
  85. }
  86. err = guest.SwitchToBackup(task.UserCred)
  87. if err != nil {
  88. task.OnFail(ctx, guest, jsonutils.NewString(fmt.Sprintf("Switch to backup guest error: %s", err)))
  89. return
  90. }
  91. db.OpsLog.LogEvent(guest, db.ACT_SWITCHED, "Switch to backup", task.UserCred)
  92. logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_SWITCH_TO_BACKUP, "Switch to backup", task.UserCred, true)
  93. oldStatus, _ := task.Params.GetString("old_status")
  94. autoStart := jsonutils.QueryBoolean(task.Params, "auto_start", false) ||
  95. utils.IsInStringArray(oldStatus, api.VM_RUNNING_STATUS)
  96. if autoStart {
  97. task.SetStage("OnGuestStartCompleted", nil)
  98. if err := guest.StartGueststartTask(ctx, task.UserCred, nil, task.GetId()); err != nil {
  99. task.OnGuestStartCompletedFailed(ctx, guest,
  100. jsonutils.NewString(fmt.Sprintf("start guest start task: %s", err)))
  101. }
  102. } else {
  103. task.OnComplete(ctx, guest, nil)
  104. }
  105. }
  106. func (task *GuestSwitchToBackupTask) OnFail(ctx context.Context, guest *models.SGuest, reason jsonutils.JSONObject) {
  107. guest.SetStatus(ctx, task.UserCred, api.VM_SWITCH_TO_BACKUP_FAILED, reason.String())
  108. db.OpsLog.LogEvent(guest, db.ACT_SWITCH_FAILED, reason, task.UserCred)
  109. logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_SWITCH_TO_BACKUP, reason, task.UserCred, false)
  110. task.SetStageFailed(ctx, reason)
  111. }
  112. func (task *GuestSwitchToBackupTask) OnGuestStartCompleted(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  113. task.SetStageComplete(ctx, nil)
  114. }
  115. func (task *GuestSwitchToBackupTask) OnGuestStartCompletedFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  116. task.SetStageFailed(ctx, data)
  117. }
  118. func (task *GuestSwitchToBackupTask) OnComplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  119. task.SetStageComplete(ctx, nil)
  120. }
  121. /********************* GuestStartAndSyncToBackupTask *********************/
  122. type GuestStartAndSyncToBackupTask struct {
  123. SGuestBaseTask
  124. }
  125. func (task *GuestStartAndSyncToBackupTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  126. guest := obj.(*models.SGuest)
  127. guest.SetStatus(ctx, task.UserCred, api.VM_BACKUP_STARTING, "GuestStartAndSyncToBackupTask")
  128. task.SetStage("OnCheckTemplete", nil)
  129. task.checkTemplete(ctx, guest)
  130. }
  131. func (task *GuestStartAndSyncToBackupTask) checkTemplete(ctx context.Context, guest *models.SGuest) {
  132. diskCat := guest.CategorizeDisks()
  133. if diskCat.Root != nil && len(diskCat.Root.GetTemplateId()) > 0 {
  134. drv, err := guest.GetDriver()
  135. if err != nil {
  136. task.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
  137. return
  138. }
  139. err = drv.CheckDiskTemplateOnStorage(ctx, task.UserCred, diskCat.Root.GetTemplateId(), diskCat.Root.DiskFormat,
  140. diskCat.Root.BackupStorageId, task)
  141. if err != nil {
  142. task.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
  143. }
  144. } else {
  145. task.OnCheckTemplete(ctx, guest, nil)
  146. }
  147. }
  148. func (task *GuestStartAndSyncToBackupTask) OnCheckTemplete(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  149. task.SetStage("OnStartBackupGuest", nil)
  150. host := models.HostManager.FetchHostById(guest.BackupHostId)
  151. if !guest.IsGuestBackupMirrorJobReady(ctx, task.UserCred) {
  152. hostMaster := models.HostManager.FetchHostById(guest.HostId)
  153. task.Params.Set("block_ready", jsonutils.JSONFalse)
  154. diskUri := fmt.Sprintf("%s/disks", hostMaster.GetFetchUrl(true))
  155. task.Params.Set("disk_uri", jsonutils.NewString(diskUri))
  156. } else {
  157. task.Params.Set("block_ready", jsonutils.JSONTrue)
  158. }
  159. drv, err := guest.GetDriver()
  160. if err != nil {
  161. task.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
  162. return
  163. }
  164. err = drv.RequestStartOnHost(ctx, guest, host, task.UserCred, task)
  165. if err != nil {
  166. task.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
  167. }
  168. }
  169. func (task *GuestStartAndSyncToBackupTask) OnStartBackupGuest(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  170. guest.SetBackupGuestStatus(task.UserCred, api.VM_RUNNING, "on start backup guest")
  171. nbdServerPort, err := data.Int("nbd_server_port")
  172. if err != nil {
  173. task.SetStageFailed(ctx, jsonutils.NewString("Start Backup Guest Missing Nbd Port"))
  174. return
  175. }
  176. backupHost := models.HostManager.FetchHostById(guest.BackupHostId)
  177. nbdServerUri := fmt.Sprintf("nbd:%s:%d", backupHost.AccessIp, nbdServerPort)
  178. guest.SetMetadata(ctx, "backup_nbd_server_uri", nbdServerUri, task.UserCred)
  179. db.OpsLog.LogEvent(guest, db.ACT_BACKUP_START, guest.GetShortDesc(ctx), task.UserCred)
  180. // try get origin guest status
  181. guestStatus, err := task.Params.GetString("guest_status")
  182. if err != nil {
  183. guestStatus = guest.Status
  184. }
  185. if utils.IsInStringArray(guestStatus, api.VM_RUNNING_STATUS) {
  186. task.SetStage("OnRequestSyncToBackup", nil)
  187. drv, err := guest.GetDriver()
  188. if err != nil {
  189. task.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
  190. return
  191. }
  192. err = drv.RequestSyncToBackup(ctx, guest, task)
  193. if err != nil {
  194. task.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
  195. }
  196. } else {
  197. task.onComplete(ctx, guest)
  198. }
  199. }
  200. func (task *GuestStartAndSyncToBackupTask) OnStartBackupGuestFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  201. guest.SetGuestBackupMirrorJobFailed(ctx, task.UserCred)
  202. db.OpsLog.LogEvent(guest, db.ACT_BACKUP_START_FAILED, data.String(), task.UserCred)
  203. task.SetStageFailed(ctx, data)
  204. }
  205. func (task *GuestStartAndSyncToBackupTask) OnRequestSyncToBackup(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  206. guest.SetGuestBackupMirrorJobInProgress(ctx, task.UserCred)
  207. drv, err := guest.GetDriver()
  208. if err != nil {
  209. guest.SetGuestBackupMirrorJobFailed(ctx, task.UserCred)
  210. guest.SetBackupGuestStatus(task.UserCred, api.VM_BLOCK_STREAM_FAIL, err.Error())
  211. task.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
  212. return
  213. }
  214. err = drv.RequestSlaveBlockStreamDisks(ctx, guest, task)
  215. if err != nil {
  216. guest.SetGuestBackupMirrorJobFailed(ctx, task.UserCred)
  217. guest.SetBackupGuestStatus(task.UserCred, api.VM_BLOCK_STREAM_FAIL, err.Error())
  218. task.SetStageFailed(ctx, jsonutils.NewString(err.Error()))
  219. return
  220. }
  221. guest.SetGuestBackupMirrorJobInProgress(ctx, task.UserCred)
  222. guest.SetBackupGuestStatus(task.UserCred, api.VM_BLOCK_STREAM, "OnSyncToBackup")
  223. task.onComplete(ctx, guest)
  224. }
  225. func (task *GuestStartAndSyncToBackupTask) onComplete(ctx context.Context, guest *models.SGuest) {
  226. guestStatus, _ := task.Params.GetString("guest_status")
  227. guest.SetStatus(ctx, task.UserCred, guestStatus, "on GuestStartAndSyncToBackupTask completed")
  228. task.SetStageComplete(ctx, nil)
  229. }
  230. func (task *GuestStartAndSyncToBackupTask) OnRequestSyncToBackupFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  231. guest.SetGuestBackupMirrorJobFailed(ctx, task.UserCred)
  232. guest.SetStatus(ctx, task.UserCred, api.VM_BLOCK_STREAM_FAIL, "OnSyncToBackup")
  233. task.SetStageFailed(ctx, data)
  234. }
  235. type GuestCreateBackupTask struct {
  236. taskutils.SSchedTask
  237. }
  238. func (task *GuestCreateBackupTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  239. taskutils.StartScheduleObjects(ctx, task, []db.IStandaloneModel{obj})
  240. }
  241. func (task *GuestCreateBackupTask) OnStartSchedule(obj taskutils.IScheduleModel) {
  242. guest := obj.(*models.SGuest)
  243. db.OpsLog.LogEvent(guest, db.ACT_START_CREATE_BACKUP, "", task.UserCred)
  244. }
  245. func (task *GuestCreateBackupTask) GetSchedParams() (*schedapi.ScheduleInput, error) {
  246. obj := task.GetObject()
  247. guest := obj.(*models.SGuest)
  248. schedDesc := guest.ToSchedDesc()
  249. if task.Params.Contains("prefer_host_id") {
  250. preferHostId, _ := task.Params.GetString("prefer_host_id")
  251. schedDesc.ServerConfig.PreferHost = preferHostId
  252. }
  253. schedDesc.ReuseNetwork = true
  254. return schedDesc, nil
  255. }
  256. func (task *GuestCreateBackupTask) OnScheduleFailCallback(ctx context.Context, obj taskutils.IScheduleModel, reason jsonutils.JSONObject, index int) {
  257. // do nothing
  258. }
  259. func (task *GuestCreateBackupTask) OnScheduleFailed(ctx context.Context, reason jsonutils.JSONObject) {
  260. obj := task.GetObject()
  261. guest := obj.(*models.SGuest)
  262. task.TaskFailed(ctx, guest, reason)
  263. }
  264. func (task *GuestCreateBackupTask) SaveScheduleResult(ctx context.Context, obj taskutils.IScheduleModel, candidate *schedapi.CandidateResource, index int) {
  265. guest := obj.(*models.SGuest)
  266. targetHostId := candidate.HostId
  267. targetHost := models.HostManager.FetchHostById(candidate.HostId)
  268. if targetHost == nil {
  269. task.TaskFailed(ctx, guest, jsonutils.NewString("target host not found?"))
  270. return
  271. }
  272. guest.SetHostIdWithBackup(task.UserCred, guest.HostId, targetHostId)
  273. db.OpsLog.LogEvent(guest, db.ACT_CREATE_BACKUP, fmt.Sprintf("guest backup start create on host %s", targetHostId), task.UserCred)
  274. task.StartCreateBackupDisks(ctx, guest, targetHost, candidate.Disks)
  275. }
  276. func (task *GuestCreateBackupTask) StartCreateBackupDisks(ctx context.Context, guest *models.SGuest, host *models.SHost, candidateDisks []*schedapi.CandidateDisk) {
  277. guestDisks, _ := guest.GetGuestDisks()
  278. for i := 0; i < len(guestDisks); i++ {
  279. var candidateDisk *schedapi.CandidateDisk
  280. if len(candidateDisks) >= i {
  281. candidateDisk = candidateDisks[i]
  282. }
  283. diskConfig := &api.DiskConfig{Backend: api.STORAGE_LOCAL}
  284. storage, err := guest.ChooseHostStorage(host, diskConfig, candidateDisk)
  285. if err != nil {
  286. task.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("unable to ChooseHostStorage: %v", err)))
  287. return
  288. }
  289. if storage == nil {
  290. task.TaskFailed(ctx, guest, jsonutils.NewString("Get backup storage error"))
  291. return
  292. }
  293. disk := guestDisks[i].GetDisk()
  294. db.Update(disk, func() error {
  295. disk.BackupStorageId = storage.Id
  296. return nil
  297. })
  298. }
  299. task.SetStage("OnCreateBackupDisks", nil)
  300. err := guest.CreateBackupDisks(ctx, task.UserCred, task.GetTaskId())
  301. if err != nil {
  302. task.TaskFailed(ctx, guest, jsonutils.NewString(err.Error()))
  303. }
  304. }
  305. func (task *GuestCreateBackupTask) StartInsertIso(ctx context.Context, guest *models.SGuest, imageId string) {
  306. task.SetStage("OnInsertIso", nil)
  307. guest.StartInsertIsoTask(ctx, 0, imageId, false, nil, guest.BackupHostId, task.UserCred, task.GetTaskId())
  308. }
  309. func (task *GuestCreateBackupTask) OnInsertIso(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  310. task.SetStage("OnCreateBackup", nil)
  311. guest.StartCreateBackup(ctx, task.UserCred, task.GetTaskId(), nil)
  312. }
  313. func (task *GuestCreateBackupTask) OnInsertIsoFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  314. task.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Backup guest insert ISO failed %s", data.String())))
  315. }
  316. func (task *GuestCreateBackupTask) OnCreateBackupDisks(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  317. if cdrom := guest.GetCdrom(); cdrom != nil && len(cdrom.ImageId) > 0 {
  318. task.StartInsertIso(ctx, guest, cdrom.ImageId)
  319. } else {
  320. task.SetStage("OnCreateBackup", nil)
  321. guest.StartCreateBackup(ctx, task.UserCred, task.GetTaskId(), nil)
  322. }
  323. }
  324. func (task *GuestCreateBackupTask) OnCreateBackupDisksFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  325. task.TaskFailed(ctx, guest, data)
  326. }
  327. func (task *GuestCreateBackupTask) OnCreateBackupFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  328. task.TaskFailed(ctx, guest, data)
  329. }
  330. func (task *GuestCreateBackupTask) OnCreateBackup(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  331. guest.SetBackupGuestStatus(task.UserCred, api.VM_READY, "on create backup")
  332. guestStatus, _ := task.Params.GetString("guest_status")
  333. if utils.IsInStringArray(guestStatus, api.VM_RUNNING_STATUS) {
  334. task.OnGuestStart(ctx, guest, guestStatus)
  335. } else if jsonutils.QueryBoolean(task.Params, "auto_start", false) {
  336. task.RequestStartGuest(ctx, guest)
  337. } else {
  338. task.TaskCompleted(ctx, guest, "")
  339. }
  340. }
  341. func (task *GuestCreateBackupTask) OnGuestStart(ctx context.Context, guest *models.SGuest, guestStatus string) {
  342. task.SetStage("OnSyncToBackup", nil)
  343. err := guest.GuestStartAndSyncToBackup(ctx, task.UserCred, task.GetTaskId(), guestStatus)
  344. if err != nil {
  345. task.TaskFailed(ctx, guest, jsonutils.NewString(fmt.Sprintf("Guest sycn to backup error %s", err.Error())))
  346. }
  347. }
  348. func (task *GuestCreateBackupTask) OnSyncToBackup(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  349. task.TaskCompleted(ctx, guest, "")
  350. }
  351. func (task *GuestCreateBackupTask) OnSyncToBackupFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  352. task.TaskFailed(ctx, guest, data)
  353. }
  354. func (task *GuestCreateBackupTask) RequestStartGuest(ctx context.Context, guest *models.SGuest) {
  355. task.SetStage("OnGuestStartCompleted", nil)
  356. guest.StartGueststartTask(ctx, task.UserCred, nil, task.GetId())
  357. }
  358. func (task *GuestCreateBackupTask) OnGuestStartCompleted(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  359. task.TaskCompleted(ctx, guest, "")
  360. }
  361. func (task *GuestCreateBackupTask) OnGuestStartCompletedFailed(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) {
  362. db.OpsLog.LogEvent(guest, db.ACT_CREATE_BACKUP_FAILED, data.String(), task.UserCred)
  363. logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_CREATE_BACKUP, data.String(), task.UserCred, false)
  364. task.SetStageFailed(ctx, data)
  365. }
  366. func (task *GuestCreateBackupTask) TaskCompleted(ctx context.Context, guest *models.SGuest, reason string) {
  367. db.OpsLog.LogEvent(guest, db.ACT_CREATE_BACKUP, reason, task.UserCred)
  368. logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_CREATE_BACKUP, reason, task.UserCred, true)
  369. task.SetStageComplete(ctx, nil)
  370. guest.StartSyncstatus(ctx, task.UserCred, "")
  371. }
  372. func (task *GuestCreateBackupTask) TaskFailed(ctx context.Context, guest *models.SGuest, reason jsonutils.JSONObject) {
  373. guest.SetStatus(ctx, task.UserCred, api.VM_BACKUP_CREATE_FAILED, reason.String())
  374. db.OpsLog.LogEvent(guest, db.ACT_CREATE_BACKUP_FAILED, reason, task.UserCred)
  375. logclient.AddActionLogWithContext(ctx, guest, logclient.ACT_CREATE_BACKUP, reason, task.UserCred, false)
  376. task.SetStageFailed(ctx, reason)
  377. }
  378. func init() {
  379. taskman.RegisterTask(GuestSwitchToBackupTask{})
  380. taskman.RegisterTask(GuestStartAndSyncToBackupTask{})
  381. taskman.RegisterTask(GuestCreateBackupTask{})
  382. taskman.RegisterTask(GuestReSyncToBackup{})
  383. }
  384. type GuestReSyncToBackup struct {
  385. GuestStartAndSyncToBackupTask
  386. }
  387. func (task *GuestReSyncToBackup) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
  388. guest := obj.(*models.SGuest)
  389. task.StartSyncToBackup(ctx, guest)
  390. }
  391. func (task *GuestReSyncToBackup) StartSyncToBackup(ctx context.Context, guest *models.SGuest) {
  392. data := jsonutils.NewDict()
  393. nbdServerPort, _ := task.Params.Int("nbd_server_port")
  394. data.Set("nbd_server_port", jsonutils.NewInt(nbdServerPort))
  395. task.OnStartBackupGuest(ctx, guest, data)
  396. }