fix(region): optimized snapshot list (#16990)

This commit is contained in:
屈轩
2023-05-13 07:52:59 +08:00
committed by GitHub
parent f11383f7d9
commit 64118e947e
2 changed files with 114 additions and 39 deletions
+5 -1
View File
@@ -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
View File
@@ -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")
}
}