diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 2d033e8475..55f2c5c2ee 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -3959,7 +3959,7 @@ func (self *SGuest) PerformDiskSnapshot(ctx context.Context, userCred mcclient.T if err != nil { return nil, httperrors.NewBadRequestError(err.Error()) } - err = ValidateSnapshotName(self.Hypervisor, name) + err = ValidateSnapshotName(self.Hypervisor, name, userCred.GetProjectId()) if err != nil { return nil, httperrors.NewBadRequestError(err.Error()) } @@ -3967,16 +3967,12 @@ func (self *SGuest) PerformDiskSnapshot(ctx context.Context, userCred mcclient.T return nil, httperrors.NewNotFoundError("Guest disk %s not found", diskId) } if self.GetHypervisor() == HYPERVISOR_KVM { - snapshots := SnapshotManager.GetDiskSnapshotsByCreate(diskId, MANUAL) - if snapshots != nil { - if len(snapshots) >= options.Options.DefaultMaxManualSnapshotCount { - return nil, httperrors.NewBadRequestError("Disk %s snapshot full, cannot take any more", diskId) - } - for _, snapshot := range snapshots { - if snapshot.Name == name { - return nil, httperrors.NewBadRequestError("Name Conflict") - } - } + q := SnapshotManager.Query() + cnt := q.Filter(sqlchemy.AND(sqlchemy.Equals(q.Field("disk_id"), diskId), + sqlchemy.Equals(q.Field("created_by"), MANUAL), + sqlchemy.Equals(q.Field("fake_deleted"), false))).Count() + if cnt >= options.Options.DefaultMaxManualSnapshotCount { + return nil, httperrors.NewBadRequestError("Disk %s snapshot full, cannot take any more", diskId) } pendingUsage := &SQuota{Snapshot: 1} err = QuotaManager.CheckSetPendingQuota(ctx, userCred, self.ProjectId, pendingUsage) diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index 9d2445cd08..23d82a49fb 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -58,7 +58,13 @@ func init() { SnapshotManager = &SSnapshotManager{SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(SSnapshot{}, "snapshots_tbl", "snapshot", "snapshots")} } -func ValidateSnapshotName(hypervisor, name string) error { +func ValidateSnapshotName(hypervisor, name, owner string) error { + q := SnapshotManager.Query() + q = SnapshotManager.FilterByName(q, name) + q = SnapshotManager.FilterByOwner(q, owner) + if q.Count() != 0 { + return fmt.Errorf("Name conflict?") + } if !('A' <= name[0] && name[0] <= 'Z' || 'a' <= name[0] && name[0] <= 'z') { return fmt.Errorf("Name must start with letter") } diff --git a/pkg/compute/tasks/disk_reset_task.go b/pkg/compute/tasks/disk_reset_task.go index 7f3ac4cc63..25d296f5d7 100644 --- a/pkg/compute/tasks/disk_reset_task.go +++ b/pkg/compute/tasks/disk_reset_task.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type DiskResetTask struct { @@ -21,18 +22,28 @@ func init() { taskman.RegisterTask(DiskCleanUpSnapshotsTask{}) } +func (self *DiskResetTask) TaskFailed(ctx context.Context, disk *models.SDisk, reason string) { + logclient.AddActionLog(disk, logclient.ACT_RESET_DISK, reason, self.UserCred, false) + self.SetStageFailed(ctx, reason) +} + +func (self *DiskResetTask) TaskCompleted(ctx context.Context, disk *models.SDisk, data *jsonutils.JSONDict) { + logclient.AddActionLog(disk, logclient.ACT_RESET_DISK, data, self.UserCred, true) + self.SetStageComplete(ctx, data) +} + func (self *DiskResetTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { disk := obj.(*models.SDisk) storage := disk.GetStorage() if storage == nil { disk.SetStatus(self.UserCred, models.DISK_READY, "") - self.SetStageFailed(ctx, "Disk storage not found") + self.TaskFailed(ctx, disk, "Disk storage not found") return } host := storage.GetMasterHost() if host == nil { disk.SetStatus(self.UserCred, models.DISK_READY, "") - self.SetStageFailed(ctx, "Storage master host not found") + self.TaskFailed(ctx, disk, "Storage master host not found") return } self.RequestResetDisk(ctx, disk, host) @@ -42,7 +53,7 @@ func (self *DiskResetTask) RequestResetDisk(ctx context.Context, disk *models.SD snapshotId, err := self.Params.GetString("snapshot_id") if err != nil { disk.SetStatus(self.UserCred, models.DISK_READY, "") - self.SetStageFailed(ctx, fmt.Sprintf("Get snapshotId error %s", err.Error())) + self.TaskFailed(ctx, disk, fmt.Sprintf("Get snapshotId error %s", err.Error())) return } iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId) @@ -62,7 +73,7 @@ func (self *DiskResetTask) RequestResetDisk(ctx context.Context, disk *models.SD err = host.GetHostDriver().RequestResetDisk(ctx, host, disk, params, self) if err != nil { disk.SetStatus(self.UserCred, models.DISK_READY, "") - self.SetStageFailed(ctx, err.Error()) + self.TaskFailed(ctx, disk, err.Error()) } } @@ -83,7 +94,7 @@ func (self *DiskResetTask) OnRequestResetDisk(ctx context.Context, disk *models. err := disk.CleanUpDiskSnapshots(ctx, self.UserCred, snapshot) if err != nil { log.Errorln(err) - self.SetStageFailed(ctx, fmt.Sprintf("OnRequestResetDisk %s", err.Error())) + self.TaskFailed(ctx, disk, fmt.Sprintf("OnRequestResetDisk %s", err.Error())) return } } @@ -93,13 +104,13 @@ func (self *DiskResetTask) OnRequestResetDisk(ctx context.Context, disk *models. guest.StartGueststartTask(ctx, self.UserCred, nil, self.GetTaskId()) } else { disk.SetStatus(self.UserCred, models.DISK_READY, "") - self.SetStageComplete(ctx, nil) + self.TaskCompleted(ctx, disk, nil) } } func (self *DiskResetTask) OnStartGuest(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) { disk.SetStatus(self.UserCred, models.DISK_READY, "") - self.SetStageComplete(ctx, nil) + self.TaskCompleted(ctx, disk, nil) } type DiskCleanUpSnapshotsTask struct { diff --git a/pkg/compute/tasks/disk_resize_task.go b/pkg/compute/tasks/disk_resize_task.go index dd25da5879..3fff258569 100644 --- a/pkg/compute/tasks/disk_resize_task.go +++ b/pkg/compute/tasks/disk_resize_task.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type DiskResizeTask struct { @@ -30,11 +31,12 @@ func (self *DiskResizeTask) OnInit(ctx context.Context, obj db.IStandaloneModel, host = guest.GetHost() } } - resion := "Cannot find host for disk" + reason := "Cannot find host for disk" if host == nil || host.HostStatus != models.HOST_ONLINE { - disk.SetDiskReady(ctx, self.GetUserCred(), resion) - self.SetStageFailed(ctx, resion) - db.OpsLog.LogEvent(disk, db.ACT_RESIZE_FAIL, resion, self.GetUserCred()) + disk.SetDiskReady(ctx, self.GetUserCred(), reason) + self.SetStageFailed(ctx, reason) + db.OpsLog.LogEvent(disk, db.ACT_RESIZE_FAIL, reason, self.GetUserCred()) + logclient.AddActionLog(disk, logclient.ACT_RESIZE, reason, self.UserCred, false) } else { disk.SetStatus(self.GetUserCred(), models.DISK_START_RESIZE, "") for _, guest := range disk.GetGuests() { @@ -64,10 +66,11 @@ func (self *DiskResizeTask) OnStartResizeDiskSucc(ctx context.Context, disk *mod disk.SetStatus(self.GetUserCred(), models.DISK_RESIZING, "") } -func (self *DiskResizeTask) OnStartResizeDiskFailed(ctx context.Context, disk *models.SDisk, resion error) { - disk.SetDiskReady(ctx, self.GetUserCred(), resion.Error()) - self.SetStageFailed(ctx, resion.Error()) - db.OpsLog.LogEvent(disk, db.ACT_RESIZE_FAIL, resion.Error(), self.GetUserCred()) +func (self *DiskResizeTask) OnStartResizeDiskFailed(ctx context.Context, disk *models.SDisk, reason error) { + disk.SetDiskReady(ctx, self.GetUserCred(), reason.Error()) + self.SetStageFailed(ctx, reason.Error()) + db.OpsLog.LogEvent(disk, db.ACT_RESIZE_FAIL, reason.Error(), self.GetUserCred()) + logclient.AddActionLog(disk, logclient.ACT_RESIZE, reason.Error(), self.UserCred, false) } func (self *DiskResizeTask) OnDiskResizeComplete(ctx context.Context, disk *models.SDisk, data jsonutils.JSONObject) { @@ -99,11 +102,13 @@ func (self *DiskResizeTask) OnDiskResizeComplete(ctx context.Context, disk *mode db.OpsLog.LogEvent(disk, db.ACT_UPDATE_STATUS, notes, self.UserCred) self.CleanHostSchedCache(disk) db.OpsLog.LogEvent(disk, db.ACT_RESIZE, disk.GetShortDesc(), self.UserCred) + logclient.AddActionLog(disk, logclient.ACT_RESIZE, nil, self.UserCred, true) self.SetStageComplete(ctx, disk.GetShortDesc()) self.finalReleasePendingUsage(ctx) } -func (self *DiskResizeTask) OnDiskResizeCompleteFailed(ctx context.Context, disk *models.SDisk, resion error) { - disk.SetDiskReady(ctx, self.GetUserCred(), resion.Error()) +func (self *DiskResizeTask) OnDiskResizeCompleteFailed(ctx context.Context, disk *models.SDisk, reason error) { + disk.SetDiskReady(ctx, self.GetUserCred(), reason.Error()) db.OpsLog.LogEvent(disk, db.ACT_RESIZE_FAIL, disk.GetShortDesc(), self.UserCred) + logclient.AddActionLog(disk, logclient.ACT_RESIZE, reason.Error(), self.UserCred, false) } diff --git a/pkg/compute/tasks/guest_disk_snapshot_task.go b/pkg/compute/tasks/guest_disk_snapshot_task.go index 9cce3fde54..9c9e7aa7ea 100644 --- a/pkg/compute/tasks/guest_disk_snapshot_task.go +++ b/pkg/compute/tasks/guest_disk_snapshot_task.go @@ -12,6 +12,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" + "yunion.io/x/onecloud/pkg/util/logclient" ) type GuestDiskSnapshotTask struct { @@ -103,6 +104,10 @@ func (self *GuestDiskSnapshotTask) TaskComplete(ctx context.Context, guest *mode } func (self *GuestDiskSnapshotTask) OnSyncStatus(ctx context.Context, guest *models.SGuest, data jsonutils.JSONObject) { + snapshotId, _ := self.Params.GetString("snapshot_id") + iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId) + db.OpsLog.LogEvent(iSnapshot, db.ACT_SNAPSHOT_DONE, nil, self.UserCred) + logclient.AddActionLog(iSnapshot, logclient.ACT_CREATE, nil, self.UserCred, true) self.SetStageComplete(ctx, nil) } @@ -116,6 +121,8 @@ func (self *GuestDiskSnapshotTask) TaskFailed(ctx context.Context, guest *models }) self.SetStageFailed(ctx, reason) guest.SetStatus(self.UserCred, models.VM_SNAPSHOT_FAILED, reason) + db.OpsLog.LogEvent(iSnapshot, db.ACT_SNAPSHOT_FAIL, reason, self.UserCred) + logclient.AddActionLog(iSnapshot, logclient.ACT_CREATE, reason, self.UserCred, false) } /***************************** Snapshot Delete Task *****************************/ @@ -289,6 +296,8 @@ func (self *SnapshotDeleteTask) OnReloadDiskSnapshot(ctx context.Context, snapsh } func (self *SnapshotDeleteTask) TaskComplete(ctx context.Context, snapshot *models.SSnapshot, data jsonutils.JSONObject) { + db.OpsLog.LogEvent(snapshot, db.ACT_SNAPSHOT_DELETE, nil, self.UserCred) + logclient.AddActionLog(snapshot, logclient.ACT_DELETE, nil, self.UserCred, true) self.SetStageComplete(ctx, nil) } diff --git a/pkg/util/aliyun/snapshot.go b/pkg/util/aliyun/snapshot.go index fc1ee257bc..e0cada0372 100644 --- a/pkg/util/aliyun/snapshot.go +++ b/pkg/util/aliyun/snapshot.go @@ -15,6 +15,9 @@ const ( SnapshotStatusAccomplished SnapshotStatusType = "accomplished" SnapshotStatusProgress SnapshotStatusType = "progressing" SnapshotStatusFailed SnapshotStatusType = "failed" + + SnapshotTypeSystem string = "System" + SnapshotTypeData string = "Data" ) type SSnapshot struct { @@ -65,7 +68,13 @@ func (self *SSnapshot) GetDiskId() string { } func (self *SSnapshot) GetDiskType() string { - return self.SourceDiskType + if self.SourceDiskType == SnapshotTypeSystem { + return models.DISK_TYPE_SYS + } else if self.SourceDiskType == SnapshotTypeData { + return models.DISK_TYPE_DATA + } else { + return "" + } } func (self *SSnapshot) Refresh() error { diff --git a/pkg/util/logclient/logclient.go b/pkg/util/logclient/logclient.go index 76796053e3..6e15876f66 100644 --- a/pkg/util/logclient/logclient.go +++ b/pkg/util/logclient/logclient.go @@ -56,6 +56,7 @@ const ( ACT_VM_SYNC_STATUS = "同步状态" ACT_VM_UNBIND_KEYPAIR = "解绑密钥" ACT_VM_ASSIGNSECGROUP = "关联安全组" + ACT_RESET_DISK = "回滚磁盘" ) // golang 不支持 const 的string array, http://t.cn/EzAvbw8