diff --git a/cmd/climc/shell/disks.go b/cmd/climc/shell/disks.go index 4d5ccbde7d..e802a77279 100644 --- a/cmd/climc/shell/disks.go +++ b/cmd/climc/shell/disks.go @@ -208,12 +208,16 @@ func init() { return nil }) type DiskResetOptions struct { - DISK string `help:"ID or name of disk"` - SNAPSHOT string `help:"snapshots ID of disk` + DISK string `help:"ID or name of disk"` + SNAPSHOT string `help:"snapshots ID of disk` + AutoStart bool `help:"Autostart guest"` } R(&DiskResetOptions{}, "disk-reset", "Resize a disk", func(s *mcclient.ClientSession, args *DiskResetOptions) error { params := jsonutils.NewDict() params.Add(jsonutils.NewString(args.SNAPSHOT), "snapshot_id") + if args.AutoStart { + params.Add(jsonutils.JSONTrue, "auto_start") + } disk, err := modules.Disks.PerformAction(s, args.DISK, "disk-reset", params) if err != nil { return err diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 5cc92da4f2..c5d872f206 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -38,6 +38,7 @@ const ( DISK_STARTALLOC = "start_alloc" DISK_ALLOCATING = "allocating" DISK_READY = "ready" + DISK_RESET = "reset" DISK_DEALLOC = "deallocating" DISK_DEALLOC_FAILED = "dealloc_failed" DISK_UNKNOWN = "unknown" @@ -391,10 +392,8 @@ func (self *SDisk) CleanUpDiskSnapshots(ctx context.Context, userCred mcclient.T convertSnapshots := jsonutils.NewArray() deleteSnapshots := jsonutils.NewArray() for i := 0; i < len(dest); i++ { - if dest[i].CreatedBy == MANUAL && !dest[i].FakeDeleted { - if !dest[i].OutOfChain { - convertSnapshots.Add(jsonutils.NewString(dest[i].Id)) - } + if !dest[i].FakeDeleted && !dest[i].OutOfChain { + convertSnapshots.Add(jsonutils.NewString(dest[i].Id)) } else { deleteSnapshots.Add(jsonutils.NewString(dest[i].Id)) } @@ -416,6 +415,9 @@ func (self *SDisk) AllowPerformDiskReset(ctx context.Context, userCred mcclient. } func (self *SDisk) PerformDiskReset(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if self.Status != DISK_READY { + return nil, httperrors.NewInvalidStatusError("Cannot reset disk in status %s", self.Status) + } snapshotId, err := data.GetString("snapshot_id") if err != nil { return nil, err @@ -436,13 +438,16 @@ func (self *SDisk) PerformDiskReset(ctx context.Context, userCred mcclient.Token if snapshot.Status != SNAPSHOT_READY { return nil, httperrors.NewBadRequestError("Cannot reset disk with snapshot in status %s", snapshot.Status) } - self.StartResetDisk(ctx, userCred, snapshotId) + autoStart := jsonutils.QueryBoolean(data, "auto_start", false) + self.StartResetDisk(ctx, userCred, snapshotId, autoStart) return nil, nil } -func (self *SDisk) StartResetDisk(ctx context.Context, userCred mcclient.TokenCredential, snapshotId string) error { +func (self *SDisk) StartResetDisk(ctx context.Context, userCred mcclient.TokenCredential, snapshotId string, autoStart bool) error { + self.SetStatus(userCred, DISK_RESET, "") params := jsonutils.NewDict() params.Set("snapshot_id", jsonutils.NewString(snapshotId)) + params.Set("auto_start", jsonutils.NewBool(autoStart)) task, err := taskman.TaskManager.NewTask(ctx, "DiskResetTask", self, userCred, params, "", "", nil) if err != nil { return err @@ -1249,7 +1254,7 @@ func (manager *SDiskManager) AutoDiskSnapshot(ctx context.Context, userCred mccl continue } // name - name := guests[0].Name + time.Now().Format("2006-01-02#15:04:05") + name := "Auto-" + guests[0].Name + time.Now().Format("2006-01-02#15:04:05") snap, err := SnapshotManager.CreateSnapshot(ctx, userCred, AUTO, disk.Id, guests[0].Id, "", name) if err != nil { log.Errorln(err) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 7d53b31407..2972098f76 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -555,7 +555,7 @@ func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.To err = self.checkUpdateQuota(ctx, userCred, vcpuCount, vmemSize) if err != nil { - return nil, err + return nil, httperrors.NewOutOfQuotaError(err.Error()) } if data.Contains("name") { diff --git a/pkg/compute/models/quotas.go b/pkg/compute/models/quotas.go index ad73a7a1c9..152095735e 100644 --- a/pkg/compute/models/quotas.go +++ b/pkg/compute/models/quotas.go @@ -7,9 +7,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/pkg/tristate" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/pkg/tristate" ) var QuotaManager *quotas.SQuotaManager @@ -278,7 +278,7 @@ func (self *SQuota) Exceed(request quotas.IQuota, quota quotas.IQuota) error { if sreq.IsolatedDevice > 0 && self.IsolatedDevice > squota.IsolatedDevice { return ErrOutOfIsolatedDevice } - if self.Snapshot > squota.Snapshot { + if sreq.Snapshot > 0 && self.Snapshot > squota.Snapshot { return ErrOutOfSnapshot } return nil diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index 43ed994217..02d1011d94 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -89,6 +89,32 @@ func (manager *SSnapshotManager) ListItemFilter(ctx context.Context, q *sqlchemy return q, nil } +func (self *SSnapshot) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + extra := self.SVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query) + return self.getMoreDetails(extra) +} + +func (self *SSnapshot) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + extra := self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query) + return self.getMoreDetails(extra) +} + +func (self *SSnapshot) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict { + disk, _ := self.GetDisk() + if disk != nil { + extra.Add(jsonutils.NewString(disk.DiskType), "disk_type") + guests := disk.GetGuests() + if len(guests) == 1 { + extra.Add(jsonutils.NewString(guests[0].Id), "guest") + extra.Add(jsonutils.NewString(guests[0].Status), "guest_status") + } + } + if cloudprovider := self.GetCloudprovider(); cloudprovider != nil { + extra.Add(jsonutils.NewString(cloudprovider.Provider), "provider") + } + return extra +} + func (self *SSnapshot) AllowCreateItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { return false } diff --git a/pkg/compute/tasks/disk_reset_task.go b/pkg/compute/tasks/disk_reset_task.go index 1d74fd1ae3..7f3ac4cc63 100644 --- a/pkg/compute/tasks/disk_reset_task.go +++ b/pkg/compute/tasks/disk_reset_task.go @@ -25,11 +25,13 @@ func (self *DiskResetTask) OnInit(ctx context.Context, obj db.IStandaloneModel, disk := obj.(*models.SDisk) storage := disk.GetStorage() if storage == nil { + disk.SetStatus(self.UserCred, models.DISK_READY, "") self.SetStageFailed(ctx, "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") return } @@ -39,6 +41,7 @@ func (self *DiskResetTask) OnInit(ctx context.Context, obj db.IStandaloneModel, func (self *DiskResetTask) RequestResetDisk(ctx context.Context, disk *models.SDisk, host *models.SHost) { 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())) return } @@ -58,6 +61,7 @@ func (self *DiskResetTask) RequestResetDisk(ctx context.Context, disk *models.SD self.SetStage("OnRequestResetDisk", nil) err = host.GetHostDriver().RequestResetDisk(ctx, host, disk, params, self) if err != nil { + disk.SetStatus(self.UserCred, models.DISK_READY, "") self.SetStageFailed(ctx, err.Error()) } } @@ -83,6 +87,18 @@ func (self *DiskResetTask) OnRequestResetDisk(ctx context.Context, disk *models. return } } + if jsonutils.QueryBoolean(self.Params, "auto_start", false) { + guest := disk.GetGuests()[0] + self.SetStage("OnStartGuest", nil) + guest.StartGueststartTask(ctx, self.UserCred, nil, self.GetTaskId()) + } else { + disk.SetStatus(self.UserCred, models.DISK_READY, "") + self.SetStageComplete(ctx, 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) } diff --git a/pkg/mcclient/modules/mod_snapshots.go b/pkg/mcclient/modules/mod_snapshots.go index 8def8e7e3f..edb86378c1 100644 --- a/pkg/mcclient/modules/mod_snapshots.go +++ b/pkg/mcclient/modules/mod_snapshots.go @@ -8,7 +8,7 @@ func init() { Snapshots = NewComputeManager("snapshot", "snapshots", []string{"ID", "Name", "Size", "Status", "Disk_id", "Guest_id", "Created_at"}, - []string{"Storage_id", "Create_by", "Location", "Out_of_chain"}) + []string{"Storage_id", "Create_by", "Location", "Out_of_chain", "disk_type", "provider"}) registerCompute(&Snapshots) }