mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
fix(region): optimized snapshot list (#16990)
This commit is contained in:
@@ -578,7 +578,11 @@ func (snapshot *SSnapshot) purge(ctx context.Context, userCred mcclient.TokenCre
|
||||
lockman.LockObject(ctx, snapshot)
|
||||
defer lockman.ReleaseObject(ctx, snapshot)
|
||||
|
||||
err := snapshot.ValidatePurgeCondition(ctx)
|
||||
if snapshot.Status == api.SNAPSHOT_DELETING {
|
||||
snapshot.SetStatus(userCred, api.SNAPSHOT_READY, "for purge")
|
||||
}
|
||||
|
||||
err := snapshot.ValidateDeleteCondition(ctx, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "ValidatePurgeCondition for snapshot %s(%s)", snapshot.Name, snapshot.Id)
|
||||
}
|
||||
|
||||
+109
-38
@@ -24,6 +24,7 @@ import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/gotypes"
|
||||
"yunion.io/x/pkg/util/compare"
|
||||
"yunion.io/x/pkg/util/rbacscope"
|
||||
"yunion.io/x/pkg/util/timeutils"
|
||||
@@ -290,6 +291,13 @@ func (manager *SSnapshotManager) QueryDistinctExtraField(q *sqlchemy.SQuery, fie
|
||||
return q, httperrors.ErrNotFound
|
||||
}
|
||||
|
||||
type sSnapshotGuest struct {
|
||||
DiskId string
|
||||
GuestId string
|
||||
GuestName string
|
||||
GuestStatus string
|
||||
}
|
||||
|
||||
func (manager *SSnapshotManager) FetchCustomizeColumns(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
@@ -305,6 +313,9 @@ func (manager *SSnapshotManager) FetchCustomizeColumns(
|
||||
regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
encRows := manager.SEncryptedResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
||||
|
||||
storageIds := make([]string, len(objs))
|
||||
diskIds := make([]string, len(objs))
|
||||
snapshotIds := make([]string, len(objs))
|
||||
for i := range rows {
|
||||
rows[i] = api.SnapshotDetails{
|
||||
VirtualResourceDetails: virtRows[i],
|
||||
@@ -313,35 +324,90 @@ func (manager *SSnapshotManager) FetchCustomizeColumns(
|
||||
|
||||
EncryptedResourceDetails: encRows[i],
|
||||
}
|
||||
rows[i] = objs[i].(*SSnapshot).getMoreDetails(rows[i])
|
||||
snapshot := objs[i].(*SSnapshot)
|
||||
storageIds[i] = snapshot.StorageId
|
||||
diskIds[i] = snapshot.DiskId
|
||||
snapshotIds[i] = snapshot.Id
|
||||
}
|
||||
|
||||
storages := map[string]SStorage{}
|
||||
err := db.FetchModelObjectsByIds(StorageManager, "id", storageIds, storages)
|
||||
if err != nil {
|
||||
log.Errorf("FetchModelObjectsByIds")
|
||||
return rows
|
||||
}
|
||||
disks := map[string]SDisk{}
|
||||
err = db.FetchModelObjectsByIds(DiskManager, "id", diskIds, disks)
|
||||
if err != nil {
|
||||
log.Errorf("FetchModelObjectsByIds")
|
||||
return rows
|
||||
}
|
||||
iss := []SInstanceSnapshotJoint{}
|
||||
err = InstanceSnapshotJointManager.Query().In("snapshot_id", snapshotIds).All(&iss)
|
||||
if err != nil {
|
||||
log.Errorf("query instance snapshot joint")
|
||||
return rows
|
||||
}
|
||||
issMap := map[string]bool{}
|
||||
for i := range iss {
|
||||
issMap[iss[i].SnapshotId] = true
|
||||
}
|
||||
q := GuestManager.Query()
|
||||
gds := GuestdiskManager.Query().SubQuery()
|
||||
sq := q.SubQuery()
|
||||
guests := sq.Query(
|
||||
sq.Field("id").Label("guest_id"),
|
||||
sq.Field("name").Label("guest_name"),
|
||||
sq.Field("status").Label("guest_status"),
|
||||
gds.Field("disk_id"),
|
||||
).Join(gds, sqlchemy.Equals(gds.Field("guest_id"), sq.Field("id"))).Filter(sqlchemy.In(gds.Field("disk_id"), diskIds))
|
||||
guestdisks := []struct {
|
||||
DiskId string
|
||||
GuestId string
|
||||
GuestName string
|
||||
GuestStatus string
|
||||
}{}
|
||||
err = guests.All(&guestdisks)
|
||||
if err != nil {
|
||||
log.Errorf("guests.All")
|
||||
return rows
|
||||
}
|
||||
guestMap := map[string]struct {
|
||||
GuestId string
|
||||
GuestName string
|
||||
GuestStatus string
|
||||
}{}
|
||||
for _, gd := range guestdisks {
|
||||
guestMap[gd.DiskId] = struct {
|
||||
GuestId string
|
||||
GuestName string
|
||||
GuestStatus string
|
||||
}{
|
||||
GuestId: gd.GuestId,
|
||||
GuestName: gd.GuestName,
|
||||
GuestStatus: gd.GuestStatus,
|
||||
}
|
||||
}
|
||||
|
||||
for i := range rows {
|
||||
if storage, ok := storages[storageIds[i]]; ok {
|
||||
rows[i].StorageType = storage.StorageType
|
||||
}
|
||||
if disk, ok := disks[diskIds[i]]; ok {
|
||||
rows[i].DiskStatus = disk.Status
|
||||
rows[i].DiskName = disk.Name
|
||||
}
|
||||
if guest, ok := guestMap[diskIds[i]]; ok {
|
||||
rows[i].GuestId = guest.GuestId
|
||||
rows[i].Guest = guest.GuestName
|
||||
rows[i].GuestStatus = guest.GuestStatus
|
||||
}
|
||||
rows[i].IsSubSnapshot, _ = issMap[snapshotIds[i]]
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
func (self *SSnapshot) getMoreDetails(out api.SnapshotDetails) api.SnapshotDetails {
|
||||
if IStorage, _ := StorageManager.FetchById(self.StorageId); IStorage != nil {
|
||||
storage := IStorage.(*SStorage)
|
||||
out.StorageType = storage.StorageType
|
||||
}
|
||||
disk, _ := self.GetDisk()
|
||||
if disk != nil {
|
||||
out.DiskStatus = disk.Status
|
||||
out.DiskName = disk.Name
|
||||
guests := disk.GetGuests()
|
||||
if len(guests) == 1 {
|
||||
out.Guest = guests[0].Name
|
||||
out.GuestId = guests[0].Id
|
||||
out.GuestStatus = guests[0].Status
|
||||
}
|
||||
}
|
||||
if t, _ := InstanceSnapshotJointManager.IsSubSnapshot(self.Id); t {
|
||||
out.IsSubSnapshot = true
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (self *SSnapshot) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
|
||||
res := self.SVirtualResourceBase.GetShortDesc(ctx)
|
||||
res.Add(jsonutils.NewInt(int64(self.Size)), "size")
|
||||
@@ -660,23 +726,28 @@ func (self *SSnapshot) StartSnapshotDeleteTask(ctx context.Context, userCred mcc
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SSnapshot) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
|
||||
func (self *SSnapshot) ValidateDeleteCondition(ctx context.Context, info *api.SnapshotDetails) error {
|
||||
if self.Status == api.SNAPSHOT_DELETING {
|
||||
return httperrors.NewBadRequestError("Cannot delete snapshot in status %s", self.Status)
|
||||
}
|
||||
return self.ValidatePurgeCondition(ctx)
|
||||
}
|
||||
|
||||
func (self *SSnapshot) ValidatePurgeCondition(ctx context.Context) error {
|
||||
count, err := InstanceSnapshotJointManager.Query().Equals("snapshot_id", self.Id).CountWithError()
|
||||
if err != nil {
|
||||
return httperrors.NewInternalServerError("Fetch instance snapshot error %s", err)
|
||||
}
|
||||
if count > 0 {
|
||||
return httperrors.NewBadRequestError("snapshot referenced by instance snapshot")
|
||||
}
|
||||
if disk, err := self.GetDisk(); err == nil {
|
||||
if disk.Status == api.DISK_RESET {
|
||||
if gotypes.IsNil(info) {
|
||||
count, err := InstanceSnapshotJointManager.Query().Equals("snapshot_id", self.Id).CountWithError()
|
||||
if err != nil {
|
||||
return httperrors.NewInternalServerError("Fetch instance snapshot error %s", err)
|
||||
}
|
||||
if count > 0 {
|
||||
return httperrors.NewBadRequestError("snapshot referenced by instance snapshot")
|
||||
}
|
||||
if disk, err := self.GetDisk(); err == nil {
|
||||
if disk.Status == api.DISK_RESET {
|
||||
return httperrors.NewBadRequestError("Cannot delete snapshot on disk reset")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if info.IsSubSnapshot {
|
||||
return httperrors.NewBadRequestError("snapshot referenced by instance snapshot")
|
||||
}
|
||||
if info.DiskStatus == api.DISK_RESET {
|
||||
return httperrors.NewBadRequestError("Cannot delete snapshot on disk reset")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user