storagecachedimages.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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. "strings"
  20. "time"
  21. "github.com/serialx/hashring"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/log"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/utils"
  27. "yunion.io/x/sqlchemy"
  28. api "yunion.io/x/onecloud/pkg/apis/compute"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  31. "yunion.io/x/onecloud/pkg/httperrors"
  32. "yunion.io/x/onecloud/pkg/mcclient"
  33. "yunion.io/x/onecloud/pkg/util/stringutils2"
  34. )
  35. type SStoragecachedimageManager struct {
  36. db.SJointResourceBaseManager
  37. db.SExternalizedResourceBaseManager
  38. SStoragecacheResourceBaseManager
  39. }
  40. var StoragecachedimageManager *SStoragecachedimageManager
  41. func init() {
  42. db.InitManager(func() {
  43. StoragecachedimageManager = &SStoragecachedimageManager{
  44. SJointResourceBaseManager: db.NewJointResourceBaseManager(
  45. SStoragecachedimage{},
  46. "storagecachedimages_tbl",
  47. "storagecachedimage",
  48. "storagecachedimages",
  49. StoragecacheManager,
  50. CachedimageManager,
  51. ),
  52. }
  53. StoragecachedimageManager.SetVirtualObject(StoragecachedimageManager)
  54. })
  55. }
  56. type SStoragecachedimage struct {
  57. db.SJointResourceBase
  58. db.SExternalizedResourceBase
  59. SStoragecacheResourceBase
  60. // 镜像缓存Id
  61. CachedimageId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
  62. // 外部Id
  63. // ExternalId string `width:"256" charset:"utf8" nullable:"false" get:"admin"`
  64. // 镜像状态
  65. Status string `width:"32" charset:"ascii" nullable:"false" default:"init" list:"admin" update:"admin" create:"admin_required"`
  66. Path string `width:"256" charset:"utf8" nullable:"true" list:"admin" update:"admin" create:"admin_optional"`
  67. // 上次下载时间
  68. LastDownload time.Time `get:"admin"`
  69. // 下载引用次数
  70. DownloadRefcnt int `get:"admin"`
  71. }
  72. func (manager *SStoragecachedimageManager) GetMasterFieldName() string {
  73. return "storagecache_id"
  74. }
  75. func (manager *SStoragecachedimageManager) GetSlaveFieldName() string {
  76. return "cachedimage_id"
  77. }
  78. func (sci *SStoragecachedimage) getStorageHostId() (string, error) {
  79. var s SStorage
  80. storage := StorageManager.Query()
  81. err := storage.Filter(sqlchemy.Equals(storage.Field("storagecache_id"), sci.StoragecacheId)).First(&s)
  82. if err != nil {
  83. return "", err
  84. }
  85. hosts := s.GetAllAttachingHosts()
  86. var hostIds = make([]string, 0)
  87. for _, host := range hosts {
  88. hostIds = append(hostIds, host.Id)
  89. }
  90. if len(hostIds) == 0 {
  91. return "", nil
  92. }
  93. ring := hashring.New(hostIds)
  94. ret, _ := ring.GetNode(sci.StoragecacheId)
  95. return ret, nil
  96. }
  97. func (sci *SStoragecachedimage) GetHost() (*SHost, error) {
  98. sc := sci.GetStoragecache()
  99. return sc.GetMasterHost()
  100. }
  101. func (manager *SStoragecachedimageManager) FetchCustomizeColumns(
  102. ctx context.Context,
  103. userCred mcclient.TokenCredential,
  104. query jsonutils.JSONObject,
  105. objs []interface{},
  106. fields stringutils2.SSortedStrings,
  107. isList bool,
  108. ) []api.StoragecachedimageDetails {
  109. rows := make([]api.StoragecachedimageDetails, len(objs))
  110. storagecacheIds := make([]string, 0)
  111. imageIds := make([]string, 0)
  112. jointRows := manager.SJointResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  113. scRows := manager.SStoragecacheResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  114. for i := range rows {
  115. rows[i] = api.StoragecachedimageDetails{
  116. JointResourceBaseDetails: jointRows[i],
  117. StoragecacheResourceInfo: scRows[i],
  118. }
  119. sci := objs[i].(*SStoragecachedimage)
  120. storagecacheIds = append(storagecacheIds, sci.StoragecacheId)
  121. imageIds = append(imageIds, sci.CachedimageId)
  122. }
  123. cachedImages := make(map[string]SCachedimage)
  124. err := db.FetchModelObjectsByIds(CachedimageManager, "id", imageIds, &cachedImages)
  125. if err != nil {
  126. log.Errorf("db.FetchModelObjectsByIds fail %s", err)
  127. }
  128. cdromRefs, err := manager.fetchCdromReferenceCounts(storagecacheIds, imageIds)
  129. if err != nil {
  130. log.Errorf("manager.fetchCdromReferenceCounts fail %s", err)
  131. }
  132. diskRefs, err := manager.fetchDiskReferenceCounts(storagecacheIds, imageIds)
  133. if err != nil {
  134. log.Errorf("manager.fetchDiskReferenceCounts fail %s", err)
  135. }
  136. for i := range rows {
  137. sci := objs[i].(*SStoragecachedimage)
  138. if cachedImages != nil {
  139. if cachedImage, ok := cachedImages[sci.CachedimageId]; ok {
  140. rows[i].Cachedimage = cachedImage.Name
  141. rows[i].Image = cachedImage.Name
  142. rows[i].Size = cachedImage.Size
  143. }
  144. }
  145. if cdromRefs != nil {
  146. if refMap, ok := cdromRefs[sci.StoragecacheId]; ok {
  147. rows[i].CdromReference = refMap[sci.CachedimageId]
  148. }
  149. }
  150. if diskRefs != nil {
  151. if refMap, ok := diskRefs[sci.StoragecacheId]; ok {
  152. rows[i].DiskReference = refMap[sci.CachedimageId]
  153. rows[i].Reference = rows[i].CdromReference + rows[i].DiskReference
  154. }
  155. }
  156. }
  157. return rows
  158. }
  159. func (sci *SStoragecachedimage) GetCachedimage() *SCachedimage {
  160. cachedImage, _ := CachedimageManager.FetchById(sci.CachedimageId)
  161. if cachedImage != nil {
  162. return cachedImage.(*SCachedimage)
  163. }
  164. return nil
  165. }
  166. /*func (sci *SStoragecachedimage) getExtraDetails(ctx context.Context, out api.StoragecachedimageDetails) api.StoragecachedimageDetails {
  167. storagecache := sci.GetStoragecache()
  168. if storagecache != nil {
  169. // out.Storagecache = storagecache.Name
  170. out.Storages = storagecache.getStorageNames()
  171. host, _ := storagecache.GetMasterHost()
  172. if host != nil {
  173. out.Host = host.GetShortDesc(ctx)
  174. } else {
  175. var err error
  176. hostDesc, err := storagecache.GetEsxiAgentHostDesc()
  177. if err != nil {
  178. log.Errorf("unable to GetEsxiAgentHostDesc of stroagecache: %s", err.Error())
  179. }
  180. if hostDesc != nil {
  181. out.Host = hostDesc
  182. }
  183. }
  184. }
  185. cachedImage := sci.GetCachedimage()
  186. if cachedImage != nil {
  187. out.Cachedimage = cachedImage.Name
  188. out.Image = cachedImage.GetName()
  189. out.Size = cachedImage.Size
  190. }
  191. out.Reference, _ = sci.getReferenceCount()
  192. return out
  193. }*/
  194. func (manager *SStoragecachedimageManager) fetchCdromReferenceCounts(storagecacheIds []string, imageIds []string) (map[string]map[string]int, error) {
  195. q := GuestcdromManager.Query()
  196. guests := GuestManager.Query().SubQuery()
  197. hostStorages := HoststorageManager.Query().SubQuery()
  198. storages := StorageManager.Query().SubQuery()
  199. q = q.Join(guests, sqlchemy.Equals(q.Field("id"), guests.Field("id")))
  200. q = q.Join(hostStorages, sqlchemy.Equals(guests.Field("host_id"), hostStorages.Field("host_id")))
  201. q = q.Join(storages, sqlchemy.Equals(hostStorages.Field("storage_id"), storages.Field("id")))
  202. q = q.GroupBy(q.Field("image_id"))
  203. q = q.GroupBy(storages.Field("storagecache_id"))
  204. q = q.Filter(sqlchemy.In(q.Field("image_id"), imageIds))
  205. q = q.Filter(sqlchemy.In(storages.Field("storagecache_id"), storagecacheIds))
  206. q = q.AppendField(sqlchemy.COUNT("ref_count"))
  207. q = q.AppendField(q.Field("image_id"))
  208. q = q.AppendField(storages.Field("storagecache_id"))
  209. return manager.fetchRefCount(q)
  210. }
  211. func (maanger *SStoragecachedimageManager) fetchRefCount(q *sqlchemy.SQuery) (map[string]map[string]int, error) {
  212. results := []struct {
  213. RefCount int `json:"ref_count"`
  214. ImageId string `json:"image_id"`
  215. StoragecacheId string `json:"storagecache_id"`
  216. }{}
  217. err := q.All(&results)
  218. if err != nil {
  219. return nil, errors.Wrap(err, "Query")
  220. }
  221. ret := make(map[string]map[string]int)
  222. for _, r := range results {
  223. if _, ok := ret[r.StoragecacheId]; !ok {
  224. ret[r.StoragecacheId] = make(map[string]int)
  225. }
  226. ret[r.StoragecacheId][r.ImageId] = r.RefCount
  227. }
  228. return ret, nil
  229. }
  230. func (sci *SStoragecachedimage) getCdromReferenceCount() (int, error) {
  231. cdroms := GuestcdromManager.Query().SubQuery()
  232. guests := GuestManager.Query().SubQuery()
  233. q := cdroms.Query()
  234. q = q.Join(guests, sqlchemy.Equals(cdroms.Field("id"), guests.Field("id")))
  235. q = q.Filter(sqlchemy.Equals(cdroms.Field("image_id"), sci.CachedimageId))
  236. return q.CountWithError()
  237. }
  238. func (manager *SStoragecachedimageManager) fetchDiskReferenceCounts(storagecacheIds, imageIds []string) (map[string]map[string]int, error) {
  239. disks := DiskManager.Query().SubQuery()
  240. storages := StorageManager.Query().SubQuery()
  241. q := disks.Query()
  242. q = q.Join(storages, sqlchemy.Equals(disks.Field("storage_id"), storages.Field("id")))
  243. q = q.GroupBy(disks.Field("template_id"))
  244. q = q.GroupBy(storages.Field("storagecache_id"))
  245. q = q.Filter(sqlchemy.In(disks.Field("template_id"), imageIds))
  246. q = q.Filter(sqlchemy.In(storages.Field("storagecache_id"), storagecacheIds))
  247. q = q.AppendField(sqlchemy.COUNT("ref_count"))
  248. q = q.AppendField(disks.Field("template_id").Label("image_id"))
  249. q = q.AppendField(storages.Field("storagecache_id"))
  250. return manager.fetchRefCount(q)
  251. }
  252. func (sci *SStoragecachedimage) getDiskReferenceCount() (int, error) {
  253. guestdisks := GuestdiskManager.Query().SubQuery()
  254. disks := DiskManager.Query().SubQuery()
  255. storages := StorageManager.Query().SubQuery()
  256. q := guestdisks.Query()
  257. q = q.Join(disks, sqlchemy.AND(sqlchemy.Equals(disks.Field("id"), guestdisks.Field("disk_id")),
  258. sqlchemy.IsFalse(disks.Field("deleted"))))
  259. q = q.Join(storages, sqlchemy.AND(sqlchemy.Equals(disks.Field("storage_id"), storages.Field("id")),
  260. sqlchemy.IsFalse(storages.Field("deleted"))))
  261. q = q.Filter(sqlchemy.Equals(storages.Field("storagecache_id"), sci.StoragecacheId))
  262. q = q.Filter(sqlchemy.Equals(disks.Field("template_id"), sci.CachedimageId))
  263. q = q.Filter(sqlchemy.NOT(sqlchemy.In(disks.Field("status"), []string{api.DISK_ALLOC_FAILED, api.DISK_INIT})))
  264. return q.CountWithError()
  265. }
  266. func (sci *SStoragecachedimage) getReferenceCount() (int, error) {
  267. totalCnt := 0
  268. cnt, err := sci.getCdromReferenceCount()
  269. if err != nil {
  270. return -1, err
  271. }
  272. totalCnt += cnt
  273. cnt, err = sci.getDiskReferenceCount()
  274. if err != nil {
  275. return -1, err
  276. }
  277. totalCnt += cnt
  278. return totalCnt, nil
  279. }
  280. func (manager *SStoragecachedimageManager) GetStoragecachedimage(cacheId string, imageId string) *SStoragecachedimage {
  281. obj, err := db.FetchJointByIds(manager, cacheId, imageId, nil)
  282. if err != nil {
  283. if err != sql.ErrNoRows {
  284. log.Errorf("manager.FetchByIds %s %s error %s", cacheId, imageId, err)
  285. }
  286. return nil
  287. }
  288. return obj.(*SStoragecachedimage)
  289. }
  290. func (manager *SStoragecachedimageManager) RecoverStoragecachedImage(
  291. ctx context.Context, userCred mcclient.TokenCredential, scId, imgId string,
  292. ) (*SStoragecachedimage, error) {
  293. lockman.LockRawObject(ctx, manager.Keyword(), "name")
  294. defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
  295. storagecachedImage := SStoragecachedimage{}
  296. storagecachedImage.SetModelManager(manager, &storagecachedImage)
  297. err := manager.RawQuery().Equals("storagecache_id", scId).Equals("cachedimage_id", imgId).First(&storagecachedImage)
  298. if err != nil {
  299. return nil, err
  300. }
  301. diff, err := db.Update(&storagecachedImage, func() error {
  302. storagecachedImage.Status = api.CACHED_IMAGE_STATUS_ACTIVE
  303. if storagecachedImage.Deleted == true {
  304. storagecachedImage.Deleted = false
  305. storagecachedImage.DeletedAt = time.Time{}
  306. storagecachedImage.UpdateVersion = 0
  307. }
  308. return nil
  309. })
  310. db.OpsLog.LogEvent(&storagecachedImage, db.ACT_UPDATE, diff, userCred)
  311. return &storagecachedImage, nil
  312. }
  313. func (sci *SStoragecachedimage) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  314. _, err := sqlchemy.GetDB().Exec(
  315. fmt.Sprintf(
  316. "delete from %s where row_id = ?",
  317. sci.GetModelManager().TableSpec().Name(),
  318. ), sci.RowId,
  319. )
  320. return err
  321. }
  322. func (sci *SStoragecachedimage) Detach(ctx context.Context, userCred mcclient.TokenCredential) error {
  323. return db.DetachJoint(ctx, userCred, sci)
  324. }
  325. func (sci *SStoragecachedimage) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  326. if sci.Status != api.CACHED_IMAGE_STATUS_CACHE_FAILED {
  327. cnt, err := sci.getReferenceCount()
  328. if err != nil {
  329. return httperrors.NewInternalServerError("getReferenceCount fail %s", err)
  330. }
  331. if cnt > 0 {
  332. return httperrors.NewNotEmptyError("Image is in use")
  333. }
  334. }
  335. return sci.SJointResourceBase.ValidateDeleteCondition(ctx, nil)
  336. }
  337. func (sci *SStoragecachedimage) isCachedImageInUse() error {
  338. if !sci.isDownloadSessionExpire() {
  339. return httperrors.NewResourceBusyError("Active download session not expired")
  340. }
  341. image := sci.GetCachedimage()
  342. if image != nil && !image.canDeleteLastCache() {
  343. return httperrors.NewResourceBusyError("Cannot delete the last cache")
  344. }
  345. return nil
  346. }
  347. func (sci *SStoragecachedimage) isDownloadSessionExpire() bool {
  348. if !sci.LastDownload.IsZero() && time.Now().Sub(sci.LastDownload) < api.DOWNLOAD_SESSION_LENGTH {
  349. return false
  350. } else {
  351. return true
  352. }
  353. }
  354. func (sci *SStoragecachedimage) markDeleting(ctx context.Context, userCred mcclient.TokenCredential, isForce bool) error {
  355. err := sci.ValidateDeleteCondition(ctx, nil)
  356. if err != nil {
  357. return err
  358. }
  359. if !isForce {
  360. err = sci.isCachedImageInUse()
  361. if err != nil {
  362. return err
  363. }
  364. }
  365. cache := sci.GetStoragecache()
  366. image := sci.GetCachedimage()
  367. if image != nil {
  368. lockman.LockJointObject(ctx, cache, image)
  369. defer lockman.ReleaseJointObject(ctx, cache, image)
  370. }
  371. if !isForce && !utils.IsInStringArray(sci.Status,
  372. []string{
  373. api.CACHED_IMAGE_STATUS_ACTIVE,
  374. api.CACHED_IMAGE_STATUS_DELETING,
  375. api.CACHED_IMAGE_STATUS_CACHE_FAILED,
  376. api.CACHED_IMAGE_STATUS_DELETE_FAILED,
  377. api.CACHED_IMAGE_STATUS_UNCACHE_IMAGE_FAILED,
  378. }) {
  379. return httperrors.NewInvalidStatusError("Cannot uncache in status %s", sci.Status)
  380. }
  381. _, err = db.Update(sci, func() error {
  382. sci.Status = api.CACHED_IMAGE_STATUS_DELETING
  383. return nil
  384. })
  385. return err
  386. }
  387. func (manager *SStoragecachedimageManager) Register(ctx context.Context, userCred mcclient.TokenCredential, cacheId, imageId string, status string) *SStoragecachedimage {
  388. lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred))
  389. defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred))
  390. cachedimage := manager.GetStoragecachedimage(cacheId, imageId)
  391. if cachedimage != nil {
  392. return cachedimage
  393. }
  394. cachedimage = &SStoragecachedimage{}
  395. cachedimage.SetModelManager(manager, cachedimage)
  396. cachedimage.StoragecacheId = cacheId
  397. cachedimage.CachedimageId = imageId
  398. if len(status) == 0 {
  399. status = api.CACHED_IMAGE_STATUS_INIT
  400. }
  401. cachedimage.Status = status
  402. err := manager.TableSpec().Insert(ctx, cachedimage)
  403. if err != nil {
  404. log.Errorf("insert error %s", err)
  405. return nil
  406. }
  407. return cachedimage
  408. }
  409. func (sci *SStoragecachedimage) SetStatus(ctx context.Context, userCred mcclient.TokenCredential, status string, reason string) error {
  410. if sci.Status == status {
  411. return nil
  412. }
  413. oldStatus := sci.Status
  414. _, err := db.Update(sci, func() error {
  415. sci.Status = status
  416. return nil
  417. })
  418. if err != nil {
  419. return err
  420. }
  421. if userCred != nil {
  422. notes := fmt.Sprintf("%s=>%s", oldStatus, status)
  423. if len(reason) > 0 {
  424. notes = fmt.Sprintf("%s: %s", notes, reason)
  425. }
  426. db.OpsLog.LogEvent(sci, db.ACT_UPDATE_STATUS, notes, userCred)
  427. }
  428. return nil
  429. }
  430. func (sci *SStoragecachedimage) AddDownloadRefcount() error {
  431. _, err := db.Update(sci, func() error {
  432. sci.DownloadRefcnt += 1
  433. sci.LastDownload = time.Now()
  434. return nil
  435. })
  436. return err
  437. }
  438. func (sci *SStoragecachedimage) SetExternalId(externalId string) error {
  439. _, err := db.Update(sci, func() error {
  440. sci.ExternalId = externalId
  441. return nil
  442. })
  443. return err
  444. }
  445. func (sci SStoragecachedimage) GetExternalId() string {
  446. return sci.ExternalId
  447. }
  448. func (sci *SStoragecachedimage) syncRemoveCloudImage(ctx context.Context, userCred mcclient.TokenCredential) error {
  449. lockman.LockObject(ctx, sci)
  450. defer lockman.ReleaseObject(ctx, sci)
  451. image := sci.GetCachedimage()
  452. err := sci.Delete(ctx, userCred)
  453. if err != nil {
  454. return err
  455. }
  456. if image != nil {
  457. cnt, err := image.getStoragecacheCount()
  458. if err != nil {
  459. log.Errorf("getStoragecacheCount fail %s", err)
  460. return err
  461. }
  462. if cnt == 0 {
  463. err = image.Delete(ctx, userCred)
  464. if err != nil {
  465. log.Errorf("image delete error %s", err)
  466. return err
  467. }
  468. }
  469. }
  470. return nil
  471. }
  472. func (sci *SStoragecachedimage) syncWithCloudImage(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, image cloudprovider.ICloudImage, managerId string) error {
  473. cachedImage := sci.GetCachedimage()
  474. if len(sci.ExternalId) == 0 {
  475. sci.SetExternalId(cachedImage.GetExternalId())
  476. }
  477. if len(cachedImage.ExternalId) > 0 {
  478. sci.SetStatus(ctx, userCred, image.GetStatus(), "")
  479. return cachedImage.syncWithCloudImage(ctx, userCred, ownerId, image, nil)
  480. } else {
  481. return nil
  482. }
  483. }
  484. func (manager *SStoragecachedimageManager) newFromCloudImage(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, image cloudprovider.ICloudImage, cache *SStoragecache) error {
  485. var cachedImage *SCachedimage
  486. provider := cache.GetCloudprovider()
  487. imgObj, err := db.FetchByExternalId(CachedimageManager, image.GetGlobalId())
  488. if err != nil {
  489. if err != sql.ErrNoRows {
  490. // unhandled error
  491. log.Errorf("CachedimageManager.FetchByExternalId error %s", err)
  492. return err
  493. }
  494. // not found
  495. // first test if this image is uploaded by onecloud, if true, image name should be ID of onecloud image
  496. name := image.GetName()
  497. if utils.IsAscii(name) {
  498. if strings.HasPrefix(name, "img") {
  499. name = name[3:]
  500. }
  501. imgObj, err := CachedimageManager.FetchById(name)
  502. if err == nil && imgObj != nil {
  503. cachedImage = imgObj.(*SCachedimage)
  504. }
  505. }
  506. if cachedImage == nil {
  507. // no such image
  508. cachedImage, err = CachedimageManager.newFromCloudImage(ctx, userCred, ownerId, image, provider)
  509. if err != nil {
  510. log.Errorf("CachedimageManager.newFromCloudImage fail %s", err)
  511. return err
  512. }
  513. }
  514. } else {
  515. cachedImage = imgObj.(*SCachedimage)
  516. }
  517. if len(cachedImage.ExternalId) > 0 {
  518. cachedImage.syncWithCloudImage(ctx, userCred, ownerId, image, provider)
  519. }
  520. scimg := manager.Register(ctx, userCred, cache.GetId(), cachedImage.GetId(), image.GetStatus())
  521. if scimg == nil {
  522. return fmt.Errorf("register cached image fail")
  523. }
  524. return scimg.SetExternalId(image.GetGlobalId())
  525. }
  526. func (manager *SStoragecachedimageManager) ListItemFilter(
  527. ctx context.Context,
  528. q *sqlchemy.SQuery,
  529. userCred mcclient.TokenCredential,
  530. query api.StoragecachedimageListInput,
  531. ) (*sqlchemy.SQuery, error) {
  532. var err error
  533. q, err = manager.SJointResourceBaseManager.ListItemFilter(ctx, q, userCred, query.JointResourceBaseListInput)
  534. if err != nil {
  535. return nil, errors.Wrap(err, "SSchedtagJointsManager.ListItemFilter")
  536. }
  537. q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  538. if err != nil {
  539. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  540. }
  541. q, err = manager.SStoragecacheResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StoragecacheFilterListInput)
  542. if err != nil {
  543. return nil, errors.Wrap(err, "SStoragecacheResourceBaseManager.ListItemFilter")
  544. }
  545. if len(query.CachedimageId) > 0 {
  546. cachedImageObj, err := CachedimageManager.FetchByIdOrName(ctx, userCred, query.CachedimageId)
  547. if err != nil {
  548. if errors.Cause(err) == sql.ErrNoRows {
  549. return nil, httperrors.NewResourceNotFoundError2(CachedimageManager.Keyword(), query.CachedimageId)
  550. } else {
  551. return nil, errors.Wrap(err, "CachedimageManager.FetchByIdOrName")
  552. }
  553. }
  554. q = q.Equals("cachedimage_id", cachedImageObj.GetId())
  555. }
  556. if len(query.Status) > 0 {
  557. q = q.In("status", query.Status)
  558. }
  559. return q, nil
  560. }
  561. func (manager *SStoragecachedimageManager) OrderByExtraFields(
  562. ctx context.Context,
  563. q *sqlchemy.SQuery,
  564. userCred mcclient.TokenCredential,
  565. query api.StoragecachedimageListInput,
  566. ) (*sqlchemy.SQuery, error) {
  567. var err error
  568. q, err = manager.SJointResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.JointResourceBaseListInput)
  569. if err != nil {
  570. return nil, errors.Wrap(err, "SSchedtagJointsManager.OrderByExtraFields")
  571. }
  572. q, err = manager.SStoragecacheResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StoragecacheFilterListInput)
  573. if err != nil {
  574. return nil, errors.Wrap(err, "SStoragecacheResourceBaseManager.OrderByExtraFields")
  575. }
  576. return q, nil
  577. }
  578. func (manager *SStoragecachedimageManager) InitializeData() error {
  579. images := []SStoragecachedimage{}
  580. q := manager.Query().Equals("status", "ready")
  581. err := db.FetchModelObjects(manager, q, &images)
  582. if err != nil {
  583. return errors.Wrapf(err, "db.FetchModelObjects")
  584. }
  585. for i := range images {
  586. _, err := db.Update(&images[i], func() error {
  587. images[i].Status = api.CACHED_IMAGE_STATUS_ACTIVE
  588. return nil
  589. })
  590. if err != nil {
  591. return errors.Wrapf(err, "db.Update(%d)", images[i].RowId)
  592. }
  593. }
  594. return nil
  595. }