From 706238404ed521dcbce40abf085449e64958f5a7 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Fri, 11 Jan 2019 21:13:40 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=EF=BC=9A1.=20=E5=8C=85?= =?UTF-8?q?=E5=B9=B4=E5=8C=85=E6=9C=88=E8=B5=84=E6=BA=90=E6=B1=A0=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=92=8C=E5=87=8F=E5=B0=91=E6=93=8D=E4=BD=9C=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E5=81=9A=E7=8A=B6=E6=80=81=E6=A3=80=E6=9F=A5=202.=20?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=97=B6=E5=80=99=E5=BF=BD=E7=95=A5=E5=8C=85?= =?UTF-8?q?=E5=B9=B4=E5=8C=85=E6=9C=88=E8=B5=84=E6=BA=90=E6=AC=A1=E7=9A=84?= =?UTF-8?q?host=E5=92=8Cstorage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/climc/shell/hosts.go | 39 ++++++++++---------------- pkg/cloudcommon/db/statusstandalone.go | 6 ++++ pkg/compute/models/disks.go | 4 +-- pkg/compute/models/host_recycle.go | 31 ++++++++++++++++++-- pkg/compute/models/hosts.go | 7 +++++ pkg/compute/models/storages.go | 25 +++++++++++++---- 6 files changed, 78 insertions(+), 34 deletions(-) diff --git a/cmd/climc/shell/hosts.go b/cmd/climc/shell/hosts.go index efdfa2fa06..3b7783bdbd 100644 --- a/cmd/climc/shell/hosts.go +++ b/cmd/climc/shell/hosts.go @@ -85,39 +85,30 @@ func init() { return nil }) - R(&HostDetailOptions{}, "host-enable", "Enable a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { - result, err := modules.Hosts.PerformAction(s, args.ID, "enable", nil) - if err != nil { - return err - } - printObject(result) + type HostOpsOptions struct { + ID []string `help:"ID or name of hosts"` + } + R(&HostOpsOptions{}, "host-enable", "Enable a host", func(s *mcclient.ClientSession, args *HostOpsOptions) error { + results := modules.Hosts.BatchPerformAction(s, args.ID, "enable", nil) + printBatchResults(results, modules.Hosts.GetColumns(s)) return nil }) - R(&HostDetailOptions{}, "host-disable", "Disable a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { - result, err := modules.Hosts.PerformAction(s, args.ID, "disable", nil) - if err != nil { - return err - } - printObject(result) + R(&HostOpsOptions{}, "host-disable", "Disable a host", func(s *mcclient.ClientSession, args *HostOpsOptions) error { + results := modules.Hosts.BatchPerformAction(s, args.ID, "disable", nil) + printBatchResults(results, modules.Hosts.GetColumns(s)) return nil }) - R(&HostDetailOptions{}, "host-syncstatus", "Synchronize status of a host", func(s *mcclient.ClientSession, args *HostDetailOptions) error { - result, err := modules.Hosts.PerformAction(s, args.ID, "syncstatus", nil) - if err != nil { - return err - } - printObject(result) + R(&HostOpsOptions{}, "host-syncstatus", "Synchronize status of a host", func(s *mcclient.ClientSession, args *HostOpsOptions) error { + results := modules.Hosts.BatchPerformAction(s, args.ID, "syncstatus", nil) + printBatchResults(results, modules.Hosts.GetColumns(s)) return nil }) - R(&HostDetailOptions{}, "host-prepare", "Prepare a host for installation", func(s *mcclient.ClientSession, args *HostDetailOptions) error { - result, err := modules.Hosts.PerformAction(s, args.ID, "prepare", nil) - if err != nil { - return err - } - printObject(result) + R(&HostOpsOptions{}, "host-prepare", "Prepare a host for installation", func(s *mcclient.ClientSession, args *HostOpsOptions) error { + results := modules.Hosts.BatchPerformAction(s, args.ID, "prepare", nil) + printBatchResults(results, modules.Hosts.GetColumns(s)) return nil }) diff --git a/pkg/cloudcommon/db/statusstandalone.go b/pkg/cloudcommon/db/statusstandalone.go index 5d3a6e66b3..ac6953e3cf 100644 --- a/pkg/cloudcommon/db/statusstandalone.go +++ b/pkg/cloudcommon/db/statusstandalone.go @@ -6,6 +6,8 @@ import ( "strings" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/utils" + "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" ) @@ -62,3 +64,7 @@ func (model *SStatusStandaloneResourceBase) PerformStatus(ctx context.Context, u err = model.SetStatus(userCred, status, reason) return nil, err } + +func (model *SStatusStandaloneResourceBase) IsInStatus(status ...string) bool { + return utils.IsInStringArray(model.Status, status) +} diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 8099a22623..396096eae8 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -1061,9 +1061,9 @@ func totalDiskSize(projectId string, active tristate.TriState, ready tristate.Tr q = q.Join(storages, sqlchemy.AND(sqlchemy.IsFalse(storages.Field("deleted")), sqlchemy.Equals(storages.Field("id"), disks.Field("storage_id")))) if active.IsTrue() { - q = q.Filter(sqlchemy.Equals(storages.Field("status"), STORAGE_ENABLED)) + q = q.Filter(sqlchemy.In(storages.Field("status"), []string{STORAGE_ENABLED, STORAGE_ONLINE})) } else { - q = q.Filter(sqlchemy.NotEquals(storages.Field("status"), STORAGE_ENABLED)) + q = q.Filter(sqlchemy.NotIn(storages.Field("status"), []string{STORAGE_ENABLED, STORAGE_ONLINE})) } } if len(projectId) > 0 { diff --git a/pkg/compute/models/host_recycle.go b/pkg/compute/models/host_recycle.go index ccef50735e..bfe77ace17 100644 --- a/pkg/compute/models/host_recycle.go +++ b/pkg/compute/models/host_recycle.go @@ -53,6 +53,9 @@ func (self *SGuest) CanPerformPrepaidRecycle() error { } func (self *SGuest) PerformPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if !self.IsInStatus(VM_READY, VM_RUNNING) { + return nil, httperrors.NewInvalidStatusError("cannot recycle in status %s", self.Status) + } err := self.CanPerformPrepaidRecycle() if err != nil { return nil, httperrors.NewInvalidStatusError(err.Error()) @@ -282,6 +285,10 @@ func (self *SGuest) AllowPerformUndoPrepaidRecycle(ctx context.Context, userCred } func (self *SGuest) PerformUndoPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if !self.IsInStatus(VM_READY, VM_RUNNING) { + return nil, httperrors.NewInvalidStatusError("cannot undo recycle in status %s", self.Status) + } + host := self.GetHost() if host == nil { @@ -296,7 +303,7 @@ func (self *SGuest) PerformUndoPrepaidRecycle(ctx context.Context, userCred mccl return nil, httperrors.NewInvalidStatusError("host is not a prepaid recycle host") } - err := doUndoPrepaidRecycle(ctx, userCred, host, self) + err := doUndoPrepaidRecycleLockHost(ctx, userCred, host, self) if err != nil { logclient.AddActionLog(self, logclient.ACT_UNDO_RECYCLE_PREPAID, self.GetShortDesc(ctx), userCred, false) return nil, httperrors.NewGeneralError(err) @@ -331,11 +338,15 @@ func (self *SHost) PerformUndoPrepaidRecycle(ctx context.Context, userCred mccli return nil, httperrors.NewInvalidStatusError("a recycle host shoud not allocate more than 1 guest") } + if !guests[0].IsInStatus(VM_READY, VM_RUNNING) { + return nil, httperrors.NewInvalidStatusError("cannot undo recycle in status %s", self.Status) + } + if guests[0].PendingDeleted { return nil, httperrors.NewInvalidStatusError("cannot undo a recycle host with pending_deleted guest") } - err := doUndoPrepaidRecycle(ctx, userCred, self, &guests[0]) + err := doUndoPrepaidRecycleLockGuest(ctx, userCred, self, &guests[0]) if err != nil { logclient.AddActionLog(self, logclient.ACT_UNDO_RECYCLE_PREPAID, self.GetShortDesc(ctx), userCred, false) return nil, httperrors.NewGeneralError(err) @@ -356,7 +367,21 @@ func findIdiskById(idisks []cloudprovider.ICloudDisk, uuid string) cloudprovider return nil } -func doUndoPrepaidRecycle(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, server *SGuest) error { +func doUndoPrepaidRecycleLockGuest(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, server *SGuest) error { + lockman.LockObject(ctx, server) + defer lockman.ReleaseObject(ctx, server) + + return doUndoPrepaidRecycleNoLock(ctx, userCred, host, server) +} + +func doUndoPrepaidRecycleLockHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, server *SGuest) error { + lockman.LockObject(ctx, host) + defer lockman.ReleaseObject(ctx, host) + + return doUndoPrepaidRecycleNoLock(ctx, userCred, host, server) +} + +func doUndoPrepaidRecycleNoLock(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, server *SGuest) error { if host.RealExternalId != server.ExternalId { msg := "host and server external id not match!!!!" log.Errorf(msg) diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index 61d54c04de..50becad1cd 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -1217,6 +1217,9 @@ func (manager *SHostManager) SyncHosts(ctx context.Context, userCred mcclient.To } for i := 0; i < len(removed); i += 1 { + if removed[i].IsPrepaidRecycleResource() { + continue + } err = removed[i].ValidateDeleteCondition(ctx) if err != nil { // cannot delete err = removed[i].SetStatus(userCred, HOST_OFFLINE, "sync to delete") @@ -3636,3 +3639,7 @@ func (manager *SHostManager) PingDetectionTask(ctx context.Context, userCred mcc host.MarkGuestUnknown(userCred) } } + +func (self *SHost) IsPrepaidRecycleResource() bool { + return self.ResourceType == HostResourceTypePrepaidRecycle +} diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index c2901beac0..e41f967318 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -65,10 +65,10 @@ const ( ) const ( - STORAGE_ENABLED = "enabled" - STORAGE_DISABLED = "disabled" - STORAGE_OFFLINE = "offline" - STORAGE_ONLINE = "online" + STORAGE_ENABLED = "enabled" + // STORAGE_DISABLED = "disabled" + STORAGE_OFFLINE = "offline" + STORAGE_ONLINE = "online" DISK_TYPE_ROTATE = "rotate" DISK_TYPE_SSD = "ssd" @@ -679,9 +679,13 @@ func (manager *SStorageManager) SyncStorages(ctx context.Context, userCred mccli } for i := 0; i < len(removed); i += 1 { + // may be a fake storage for prepaid recycle host + if removed[i].IsPrepaidRecycleResource() { + continue + } err = removed[i].ValidateDeleteCondition(ctx) if err != nil { // cannot delete - err = removed[i].SetStatus(userCred, STORAGE_DISABLED, "sync to delete") + err = removed[i].SetStatus(userCred, STORAGE_OFFLINE, "sync to delete") if err == nil { _, err = removed[i].PerformDisable(ctx, userCred, nil, nil) } @@ -1201,3 +1205,14 @@ func (self *SStorage) GetShortDesc(ctx context.Context) *jsonutils.JSONDict { desc.Update(jsonutils.Marshal(&info)) return desc } + +func (self *SStorage) IsPrepaidRecycleResource() bool { + if !self.IsLocal() { + return false + } + hosts := self.GetAttachedHosts() + if len(hosts) != 1 { + return false + } + return hosts[0].IsPrepaidRecycleResource() +} From caa7b8f25ad2c21afeaa4bcdebc875bad593e534 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Mon, 14 Jan 2019 12:24:54 +0800 Subject: [PATCH 2/2] user-create default-project-id --- cmd/climc/shell/users.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cmd/climc/shell/users.go b/cmd/climc/shell/users.go index b6b977e307..e5154134af 100644 --- a/cmd/climc/shell/users.go +++ b/cmd/climc/shell/users.go @@ -176,6 +176,8 @@ func init() { Mobile string `help:"Mobile"` Enabled bool `help:"Enabled"` Disabled bool `help:"Disabled"` + + DefaultProject string `help:"Default project"` } R(&UserCreateOptions{}, "user-create", "Create a user", func(s *mcclient.ClientSession, args *UserCreateOptions) error { mod, err := modules.GetModule(s, "users") @@ -211,6 +213,15 @@ func init() { } else if !args.Enabled && args.Disabled { params.Add(jsonutils.JSONFalse, "enabled") } + + if len(args.DefaultProject) > 0 { + projId, err := modules.Projects.GetId(s, args.DefaultProject, nil) + if err != nil { + return err + } + params.Add(jsonutils.NewString(projId), "default_project_id") + } + user, err := mod.Create(s, params) if err != nil { return err