Merge pull request #3578 from ioito/hotfix/qx-dbinstance-privilege

fix: 创建数据库时指定账号权限时,避免数据库出现中间状态
This commit is contained in:
yunion-ci-robot
2019-11-13 20:31:21 +08:00
committed by GitHub
8 changed files with 193 additions and 53 deletions
+64
View File
@@ -0,0 +1,64 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/modules"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
func init() {
type DBInstanceAccountListOptions struct {
options.BaseListOptions
DBInstance string `help:"ID or Name of DBInstance" json:"dbinstance"`
}
R(&DBInstanceAccountListOptions{}, "dbinstance-account-list", "List DB instance accounts", func(s *mcclient.ClientSession, opts *DBInstanceAccountListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
result, err := modules.DBInstanceAccounts.List(s, params)
if err != nil {
return err
}
printList(result, modules.DBInstanceAccounts.GetColumns(s))
return nil
})
type DBInstanceAccountIdOptions struct {
ID string `help:"ID or Name of DBInstanceaccount"`
}
R(&DBInstanceAccountIdOptions{}, "dbinstance-account-show", "Show DB instance account", func(s *mcclient.ClientSession, opts *DBInstanceAccountIdOptions) error {
account, err := modules.DBInstanceAccounts.Get(s, opts.ID, nil)
if err != nil {
return err
}
printObject(account)
return nil
})
R(&DBInstanceAccountIdOptions{}, "dbinstance-account-delete", "Delete DB instance account", func(s *mcclient.ClientSession, opts *DBInstanceAccountIdOptions) error {
account, err := modules.DBInstanceAccounts.Delete(s, opts.ID, nil)
if err != nil {
return err
}
printObject(account)
return nil
})
}
+17 -31
View File
@@ -312,37 +312,6 @@ func init() {
return nil
})
type DBInstanceAccountListOptions struct {
options.BaseListOptions
DBInstance string `help:"ID or Name of DBInstance" json:"dbinstance"`
}
R(&DBInstanceAccountListOptions{}, "dbinstance-account-list", "List DB instance accounts", func(s *mcclient.ClientSession, opts *DBInstanceAccountListOptions) error {
params, err := options.ListStructToParams(opts)
if err != nil {
return err
}
result, err := modules.DBInstanceAccounts.List(s, params)
if err != nil {
return err
}
printList(result, modules.DBInstanceAccounts.GetColumns(s))
return nil
})
type DBInstanceAccountIdOptions struct {
ID string `help:"ID or Name of DBInstanceaccount"`
}
R(&DBInstanceAccountIdOptions{}, "dbinstance-account-show", "Show DB instance account", func(s *mcclient.ClientSession, opts *DBInstanceAccountIdOptions) error {
account, err := modules.DBInstanceAccounts.Get(s, opts.ID, nil)
if err != nil {
return err
}
printObject(account)
return nil
})
type DBInstancePrivilegeListOptions struct {
options.BaseListOptions
DBInstanceaccount string `help:"ID or Name of DBInstanceaccount" json:"dbinstanceaccount"`
@@ -362,4 +331,21 @@ func init() {
return nil
})
type DBInstanceChangeOwnerOptions struct {
ID string `help:"DBInstance to change owner" json:"-"`
PROJECT string `help:"Project ID or change" json:"tenant"`
}
R(&DBInstanceChangeOwnerOptions{}, "dbinstance-change-owner", "Change owner porject of a dbinstance", func(s *mcclient.ClientSession, opts *DBInstanceChangeOwnerOptions) error {
params, err := options.StructToParams(opts)
if err != nil {
return err
}
result, err := modules.DBInstance.PerformAction(s, opts.ID, "change-owner", params)
if err != nil {
return err
}
printObject(result)
return nil
})
}
+6 -5
View File
@@ -56,11 +56,12 @@ const (
BACKUP_MODE_MANUAL = "manual" //手动
//实例数据库状态
DBINSTANCE_DATABASE_CREATING = "creating" //创建中
DBINSTANCE_DATABASE_CREATE_FAILE = "create_failed" //创建失败
DBINSTANCE_DATABASE_RUNNING = "running" //正常
DBINSTANCE_DATABASE_DELETING = "deleting" //删除
DBINSTANCE_DATABASE_DELETE_FAILED = "delete_failed" //删除失败
DBINSTANCE_DATABASE_CREATING = "creating" //创建中
DBINSTANCE_DATABASE_CREATE_FAILE = "create_failed" //创建失败
DBINSTANCE_DATABASE_RUNNING = "running" //正常
DBINSTANCE_DATABASE_GRANT_PRIVILEGE = "grant_privilege" //赋予权限
DBINSTANCE_DATABASE_DELETING = "deleting" //删除
DBINSTANCE_DATABASE_DELETE_FAILED = "delete_failed" //删除失败
//实例用户状态
DBINSTANCE_USER_UNAVAILABLE = "unavailable" //不可用
+1 -1
View File
@@ -18,7 +18,7 @@ import "yunion.io/x/onecloud/pkg/apis"
type SDBInstanceDatabasePrivilege struct {
Account string
DBInstancedccountId string
DBInstanceaccountId string
Privilege string
}
+10 -1
View File
@@ -138,7 +138,7 @@ func (manager *SDBInstanceDatabaseManager) ValidateCreateData(ctx context.Contex
if err != nil {
return nil, httperrors.NewInputParameterError("failed to found dbinstance %s(%s) account %s: %v", instance.Name, instance.Id, _account.Account, err)
}
input.Accounts[i].DBInstancedccountId = account.Id
input.Accounts[i].DBInstanceaccountId = account.Id
}
input, err = region.GetDriver().ValidateCreateDBInstanceDatabaseData(ctx, userCred, ownerId, instance, input)
@@ -178,6 +178,15 @@ func (self *SDBInstanceDatabase) GetDBInstance() (*SDBInstance, error) {
return instance.(*SDBInstance), nil
}
func (self *SDBInstanceDatabase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
extra, err := self.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query)
if err != nil {
return nil, err
}
return self.getMoreDetails(ctx, userCred, extra)
}
func (self *SDBInstanceDatabase) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := self.SVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query)
extra, _ = self.getMoreDetails(ctx, userCred, extra)
@@ -16,6 +16,7 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
@@ -72,13 +73,58 @@ func (self *DBInstanceAccountCreateTask) CreateDBInstanceAccount(ctx context.Con
return
}
account.SetStatus(self.UserCred, api.DBINSTANCE_USER_AVAILABLE, "")
input := api.SDBInstanceAccountCreateInput{}
self.GetParams().Unmarshal(&input)
for _, _privilege := range input.Privileges {
account.StartGrantPrivilegeTask(ctx, self.UserCred, _privilege.Database, _privilege.Privilege, "")
if len(input.Privileges) == 0 {
account.SetStatus(self.UserCred, api.DBINSTANCE_USER_AVAILABLE, "")
self.SetStageComplete(ctx, nil)
return
}
iAccounts, err := iRds.GetIDBInstanceAccounts()
if err != nil {
msg := fmt.Sprintf("failed to found accounts from cloud dbinstance error: %v", err)
db.OpsLog.LogEvent(account, db.ACT_GRANT_PRIVILEGE, msg, self.GetUserCred())
logclient.AddActionLogWithStartable(self, account, logclient.ACT_GRANT_PRIVILEGE, msg, self.UserCred, false)
account.SetStatus(self.UserCred, api.DBINSTANCE_USER_AVAILABLE, "")
self.SetStageComplete(ctx, nil)
return
}
var iAccount cloudprovider.ICloudDBInstanceAccount = nil
for i := range iAccounts {
if iAccounts[i].GetName() == account.Name {
iAccount = iAccounts[i]
break
}
}
if iAccount == nil {
msg := fmt.Sprintf("failed to found account %s from cloud dbinstance", account.Name)
db.OpsLog.LogEvent(account, db.ACT_GRANT_PRIVILEGE, msg, self.GetUserCred())
logclient.AddActionLogWithStartable(self, account, logclient.ACT_GRANT_PRIVILEGE, msg, self.UserCred, false)
account.SetStatus(self.UserCred, api.DBINSTANCE_USER_AVAILABLE, "")
self.SetStageComplete(ctx, nil)
return
}
account.SetStatus(self.UserCred, api.DBINSTANCE_USER_GRANT_PRIVILEGE, "")
for _, privilege := range input.Privileges {
err = iAccount.GrantPrivilege(privilege.Database, privilege.Privilege)
if err != nil {
db.OpsLog.LogEvent(account, db.ACT_GRANT_PRIVILEGE, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, account, logclient.ACT_GRANT_PRIVILEGE, err, self.UserCred, false)
continue
}
_privilege := models.SDBInstancePrivilege{
Privilege: privilege.Privilege,
DBInstanceaccountId: account.Id,
DBInstancedatabaseId: privilege.DBInstancedatabaseId,
}
models.DBInstancePrivilegeManager.TableSpec().Insert(&_privilege)
logclient.AddActionLogWithStartable(self, account, logclient.ACT_GRANT_PRIVILEGE, privilege, self.UserCred, true)
}
account.SetStatus(self.UserCred, api.DBINSTANCE_USER_AVAILABLE, "")
self.SetStageComplete(ctx, nil)
}
@@ -16,9 +16,9 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -74,18 +74,52 @@ func (self *DBInstanceDatabaseCreateTask) CreateDBInstanceDatabase(ctx context.C
return
}
database.SetStatus(self.UserCred, api.DBINSTANCE_DATABASE_RUNNING, "")
input := api.SDBInstanceDatabaseCreateInput{}
self.GetParams().Unmarshal(&input)
for _, _account := range input.Accounts {
account, err := instance.GetDBInstanceAccount(_account.DBInstancedccountId)
if err != nil {
log.Errorf("failed to found account %s(%s) for instance %s(%s) error: %v", _account.Account, _account.DBInstancedccountId, instance.Name, instance.Id, err)
} else {
account.StartGrantPrivilegeTask(ctx, self.UserCred, database.Name, _account.Privilege, "")
}
if len(input.Accounts) == 0 {
database.SetStatus(self.UserCred, api.DBINSTANCE_DATABASE_RUNNING, "")
self.SetStageComplete(ctx, nil)
return
}
_iAccounts, err := iRds.GetIDBInstanceAccounts()
if err != nil {
msg := fmt.Sprintf("failed to found accounts from cloud dbinstance error: %v", err)
db.OpsLog.LogEvent(database, db.ACT_GRANT_PRIVILEGE, msg, self.GetUserCred())
logclient.AddActionLogWithStartable(self, database, logclient.ACT_GRANT_PRIVILEGE, msg, self.UserCred, false)
database.SetStatus(self.UserCred, api.DBINSTANCE_DATABASE_RUNNING, "")
self.SetStageComplete(ctx, nil)
return
}
database.SetStatus(self.UserCred, api.DBINSTANCE_DATABASE_GRANT_PRIVILEGE, "")
iAccounts := map[string]cloudprovider.ICloudDBInstanceAccount{}
for _, iAccount := range _iAccounts {
iAccounts[iAccount.GetName()] = iAccount
}
for _, account := range input.Accounts {
iAccount, ok := iAccounts[account.Account]
if !ok {
msg := fmt.Sprintf("failed to found account %s from dbinstance", account.Account)
db.OpsLog.LogEvent(database, db.ACT_GRANT_PRIVILEGE, msg, self.GetUserCred())
logclient.AddActionLogWithStartable(self, database, logclient.ACT_GRANT_PRIVILEGE, msg, self.UserCred, false)
continue
}
err = iAccount.GrantPrivilege(database.Name, account.Privilege)
if err != nil {
db.OpsLog.LogEvent(database, db.ACT_GRANT_PRIVILEGE, err, self.GetUserCred())
logclient.AddActionLogWithStartable(self, database, logclient.ACT_GRANT_PRIVILEGE, err, self.UserCred, false)
continue
}
privilege := models.SDBInstancePrivilege{
Privilege: account.Privilege,
DBInstanceaccountId: account.DBInstanceaccountId,
DBInstancedatabaseId: database.Id,
}
models.DBInstancePrivilegeManager.TableSpec().Insert(&privilege)
logclient.AddActionLogWithStartable(self, database, logclient.ACT_GRANT_PRIVILEGE, account, self.UserCred, true)
}
database.SetStatus(self.UserCred, api.DBINSTANCE_DATABASE_RUNNING, "")
self.SetStageComplete(ctx, nil)
}
@@ -63,7 +63,7 @@ func init() {
AccountType string `help:"account type" choices:"Normal|Super" default:"Normal"`
}
shellutils.R(&DBInstanceAccountResetOptions{}, "dbinstance-account-delete", "Delete dbintance account", func(cli *aliyun.SRegion, args *DBInstanceAccountResetOptions) error {
shellutils.R(&DBInstanceAccountResetOptions{}, "dbinstance-account-reset-password", "Reset dbintance account password", func(cli *aliyun.SRegion, args *DBInstanceAccountResetOptions) error {
return cli.ResetDBInstanceAccountPassword(args.INSTANCE, args.NAME, args.PASSWORD, args.AccountType)
})