Merge pull request #919 in YUNIONIO/onecloud from ~QIUJIAN/onecloud:hotfix/qj-restrict-recycle-in-running-ready-status to release/2.5.0

* commit 'caa7b8f25ad2c21afeaa4bcdebc875bad593e534':
  user-create default-project-id
  修正:1. 包年包月资源池添加和减少操作需要做状态检查 2. 同步时候忽略包年包月资源次的host和storage
This commit is contained in:
邱剑
2019-01-14 12:25:33 +08:00
7 changed files with 89 additions and 34 deletions
+15 -24
View File
@@ -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
})
+11
View File
@@ -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
+6
View File
@@ -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)
}
+2 -2
View File
@@ -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 {
+28 -3
View File
@@ -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)
+7
View File
@@ -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
}
+20 -5
View File
@@ -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()
}