instance_backup.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  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 models
  15. import (
  16. "context"
  17. "database/sql"
  18. "fmt"
  19. "time"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/utils"
  24. "yunion.io/x/sqlchemy"
  25. api "yunion.io/x/onecloud/pkg/apis/compute"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/consts"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  29. "yunion.io/x/onecloud/pkg/httperrors"
  30. "yunion.io/x/onecloud/pkg/mcclient"
  31. "yunion.io/x/onecloud/pkg/mcclient/auth"
  32. identity_modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity"
  33. "yunion.io/x/onecloud/pkg/util/stringutils2"
  34. )
  35. func init() {
  36. InstanceBackupManager = &SInstanceBackupManager{
  37. SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
  38. SInstanceBackup{},
  39. "instancebackups_tbl",
  40. "instancebackup",
  41. "instancebackups",
  42. ),
  43. }
  44. InstanceBackupManager.SetVirtualObject(InstanceBackupManager)
  45. }
  46. type SInstanceBackup struct {
  47. db.SVirtualResourceBase
  48. SManagedResourceBase
  49. SCloudregionResourceBase
  50. db.SMultiArchResourceBase
  51. db.SEncryptedResource
  52. BackupStorageId string `width:"36" charset:"ascii" nullable:"true" create:"required" list:"user" index:"true"`
  53. GuestId string `width:"36" charset:"ascii" nullable:"false" list:"user" create:"optional" index:"true"`
  54. // 云主机配置 corresponds to api.ServerCreateInput
  55. ServerConfig jsonutils.JSONObject `nullable:"true" list:"user"`
  56. // 云主机标签
  57. ServerMetadata jsonutils.JSONObject `nullable:"true" list:"user"`
  58. // 安全组
  59. SecGroups jsonutils.JSONObject `nullable:"true" list:"user"`
  60. // 秘钥Id
  61. KeypairId string `width:"36" charset:"ascii" nullable:"true" list:"user"`
  62. // 操作系统类型
  63. OsType string `width:"36" charset:"ascii" nullable:"true" list:"user"`
  64. // 套餐名称
  65. InstanceType string `width:"64" charset:"utf8" nullable:"true" list:"user" create:"optional"`
  66. // 主机备份容量和
  67. SizeMb int `nullable:"false" list:"user"`
  68. }
  69. // +onecloud:swagger-gen-model-singular=instancebackup
  70. // +onecloud:swagger-gen-model-plural=instancebackups
  71. type SInstanceBackupManager struct {
  72. db.SVirtualResourceBaseManager
  73. SManagedResourceBaseManager
  74. SCloudregionResourceBaseManager
  75. db.SMultiArchResourceBaseManager
  76. db.SEncryptedResourceManager
  77. }
  78. var InstanceBackupManager *SInstanceBackupManager
  79. func (manager *SInstanceBackupManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.InstanceBackupListInput) (*sqlchemy.SQuery, error) {
  80. q, err := manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput)
  81. if err != nil {
  82. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
  83. }
  84. q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
  85. if err != nil {
  86. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
  87. }
  88. q, err = manager.SMultiArchResourceBaseManager.ListItemFilter(ctx, q, userCred, query.MultiArchResourceBaseListInput)
  89. if err != nil {
  90. return nil, errors.Wrap(err, "SMultiArchResourceBaseManager.ListItemFilter")
  91. }
  92. guestStr := query.ServerId
  93. if len(guestStr) > 0 {
  94. guestObj, err := GuestManager.FetchByIdOrName(ctx, userCred, guestStr)
  95. if err != nil {
  96. if errors.Cause(err) == sql.ErrNoRows {
  97. return nil, httperrors.NewResourceNotFoundError2("guests", guestStr)
  98. } else {
  99. return nil, httperrors.NewGeneralError(err)
  100. }
  101. }
  102. q = q.Equals("guest_id", guestObj.GetId())
  103. }
  104. if len(query.OsType) > 0 {
  105. q = q.In("os_type", query.OsType)
  106. }
  107. return q, nil
  108. }
  109. func (manager *SInstanceBackupManager) OrderByExtraFields(
  110. ctx context.Context,
  111. q *sqlchemy.SQuery,
  112. userCred mcclient.TokenCredential,
  113. query api.InstanceBackupListInput,
  114. ) (*sqlchemy.SQuery, error) {
  115. var err error
  116. q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput)
  117. if err != nil {
  118. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields")
  119. }
  120. q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
  121. if err != nil {
  122. return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields")
  123. }
  124. if db.NeedOrderQuery([]string{query.OrderByGuest}) {
  125. gQ := GuestManager.Query()
  126. gSQ := gQ.AppendField(gQ.Field("name").Label("guest_name"), gQ.Field("id")).SubQuery()
  127. q = q.LeftJoin(gSQ, sqlchemy.Equals(gSQ.Field("id"), q.Field("guest_id")))
  128. q = q.AppendField(q.QueryFields()...)
  129. q = q.AppendField(gSQ.Field("guest_name"))
  130. q = db.OrderByFields(q, []string{query.OrderByGuest}, []sqlchemy.IQueryField{q.Field("guest_name")})
  131. }
  132. return q, nil
  133. }
  134. func (manager *SInstanceBackupManager) ListItemExportKeys(ctx context.Context,
  135. q *sqlchemy.SQuery,
  136. userCred mcclient.TokenCredential,
  137. keys stringutils2.SSortedStrings,
  138. ) (*sqlchemy.SQuery, error) {
  139. var err error
  140. q, err = manager.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  141. if err != nil {
  142. return nil, err
  143. }
  144. return q, nil
  145. }
  146. func (manager *SInstanceBackupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  147. var err error
  148. q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  149. if err == nil {
  150. return q, nil
  151. }
  152. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
  153. if err == nil {
  154. return q, nil
  155. }
  156. return q, httperrors.ErrNotFound
  157. }
  158. func (manager *SInstanceBackupManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  159. var err error
  160. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  161. if err == nil {
  162. return q, nil
  163. }
  164. return q, httperrors.ErrNotFound
  165. }
  166. func (self *SInstanceBackup) GetGuest() (*SGuest, error) {
  167. if len(self.GuestId) == 0 {
  168. return nil, errors.ErrNotFound
  169. }
  170. guest := GuestManager.FetchGuestById(self.GuestId)
  171. if guest == nil {
  172. return nil, errors.ErrNotFound
  173. }
  174. return guest, nil
  175. }
  176. func (self *SInstanceBackup) GetBackupStorage() (*SBackupStorage, error) {
  177. ibs, err := BackupStorageManager.FetchById(self.BackupStorageId)
  178. if err != nil {
  179. return nil, err
  180. }
  181. return ibs.(*SBackupStorage), nil
  182. }
  183. func (self *SInstanceBackup) getMoreDetails(userCred mcclient.TokenCredential, out api.InstanceBackupDetails) api.InstanceBackupDetails {
  184. guest := GuestManager.FetchGuestById(self.GuestId)
  185. if guest != nil {
  186. out.Guest = guest.Name
  187. out.GuestStatus = guest.Status
  188. }
  189. backupStorage, _ := self.GetBackupStorage()
  190. if backupStorage != nil {
  191. out.BackupStorageName = backupStorage.GetName()
  192. }
  193. backups, _ := self.GetBackups()
  194. out.DiskBackups = []api.SSimpleBackup{}
  195. for i := 0; i < len(backups); i++ {
  196. out.DiskBackups = append(out.DiskBackups, api.SSimpleBackup{
  197. Id: backups[i].Id,
  198. Name: backups[i].Name,
  199. SizeMb: backups[i].SizeMb,
  200. DiskSizeMb: backups[i].DiskSizeMb,
  201. DiskType: backups[i].DiskType,
  202. Status: backups[i].Status,
  203. EncryptKeyId: backups[i].EncryptKeyId,
  204. CreatedAt: backups[i].CreatedAt,
  205. })
  206. }
  207. out.Size = self.SizeMb * 1024 * 1024
  208. return out
  209. }
  210. func (manager *SInstanceBackupManager) FetchCustomizeColumns(
  211. ctx context.Context,
  212. userCred mcclient.TokenCredential,
  213. query jsonutils.JSONObject,
  214. objs []interface{},
  215. fields stringutils2.SSortedStrings,
  216. isList bool,
  217. ) []api.InstanceBackupDetails {
  218. rows := make([]api.InstanceBackupDetails, len(objs))
  219. virtRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  220. manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  221. encRows := manager.SEncryptedResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  222. for i := range rows {
  223. rows[i] = api.InstanceBackupDetails{
  224. VirtualResourceDetails: virtRows[i],
  225. ManagedResourceInfo: manRows[i],
  226. EncryptedResourceDetails: encRows[i],
  227. }
  228. rows[i] = objs[i].(*SInstanceBackup).getMoreDetails(userCred, rows[i])
  229. }
  230. return rows
  231. }
  232. func (self *SInstanceBackup) StartCreateInstanceBackupTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  233. self.SetStatus(ctx, userCred, api.INSTANCE_BACKUP_STATUS_CREATING, "")
  234. if task, err := taskman.TaskManager.NewTask(ctx, "InstanceBackupCreateTask", self, userCred, nil, parentTaskId, "", nil); err != nil {
  235. return err
  236. } else {
  237. task.ScheduleRun(nil)
  238. }
  239. return nil
  240. }
  241. func (manager *SInstanceBackupManager) fillInstanceBackup(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, instanceBackup *SInstanceBackup) {
  242. instanceBackup.SetModelManager(manager, instanceBackup)
  243. instanceBackup.ProjectId = guest.ProjectId
  244. instanceBackup.DomainId = guest.DomainId
  245. instanceBackup.GuestId = guest.Id
  246. // inherit encrypt_key_id from guest
  247. instanceBackup.EncryptKeyId = guest.EncryptKeyId
  248. host, _ := guest.GetHost()
  249. instanceBackup.ManagerId = host.ManagerId
  250. zone, _ := host.GetZone()
  251. instanceBackup.CloudregionId = zone.CloudregionId
  252. createInput := guest.ToCreateInput(ctx, userCred)
  253. createInput.ProjectId = guest.ProjectId
  254. createInput.ProjectDomainId = guest.DomainId
  255. for i := 0; i < len(createInput.Networks); i++ {
  256. createInput.Networks[i].Mac = ""
  257. createInput.Networks[i].Address = ""
  258. createInput.Networks[i].Address6 = ""
  259. }
  260. instanceBackup.ServerConfig = jsonutils.Marshal(createInput)
  261. if len(guest.KeypairId) > 0 {
  262. instanceBackup.KeypairId = guest.KeypairId
  263. }
  264. serverMetadata := jsonutils.NewDict()
  265. if loginAccount := guest.GetMetadata(ctx, "login_account", nil); len(loginAccount) > 0 {
  266. loginKey := guest.GetMetadata(ctx, "login_key", nil)
  267. if len(guest.KeypairId) == 0 && len(loginKey) > 0 {
  268. passwd, e := utils.DescryptAESBase64(guest.Id, loginKey)
  269. if e == nil {
  270. serverMetadata.Set("login_account", jsonutils.NewString(loginAccount))
  271. serverMetadata.Set("passwd", jsonutils.NewString(passwd))
  272. }
  273. } else {
  274. serverMetadata.Set("login_key", jsonutils.NewString(loginKey))
  275. serverMetadata.Set("login_account", jsonutils.NewString(loginAccount))
  276. }
  277. }
  278. if osArch := guest.GetMetadata(ctx, "os_arch", nil); len(osArch) > 0 {
  279. serverMetadata.Set("os_arch", jsonutils.NewString(osArch))
  280. }
  281. if osDist := guest.GetMetadata(ctx, "os_distribution", nil); len(osDist) > 0 {
  282. serverMetadata.Set("os_distribution", jsonutils.NewString(osDist))
  283. }
  284. if osName := guest.GetMetadata(ctx, "os_name", nil); len(osName) > 0 {
  285. serverMetadata.Set("os_name", jsonutils.NewString(osName))
  286. }
  287. if osVersion := guest.GetMetadata(ctx, "os_version", nil); len(osVersion) > 0 {
  288. serverMetadata.Set("os_version", jsonutils.NewString(osVersion))
  289. }
  290. secs, _ := guest.GetSecgroups()
  291. if len(secs) > 0 {
  292. secIds := make([]string, len(secs))
  293. for i := 0; i < len(secs); i++ {
  294. secIds[i] = secs[i].Id
  295. }
  296. instanceBackup.SecGroups = jsonutils.Marshal(secIds)
  297. }
  298. instanceBackup.OsType = guest.OsType
  299. instanceBackup.OsArch = guest.OsArch
  300. instanceBackup.ServerMetadata = serverMetadata
  301. instanceBackup.InstanceType = guest.InstanceType
  302. }
  303. func (manager *SInstanceBackupManager) CreateInstanceBackup(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, name, backupStorageId string) (*SInstanceBackup, error) {
  304. instanceBackup := &SInstanceBackup{}
  305. instanceBackup.SetModelManager(manager, instanceBackup)
  306. instanceBackup.Name = name
  307. instanceBackup.BackupStorageId = backupStorageId
  308. manager.fillInstanceBackup(ctx, userCred, guest, instanceBackup)
  309. // compute size of instanceBackup
  310. //instanceBackup.SizeMb = guest.getDiskSize()
  311. err := manager.TableSpec().Insert(ctx, instanceBackup)
  312. if err != nil {
  313. return nil, err
  314. }
  315. return instanceBackup, nil
  316. }
  317. func (self *SInstanceBackup) ToInstanceCreateInput(sourceInput *api.ServerCreateInput) (*api.ServerCreateInput, error) {
  318. createInput := new(api.ServerCreateInput)
  319. createInput.ServerConfigs = new(api.ServerConfigs)
  320. if err := self.ServerConfig.Unmarshal(createInput); err != nil {
  321. return nil, errors.Wrap(err, "unmarshal sched input")
  322. }
  323. isjs := make([]SInstanceBackupJoint, 0)
  324. err := InstanceBackupJointManager.Query().Equals("instance_backup_id", self.Id).Asc("disk_index").All(&isjs)
  325. if err != nil {
  326. return nil, errors.Wrap(err, "fetch instance backups")
  327. }
  328. for i := 0; i < len(createInput.Disks); i++ {
  329. index := createInput.Disks[i].Index
  330. if index < len(isjs) {
  331. createInput.Disks[i].BackupId = isjs[index].DiskBackupId
  332. createInput.Disks[i].ImageId = ""
  333. createInput.Disks[i].SnapshotId = ""
  334. if i < len(sourceInput.Disks) {
  335. createInput.Disks[i].Backend = sourceInput.Disks[i].Backend
  336. }
  337. }
  338. }
  339. sourceInput.Disks = createInput.Disks
  340. if sourceInput.VmemSize == 0 {
  341. sourceInput.VmemSize = createInput.VmemSize
  342. }
  343. if sourceInput.VcpuCount == 0 {
  344. sourceInput.VcpuCount = createInput.VcpuCount
  345. }
  346. if len(sourceInput.OsArch) == 0 {
  347. sourceInput.OsArch = createInput.OsArch
  348. }
  349. if len(self.KeypairId) > 0 {
  350. sourceInput.KeypairId = self.KeypairId
  351. }
  352. if self.SecGroups != nil {
  353. secGroups := make([]string, 0)
  354. inputSecgs := make([]string, 0)
  355. self.SecGroups.Unmarshal(&secGroups)
  356. for i := 0; i < len(secGroups); i++ {
  357. _, err := SecurityGroupManager.FetchSecgroupById(secGroups[i])
  358. if err == nil {
  359. inputSecgs = append(inputSecgs, secGroups[i])
  360. }
  361. }
  362. sourceInput.Secgroups = inputSecgs
  363. }
  364. sourceInput.OsType = self.OsType
  365. sourceInput.InstanceType = self.InstanceType
  366. if len(sourceInput.Networks) == 0 {
  367. sourceInput.Networks = createInput.Networks
  368. }
  369. if sourceInput.Vga == "" {
  370. sourceInput.Vga = createInput.Vga
  371. }
  372. if sourceInput.Vdi == "" {
  373. sourceInput.Vdi = createInput.Vdi
  374. }
  375. if sourceInput.Vdi == "" {
  376. sourceInput.Vdi = createInput.Vdi
  377. }
  378. if sourceInput.Bios == "" {
  379. sourceInput.Bios = createInput.Bios
  380. }
  381. if sourceInput.BootOrder == "" {
  382. sourceInput.BootOrder = createInput.BootOrder
  383. }
  384. if sourceInput.ShutdownBehavior == "" {
  385. sourceInput.ShutdownBehavior = createInput.ShutdownBehavior
  386. }
  387. if sourceInput.IsolatedDevices == nil {
  388. sourceInput.IsolatedDevices = createInput.IsolatedDevices
  389. }
  390. if self.IsEncrypted() {
  391. if sourceInput.EncryptKeyId != nil && *sourceInput.EncryptKeyId != self.EncryptKeyId {
  392. return nil, errors.Wrap(httperrors.ErrConflict, "encrypt_key_id conflict with instance_backup's encrypt_key_id")
  393. }
  394. sourceInput.EncryptKeyId = &self.EncryptKeyId
  395. }
  396. return sourceInput, nil
  397. }
  398. func (self *SInstanceBackup) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  399. if self.Status == api.INSTANCE_SNAPSHOT_START_DELETE || self.Status == api.INSTANCE_SNAPSHOT_RESET {
  400. return httperrors.NewForbiddenError("can't delete instance snapshot with wrong status")
  401. }
  402. return nil
  403. }
  404. func (self *SInstanceBackup) CustomizeDelete(
  405. ctx context.Context, userCred mcclient.TokenCredential,
  406. query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  407. forceDelete := jsonutils.QueryBoolean(query, "force", false)
  408. return self.StartInstanceBackupDeleteTask(ctx, userCred, "", forceDelete)
  409. }
  410. func (self *SInstanceBackup) StartInstanceBackupDeleteTask(
  411. ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, forceDelete bool) error {
  412. params := jsonutils.NewDict()
  413. if forceDelete {
  414. params.Set("force_delete", jsonutils.JSONTrue)
  415. }
  416. task, err := taskman.TaskManager.NewTask(ctx, "InstanceBackupDeleteTask", self, userCred, params, parentTaskId, "", nil)
  417. if err != nil {
  418. log.Errorf("%s", err)
  419. return err
  420. }
  421. self.SetStatus(ctx, userCred, api.INSTANCE_BACKUP_STATUS_DELETING, "InstanceBackupDeleteTask")
  422. task.ScheduleRun(nil)
  423. return nil
  424. }
  425. func (self *SInstanceBackup) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  426. return db.DeleteModel(ctx, userCred, self)
  427. }
  428. func (self *SInstanceBackup) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  429. return nil
  430. }
  431. func (self *SInstanceBackup) GetRegionDriver() IRegionDriver {
  432. provider := self.GetProviderName()
  433. return GetRegionDriver(provider)
  434. }
  435. func (self *SInstanceBackup) GetBackups() ([]SDiskBackup, error) {
  436. isjq := InstanceBackupJointManager.Query().SubQuery()
  437. backups := make([]SDiskBackup, 0)
  438. dq := DiskBackupManager.Query()
  439. q := dq.Join(isjq, sqlchemy.Equals(dq.Field("id"), isjq.Field("disk_backup_id"))).Filter(
  440. sqlchemy.Equals(isjq.Field("instance_backup_id"), self.GetId())).Asc(isjq.Field("disk_index"))
  441. err := db.FetchModelObjects(DiskBackupManager, q, &backups)
  442. if err != nil {
  443. return nil, errors.Wrap(err, "db.FetchModelObjects")
  444. }
  445. return backups, nil
  446. }
  447. func (self *SInstanceBackup) PerformRecovery(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.InstanceBackupRecoveryInput) (jsonutils.JSONObject, error) {
  448. return nil, self.StartRecoveryTask(ctx, userCred, "", input.Name)
  449. }
  450. func (self *SInstanceBackup) StartRecoveryTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, serverName string) error {
  451. self.SetStatus(ctx, userCred, api.INSTANCE_BACKUP_STATUS_RECOVERY, "")
  452. params := jsonutils.NewDict()
  453. if serverName != "" {
  454. params.Set("server_name", jsonutils.NewString(serverName))
  455. }
  456. task, err := taskman.TaskManager.NewTask(ctx, "InstanceBackupRecoveryTask", self, userCred, params, parentTaskId, "", nil)
  457. if err != nil {
  458. return err
  459. } else {
  460. task.ScheduleRun(nil)
  461. }
  462. return nil
  463. }
  464. func (self *SInstanceBackup) PerformPack(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.InstanceBackupPackInput) (jsonutils.JSONObject, error) {
  465. if input.PackageName == "" {
  466. return nil, httperrors.NewMissingParameterError("miss package_name")
  467. }
  468. self.SetStatus(ctx, userCred, api.INSTANCE_BACKUP_STATUS_PACK, "")
  469. params := jsonutils.NewDict()
  470. params.Set("package_name", jsonutils.NewString(input.PackageName))
  471. task, err := taskman.TaskManager.NewTask(ctx, "InstanceBackupPackTask", self, userCred, params, "", "", nil)
  472. if err != nil {
  473. return nil, err
  474. } else {
  475. task.ScheduleRun(nil)
  476. }
  477. return nil, nil
  478. }
  479. func (manager *SInstanceBackupManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.InstanceBackupManagerCreateFromPackageInput) (api.InstanceBackupManagerCreateFromPackageInput, error) {
  480. if input.PackageName == "" {
  481. return input, httperrors.NewMissingParameterError("miss package_name")
  482. }
  483. _, err := BackupStorageManager.FetchById(input.BackupStorageId)
  484. if err != nil {
  485. return input, httperrors.NewInputParameterError("unable to fetch backupStorage %s", input.BackupStorageId)
  486. }
  487. input.VirtualResourceCreateInput, err = manager.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
  488. if err != nil {
  489. return input, errors.Wrap(err, "SVirtualResourceBaseManager.ValidateCreateData")
  490. }
  491. return input, nil
  492. }
  493. func (manager *SInstanceBackupManager) OnCreateComplete(ctx context.Context, items []db.IModel, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data []jsonutils.JSONObject) {
  494. packageName, _ := data[0].GetString("package_name")
  495. params := jsonutils.NewDict()
  496. params.Set("package_name", jsonutils.NewString(packageName))
  497. for i := range items {
  498. ib := items[i].(*SInstanceBackup)
  499. task, err := taskman.TaskManager.NewTask(ctx, "InstanceBackupUnpackTask", ib, userCred, params, "", "", nil)
  500. if err != nil {
  501. log.Errorf("InstanceBackupUnpackTask fail %s", err)
  502. } else {
  503. task.ScheduleRun(nil)
  504. }
  505. }
  506. }
  507. func (self *SInstanceBackup) PackMetadata(ctx context.Context, userCred mcclient.TokenCredential) (*api.InstanceBackupPackMetadata, error) {
  508. allMetadata, err := self.GetAllMetadata(ctx, userCred)
  509. if err != nil {
  510. return nil, errors.Wrap(err, "GetAllMetadata")
  511. }
  512. metadata := &api.InstanceBackupPackMetadata{
  513. OsArch: self.OsArch,
  514. ServerConfig: self.ServerConfig,
  515. ServerMetadata: self.ServerMetadata,
  516. SecGroups: self.SecGroups,
  517. KeypairId: self.KeypairId,
  518. OsType: self.OsType,
  519. InstanceType: self.InstanceType,
  520. SizeMb: self.SizeMb,
  521. EncryptKeyId: self.EncryptKeyId,
  522. Metadata: allMetadata,
  523. }
  524. dbs, err := self.GetBackups()
  525. if err != nil {
  526. return nil, err
  527. }
  528. for i := range dbs {
  529. mt := dbs[i].PackMetadata()
  530. metadata.DiskMetadatas = append(metadata.DiskMetadatas, *mt)
  531. }
  532. return metadata, nil
  533. }
  534. /*func (manager *SInstanceBackupManager) CreateInstanceBackupFromPackage(ctx context.Context, owner mcclient.TokenCredential, backupStorageId, name string) (*SInstanceBackup, error) {
  535. ib := &SInstanceBackup{}
  536. ib.SetModelManager(manager, ib)
  537. ib.ProjectId = owner.GetProjectId()
  538. ib.DomainId = owner.GetProjectDomainId()
  539. ib.Name = name
  540. ib.BackupStorageId = backupStorageId
  541. ib.CloudregionId = "default"
  542. ib.Status = api.INSTANCE_BACKUP_STATUS_CREATING_FROM_PACKAGE
  543. err := manager.TableSpec().Insert(ctx, ib)
  544. if err != nil {
  545. return nil, errors.Wrap(err, "unable to insert instance backup")
  546. }
  547. return ib, nil
  548. }*/
  549. func (ib *SInstanceBackup) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.InstanceBackupManagerSyncstatusInput) (jsonutils.JSONObject, error) {
  550. var openTask = true
  551. count, err := taskman.TaskManager.QueryTasksOfObject(ib, time.Now().Add(-3*time.Minute), &openTask).CountWithError()
  552. if err != nil {
  553. return nil, err
  554. }
  555. if count > 0 {
  556. return nil, httperrors.NewBadRequestError("InstanceBackup has %d task active, can't sync status", count)
  557. }
  558. return nil, StartResourceSyncStatusTask(ctx, userCred, ib, "InstanceBackupSyncstatusTask", "")
  559. }
  560. func (ib *SInstanceBackup) FillFromPackMetadata(ctx context.Context, userCred mcclient.TokenCredential, diskBackupIds []string, metadata *api.InstanceBackupPackMetadata) (*SInstanceBackup, error) {
  561. if len(metadata.Metadata) > 0 {
  562. // check class metadata
  563. allOwner := db.AllMetadataOwner(metadata.Metadata)
  564. err := db.RequireSameClass(ctx, allOwner, ib)
  565. if err != nil {
  566. return nil, errors.Wrap(err, "db.IsInSameClass")
  567. }
  568. meta := make(map[string]interface{})
  569. for k, v := range metadata.Metadata {
  570. meta[k] = v
  571. }
  572. ib.SetAllMetadata(ctx, meta, userCred)
  573. }
  574. if len(metadata.EncryptKeyId) > 0 {
  575. session := auth.GetSession(ctx, userCred, consts.GetRegion())
  576. _, err := identity_modules.Credentials.GetEncryptKey(session, metadata.EncryptKeyId)
  577. if err != nil {
  578. return nil, errors.Wrap(err, "GetEncryptKey")
  579. }
  580. }
  581. for i, backupId := range diskBackupIds {
  582. _, err := DiskBackupManager.CreateFromPackMetadata(ctx, userCred, ib.BackupStorageId, backupId, fmt.Sprintf("%s_disk_%d", ib.Name, i), &metadata.DiskMetadatas[i])
  583. if err != nil {
  584. return nil, errors.Wrapf(err, "unable to create diskbackup %s", backupId)
  585. }
  586. err = InstanceBackupJointManager.CreateJoint(ctx, ib.GetId(), backupId, int8(i))
  587. if err != nil {
  588. return nil, errors.Wrapf(err, "unable to CreateJoint for instanceBackup %s and diskBackup %s", ib.GetId(), backupId)
  589. }
  590. }
  591. _, err := db.Update(ib, func() error {
  592. ib.OsArch = metadata.OsArch
  593. ib.ServerConfig = metadata.ServerConfig
  594. ib.ServerMetadata = metadata.ServerMetadata
  595. ib.SecGroups = metadata.SecGroups
  596. ib.KeypairId = metadata.KeypairId
  597. ib.OsType = metadata.OsType
  598. ib.InstanceType = metadata.InstanceType
  599. ib.SizeMb = metadata.SizeMb
  600. ib.EncryptKeyId = metadata.EncryptKeyId
  601. return nil
  602. })
  603. if err != nil {
  604. return nil, err
  605. }
  606. return ib, nil
  607. }
  608. func (self *SInstanceBackup) CustomizeCreate(
  609. ctx context.Context,
  610. userCred mcclient.TokenCredential,
  611. ownerId mcclient.IIdentityProvider,
  612. query jsonutils.JSONObject,
  613. data jsonutils.JSONObject,
  614. ) error {
  615. if len(self.GuestId) > 0 {
  616. // use disk's ownerId instead of default ownerId
  617. guestObj, err := GuestManager.FetchById(self.GuestId)
  618. if err != nil {
  619. return errors.Wrap(err, "GuestManager.FetchById")
  620. }
  621. ownerId = guestObj.(*SGuest).GetOwnerId()
  622. }
  623. return self.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
  624. }