Skip to content

Commit

Permalink
ddl: prevent dropping in-use resource group (#40716)
Browse files Browse the repository at this point in the history
ref #38825
  • Loading branch information
BornChanger committed Jan 19, 2023
1 parent efbdeed commit 280b773
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 2 deletions.
1 change: 1 addition & 0 deletions ddl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ go_library(
"//parser/opcode",
"//parser/terror",
"//parser/types",
"//privilege",
"//sessionctx",
"//sessionctx/binloginfo",
"//sessionctx/stmtctx",
Expand Down
12 changes: 12 additions & 0 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/pingcap/tidb/parser/mysql"
"github.com/pingcap/tidb/parser/terror"
field_types "github.com/pingcap/tidb/parser/types"
"github.com/pingcap/tidb/privilege"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/sessiontxn"
Expand Down Expand Up @@ -7668,6 +7669,17 @@ func (d *ddl) DropResourceGroup(ctx sessionctx.Context, stmt *ast.DropResourceGr
return err
}

// check to see if some user has dependency on the group
checker := privilege.GetPrivilegeManager(ctx)
if checker == nil {
return errors.New("miss privilege checker")
}
user, matched := checker.MatchUserResourceGroupName(groupName.L)
if matched {
err = errors.Errorf("user [%s] depends on the resource group to drop", user)
return err
}

job := &model.Job{
SchemaID: group.ID,
SchemaName: group.Name.L,
Expand Down
4 changes: 4 additions & 0 deletions ddl/resource_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ func TestResourceGroupBasic(t *testing.T) {
tk.MustGetErrCode("create user usr_fail resource group nil_group", mysql.ErrResourceGroupNotExists)
tk.MustExec("create user user2")
tk.MustGetErrCode("alter user user2 resource group nil_group", mysql.ErrResourceGroupNotExists)

tk.MustExec("create resource group do_not_delete_rg rru_per_sec=100 wru_per_sec=200")
tk.MustExec("create user usr3 resource group do_not_delete_rg")
tk.MustContainErrMsg("drop resource group do_not_delete_rg", "user [usr3] depends on the resource group to drop")
}

func testResourceGroupNameFromIS(t *testing.T, ctx sessionctx.Context, name string) *model.ResourceGroupInfo {
Expand Down
2 changes: 1 addition & 1 deletion errno/errname.go
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ var MySQLErrName = map[uint16]*mysql.ErrMessage{
ErrResourceGroupNotExists: mysql.Message("Unknown resource group '%-.192s'", nil),

ErrColumnInChange: mysql.Message("column %s id %d does not exist, this column may have been updated by other DDL ran in parallel", nil),
ErrResourceGroupSupportDisabled: mysql.Message("Resource group feature is disabled", nil),
ErrResourceGroupSupportDisabled: mysql.Message("Resource control feature is disabled. Run `SET GLOBAL tidb_enable_resource_control='on'` to enable the feature", nil),

// TiKV/PD errors.
ErrPDServerTimeout: mysql.Message("PD server timeout: %s", nil),
Expand Down
2 changes: 1 addition & 1 deletion errors.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2538,7 +2538,7 @@ Unknown resource group '%-.192s'

["schema:8250"]
error = '''
Resource group feature is disabled
Resource control feature is disabled. Run `SET GLOBAL tidb_enable_resource_control='on'` to enable the feature
'''

["session:8002"]
Expand Down
3 changes: 3 additions & 0 deletions privilege/privilege.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ type Manager interface {
// MatchIdentity matches an identity
MatchIdentity(user, host string, skipNameResolve bool) (string, string, bool)

// MatchUserResourceGroupName matches a user with specified resource group name
MatchUserResourceGroupName(resourceGroupName string) (string, bool)

// DBIsVisible returns true is the database is visible to current user.
DBIsVisible(activeRole []*auth.RoleIdentity, db string) bool

Expand Down
11 changes: 11 additions & 0 deletions privilege/privileges/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,17 @@ func (p *MySQLPrivilege) matchIdentity(user, host string, skipNameResolve bool)
return nil
}

// matchResoureGroup finds an identity to match resource group.
func (p *MySQLPrivilege) matchResoureGroup(resourceGroupName string) *UserRecord {
for i := 0; i < len(p.User); i++ {
record := &p.User[i]
if record.ResourceGroup == resourceGroupName {
return record
}
}
return nil
}

// connectionVerification verifies the username + hostname according to exact
// match from the mysql.user privilege table. call matchIdentity() first if you
// do not have an exact match yet.
Expand Down
10 changes: 10 additions & 0 deletions privilege/privileges/privileges.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@ func (p *UserPrivileges) MatchIdentity(user, host string, skipNameResolve bool)
return "", "", false
}

// MatchUserResourceGroupName implements the Manager interface.
func (p *UserPrivileges) MatchUserResourceGroupName(resourceGroupName string) (u string, success bool) {
mysqlPriv := p.Handle.Get()
record := mysqlPriv.matchResoureGroup(resourceGroupName)
if record != nil {
return record.User, true
}
return "", false
}

// GetAuthWithoutVerification implements the Manager interface.
func (p *UserPrivileges) GetAuthWithoutVerification(user, host string) (success bool) {
if SkipWithGrant {
Expand Down

0 comments on commit 280b773

Please sign in to comment.