mirror of https://github.com/milvus-io/milvus.git
Implement the mysql metastore of the rbac (#18704)
Signed-off-by: SimFG <bang.fu@zilliz.com> Signed-off-by: SimFG <bang.fu@zilliz.com>pull/18769/head
parent
94ffa8a275
commit
ce434b496e
|
@ -55,7 +55,7 @@ metastore:
|
|||
# Related configuration of mysql, used to store Milvus metadata.
|
||||
mysql:
|
||||
username: root
|
||||
password: 11111111
|
||||
password: 123456
|
||||
address: localhost
|
||||
port: 3306
|
||||
dbName: milvus_meta
|
||||
|
|
|
@ -38,11 +38,11 @@ type RootCoordCatalog interface {
|
|||
|
||||
CreateRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error
|
||||
DropRole(ctx context.Context, tenant string, roleName string) error
|
||||
OperateUserRole(ctx context.Context, tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error
|
||||
SelectRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error)
|
||||
SelectUser(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error)
|
||||
OperatePrivilege(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error
|
||||
SelectGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error)
|
||||
AlterUserRole(ctx context.Context, tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error
|
||||
ListRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error)
|
||||
ListUser(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error)
|
||||
AlterGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error
|
||||
ListGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error)
|
||||
ListPolicy(ctx context.Context, tenant string) ([]string, error)
|
||||
ListUserRole(ctx context.Context, tenant string) ([]string, error)
|
||||
|
||||
|
|
|
@ -44,6 +44,9 @@ var (
|
|||
indexTestDb dbmodel.IIndexDb
|
||||
segIndexTestDb dbmodel.ISegmentIndexDb
|
||||
userTestDb dbmodel.IUserDb
|
||||
roleTestDb dbmodel.IRoleDb
|
||||
userRoleTestDb dbmodel.IUserRoleDb
|
||||
grantTestDb dbmodel.IGrantDb
|
||||
)
|
||||
|
||||
// TestMain is the first function executed in current package, we will do some initial here
|
||||
|
@ -51,6 +54,7 @@ func TestMain(m *testing.M) {
|
|||
var (
|
||||
db *sql.DB
|
||||
err error
|
||||
ctx = context.TODO()
|
||||
)
|
||||
|
||||
// setting sql MUST exact match
|
||||
|
@ -70,14 +74,17 @@ func TestMain(m *testing.M) {
|
|||
// set mocked database
|
||||
dbcore.SetGlobalDB(DB)
|
||||
|
||||
collTestDb = NewMetaDomain().CollectionDb(context.TODO())
|
||||
aliasTestDb = NewMetaDomain().CollAliasDb(context.TODO())
|
||||
channelTestDb = NewMetaDomain().CollChannelDb(context.TODO())
|
||||
fieldTestDb = NewMetaDomain().FieldDb(context.TODO())
|
||||
partitionTestDb = NewMetaDomain().PartitionDb(context.TODO())
|
||||
indexTestDb = NewMetaDomain().IndexDb(context.TODO())
|
||||
segIndexTestDb = NewMetaDomain().SegmentIndexDb(context.TODO())
|
||||
userTestDb = NewMetaDomain().UserDb(context.TODO())
|
||||
collTestDb = NewMetaDomain().CollectionDb(ctx)
|
||||
aliasTestDb = NewMetaDomain().CollAliasDb(ctx)
|
||||
channelTestDb = NewMetaDomain().CollChannelDb(ctx)
|
||||
fieldTestDb = NewMetaDomain().FieldDb(ctx)
|
||||
partitionTestDb = NewMetaDomain().PartitionDb(ctx)
|
||||
indexTestDb = NewMetaDomain().IndexDb(ctx)
|
||||
segIndexTestDb = NewMetaDomain().SegmentIndexDb(ctx)
|
||||
userTestDb = NewMetaDomain().UserDb(ctx)
|
||||
roleTestDb = NewMetaDomain().RoleDb(ctx)
|
||||
userRoleTestDb = NewMetaDomain().UserRoleDb(ctx)
|
||||
grantTestDb = NewMetaDomain().GrantDb(ctx)
|
||||
|
||||
// m.Run entry for executing tests
|
||||
os.Exit(m.Run())
|
||||
|
@ -392,3 +399,24 @@ func (a AnyTime) Match(v driver.Value) bool {
|
|||
_, ok := v.(time.Time)
|
||||
return ok
|
||||
}
|
||||
|
||||
func GetBase() dbmodel.Base {
|
||||
return dbmodel.Base{
|
||||
TenantID: tenantID,
|
||||
IsDeleted: false,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func SuccessExec(f func()) {
|
||||
mock.ExpectBegin()
|
||||
f()
|
||||
mock.ExpectCommit()
|
||||
}
|
||||
|
||||
func ErrorExec(f func()) {
|
||||
mock.ExpectBegin()
|
||||
f()
|
||||
mock.ExpectRollback()
|
||||
}
|
||||
|
|
|
@ -44,3 +44,15 @@ func (*metaDomain) SegmentIndexDb(ctx context.Context) dbmodel.ISegmentIndexDb {
|
|||
func (*metaDomain) UserDb(ctx context.Context) dbmodel.IUserDb {
|
||||
return &userDb{dbcore.GetDB(ctx)}
|
||||
}
|
||||
|
||||
func (d *metaDomain) RoleDb(ctx context.Context) dbmodel.IRoleDb {
|
||||
return &roleDb{dbcore.GetDB(ctx)}
|
||||
}
|
||||
|
||||
func (d *metaDomain) UserRoleDb(ctx context.Context) dbmodel.IUserRoleDb {
|
||||
return &userRoleDb{dbcore.GetDB(ctx)}
|
||||
}
|
||||
|
||||
func (d *metaDomain) GrantDb(ctx context.Context) dbmodel.IGrantDb {
|
||||
return &grantDb{dbcore.GetDB(ctx)}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/common"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/log"
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type grantDb struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (g *grantDb) GetGrants(tenantID string, roleID int64, object string, objectName string) ([]*dbmodel.Grant, error) {
|
||||
var (
|
||||
grants []*dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
err = g.db.Model(&dbmodel.Grant{}).Where(&dbmodel.Grant{RoleID: roleID, Object: object, ObjectName: objectName}).Where(dbmodel.GetCommonCondition(tenantID, false)).Preload("Role").Find(&grants).Error
|
||||
if err != nil {
|
||||
log.Error("fail to get grants", zap.String("tenant_id", tenantID), zap.Int64("roleID", roleID), zap.String("object", object), zap.String("object_name", objectName), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return grants, nil
|
||||
}
|
||||
|
||||
func (g *grantDb) Insert(in *dbmodel.Grant) error {
|
||||
var (
|
||||
sqlWhere = &dbmodel.Grant{RoleID: in.RoleID, Object: in.Object, ObjectName: in.ObjectName}
|
||||
dbGrant *dbmodel.Grant
|
||||
newDbDetail string
|
||||
err error
|
||||
)
|
||||
err = g.db.Model(&dbmodel.Grant{}).Where(sqlWhere).Where(dbmodel.GetCommonCondition(in.TenantID, false)).Take(&dbGrant).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
err = g.db.Create(in).Error
|
||||
if err != nil {
|
||||
log.Error("fail to insert the grant", zap.Any("in", in), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("fail to take the origin grant", zap.Any("in", in), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
if newDbDetail, err = dbmodel.EncodeGrantDetailForString(dbGrant.Detail, in.Detail, true); err != nil {
|
||||
log.Error("fail to encode the grant detail", zap.Any("in", in), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
err = g.db.Model(dbmodel.Grant{}).Where(sqlWhere).Where(dbmodel.GetCommonCondition(in.TenantID, false)).Update("detail", newDbDetail).Error
|
||||
if err != nil {
|
||||
log.Error("fail to update the grant", zap.Any("in", in), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *grantDb) Delete(tenantID string, roleID int64, object string, objectName string, privilege string) error {
|
||||
var (
|
||||
sqlWhere = &dbmodel.Grant{RoleID: roleID, Object: object, ObjectName: objectName}
|
||||
dbGrant *dbmodel.Grant
|
||||
newDbDetail string
|
||||
db *gorm.DB
|
||||
err error
|
||||
)
|
||||
|
||||
err = g.db.Model(&dbmodel.Grant{}).Where(sqlWhere).Where(dbmodel.GetCommonCondition(tenantID, false)).Take(&dbGrant).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return common.NewIgnorableError(fmt.Errorf("the privilege[%s-%s-%s] isn't granted", object, objectName, privilege))
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("fail to take the origin grant", zap.Any("where", sqlWhere), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
if newDbDetail, err = dbmodel.EncodeGrantDetail(dbGrant.Detail, "", privilege, false); err != nil {
|
||||
log.Error("fail to encode the grant detail", zap.Any("detail", dbGrant.Detail), zap.String("privilege", privilege), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
db = g.db.Model(dbmodel.Grant{}).Where(sqlWhere).Where(dbmodel.GetCommonCondition(tenantID, false))
|
||||
if newDbDetail == "" {
|
||||
err = db.Update("is_deleted", true).Error
|
||||
} else {
|
||||
err = db.Update("detail", newDbDetail).Error
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("fail to delete the grant", zap.Bool("is_delete", newDbDetail == ""), zap.Any("where", sqlWhere), zap.String("privilege", privilege), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,419 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/common"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGrant_GetGrants(t *testing.T) {
|
||||
var (
|
||||
roleID1 = 10
|
||||
roleID2 = 20
|
||||
object = "Collection"
|
||||
objectName = "col1"
|
||||
grants []*dbmodel.Grant
|
||||
getQuery func() *sqlmock.ExpectedQuery
|
||||
err error
|
||||
)
|
||||
|
||||
getQuery = func() *sqlmock.ExpectedQuery {
|
||||
return mock.ExpectQuery("SELECT * FROM `grant` WHERE `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(false, tenantID)
|
||||
}
|
||||
getQuery().WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name"}).
|
||||
AddRow(tenantID, roleID1, object, objectName).
|
||||
AddRow(tenantID, roleID2, object, objectName))
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `role`.`id` IN (?,?)").
|
||||
WithArgs(roleID1, roleID2).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "name"}).
|
||||
AddRow(roleID1, tenantID, "foo1").
|
||||
AddRow(roleID2, tenantID, "foo2"))
|
||||
|
||||
grants, err = grantTestDb.GetGrants(tenantID, 0, "", "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(grants))
|
||||
assert.Equal(t, "foo2", grants[1].Role.Name)
|
||||
assert.Equal(t, object, grants[0].Object)
|
||||
assert.Equal(t, objectName, grants[0].ObjectName)
|
||||
|
||||
getQuery().WillReturnError(errors.New("test error"))
|
||||
_, err = grantTestDb.GetGrants(tenantID, 0, "", "")
|
||||
assert.Error(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestGrant_GetGrantsWithRoleID(t *testing.T) {
|
||||
var (
|
||||
roleID1 = 10
|
||||
object1 = "Collection"
|
||||
objectName1 = "col1"
|
||||
object2 = "Global"
|
||||
objectName2 = "*"
|
||||
grants []*dbmodel.Grant
|
||||
getQuery func() *sqlmock.ExpectedQuery
|
||||
err error
|
||||
)
|
||||
|
||||
getQuery = func() *sqlmock.ExpectedQuery {
|
||||
return mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(roleID1, false, tenantID)
|
||||
}
|
||||
getQuery().WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name"}).
|
||||
AddRow(tenantID, roleID1, object1, objectName1).
|
||||
AddRow(tenantID, roleID1, object2, objectName2))
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `role`.`id` = ?").
|
||||
WithArgs(roleID1).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "name"}).
|
||||
AddRow(roleID1, tenantID, "foo1"))
|
||||
|
||||
grants, err = grantTestDb.GetGrants(tenantID, int64(roleID1), "", "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(grants))
|
||||
assert.Equal(t, "foo1", grants[0].Role.Name)
|
||||
assert.Equal(t, object1, grants[0].Object)
|
||||
assert.Equal(t, objectName2, grants[1].ObjectName)
|
||||
}
|
||||
|
||||
func TestGrant_GetGrantsWithObject(t *testing.T) {
|
||||
var (
|
||||
roleID = 10
|
||||
object = "Collection"
|
||||
objectName = "col1"
|
||||
detail1 = "privilege1..."
|
||||
detail2 = "privilege2..."
|
||||
grants []*dbmodel.Grant
|
||||
getQuery func() *sqlmock.ExpectedQuery
|
||||
err error
|
||||
)
|
||||
|
||||
getQuery = func() *sqlmock.ExpectedQuery {
|
||||
return mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(roleID, object, objectName, false, tenantID)
|
||||
}
|
||||
getQuery().WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name", "detail"}).
|
||||
AddRow(tenantID, roleID, object, objectName, detail1).
|
||||
AddRow(tenantID, roleID, object, objectName, detail2))
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `role`.`id` = ?").
|
||||
WithArgs(roleID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "name"}).
|
||||
AddRow(roleID, tenantID, "foo1"))
|
||||
|
||||
grants, err = grantTestDb.GetGrants(tenantID, int64(roleID), object, objectName)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(grants))
|
||||
assert.Equal(t, "foo1", grants[0].Role.Name)
|
||||
assert.Equal(t, object, grants[1].Object)
|
||||
assert.Equal(t, objectName, grants[1].ObjectName)
|
||||
assert.Equal(t, detail2, grants[1].Detail)
|
||||
}
|
||||
|
||||
func TestGrant_Insert(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail1\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnError(gorm.ErrRecordNotFound)
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("INSERT INTO `grant` (`tenant_id`,`is_deleted`,`created_at`,`updated_at`,`role_id`,`object`,`object_name`,`detail`) VALUES (?,?,?,?,?,?,?,?)").
|
||||
WithArgs(grant.TenantID, grant.IsDeleted, grant.CreatedAt, grant.UpdatedAt, grant.RoleID, grant.Object, grant.ObjectName, grant.Detail).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
err = grantTestDb.Insert(grant)
|
||||
assert.NoError(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestGrant_Insert_Error(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail2\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnError(gorm.ErrRecordNotFound)
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("INSERT INTO `grant` (`tenant_id`,`is_deleted`,`created_at`,`updated_at`,`role_id`,`object`,`object_name`,`detail`) VALUES (?,?,?,?,?,?,?,?)").
|
||||
WithArgs(grant.TenantID, grant.IsDeleted, grant.CreatedAt, grant.UpdatedAt, grant.RoleID, grant.Object, grant.ObjectName, grant.Detail).
|
||||
WillReturnError(errors.New("test error"))
|
||||
mock.ExpectRollback()
|
||||
err = grantTestDb.Insert(grant)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGrant_Insert_SelectError(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail3\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnError(errors.New("test error"))
|
||||
err = grantTestDb.Insert(grant)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGrant_InsertDecode(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name", "detail"}).
|
||||
AddRow(tenantID, grant.RoleID, grant.Object, grant.ObjectName, "aaa"))
|
||||
err = grantTestDb.Insert(grant)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGrant_InsertUpdate(t *testing.T) {
|
||||
var (
|
||||
originDetail = "[[\"admin\",\"PrivilegeLoad\"]]"
|
||||
grant *dbmodel.Grant
|
||||
expectDetail string
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"]]",
|
||||
}
|
||||
|
||||
expectDetail, _ = dbmodel.EncodeGrantDetailForString(originDetail, grant.Detail, true)
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name", "detail"}).
|
||||
AddRow(tenantID, grant.RoleID, grant.Object, grant.ObjectName, originDetail))
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("UPDATE `grant` SET `detail`=?,`updated_at`=? WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(expectDetail, AnyTime{}, grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
err = grantTestDb.Insert(grant)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGrant_InsertUpdateError(t *testing.T) {
|
||||
var (
|
||||
originDetail = "[[\"admin\",\"PrivilegeIndexDetail\"]]"
|
||||
grant *dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name", "detail"}).
|
||||
AddRow(tenantID, grant.RoleID, grant.Object, grant.ObjectName, originDetail))
|
||||
err = grantTestDb.Insert(grant)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, common.IsIgnorableError(err))
|
||||
}
|
||||
|
||||
func TestGrant_DeleteWithoutPrivilege(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
privilege = "PrivilegeIndexDetail"
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnError(gorm.ErrRecordNotFound)
|
||||
err = grantTestDb.Delete(grant.TenantID, grant.RoleID, grant.Object, grant.ObjectName, privilege)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, common.IsIgnorableError(err))
|
||||
}
|
||||
|
||||
func TestGrant_Delete_GetError(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
privilege = "PrivilegeIndexDetail"
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnError(errors.New("test error"))
|
||||
err = grantTestDb.Delete(grant.TenantID, grant.RoleID, grant.Object, grant.ObjectName, privilege)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGrant_Delete_DecodeError(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
privilege = "PrivilegeIndexDetail"
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name", "detail"}).
|
||||
AddRow(tenantID, grant.RoleID, grant.Object, grant.ObjectName, "aaa"))
|
||||
err = grantTestDb.Delete(grant.TenantID, grant.RoleID, grant.Object, grant.ObjectName, privilege)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGrant_Delete_Mark(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
privilege = "PrivilegeIndexDetail"
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name", "detail"}).
|
||||
AddRow(tenantID, grant.RoleID, grant.Object, grant.ObjectName, grant.Detail))
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("UPDATE `grant` SET `is_deleted`=?,`updated_at`=? WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(true, AnyTime{}, grant.RoleID, grant.Object, grant.ObjectName, false, grant.TenantID).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
err = grantTestDb.Delete(grant.TenantID, grant.RoleID, grant.Object, grant.ObjectName, privilege)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGrant_Delete_Update(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
privilege = "PrivilegeIndexDetail"
|
||||
expectDetail = "[[\"admin\",\"PrivilegeLoad\"]]"
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"],[\"admin\",\"PrivilegeLoad\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name", "detail"}).
|
||||
AddRow(tenantID, grant.RoleID, grant.Object, grant.ObjectName, grant.Detail))
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("UPDATE `grant` SET `detail`=?,`updated_at`=? WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(expectDetail, AnyTime{}, grant.RoleID, grant.Object, grant.ObjectName, false, grant.TenantID).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
err = grantTestDb.Delete(grant.TenantID, grant.RoleID, grant.Object, grant.ObjectName, privilege)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGrant_Delete_UpdateError(t *testing.T) {
|
||||
var (
|
||||
grant *dbmodel.Grant
|
||||
privilege = "PrivilegeIndexDetail"
|
||||
err error
|
||||
)
|
||||
grant = &dbmodel.Grant{
|
||||
Base: GetBase(),
|
||||
RoleID: 1,
|
||||
Object: "Global",
|
||||
ObjectName: "Col",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexLoad\"],[\"admin\",\"PrivilegeQuery\"]]",
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `grant` WHERE `grant`.`role_id` = ? AND `grant`.`object` = ? AND `grant`.`object_name` = ? AND `is_deleted` = ? AND `tenant_id` = ? LIMIT 1").
|
||||
WithArgs(grant.RoleID, grant.Object, grant.ObjectName, grant.IsDeleted, grant.TenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "role_id", "object", "object_name", "detail"}).
|
||||
AddRow(tenantID, grant.RoleID, grant.Object, grant.ObjectName, grant.Detail))
|
||||
err = grantTestDb.Delete(grant.TenantID, grant.RoleID, grant.Object, grant.ObjectName, privilege)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, common.IsIgnorableError(err))
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"github.com/milvus-io/milvus/internal/log"
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type roleDb struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (r *roleDb) GetRoles(tenantID string, name string) ([]*dbmodel.Role, error) {
|
||||
var (
|
||||
roles []*dbmodel.Role
|
||||
err error
|
||||
)
|
||||
err = r.db.Model(&dbmodel.Role{}).Where(&dbmodel.Role{Name: name}).Where(dbmodel.GetCommonCondition(tenantID, false)).Find(&roles).Error
|
||||
if err != nil {
|
||||
log.Error("fail to get roles", zap.String("tenant_id", tenantID), zap.String("name", name), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func (r *roleDb) Insert(in *dbmodel.Role) error {
|
||||
err := r.db.Create(in).Error
|
||||
if err != nil {
|
||||
log.Error("fail to insert the role", zap.Any("in", in), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *roleDb) Delete(tenantID string, name string) error {
|
||||
err := r.db.Model(dbmodel.Role{}).Where(&dbmodel.Role{Name: name}).Where(dbmodel.GetCommonCondition(tenantID, false)).Update("is_deleted", true).Error
|
||||
if err != nil {
|
||||
log.Error("fail to delete the role", zap.String("tenant_id", tenantID), zap.String("name", name), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
)
|
||||
|
||||
func TestRole_GetRoles(t *testing.T) {
|
||||
var (
|
||||
roles []*dbmodel.Role
|
||||
err error
|
||||
)
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(false, tenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "name"}).
|
||||
AddRow(tenantID, "foo1").
|
||||
AddRow(tenantID, "foo2"))
|
||||
|
||||
roles, err = roleTestDb.GetRoles(tenantID, "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(roles))
|
||||
}
|
||||
|
||||
func TestRole_GetRoles_Error(t *testing.T) {
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(false, tenantID).
|
||||
WillReturnError(errors.New("test error"))
|
||||
_, err := roleTestDb.GetRoles(tenantID, "")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestRole_GetRoles_WithRoleName(t *testing.T) {
|
||||
var (
|
||||
roleName = "foo1"
|
||||
roles []*dbmodel.Role
|
||||
err error
|
||||
)
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `role`.`name` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(roleName, false, tenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "name"}).
|
||||
AddRow(tenantID, roleName))
|
||||
roles, err = roleTestDb.GetRoles(tenantID, roleName)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(roles))
|
||||
assert.Equal(t, roleName, roles[0].Name)
|
||||
}
|
||||
|
||||
func TestRole_Insert(t *testing.T) {
|
||||
var (
|
||||
role *dbmodel.Role
|
||||
err error
|
||||
)
|
||||
role = &dbmodel.Role{
|
||||
Base: GetBase(),
|
||||
Name: "foo",
|
||||
}
|
||||
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("INSERT INTO `role` (`tenant_id`,`is_deleted`,`created_at`,`updated_at`,`name`) VALUES (?,?,?,?,?)").
|
||||
WithArgs(role.TenantID, role.IsDeleted, role.CreatedAt, role.UpdatedAt, role.Name).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
|
||||
err = roleTestDb.Insert(role)
|
||||
assert.NoError(t, err)
|
||||
|
||||
}
|
||||
|
||||
func TestRole_Insert_Error(t *testing.T) {
|
||||
var (
|
||||
role *dbmodel.Role
|
||||
err error
|
||||
)
|
||||
role = &dbmodel.Role{
|
||||
Base: GetBase(),
|
||||
Name: "foo",
|
||||
}
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("INSERT INTO `role` (`tenant_id`,`is_deleted`,`created_at`,`updated_at`,`name`) VALUES (?,?,?,?,?)").
|
||||
WithArgs(role.TenantID, role.IsDeleted, role.CreatedAt, role.UpdatedAt, role.Name).
|
||||
WillReturnError(errors.New("test error"))
|
||||
mock.ExpectRollback()
|
||||
err = roleTestDb.Insert(role)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestRole_Delete(t *testing.T) {
|
||||
var (
|
||||
role *dbmodel.Role
|
||||
err error
|
||||
)
|
||||
role = &dbmodel.Role{
|
||||
Base: GetBase(),
|
||||
Name: "foo",
|
||||
}
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("UPDATE `role` SET `is_deleted`=?,`updated_at`=? WHERE `role`.`name` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(true, AnyTime{}, role.Name, role.IsDeleted, role.TenantID).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
|
||||
err = roleTestDb.Delete(role.TenantID, role.Name)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRole_Delete_Error(t *testing.T) {
|
||||
var (
|
||||
role *dbmodel.Role
|
||||
err error
|
||||
)
|
||||
role = &dbmodel.Role{
|
||||
Base: GetBase(),
|
||||
Name: "foo",
|
||||
}
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("UPDATE `role` SET `is_deleted`=?,`updated_at`=? WHERE `role`.`name` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(true, AnyTime{}, role.Name, role.IsDeleted, role.TenantID).
|
||||
WillReturnError(errors.New("test error"))
|
||||
mock.ExpectRollback()
|
||||
|
||||
err = roleTestDb.Delete(role.TenantID, role.Name)
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -4,6 +4,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/common"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/log"
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
"go.uber.org/zap"
|
||||
|
@ -20,7 +22,7 @@ func (s *userDb) GetByUsername(tenantID string, username string) (*dbmodel.User,
|
|||
err := s.db.Model(&dbmodel.User{}).Where("tenant_id = ? AND username = ? AND is_deleted = false", tenantID, username).Take(&r).Error
|
||||
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("user %s not found", username)
|
||||
return nil, common.NewKeyNotExistError(fmt.Sprintf("%s/%s", tenantID, username))
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("get user by username failed", zap.String("tenant", tenantID), zap.String("username", username), zap.Error(err))
|
||||
|
@ -30,16 +32,16 @@ func (s *userDb) GetByUsername(tenantID string, username string) (*dbmodel.User,
|
|||
return r, nil
|
||||
}
|
||||
|
||||
func (s *userDb) ListUsername(tenantID string) ([]string, error) {
|
||||
var usernames []string
|
||||
func (s *userDb) ListUser(tenantID string) ([]*dbmodel.User, error) {
|
||||
var users []*dbmodel.User
|
||||
|
||||
err := s.db.Model(&dbmodel.User{}).Select("username").Where("tenant_id = ? AND is_deleted = false", tenantID).Find(&usernames).Error
|
||||
err := s.db.Model(&dbmodel.User{}).Where("tenant_id = ? AND is_deleted = false", tenantID).Find(&users).Error
|
||||
if err != nil {
|
||||
log.Error("list usernames failed", zap.String("tenant", tenantID), zap.Error(err))
|
||||
log.Error("list user failed", zap.String("tenant", tenantID), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return usernames, nil
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (s *userDb) Insert(in *dbmodel.User) error {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"github.com/milvus-io/milvus/internal/log"
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type userRoleDb struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (u *userRoleDb) GetUserRoles(tenantID string, userID int64, roleID int64) ([]*dbmodel.UserRole, error) {
|
||||
var (
|
||||
userRoles []*dbmodel.UserRole
|
||||
err error
|
||||
)
|
||||
err = u.db.Model(&dbmodel.UserRole{}).Where(&dbmodel.UserRole{UserID: userID, RoleID: roleID}).Where(dbmodel.GetCommonCondition(tenantID, false)).Preload("User").Preload("Role").Find(&userRoles).Error
|
||||
if err != nil {
|
||||
log.Error("fail to get user-roles", zap.String("tenant_id", tenantID), zap.Int64("userID", userID), zap.Int64("roleID", roleID), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return userRoles, nil
|
||||
}
|
||||
|
||||
func (u *userRoleDb) Insert(in *dbmodel.UserRole) error {
|
||||
err := u.db.Create(in).Error
|
||||
if err != nil {
|
||||
log.Error("fail to insert the user-role", zap.Any("in", in), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *userRoleDb) Delete(tenantID string, userID int64, roleID int64) error {
|
||||
err := u.db.Model(dbmodel.UserRole{}).Where(&dbmodel.UserRole{UserID: userID, RoleID: roleID}).Where(dbmodel.GetCommonCondition(tenantID, false)).Update("is_deleted", true).Error
|
||||
if err != nil {
|
||||
log.Error("fail to delete the user-role", zap.String("tenant_id", tenantID), zap.Int64("userID", userID), zap.Int64("roleID", roleID), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUserRole_GetUserRoles(t *testing.T) {
|
||||
var (
|
||||
userID1 = 1
|
||||
userID2 = 2
|
||||
roleID1 = 10
|
||||
roleID2 = 20
|
||||
userRoles []*dbmodel.UserRole
|
||||
getQuery func() *sqlmock.ExpectedQuery
|
||||
err error
|
||||
)
|
||||
|
||||
// mock user and role
|
||||
getQuery = func() *sqlmock.ExpectedQuery {
|
||||
return mock.ExpectQuery("SELECT * FROM `user_role` WHERE `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(false, tenantID)
|
||||
}
|
||||
getQuery().WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "user_id", "role_id"}).
|
||||
AddRow(tenantID, userID1, roleID1).
|
||||
AddRow(tenantID, userID2, roleID2))
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `role`.`id` IN (?,?)").
|
||||
WithArgs(roleID1, roleID2).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "name"}).
|
||||
AddRow(roleID1, tenantID, "foo1").
|
||||
AddRow(roleID2, tenantID, "foo2"))
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `credential_users` WHERE `credential_users`.`id` IN (?,?)").
|
||||
WithArgs(userID1, userID2).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "username"}).
|
||||
AddRow(userID1, tenantID, "fo1").
|
||||
AddRow(userID2, tenantID, "fo2"))
|
||||
|
||||
userRoles, err = userRoleTestDb.GetUserRoles(tenantID, 0, 0)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(userRoles))
|
||||
assert.Equal(t, "foo1", userRoles[0].Role.Name)
|
||||
assert.Equal(t, "fo1", userRoles[0].User.Username)
|
||||
|
||||
getQuery().WillReturnError(errors.New("test error"))
|
||||
_, err = userRoleTestDb.GetUserRoles(tenantID, 0, 0)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestUserRole_GetUserRolesWithUserID(t *testing.T) {
|
||||
var (
|
||||
userID1 = 1
|
||||
roleID1 = 10
|
||||
roleID2 = 20
|
||||
userRoles []*dbmodel.UserRole
|
||||
err error
|
||||
)
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `user_role` WHERE `user_role`.`user_id` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(userID1, false, tenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "user_id", "role_id"}).
|
||||
AddRow(tenantID, userID1, roleID1).
|
||||
AddRow(tenantID, userID1, roleID2))
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `role`.`id` IN (?,?)").
|
||||
WithArgs(roleID1, roleID2).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "name"}).
|
||||
AddRow(roleID1, tenantID, "foo1").
|
||||
AddRow(roleID2, tenantID, "foo2"))
|
||||
mock.ExpectQuery("SELECT * FROM `credential_users` WHERE `credential_users`.`id` = ?").
|
||||
WithArgs(userID1).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "username"}).
|
||||
AddRow(userID1, tenantID, "fo1"))
|
||||
|
||||
userRoles, err = userRoleTestDb.GetUserRoles(tenantID, int64(userID1), 0)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(userRoles))
|
||||
assert.Equal(t, "foo2", userRoles[1].Role.Name)
|
||||
assert.Equal(t, "fo1", userRoles[0].User.Username)
|
||||
}
|
||||
|
||||
func TestUserRole_GetUserRolesWithRoleID(t *testing.T) {
|
||||
var (
|
||||
userID1 = 1
|
||||
userID2 = 2
|
||||
roleID1 = 10
|
||||
userRoles []*dbmodel.UserRole
|
||||
err error
|
||||
)
|
||||
|
||||
mock.ExpectQuery("SELECT * FROM `user_role` WHERE `user_role`.`role_id` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(roleID1, false, tenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"tenant_id", "user_id", "role_id"}).
|
||||
AddRow(tenantID, userID1, roleID1).
|
||||
AddRow(tenantID, userID2, roleID1))
|
||||
mock.ExpectQuery("SELECT * FROM `role` WHERE `role`.`id` = ?").
|
||||
WithArgs(roleID1).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "name"}).
|
||||
AddRow(roleID1, tenantID, "foo1"))
|
||||
mock.ExpectQuery("SELECT * FROM `credential_users` WHERE `credential_users`.`id` IN (?,?)").
|
||||
WithArgs(userID1, userID2).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"id", "tenant_id", "username"}).
|
||||
AddRow(userID1, tenantID, "fo1").
|
||||
AddRow(userID2, tenantID, "fo2"))
|
||||
|
||||
userRoles, err = userRoleTestDb.GetUserRoles(tenantID, 0, int64(roleID1))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(userRoles))
|
||||
assert.Equal(t, "foo1", userRoles[0].Role.Name)
|
||||
assert.Equal(t, "fo2", userRoles[1].User.Username)
|
||||
}
|
||||
|
||||
func TestUserRole_Insert(t *testing.T) {
|
||||
var (
|
||||
userRole *dbmodel.UserRole
|
||||
err error
|
||||
)
|
||||
userRole = &dbmodel.UserRole{
|
||||
Base: GetBase(),
|
||||
UserID: 1,
|
||||
RoleID: 1,
|
||||
}
|
||||
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("INSERT INTO `user_role` (`tenant_id`,`is_deleted`,`created_at`,`updated_at`,`user_id`,`role_id`) VALUES (?,?,?,?,?,?)").
|
||||
WithArgs(userRole.TenantID, userRole.IsDeleted, userRole.CreatedAt, userRole.UpdatedAt, userRole.UserID, userRole.RoleID).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
err = userRoleTestDb.Insert(userRole)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestUserRole_InsertError(t *testing.T) {
|
||||
var (
|
||||
userRole *dbmodel.UserRole
|
||||
err error
|
||||
)
|
||||
userRole = &dbmodel.UserRole{
|
||||
Base: GetBase(),
|
||||
UserID: 1,
|
||||
RoleID: 1,
|
||||
}
|
||||
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec("INSERT INTO `user_role` (`tenant_id`,`is_deleted`,`created_at`,`updated_at`,`user_id`,`role_id`) VALUES (?,?,?,?,?,?)").
|
||||
WithArgs(userRole.TenantID, userRole.IsDeleted, userRole.CreatedAt, userRole.UpdatedAt, userRole.UserID, userRole.RoleID).
|
||||
WillReturnError(errors.New("test error"))
|
||||
mock.ExpectRollback()
|
||||
err = userRoleTestDb.Insert(userRole)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestUserRole_Delete(t *testing.T) {
|
||||
var (
|
||||
userRole *dbmodel.UserRole
|
||||
getExec func() *sqlmock.ExpectedExec
|
||||
err error
|
||||
)
|
||||
userRole = &dbmodel.UserRole{
|
||||
Base: GetBase(),
|
||||
UserID: 1,
|
||||
RoleID: 1,
|
||||
}
|
||||
getExec = func() *sqlmock.ExpectedExec {
|
||||
return mock.ExpectExec("UPDATE `user_role` SET `is_deleted`=?,`updated_at`=? WHERE `user_role`.`user_id` = ? AND `user_role`.`role_id` = ? AND `is_deleted` = ? AND `tenant_id` = ?").
|
||||
WithArgs(true, AnyTime{}, userRole.UserID, userRole.RoleID, userRole.IsDeleted, userRole.TenantID)
|
||||
}
|
||||
mock.ExpectBegin()
|
||||
getExec().WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
err = userRoleTestDb.Delete(userRole.TenantID, userRole.UserID, userRole.RoleID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
mock.ExpectBegin()
|
||||
getExec().WillReturnError(errors.New("test error"))
|
||||
mock.ExpectRollback()
|
||||
err = userRoleTestDb.Delete(userRole.TenantID, userRole.UserID, userRole.RoleID)
|
||||
assert.Error(t, err)
|
||||
}
|
|
@ -62,33 +62,42 @@ func TestUser_GetByUsername_Error(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUser_ListUsername(t *testing.T) {
|
||||
var usernames = []string{
|
||||
"test_username_1",
|
||||
"test_username_2",
|
||||
}
|
||||
var (
|
||||
usernames = []string{
|
||||
"test_username_1",
|
||||
"test_username_2",
|
||||
}
|
||||
user = &dbmodel.User{
|
||||
TenantID: tenantID,
|
||||
EncryptedPassword: "xxx",
|
||||
IsSuper: false,
|
||||
}
|
||||
)
|
||||
|
||||
// expectation
|
||||
mock.ExpectQuery("SELECT `username` FROM `credential_users` WHERE tenant_id = ? AND is_deleted = false").
|
||||
mock.ExpectQuery("SELECT * FROM `credential_users` WHERE tenant_id = ? AND is_deleted = false").
|
||||
WithArgs(tenantID).
|
||||
WillReturnRows(
|
||||
sqlmock.NewRows([]string{"username"}).
|
||||
AddRow(usernames[0]).
|
||||
AddRow(usernames[1]))
|
||||
sqlmock.NewRows([]string{"tenant_id", "username", "encrypted_password", "is_super"}).
|
||||
AddRow(user.TenantID, usernames[0], user.EncryptedPassword, user.IsSuper).
|
||||
AddRow(user.TenantID, usernames[1], user.EncryptedPassword, user.IsSuper))
|
||||
|
||||
// actual
|
||||
res, err := userTestDb.ListUsername(tenantID)
|
||||
res, err := userTestDb.ListUser(tenantID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, usernames, res)
|
||||
assert.Equal(t, 2, len(res))
|
||||
assert.Equal(t, usernames[0], res[0].Username)
|
||||
assert.Equal(t, usernames[1], res[1].Username)
|
||||
}
|
||||
|
||||
func TestUser_ListUsername_Error(t *testing.T) {
|
||||
// expectation
|
||||
mock.ExpectQuery("SELECT `username` FROM `credential_users` WHERE tenant_id = ? AND is_deleted = false").
|
||||
mock.ExpectQuery("SELECT * FROM `credential_users` WHERE tenant_id = ? AND is_deleted = false").
|
||||
WithArgs(tenantID).
|
||||
WillReturnError(errors.New("test error"))
|
||||
|
||||
// actual
|
||||
res, err := userTestDb.ListUsername(tenantID)
|
||||
res, err := userTestDb.ListUser(tenantID)
|
||||
assert.Nil(t, res)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package dbmodel
|
||||
|
||||
import "time"
|
||||
|
||||
type Base struct {
|
||||
ID int64 `gorm:"id"`
|
||||
TenantID string `gorm:"tenant_id"`
|
||||
IsDeleted bool `gorm:"is_deleted"`
|
||||
CreatedAt time.Time `gorm:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"updated_at"`
|
||||
}
|
|
@ -12,8 +12,18 @@ type IMetaDomain interface {
|
|||
IndexDb(ctx context.Context) IIndexDb
|
||||
SegmentIndexDb(ctx context.Context) ISegmentIndexDb
|
||||
UserDb(ctx context.Context) IUserDb
|
||||
RoleDb(ctx context.Context) IRoleDb
|
||||
UserRoleDb(ctx context.Context) IUserRoleDb
|
||||
GrantDb(ctx context.Context) IGrantDb
|
||||
}
|
||||
|
||||
type ITransaction interface {
|
||||
Transaction(ctx context.Context, fn func(txCtx context.Context) error) error
|
||||
}
|
||||
|
||||
func GetCommonCondition(tenant string, isDelete bool) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"tenant_id": tenant,
|
||||
"is_deleted": isDelete,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
package dbmodel
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/common"
|
||||
)
|
||||
|
||||
type Grant struct {
|
||||
Base
|
||||
RoleID int64 `gorm:"role_id"`
|
||||
Role Role `gorm:"foreignKey:RoleID"`
|
||||
Object string `gorm:"object"`
|
||||
ObjectName string `gorm:"object_name"`
|
||||
Detail string `gorm:"detail"`
|
||||
}
|
||||
|
||||
func (g *Grant) TableName() string {
|
||||
return "grant"
|
||||
}
|
||||
|
||||
//go:generate mockery --name=IGrantDb
|
||||
type IGrantDb interface {
|
||||
GetGrants(tenantID string, roleID int64, object string, objectName string) ([]*Grant, error)
|
||||
Insert(in *Grant) error
|
||||
Delete(tenantID string, roleID int64, object string, objectName string, privilege string) error
|
||||
}
|
||||
|
||||
func EncodeGrantDetail(detail string, grantor string, privilege string, isAdd bool) (string, error) {
|
||||
var (
|
||||
grant = []string{grantor, privilege}
|
||||
resBytes []byte
|
||||
originGrants [][]string
|
||||
index = -1
|
||||
err error
|
||||
|
||||
handleGrant = func(grants [][]string) (string, error) {
|
||||
if resBytes, err = json.Marshal(grants); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(resBytes), nil
|
||||
}
|
||||
)
|
||||
|
||||
if detail == "" {
|
||||
if !isAdd {
|
||||
return "", common.NewIgnorableError(fmt.Errorf("the empty detail can't be remove"))
|
||||
}
|
||||
return handleGrant(append(originGrants, grant))
|
||||
}
|
||||
if originGrants, err = DecodeGrantDetail(detail); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for i, origin := range originGrants {
|
||||
if origin[1] == privilege {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if isAdd {
|
||||
if index != -1 {
|
||||
return detail, common.NewIgnorableError(fmt.Errorf("the grant[%s-%s] is existed", grantor, privilege))
|
||||
}
|
||||
return handleGrant(append(originGrants, grant))
|
||||
}
|
||||
if index == -1 {
|
||||
return detail, common.NewIgnorableError(fmt.Errorf("the grant[%s-%s] isn't existed", grantor, privilege))
|
||||
}
|
||||
if len(originGrants) == 1 {
|
||||
return "", nil
|
||||
}
|
||||
return handleGrant(append(originGrants[:index], originGrants[index+1:]...))
|
||||
}
|
||||
|
||||
func EncodeGrantDetailForString(originDetail string, operateDetail string, isAdd bool) (string, error) {
|
||||
var (
|
||||
operateGrant [][]string
|
||||
err error
|
||||
)
|
||||
|
||||
if operateGrant, err = DecodeGrantDetail(operateDetail); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(operateGrant) != 1 || len(operateGrant[0]) != 2 {
|
||||
return "", fmt.Errorf("invalid operateDetail: [%s], decode result: %+v", operateDetail, operateGrant)
|
||||
}
|
||||
return EncodeGrantDetail(originDetail, operateGrant[0][0], operateGrant[0][1], isAdd)
|
||||
}
|
||||
|
||||
func DecodeGrantDetail(detail string) ([][]string, error) {
|
||||
var (
|
||||
grants [][]string
|
||||
err error
|
||||
)
|
||||
if err = json.Unmarshal([]byte(detail), &grants); err != nil {
|
||||
return grants, err
|
||||
}
|
||||
return grants, nil
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
dbmodel "github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// IGrantDb is an autogenerated mock type for the IGrantDb type
|
||||
type IGrantDb struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: tenantID, roleID, object, objectName, privilege
|
||||
func (_m *IGrantDb) Delete(tenantID string, roleID int64, object string, objectName string, privilege string) error {
|
||||
ret := _m.Called(tenantID, roleID, object, objectName, privilege)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64, string, string, string) error); ok {
|
||||
r0 = rf(tenantID, roleID, object, objectName, privilege)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetGrants provides a mock function with given fields: tenantID, roleID, object, objectName
|
||||
func (_m *IGrantDb) GetGrants(tenantID string, roleID int64, object string, objectName string) ([]*dbmodel.Grant, error) {
|
||||
ret := _m.Called(tenantID, roleID, object, objectName)
|
||||
|
||||
var r0 []*dbmodel.Grant
|
||||
if rf, ok := ret.Get(0).(func(string, int64, string, string) []*dbmodel.Grant); ok {
|
||||
r0 = rf(tenantID, roleID, object, objectName)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*dbmodel.Grant)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, string, string) error); ok {
|
||||
r1 = rf(tenantID, roleID, object, objectName)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Insert provides a mock function with given fields: in
|
||||
func (_m *IGrantDb) Insert(in *dbmodel.Grant) error {
|
||||
ret := _m.Called(in)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*dbmodel.Grant) error); ok {
|
||||
r0 = rf(in)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewIGrantDb interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewIGrantDb creates a new instance of IGrantDb. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewIGrantDb(t mockConstructorTestingTNewIGrantDb) *IGrantDb {
|
||||
mock := &IGrantDb{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
|
@ -78,6 +78,22 @@ func (_m *IMetaDomain) FieldDb(ctx context.Context) dbmodel.IFieldDb {
|
|||
return r0
|
||||
}
|
||||
|
||||
// GrantDb provides a mock function with given fields: ctx
|
||||
func (_m *IMetaDomain) GrantDb(ctx context.Context) dbmodel.IGrantDb {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 dbmodel.IGrantDb
|
||||
if rf, ok := ret.Get(0).(func(context.Context) dbmodel.IGrantDb); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(dbmodel.IGrantDb)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IndexDb provides a mock function with given fields: ctx
|
||||
func (_m *IMetaDomain) IndexDb(ctx context.Context) dbmodel.IIndexDb {
|
||||
ret := _m.Called(ctx)
|
||||
|
@ -110,6 +126,22 @@ func (_m *IMetaDomain) PartitionDb(ctx context.Context) dbmodel.IPartitionDb {
|
|||
return r0
|
||||
}
|
||||
|
||||
// RoleDb provides a mock function with given fields: ctx
|
||||
func (_m *IMetaDomain) RoleDb(ctx context.Context) dbmodel.IRoleDb {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 dbmodel.IRoleDb
|
||||
if rf, ok := ret.Get(0).(func(context.Context) dbmodel.IRoleDb); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(dbmodel.IRoleDb)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SegmentIndexDb provides a mock function with given fields: ctx
|
||||
func (_m *IMetaDomain) SegmentIndexDb(ctx context.Context) dbmodel.ISegmentIndexDb {
|
||||
ret := _m.Called(ctx)
|
||||
|
@ -142,6 +174,22 @@ func (_m *IMetaDomain) UserDb(ctx context.Context) dbmodel.IUserDb {
|
|||
return r0
|
||||
}
|
||||
|
||||
// UserRoleDb provides a mock function with given fields: ctx
|
||||
func (_m *IMetaDomain) UserRoleDb(ctx context.Context) dbmodel.IUserRoleDb {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
var r0 dbmodel.IUserRoleDb
|
||||
if rf, ok := ret.Get(0).(func(context.Context) dbmodel.IUserRoleDb); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(dbmodel.IUserRoleDb)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewIMetaDomain interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
dbmodel "github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// IRoleDb is an autogenerated mock type for the IRoleDb type
|
||||
type IRoleDb struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: tenantID, name
|
||||
func (_m *IRoleDb) Delete(tenantID string, name string) error {
|
||||
ret := _m.Called(tenantID, name)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, string) error); ok {
|
||||
r0 = rf(tenantID, name)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetRoles provides a mock function with given fields: tenantID, name
|
||||
func (_m *IRoleDb) GetRoles(tenantID string, name string) ([]*dbmodel.Role, error) {
|
||||
ret := _m.Called(tenantID, name)
|
||||
|
||||
var r0 []*dbmodel.Role
|
||||
if rf, ok := ret.Get(0).(func(string, string) []*dbmodel.Role); ok {
|
||||
r0 = rf(tenantID, name)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*dbmodel.Role)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||
r1 = rf(tenantID, name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Insert provides a mock function with given fields: in
|
||||
func (_m *IRoleDb) Insert(in *dbmodel.Role) error {
|
||||
ret := _m.Called(in)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*dbmodel.Role) error); ok {
|
||||
r0 = rf(in)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewIRoleDb interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewIRoleDb creates a new instance of IRoleDb. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewIRoleDb(t mockConstructorTestingTNewIRoleDb) *IRoleDb {
|
||||
mock := &IRoleDb{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
|
@ -49,16 +49,16 @@ func (_m *IUserDb) Insert(in *dbmodel.User) error {
|
|||
return r0
|
||||
}
|
||||
|
||||
// ListUsername provides a mock function with given fields: tenantID
|
||||
func (_m *IUserDb) ListUsername(tenantID string) ([]string, error) {
|
||||
// ListUser provides a mock function with given fields: tenantID
|
||||
func (_m *IUserDb) ListUser(tenantID string) ([]*dbmodel.User, error) {
|
||||
ret := _m.Called(tenantID)
|
||||
|
||||
var r0 []string
|
||||
if rf, ok := ret.Get(0).(func(string) []string); ok {
|
||||
var r0 []*dbmodel.User
|
||||
if rf, ok := ret.Get(0).(func(string) []*dbmodel.User); ok {
|
||||
r0 = rf(tenantID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
r0 = ret.Get(0).([]*dbmodel.User)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
dbmodel "github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// IUserRoleDb is an autogenerated mock type for the IUserRoleDb type
|
||||
type IUserRoleDb struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: tenantID, userID, roleID
|
||||
func (_m *IUserRoleDb) Delete(tenantID string, userID int64, roleID int64) error {
|
||||
ret := _m.Called(tenantID, userID, roleID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, int64, int64) error); ok {
|
||||
r0 = rf(tenantID, userID, roleID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetUserRoles provides a mock function with given fields: tenantID, userID, roleID
|
||||
func (_m *IUserRoleDb) GetUserRoles(tenantID string, userID int64, roleID int64) ([]*dbmodel.UserRole, error) {
|
||||
ret := _m.Called(tenantID, userID, roleID)
|
||||
|
||||
var r0 []*dbmodel.UserRole
|
||||
if rf, ok := ret.Get(0).(func(string, int64, int64) []*dbmodel.UserRole); ok {
|
||||
r0 = rf(tenantID, userID, roleID)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*dbmodel.UserRole)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, int64, int64) error); ok {
|
||||
r1 = rf(tenantID, userID, roleID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Insert provides a mock function with given fields: in
|
||||
func (_m *IUserRoleDb) Insert(in *dbmodel.UserRole) error {
|
||||
ret := _m.Called(in)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(*dbmodel.UserRole) error); ok {
|
||||
r0 = rf(in)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewIUserRoleDb interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewIUserRoleDb creates a new instance of IUserRoleDb. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewIUserRoleDb(t mockConstructorTestingTNewIUserRoleDb) *IUserRoleDb {
|
||||
mock := &IUserRoleDb{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package dbmodel
|
||||
|
||||
import "github.com/milvus-io/milvus/internal/proto/milvuspb"
|
||||
|
||||
type Role struct {
|
||||
Base
|
||||
Name string `gorm:"name"`
|
||||
}
|
||||
|
||||
func (r *Role) TableName() string {
|
||||
return "role"
|
||||
}
|
||||
|
||||
func (r *Role) Unmarshal() *milvuspb.RoleEntity {
|
||||
return &milvuspb.RoleEntity{Name: r.Name}
|
||||
}
|
||||
|
||||
//go:generate mockery --name=IRoleDb
|
||||
type IRoleDb interface {
|
||||
GetRoles(tenantID string, name string) ([]*Role, error)
|
||||
Insert(in *Role) error
|
||||
Delete(tenantID string, name string) error
|
||||
}
|
|
@ -24,7 +24,7 @@ func (v User) TableName() string {
|
|||
//go:generate mockery --name=IUserDb
|
||||
type IUserDb interface {
|
||||
GetByUsername(tenantID string, username string) (*User, error)
|
||||
ListUsername(tenantID string) ([]string, error)
|
||||
ListUser(tenantID string) ([]*User, error)
|
||||
Insert(in *User) error
|
||||
MarkDeletedByUsername(tenantID string, username string) error
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package dbmodel
|
||||
|
||||
type UserRole struct {
|
||||
Base
|
||||
UserID int64 `gorm:"user_id"`
|
||||
RoleID int64 `gorm:"role_id"`
|
||||
|
||||
User User `gorm:"foreignKey:UserID"`
|
||||
Role Role `gorm:"foreignKey:RoleID"`
|
||||
}
|
||||
|
||||
func (u *UserRole) TableName() string {
|
||||
return "user_role"
|
||||
}
|
||||
|
||||
//go:generate mockery --name=IUserRoleDb
|
||||
type IUserRoleDb interface {
|
||||
GetUserRoles(tenantID string, userID int64, roleID int64) ([]*UserRole, error)
|
||||
Insert(in *UserRole) error
|
||||
Delete(tenantID string, userID int64, roleID int64) error
|
||||
}
|
|
@ -8,6 +8,10 @@ import (
|
|||
"reflect"
|
||||
"runtime"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/common"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/util"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/log"
|
||||
"github.com/milvus-io/milvus/internal/metastore"
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
|
@ -763,57 +767,292 @@ func (tc *Catalog) DropCredential(ctx context.Context, username string) error {
|
|||
func (tc *Catalog) ListCredentials(ctx context.Context) ([]string, error) {
|
||||
tenantID := contextutil.TenantID(ctx)
|
||||
|
||||
usernames, err := tc.metaDomain.UserDb(ctx).ListUsername(tenantID)
|
||||
users, err := tc.metaDomain.UserDb(ctx).ListUser(tenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var usernames []string
|
||||
for _, user := range users {
|
||||
usernames = append(usernames, user.Username)
|
||||
}
|
||||
return usernames, nil
|
||||
}
|
||||
|
||||
func (tc *Catalog) CreateRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error {
|
||||
//TODO implement me
|
||||
return nil
|
||||
var err error
|
||||
if _, err = tc.GetRoleIDByName(ctx, tenant, entity.Name); err != nil && !common.IsKeyNotExistError(err) {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
return common.NewIgnorableError(fmt.Errorf("the role[%s] has existed", entity.Name))
|
||||
}
|
||||
return tc.metaDomain.RoleDb(ctx).Insert(&dbmodel.Role{
|
||||
Base: dbmodel.Base{TenantID: tenant},
|
||||
Name: entity.Name,
|
||||
})
|
||||
}
|
||||
|
||||
func (tc *Catalog) DropRole(ctx context.Context, tenant string, roleName string) error {
|
||||
//TODO implement me
|
||||
return nil
|
||||
return tc.metaDomain.RoleDb(ctx).Delete(tenant, roleName)
|
||||
}
|
||||
|
||||
func (tc *Catalog) OperateUserRole(ctx context.Context, tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error {
|
||||
//TODO implement me
|
||||
return nil
|
||||
func (tc *Catalog) GetRoleIDByName(ctx context.Context, tenant string, name string) (int64, error) {
|
||||
var (
|
||||
roles []*dbmodel.Role
|
||||
err error
|
||||
)
|
||||
|
||||
if roles, err = tc.metaDomain.RoleDb(ctx).GetRoles(tenant, name); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(roles) < 1 {
|
||||
return 0, common.NewKeyNotExistError(fmt.Sprintf("%s/%s", tenant, name))
|
||||
}
|
||||
return roles[0].ID, nil
|
||||
}
|
||||
|
||||
func (tc *Catalog) SelectRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
//TODO implement me
|
||||
return nil, nil
|
||||
func (tc *Catalog) AlterUserRole(ctx context.Context, tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error {
|
||||
var (
|
||||
user *dbmodel.User
|
||||
roleID int64
|
||||
userRole *dbmodel.UserRole
|
||||
userRoles []*dbmodel.UserRole
|
||||
err error
|
||||
)
|
||||
if user, err = tc.metaDomain.UserDb(ctx).GetByUsername(tenant, userEntity.Name); err != nil {
|
||||
log.Error("fail to get userID by the username", zap.String("username", userEntity.Name), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
if roleID, err = tc.GetRoleIDByName(ctx, tenant, roleEntity.Name); err != nil {
|
||||
log.Error("fail to get roleID by the role name", zap.String("role_name", roleEntity.Name), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
userRole = &dbmodel.UserRole{Base: dbmodel.Base{TenantID: tenant}, UserID: user.ID, RoleID: roleID}
|
||||
userRoles, err = tc.metaDomain.UserRoleDb(ctx).GetUserRoles(userRole.TenantID, userRole.UserID, userRole.RoleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch operateType {
|
||||
case milvuspb.OperateUserRoleType_AddUserToRole:
|
||||
if len(userRoles) > 0 {
|
||||
return common.NewIgnorableError(fmt.Errorf("the user-role[%s-%s] is existed", userEntity.Name, roleEntity.Name))
|
||||
}
|
||||
return tc.metaDomain.UserRoleDb(ctx).Insert(userRole)
|
||||
case milvuspb.OperateUserRoleType_RemoveUserFromRole:
|
||||
if len(userRoles) < 1 {
|
||||
return common.NewIgnorableError(fmt.Errorf("the user-role[%s-%s] isn't existed", userEntity.Name, roleEntity.Name))
|
||||
}
|
||||
return tc.metaDomain.UserRoleDb(ctx).Delete(userRole.TenantID, userRole.UserID, userRole.RoleID)
|
||||
default:
|
||||
err = fmt.Errorf("invalid operate type: %d", operateType)
|
||||
log.Error("error: ", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *Catalog) SelectUser(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
//TODO implement me
|
||||
return nil, nil
|
||||
func (tc *Catalog) ListRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
var (
|
||||
roleName string
|
||||
roles []*dbmodel.Role
|
||||
results []*milvuspb.RoleResult
|
||||
err error
|
||||
)
|
||||
if entity != nil {
|
||||
roleName = entity.Name
|
||||
}
|
||||
roles, err = tc.metaDomain.RoleDb(ctx).GetRoles(tenant, roleName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, role := range roles {
|
||||
var users []*milvuspb.UserEntity
|
||||
var userRoles []*dbmodel.UserRole
|
||||
if includeUserInfo {
|
||||
if userRoles, err = tc.metaDomain.UserRoleDb(ctx).GetUserRoles(tenant, 0, role.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, userRole := range userRoles {
|
||||
users = append(users, &milvuspb.UserEntity{Name: userRole.User.Username})
|
||||
}
|
||||
}
|
||||
results = append(results, &milvuspb.RoleResult{
|
||||
Role: role.Unmarshal(),
|
||||
Users: users,
|
||||
})
|
||||
}
|
||||
if !funcutil.IsEmptyString(roleName) && len(results) == 0 {
|
||||
return nil, common.NewKeyNotExistError(fmt.Sprintf("%s/%s", tenant, roleName))
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (tc *Catalog) OperatePrivilege(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error {
|
||||
//TODO implement me
|
||||
return nil
|
||||
func (tc *Catalog) ListUser(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
var (
|
||||
users []*dbmodel.User
|
||||
results []*milvuspb.UserResult
|
||||
username string
|
||||
err error
|
||||
)
|
||||
if entity != nil {
|
||||
var user *dbmodel.User
|
||||
username = entity.Name
|
||||
if user, err = tc.metaDomain.UserDb(ctx).GetByUsername(tenant, username); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, user)
|
||||
} else {
|
||||
if users, err = tc.metaDomain.UserDb(ctx).ListUser(tenant); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for _, user := range users {
|
||||
var roles []*milvuspb.RoleEntity
|
||||
var userRoles []*dbmodel.UserRole
|
||||
if includeRoleInfo {
|
||||
if userRoles, err = tc.metaDomain.UserRoleDb(ctx).GetUserRoles(tenant, user.ID, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, userRole := range userRoles {
|
||||
roles = append(roles, &milvuspb.RoleEntity{Name: userRole.Role.Name})
|
||||
}
|
||||
}
|
||||
results = append(results, &milvuspb.UserResult{
|
||||
User: &milvuspb.UserEntity{Name: user.Username},
|
||||
Roles: roles,
|
||||
})
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (tc *Catalog) SelectGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) {
|
||||
//TODO implement me
|
||||
return nil, nil
|
||||
func (tc *Catalog) AlterGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error {
|
||||
var (
|
||||
roleID int64
|
||||
detail string
|
||||
err error
|
||||
)
|
||||
|
||||
if roleID, err = tc.GetRoleIDByName(ctx, tenant, entity.Role.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
switch operateType {
|
||||
case milvuspb.OperatePrivilegeType_Revoke:
|
||||
return tc.metaDomain.GrantDb(ctx).
|
||||
Delete(tenant, roleID, entity.Object.Name, entity.ObjectName, entity.Grantor.Privilege.Name)
|
||||
case milvuspb.OperatePrivilegeType_Grant:
|
||||
if detail, err = dbmodel.EncodeGrantDetail("", entity.Grantor.User.Name, entity.Grantor.Privilege.Name, true); err != nil {
|
||||
log.Error("fail to encode grant detail", zap.String("tenant", tenant), zap.Any("entity", entity), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
return tc.metaDomain.GrantDb(ctx).Insert(&dbmodel.Grant{
|
||||
Base: dbmodel.Base{TenantID: tenant},
|
||||
RoleID: roleID,
|
||||
Object: entity.Object.Name,
|
||||
ObjectName: entity.ObjectName,
|
||||
Detail: detail,
|
||||
})
|
||||
default:
|
||||
err = fmt.Errorf("invalid operate type: %d", operateType)
|
||||
log.Error("error: ", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *Catalog) ListGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) {
|
||||
var (
|
||||
roleID int64
|
||||
object string
|
||||
objectName string
|
||||
grants []*dbmodel.Grant
|
||||
grantEntities []*milvuspb.GrantEntity
|
||||
details [][]string
|
||||
privilegeName string
|
||||
err error
|
||||
)
|
||||
if !funcutil.IsEmptyString(entity.ObjectName) && entity.Object != nil && !funcutil.IsEmptyString(entity.Object.Name) {
|
||||
object = entity.Object.Name
|
||||
objectName = entity.ObjectName
|
||||
}
|
||||
if roleID, err = tc.GetRoleIDByName(ctx, tenant, entity.Role.Name); err != nil {
|
||||
log.Error("fail to get roleID by the role name", zap.String("role_name", entity.Role.Name), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
if grants, err = tc.metaDomain.GrantDb(ctx).GetGrants(tenant, roleID, object, objectName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, grant := range grants {
|
||||
if details, err = dbmodel.DecodeGrantDetail(grant.Detail); err != nil {
|
||||
log.Error("fail to decode grant detail", zap.Any("detail", grant.Detail), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
for _, detail := range details {
|
||||
if len(detail) != 2 {
|
||||
log.Error("invalid operateDetail", zap.Any("detail", detail))
|
||||
return nil, fmt.Errorf("invalid operateDetail: [%s], decode result: %+v", grant.Detail, details)
|
||||
}
|
||||
privilegeName = util.PrivilegeNameForAPI(detail[1])
|
||||
if detail[1] == util.AnyWord {
|
||||
privilegeName = util.AnyWord
|
||||
}
|
||||
grantEntities = append(grantEntities, &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: grant.Role.Name},
|
||||
Object: &milvuspb.ObjectEntity{Name: grant.Object},
|
||||
ObjectName: grant.ObjectName,
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
User: &milvuspb.UserEntity{Name: detail[0]},
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: privilegeName},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
if !funcutil.IsEmptyString(object) && !funcutil.IsEmptyString(objectName) && len(grantEntities) == 0 {
|
||||
return nil, common.NewKeyNotExistError(fmt.Sprintf("%s/%s/%s/%s", tenant, entity.Role.Name, object, objectName))
|
||||
}
|
||||
return grantEntities, nil
|
||||
}
|
||||
|
||||
func (tc *Catalog) ListPolicy(ctx context.Context, tenant string) ([]string, error) {
|
||||
//TODO implement me
|
||||
return nil, nil
|
||||
var (
|
||||
grants []*dbmodel.Grant
|
||||
details [][]string
|
||||
policies []string
|
||||
err error
|
||||
)
|
||||
if grants, err = tc.metaDomain.GrantDb(ctx).GetGrants(tenant, 0, "", ""); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, grant := range grants {
|
||||
if details, err = dbmodel.DecodeGrantDetail(grant.Detail); err != nil {
|
||||
log.Error("fail to decode grant detail", zap.Any("detail", grant.Detail), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
for _, detail := range details {
|
||||
if len(detail) != 2 {
|
||||
log.Error("invalid operateDetail", zap.String("tenant", tenant), zap.Strings("detail", detail))
|
||||
return nil, fmt.Errorf("invalid operateDetail: %+v", detail)
|
||||
}
|
||||
policies = append(policies,
|
||||
funcutil.PolicyForPrivilege(grant.Role.Name, grant.Object, grant.ObjectName, detail[1]))
|
||||
}
|
||||
}
|
||||
|
||||
return policies, nil
|
||||
}
|
||||
|
||||
func (tc *Catalog) ListUserRole(ctx context.Context, tenant string) ([]string, error) {
|
||||
//TODO implement me
|
||||
return nil, nil
|
||||
var (
|
||||
userRoleStrs []string
|
||||
userRoles []*dbmodel.UserRole
|
||||
err error
|
||||
)
|
||||
|
||||
if userRoles, err = tc.metaDomain.UserRoleDb(ctx).GetUserRoles(tenant, 0, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, userRole := range userRoles {
|
||||
userRoleStrs = append(userRoleStrs, funcutil.EncodeUserRoleCache(userRole.User.Username, userRole.Role.Name))
|
||||
}
|
||||
|
||||
return userRoleStrs, nil
|
||||
}
|
||||
|
||||
func (tc *Catalog) Close() {
|
||||
|
|
|
@ -8,12 +8,15 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/common"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/proto/milvuspb"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/metastore"
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel"
|
||||
"github.com/milvus-io/milvus/internal/metastore/db/dbmodel/mocks"
|
||||
"github.com/milvus-io/milvus/internal/metastore/model"
|
||||
"github.com/milvus-io/milvus/internal/proto/commonpb"
|
||||
"github.com/milvus-io/milvus/internal/proto/milvuspb"
|
||||
"github.com/milvus-io/milvus/internal/proto/schemapb"
|
||||
"github.com/milvus-io/milvus/internal/util/contextutil"
|
||||
"github.com/milvus-io/milvus/internal/util/funcutil"
|
||||
|
@ -52,6 +55,9 @@ var (
|
|||
aliasDbMock *mocks.ICollAliasDb
|
||||
segIndexDbMock *mocks.ISegmentIndexDb
|
||||
userDbMock *mocks.IUserDb
|
||||
roleDbMock *mocks.IRoleDb
|
||||
userRoleDbMock *mocks.IUserRoleDb
|
||||
grantDbMock *mocks.IGrantDb
|
||||
|
||||
mockCatalog *Catalog
|
||||
)
|
||||
|
@ -68,6 +74,9 @@ func TestMain(m *testing.M) {
|
|||
aliasDbMock = &mocks.ICollAliasDb{}
|
||||
segIndexDbMock = &mocks.ISegmentIndexDb{}
|
||||
userDbMock = &mocks.IUserDb{}
|
||||
roleDbMock = &mocks.IRoleDb{}
|
||||
userRoleDbMock = &mocks.IUserRoleDb{}
|
||||
grantDbMock = &mocks.IGrantDb{}
|
||||
|
||||
metaDomainMock = &mocks.IMetaDomain{}
|
||||
metaDomainMock.On("CollectionDb", ctx).Return(collDbMock)
|
||||
|
@ -78,6 +87,9 @@ func TestMain(m *testing.M) {
|
|||
metaDomainMock.On("CollAliasDb", ctx).Return(aliasDbMock)
|
||||
metaDomainMock.On("SegmentIndexDb", ctx).Return(segIndexDbMock)
|
||||
metaDomainMock.On("UserDb", ctx).Return(userDbMock)
|
||||
metaDomainMock.On("RoleDb", ctx).Return(roleDbMock)
|
||||
metaDomainMock.On("UserRoleDb", ctx).Return(userRoleDbMock)
|
||||
metaDomainMock.On("GrantDb", ctx).Return(grantDbMock)
|
||||
|
||||
mockCatalog = mockMetaCatalog(metaDomainMock)
|
||||
|
||||
|
@ -1348,21 +1360,24 @@ func TestTableCatalog_DropCredential_MarkUserDeletedError(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTableCatalog_ListCredentials(t *testing.T) {
|
||||
usernames := []string{username}
|
||||
user := &dbmodel.User{
|
||||
Username: username,
|
||||
EncryptedPassword: password,
|
||||
}
|
||||
|
||||
// expectation
|
||||
userDbMock.On("ListUsername", tenantID).Return(usernames, nil).Once()
|
||||
userDbMock.On("ListUser", tenantID).Return([]*dbmodel.User{user}, nil).Once()
|
||||
|
||||
// actual
|
||||
res, gotErr := mockCatalog.ListCredentials(ctx)
|
||||
require.NoError(t, gotErr)
|
||||
require.Equal(t, usernames, res)
|
||||
require.Equal(t, []string{username}, res)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListCredentials_SelectUsernamesError(t *testing.T) {
|
||||
// expectation
|
||||
errTest := errors.New("test error")
|
||||
userDbMock.On("ListUsername", tenantID).Return(nil, errTest).Once()
|
||||
userDbMock.On("ListUser", tenantID).Return(nil, errTest).Once()
|
||||
|
||||
// actual
|
||||
res, gotErr := mockCatalog.ListCredentials(ctx)
|
||||
|
@ -1371,55 +1386,715 @@ func TestTableCatalog_ListCredentials_SelectUsernamesError(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTableCatalog_CreateRole(t *testing.T) {
|
||||
//TODO implement me
|
||||
gotErr := mockCatalog.CreateRole(ctx, tenantID, nil)
|
||||
require.Nil(t, gotErr)
|
||||
var (
|
||||
roleName = "foo"
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{}, nil).Once()
|
||||
roleDbMock.On("Insert", mock.Anything).Return(nil).Once()
|
||||
err = mockCatalog.CreateRole(ctx, tenantID, &milvuspb.RoleEntity{Name: roleName})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_CreateRole_Error(t *testing.T) {
|
||||
var (
|
||||
roleName = "foo"
|
||||
err error
|
||||
)
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return(nil, errors.New("test error")).Once()
|
||||
err = mockCatalog.CreateRole(ctx, tenantID, &milvuspb.RoleEntity{Name: roleName})
|
||||
require.Error(t, err)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}}}, nil).Once()
|
||||
err = mockCatalog.CreateRole(ctx, tenantID, &milvuspb.RoleEntity{Name: roleName})
|
||||
require.Equal(t, true, common.IsIgnorableError(err))
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{}, nil).Once()
|
||||
roleDbMock.On("Insert", mock.Anything).Return(errors.New("test error")).Once()
|
||||
err = mockCatalog.CreateRole(ctx, tenantID, &milvuspb.RoleEntity{Name: roleName})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_DropRole(t *testing.T) {
|
||||
//TODO implement me
|
||||
gotErr := mockCatalog.DropRole(ctx, tenantID, "")
|
||||
require.Nil(t, gotErr)
|
||||
var (
|
||||
roleName = "foo"
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("Delete", tenantID, roleName).Return(nil).Once()
|
||||
err = mockCatalog.DropRole(ctx, tenantID, roleName)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_OperateUserRole(t *testing.T) {
|
||||
//TODO implement me
|
||||
gotErr := mockCatalog.OperateUserRole(ctx, tenantID, nil, nil, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
require.Nil(t, gotErr)
|
||||
func TestTableCatalog_DropRole_Error(t *testing.T) {
|
||||
var (
|
||||
roleName = "foo"
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("Delete", tenantID, roleName).Return(errors.New("test error")).Once()
|
||||
err = mockCatalog.DropRole(ctx, tenantID, roleName)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_SelectRole(t *testing.T) {
|
||||
//TODO implement me
|
||||
_, gotErr := mockCatalog.SelectRole(ctx, tenantID, nil, false)
|
||||
require.Nil(t, gotErr)
|
||||
func TestTableCatalog_AlterUserRole(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
userID = 100
|
||||
roleName = "fo"
|
||||
roleID = 10
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: int64(roleID)}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(userID), int64(roleID)).Return([]*dbmodel.UserRole{}, nil).Once()
|
||||
userRoleDbMock.On("Insert", mock.Anything).Return(nil).Once()
|
||||
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_SelectUser(t *testing.T) {
|
||||
//TODO implement me
|
||||
_, gotErr := mockCatalog.SelectUser(ctx, tenantID, nil, false)
|
||||
require.Nil(t, gotErr)
|
||||
func TestTableCatalog_AlterUserRole_GetUserIDError(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
roleName = "fo"
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(nil, errors.New("test error")).Once()
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_OperatePrivilege(t *testing.T) {
|
||||
//TODO implement me
|
||||
gotErr := mockCatalog.OperatePrivilege(ctx, tenantID, nil, milvuspb.OperatePrivilegeType_Revoke)
|
||||
require.Nil(t, gotErr)
|
||||
func TestTableCatalog_AlterUserRole_GetRoleIDError(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
userID = 100
|
||||
roleName = "fo"
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return(nil, errors.New("test error")).Once()
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_SelectGrant(t *testing.T) {
|
||||
//TODO implement me
|
||||
_, gotErr := mockCatalog.SelectGrant(ctx, tenantID, nil)
|
||||
require.Nil(t, gotErr)
|
||||
func TestTableCatalog_AlterUserRole_GetUserRoleError(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
userID = 100
|
||||
roleName = "fo"
|
||||
roleID = 10
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: int64(roleID)}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(userID), int64(roleID)).Return([]*dbmodel.UserRole{}, errors.New("test error")).Once()
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_AlterUserRole_RepeatUserRole(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
userID = 100
|
||||
roleName = "fo"
|
||||
roleID = 10
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: int64(roleID)}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(userID), int64(roleID)).Return([]*dbmodel.UserRole{{}}, nil).Once()
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
require.Error(t, err)
|
||||
require.Equal(t, true, common.IsIgnorableError(err))
|
||||
}
|
||||
|
||||
func TestTableCatalog_AlterUserRole_InsertError(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
userID = 100
|
||||
roleName = "fo"
|
||||
roleID = 10
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: int64(roleID)}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(userID), int64(roleID)).Return([]*dbmodel.UserRole{}, nil).Once()
|
||||
userRoleDbMock.On("Insert", mock.Anything).Return(errors.New("test error")).Once()
|
||||
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_AlterUserRole_Delete(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
userID = 100
|
||||
roleName = "fo"
|
||||
roleID = 10
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: int64(roleID)}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(userID), int64(roleID)).Return([]*dbmodel.UserRole{{}}, nil).Once()
|
||||
userRoleDbMock.On("Delete", tenantID, int64(userID), int64(roleID)).Return(nil).Once()
|
||||
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_RemoveUserFromRole)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_AlterUserRole_DeleteError(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
userID = 100
|
||||
roleName = "fo"
|
||||
roleID = 10
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: int64(roleID)}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(userID), int64(roleID)).Return([]*dbmodel.UserRole{}, nil).Once()
|
||||
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_RemoveUserFromRole)
|
||||
require.Error(t, err)
|
||||
require.True(t, common.IsIgnorableError(err))
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: int64(roleID)}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(userID), int64(roleID)).Return([]*dbmodel.UserRole{{}}, nil).Once()
|
||||
userRoleDbMock.On("Delete", tenantID, int64(userID), int64(roleID)).Return(errors.New("test error")).Once()
|
||||
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, milvuspb.OperateUserRoleType_RemoveUserFromRole)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_AlterUserRole_InvalidType(t *testing.T) {
|
||||
var (
|
||||
username = "foo"
|
||||
userID = 100
|
||||
roleName = "fo"
|
||||
roleID = 10
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username).Return(&dbmodel.User{ID: int64(userID)}, nil).Once()
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: int64(roleID)}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(userID), int64(roleID)).Return([]*dbmodel.UserRole{{}}, nil).Once()
|
||||
|
||||
err = mockCatalog.AlterUserRole(ctx, tenantID, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, 100)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListRole_AllRole(t *testing.T) {
|
||||
var (
|
||||
roleName1 = "foo1"
|
||||
roleName2 = "foo2"
|
||||
result []*milvuspb.RoleResult
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, "").Return([]*dbmodel.Role{{Name: roleName1}, {Name: roleName2}}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListRole(ctx, tenantID, nil, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(result))
|
||||
require.Equal(t, roleName1, result[0].Role.Name)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListRole_AllRole_IncludeUserInfo(t *testing.T) {
|
||||
var (
|
||||
roleName1 = "foo1"
|
||||
username1 = "fo1"
|
||||
username2 = "fo2"
|
||||
roleName2 = "foo2"
|
||||
result []*milvuspb.RoleResult
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, "").Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}, Name: roleName1}, {Base: dbmodel.Base{ID: 10}, Name: roleName2}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(0), int64(1)).Return([]*dbmodel.UserRole{{User: dbmodel.User{Username: username1}}, {User: dbmodel.User{Username: username2}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(0), int64(10)).Return([]*dbmodel.UserRole{}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListRole(ctx, tenantID, nil, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(result))
|
||||
require.Equal(t, roleName1, result[0].Role.Name)
|
||||
require.Equal(t, 2, len(result[0].Users))
|
||||
require.Equal(t, username1, result[0].Users[0].Name)
|
||||
require.Equal(t, username2, result[0].Users[1].Name)
|
||||
require.Equal(t, roleName2, result[1].Role.Name)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListRole_AllRole_Empty(t *testing.T) {
|
||||
var (
|
||||
result []*milvuspb.RoleResult
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, "").Return([]*dbmodel.Role{}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListRole(ctx, tenantID, nil, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(result))
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListRole_OneRole(t *testing.T) {
|
||||
var (
|
||||
roleName1 = "foo1"
|
||||
result []*milvuspb.RoleResult
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, roleName1).Return([]*dbmodel.Role{{Name: roleName1}}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListRole(ctx, tenantID, &milvuspb.RoleEntity{Name: roleName1}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(result))
|
||||
require.Equal(t, roleName1, result[0].Role.Name)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListRole_OneRole_IncludeUserInfo(t *testing.T) {
|
||||
var (
|
||||
roleName1 = "foo1"
|
||||
username1 = "fo1"
|
||||
username2 = "fo2"
|
||||
result []*milvuspb.RoleResult
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, roleName1).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}, Name: roleName1}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(0), int64(1)).Return([]*dbmodel.UserRole{{User: dbmodel.User{Username: username1}}, {User: dbmodel.User{Username: username2}}}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListRole(ctx, tenantID, &milvuspb.RoleEntity{Name: roleName1}, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(result))
|
||||
require.Equal(t, roleName1, result[0].Role.Name)
|
||||
require.Equal(t, 2, len(result[0].Users))
|
||||
require.Equal(t, username1, result[0].Users[0].Name)
|
||||
require.Equal(t, username2, result[0].Users[1].Name)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListRole_OneRole_Empty(t *testing.T) {
|
||||
var (
|
||||
roleName = "foo"
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{}, nil).Once()
|
||||
|
||||
_, err = mockCatalog.ListRole(ctx, tenantID, &milvuspb.RoleEntity{Name: roleName}, false)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListRole_GetRolesError(t *testing.T) {
|
||||
roleDbMock.On("GetRoles", tenantID, "").Return(nil, errors.New("test error")).Once()
|
||||
|
||||
_, err := mockCatalog.ListRole(ctx, tenantID, nil, false)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListRole_GetUserRolesError(t *testing.T) {
|
||||
roleDbMock.On("GetRoles", tenantID, "").Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}, Name: "foo"}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(0), int64(1)).Return(nil, errors.New("test error")).Once()
|
||||
_, err := mockCatalog.ListRole(ctx, tenantID, nil, true)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUser_AllUser(t *testing.T) {
|
||||
var (
|
||||
username1 = "foo1"
|
||||
username2 = "foo2"
|
||||
result []*milvuspb.UserResult
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("ListUser", tenantID).Return([]*dbmodel.User{{Username: username1}, {Username: username2}}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListUser(ctx, tenantID, nil, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(result))
|
||||
require.Equal(t, username1, result[0].User.Name)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUser_AllUser_IncludeRoleInfo(t *testing.T) {
|
||||
var (
|
||||
roleName1 = "foo1"
|
||||
username1 = "fo1"
|
||||
username2 = "fo2"
|
||||
roleName2 = "foo2"
|
||||
result []*milvuspb.UserResult
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("ListUser", tenantID).Return([]*dbmodel.User{{ID: 1, Username: username1}, {ID: 10, Username: username2}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(1), int64(0)).Return([]*dbmodel.UserRole{{Role: dbmodel.Role{Name: roleName1}}, {Role: dbmodel.Role{Name: roleName2}}}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(10), int64(0)).Return([]*dbmodel.UserRole{}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListUser(ctx, tenantID, nil, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(result))
|
||||
require.Equal(t, username1, result[0].User.Name)
|
||||
require.Equal(t, 2, len(result[0].Roles))
|
||||
require.Equal(t, roleName1, result[0].Roles[0].Name)
|
||||
require.Equal(t, roleName2, result[0].Roles[1].Name)
|
||||
require.Equal(t, username2, result[1].User.Name)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUser_AllUser_Empty(t *testing.T) {
|
||||
var (
|
||||
result []*milvuspb.UserResult
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("ListUser", tenantID).Return([]*dbmodel.User{}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListUser(ctx, tenantID, nil, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(result))
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUser_OneUser(t *testing.T) {
|
||||
var (
|
||||
username1 = "foo1"
|
||||
result []*milvuspb.UserResult
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username1).Return(&dbmodel.User{Username: username1}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListUser(ctx, tenantID, &milvuspb.UserEntity{Name: username1}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(result))
|
||||
require.Equal(t, username1, result[0].User.Name)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUser_OneUser_IncludeRoleInfo(t *testing.T) {
|
||||
var (
|
||||
roleName1 = "foo1"
|
||||
roleName2 = "foo1"
|
||||
username1 = "fo1"
|
||||
result []*milvuspb.UserResult
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username1).Return(&dbmodel.User{ID: 1, Username: username1}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(1), int64(0)).
|
||||
Return([]*dbmodel.UserRole{{Role: dbmodel.Role{Name: roleName1}}, {Role: dbmodel.Role{Name: roleName2}}}, nil).Once()
|
||||
|
||||
result, err = mockCatalog.ListUser(ctx, tenantID, &milvuspb.UserEntity{Name: username1}, true)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(result))
|
||||
require.Equal(t, username1, result[0].User.Name)
|
||||
require.Equal(t, 2, len(result[0].Roles))
|
||||
require.Equal(t, roleName1, result[0].Roles[0].Name)
|
||||
require.Equal(t, roleName2, result[0].Roles[1].Name)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUser_ListUserError(t *testing.T) {
|
||||
userDbMock.On("ListUser", tenantID).Return(nil, errors.New("test error")).Once()
|
||||
|
||||
_, err := mockCatalog.ListUser(ctx, tenantID, nil, false)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUser_GetByUsernameError(t *testing.T) {
|
||||
var (
|
||||
username1 = "foo"
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username1).Return(nil, errors.New("test error")).Once()
|
||||
|
||||
_, err = mockCatalog.ListUser(ctx, tenantID, &milvuspb.UserEntity{Name: username1}, false)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUser_GetUserRolesError(t *testing.T) {
|
||||
var (
|
||||
username1 = "foo"
|
||||
err error
|
||||
)
|
||||
|
||||
userDbMock.On("GetByUsername", tenantID, username1).Return(&dbmodel.User{ID: 1, Username: username1}, nil).Once()
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(1), int64(0)).Return(nil, errors.New("test error")).Once()
|
||||
|
||||
_, err = mockCatalog.ListUser(ctx, tenantID, &milvuspb.UserEntity{Name: username1}, true)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_AlterPrivilege_Revoke(t *testing.T) {
|
||||
var (
|
||||
grant *milvuspb.GrantEntity
|
||||
err error
|
||||
)
|
||||
grant = &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
User: &milvuspb.UserEntity{Name: "foo"},
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: "PrivilegeLoad"},
|
||||
},
|
||||
}
|
||||
roleDbMock.On("GetRoles", tenantID, grant.Role.Name).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}}}, nil).Once()
|
||||
grantDbMock.On("Delete", tenantID, int64(1), grant.Object.Name, grant.ObjectName, grant.Grantor.Privilege.Name).Return(nil).Once()
|
||||
|
||||
err = mockCatalog.AlterGrant(ctx, tenantID, grant, milvuspb.OperatePrivilegeType_Revoke)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_AlterPrivilege_Grant(t *testing.T) {
|
||||
var (
|
||||
grant *milvuspb.GrantEntity
|
||||
err error
|
||||
)
|
||||
grant = &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
User: &milvuspb.UserEntity{Name: "foo"},
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: "PrivilegeLoad"},
|
||||
},
|
||||
}
|
||||
roleDbMock.On("GetRoles", tenantID, grant.Role.Name).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}}}, nil).Once()
|
||||
grantDbMock.On("Insert", mock.Anything).Return(nil).Once()
|
||||
|
||||
err = mockCatalog.AlterGrant(ctx, tenantID, grant, milvuspb.OperatePrivilegeType_Grant)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_AlterPrivilege_InvalidType(t *testing.T) {
|
||||
var (
|
||||
roleName = "foo"
|
||||
err error
|
||||
)
|
||||
|
||||
roleDbMock.On("GetRoles", tenantID, roleName).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}}}, nil).Once()
|
||||
err = mockCatalog.AlterGrant(ctx, tenantID, &milvuspb.GrantEntity{Role: &milvuspb.RoleEntity{Name: roleName}}, 100)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListGrant(t *testing.T) {
|
||||
var (
|
||||
grant *milvuspb.GrantEntity
|
||||
grants []*dbmodel.Grant
|
||||
entites []*milvuspb.GrantEntity
|
||||
err error
|
||||
)
|
||||
|
||||
grant = &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
}
|
||||
grants = []*dbmodel.Grant{
|
||||
{
|
||||
Role: dbmodel.Role{Name: "foo"},
|
||||
Object: "Collection",
|
||||
ObjectName: "col1",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"],[\"admin\",\"PrivilegeLoad\"],[\"admin\",\"*\"]]",
|
||||
},
|
||||
}
|
||||
roleDbMock.On("GetRoles", tenantID, grant.Role.Name).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}}}, nil).Once()
|
||||
grantDbMock.On("GetGrants", tenantID, int64(1), grant.Object.Name, grant.ObjectName).Return(grants, nil).Once()
|
||||
|
||||
entites, err = mockCatalog.ListGrant(ctx, tenantID, grant)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 3, len(entites))
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListGrant_GetRolesError(t *testing.T) {
|
||||
var (
|
||||
grant *milvuspb.GrantEntity
|
||||
err error
|
||||
)
|
||||
grant = &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
}
|
||||
roleDbMock.On("GetRoles", tenantID, grant.Role.Name).Return(nil, errors.New("test error")).Once()
|
||||
_, err = mockCatalog.ListGrant(ctx, tenantID, grant)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListGrant_GetGrantError(t *testing.T) {
|
||||
var (
|
||||
grant *milvuspb.GrantEntity
|
||||
err error
|
||||
)
|
||||
grant = &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
}
|
||||
roleDbMock.On("GetRoles", tenantID, grant.Role.Name).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}}}, nil).Once()
|
||||
grantDbMock.On("GetGrants", tenantID, int64(1), grant.Object.Name, grant.ObjectName).Return(nil, errors.New("test error")).Once()
|
||||
_, err = mockCatalog.ListGrant(ctx, tenantID, grant)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListGrant_DecodeError(t *testing.T) {
|
||||
var (
|
||||
grant *milvuspb.GrantEntity
|
||||
grants []*dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
grant = &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
}
|
||||
grants = []*dbmodel.Grant{
|
||||
{
|
||||
Role: dbmodel.Role{Name: "foo"},
|
||||
Object: "Collection",
|
||||
ObjectName: "col1",
|
||||
Detail: "decode error",
|
||||
},
|
||||
}
|
||||
roleDbMock.On("GetRoles", tenantID, grant.Role.Name).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}}}, nil).Once()
|
||||
grantDbMock.On("GetGrants", tenantID, int64(1), grant.Object.Name, grant.ObjectName).Return(grants, nil).Once()
|
||||
|
||||
_, err = mockCatalog.ListGrant(ctx, tenantID, grant)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListGrant_DetailLenError(t *testing.T) {
|
||||
var (
|
||||
grant *milvuspb.GrantEntity
|
||||
grants []*dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
grant = &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
}
|
||||
grants = []*dbmodel.Grant{
|
||||
{
|
||||
Role: dbmodel.Role{Name: "foo"},
|
||||
Object: "Collection",
|
||||
ObjectName: "col1",
|
||||
Detail: "[[\"admin\"]]",
|
||||
},
|
||||
}
|
||||
roleDbMock.On("GetRoles", tenantID, grant.Role.Name).Return([]*dbmodel.Role{{Base: dbmodel.Base{ID: 1}}}, nil).Once()
|
||||
grantDbMock.On("GetGrants", tenantID, int64(1), grant.Object.Name, grant.ObjectName).Return(grants, nil).Once()
|
||||
|
||||
_, err = mockCatalog.ListGrant(ctx, tenantID, grant)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListPolicy(t *testing.T) {
|
||||
//TODO implement me
|
||||
_, gotErr := mockCatalog.ListPolicy(ctx, tenantID)
|
||||
require.Nil(t, gotErr)
|
||||
var (
|
||||
grant *milvuspb.GrantEntity
|
||||
grants []*dbmodel.Grant
|
||||
policies []string
|
||||
err error
|
||||
)
|
||||
|
||||
grant = &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
}
|
||||
grants = []*dbmodel.Grant{
|
||||
{
|
||||
Role: dbmodel.Role{Name: "foo"},
|
||||
Object: "Collection",
|
||||
ObjectName: "col1",
|
||||
Detail: "[[\"admin\",\"PrivilegeIndexDetail\"]]",
|
||||
},
|
||||
}
|
||||
grantDbMock.On("GetGrants", tenantID, int64(0), "", "").Return(grants, nil).Once()
|
||||
|
||||
policies, err = mockCatalog.ListPolicy(ctx, tenantID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(policies))
|
||||
require.Equal(t, funcutil.PolicyForPrivilege(grant.Role.Name, grant.Object.Name, grant.ObjectName, "PrivilegeIndexDetail"), policies[0])
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListPolicy_GetGrantsError(t *testing.T) {
|
||||
grantDbMock.On("GetGrants", tenantID, int64(0), "", "").Return(nil, errors.New("test error")).Once()
|
||||
|
||||
_, err := mockCatalog.ListPolicy(ctx, tenantID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListPolicy_DetailLenError(t *testing.T) {
|
||||
var (
|
||||
grants []*dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
|
||||
grants = []*dbmodel.Grant{
|
||||
{
|
||||
Role: dbmodel.Role{Name: "foo"},
|
||||
Object: "Collection",
|
||||
ObjectName: "col1",
|
||||
Detail: "decode error",
|
||||
},
|
||||
}
|
||||
grantDbMock.On("GetGrants", tenantID, int64(0), "", "").Return(grants, nil).Once()
|
||||
|
||||
_, err = mockCatalog.ListPolicy(ctx, tenantID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListPolicy_DecodeError(t *testing.T) {
|
||||
var (
|
||||
grants []*dbmodel.Grant
|
||||
err error
|
||||
)
|
||||
|
||||
grants = []*dbmodel.Grant{
|
||||
{
|
||||
Role: dbmodel.Role{Name: "foo"},
|
||||
Object: "Collection",
|
||||
ObjectName: "col1",
|
||||
Detail: "[[\"admin\"]]",
|
||||
},
|
||||
}
|
||||
grantDbMock.On("GetGrants", tenantID, int64(0), "", "").Return(grants, nil).Once()
|
||||
|
||||
_, err = mockCatalog.ListPolicy(ctx, tenantID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUserRole(t *testing.T) {
|
||||
//TODO implement me
|
||||
_, gotErr := mockCatalog.ListUserRole(ctx, tenantID)
|
||||
require.Nil(t, gotErr)
|
||||
var (
|
||||
username1 = "foo1"
|
||||
username2 = "foo2"
|
||||
roleName1 = "fo1"
|
||||
roleName2 = "fo2"
|
||||
userRoles []string
|
||||
err error
|
||||
)
|
||||
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(0), int64(0)).Return([]*dbmodel.UserRole{
|
||||
{User: dbmodel.User{Username: username1}, Role: dbmodel.Role{Name: roleName1}},
|
||||
{User: dbmodel.User{Username: username2}, Role: dbmodel.Role{Name: roleName2}},
|
||||
}, nil).Once()
|
||||
|
||||
userRoles, err = mockCatalog.ListUserRole(ctx, tenantID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(userRoles))
|
||||
require.Equal(t, funcutil.EncodeUserRoleCache(username1, roleName1), userRoles[0])
|
||||
}
|
||||
|
||||
func TestTableCatalog_ListUserRole_Error(t *testing.T) {
|
||||
userRoleDbMock.On("GetUserRoles", tenantID, int64(0), int64(0)).Return(nil, errors.New("test error")).Once()
|
||||
_, err := mockCatalog.ListUserRole(ctx, tenantID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
|
|
@ -784,14 +784,35 @@ func (kc *Catalog) ListCredentials(ctx context.Context) ([]string, error) {
|
|||
return usernames, nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) CreateRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error {
|
||||
k := funcutil.HandleTenantForEtcdKey(RolePrefix, tenant, entity.Name)
|
||||
err := kc.Txn.Save(k, "")
|
||||
if err != nil {
|
||||
log.Error("fail to create role", zap.String("key", k), zap.Error(err))
|
||||
func (kc *Catalog) save(k string) error {
|
||||
var err error
|
||||
if _, err = kc.Txn.Load(k); err != nil && !common.IsKeyNotExistError(err) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if err == nil {
|
||||
return common.NewIgnorableError(fmt.Errorf("the key[%s] is existed", k))
|
||||
}
|
||||
return kc.Txn.Save(k, "")
|
||||
}
|
||||
|
||||
func (kc *Catalog) remove(k string) error {
|
||||
var err error
|
||||
if _, err = kc.Txn.Load(k); err != nil {
|
||||
return err
|
||||
}
|
||||
if common.IsKeyNotExistError(err) {
|
||||
return common.NewIgnorableError(fmt.Errorf("the key[%s] isn't existed", k))
|
||||
}
|
||||
return kc.Txn.Remove(k)
|
||||
}
|
||||
|
||||
func (kc *Catalog) CreateRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error {
|
||||
k := funcutil.HandleTenantForEtcdKey(RolePrefix, tenant, entity.Name)
|
||||
err := kc.save(k)
|
||||
if err != nil {
|
||||
log.Error("fail to save the role", zap.String("key", k), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (kc *Catalog) DropRole(ctx context.Context, tenant string, roleName string) error {
|
||||
|
@ -804,18 +825,18 @@ func (kc *Catalog) DropRole(ctx context.Context, tenant string, roleName string)
|
|||
return nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) OperateUserRole(ctx context.Context, tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error {
|
||||
func (kc *Catalog) AlterUserRole(ctx context.Context, tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error {
|
||||
k := funcutil.HandleTenantForEtcdKey(RoleMappingPrefix, tenant, fmt.Sprintf("%s/%s", userEntity.Name, roleEntity.Name))
|
||||
var err error
|
||||
if operateType == milvuspb.OperateUserRoleType_AddUserToRole {
|
||||
err = kc.Txn.Save(k, "")
|
||||
err = kc.save(k)
|
||||
if err != nil {
|
||||
log.Error("fail to add user to role", zap.String("key", k), zap.Error(err))
|
||||
log.Error("fail to save the user-role", zap.String("key", k), zap.Error(err))
|
||||
}
|
||||
} else if operateType == milvuspb.OperateUserRoleType_RemoveUserFromRole {
|
||||
err = kc.Txn.Remove(k)
|
||||
err = kc.remove(k)
|
||||
if err != nil {
|
||||
log.Error("fail to remove user from role", zap.String("key", k), zap.Error(err))
|
||||
log.Error("fail to remove the user-role", zap.String("key", k), zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("invalid operate user role type, operate type: %d", operateType)
|
||||
|
@ -823,7 +844,7 @@ func (kc *Catalog) OperateUserRole(ctx context.Context, tenant string, userEntit
|
|||
return err
|
||||
}
|
||||
|
||||
func (kc *Catalog) SelectRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
func (kc *Catalog) ListRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
var results []*milvuspb.RoleResult
|
||||
|
||||
roleToUsers := make(map[string][]string)
|
||||
|
@ -927,7 +948,7 @@ func (kc *Catalog) getUserResult(tenant string, username string, includeRoleInfo
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) SelectUser(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
func (kc *Catalog) ListUser(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
var (
|
||||
usernames []string
|
||||
err error
|
||||
|
@ -967,7 +988,7 @@ func (kc *Catalog) SelectUser(ctx context.Context, tenant string, entity *milvus
|
|||
return results, nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) OperatePrivilege(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error {
|
||||
func (kc *Catalog) AlterGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error {
|
||||
privilegeName := entity.Grantor.Privilege.Name
|
||||
k := funcutil.HandleTenantForEtcdKey(GranteePrefix, tenant, fmt.Sprintf("%s/%s/%s", entity.Role.Name, entity.Object.Name, entity.ObjectName))
|
||||
|
||||
|
@ -976,6 +997,9 @@ func (kc *Catalog) OperatePrivilege(ctx context.Context, tenant string, entity *
|
|||
if err != nil {
|
||||
log.Warn("fail to load grant privilege entity", zap.String("key", k), zap.Any("type", operateType), zap.Error(err))
|
||||
if funcutil.IsRevoke(operateType) {
|
||||
if common.IsKeyNotExistError(err) {
|
||||
return common.NewIgnorableError(fmt.Errorf("the grant[%s] isn't existed", k))
|
||||
}
|
||||
return err
|
||||
}
|
||||
if !common.IsKeyNotExistError(err) {
|
||||
|
@ -1007,9 +1031,9 @@ func (kc *Catalog) OperatePrivilege(ctx context.Context, tenant string, entity *
|
|||
User: &milvuspb.UserEntity{Name: entity.Grantor.User.Name},
|
||||
})
|
||||
} else if isExisted && funcutil.IsGrant(operateType) {
|
||||
return nil
|
||||
return common.NewIgnorableError(fmt.Errorf("the privilege[%s] is granted", privilegeName))
|
||||
} else if !isExisted && funcutil.IsRevoke(operateType) {
|
||||
return fmt.Errorf("fail to revoke the privilege because the privilege isn't granted for the role, key: /%s", k)
|
||||
return common.NewIgnorableError(fmt.Errorf("the privilege[%s] isn't granted", privilegeName))
|
||||
} else if isExisted && funcutil.IsRevoke(operateType) {
|
||||
curGrantPrivilegeEntity.Entities = append(curGrantPrivilegeEntity.Entities[:dropIndex], curGrantPrivilegeEntity.Entities[dropIndex+1:]...)
|
||||
}
|
||||
|
@ -1037,7 +1061,7 @@ func (kc *Catalog) OperatePrivilege(ctx context.Context, tenant string, entity *
|
|||
return nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) SelectGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) {
|
||||
func (kc *Catalog) ListGrant(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) {
|
||||
var entities []*milvuspb.GrantEntity
|
||||
|
||||
var k string
|
||||
|
|
|
@ -4,11 +4,11 @@ import (
|
|||
"context"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/util"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/util/crypto"
|
||||
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
// validAuth validates the authentication
|
||||
|
|
|
@ -1370,21 +1370,21 @@ func (mt *MetaTable) OperateUserRole(tenant string, userEntity *milvuspb.UserEnt
|
|||
return fmt.Errorf("role name in the role entity is empty")
|
||||
}
|
||||
|
||||
return mt.catalog.OperateUserRole(mt.ctx, tenant, userEntity, roleEntity, operateType)
|
||||
return mt.catalog.AlterUserRole(mt.ctx, tenant, userEntity, roleEntity, operateType)
|
||||
}
|
||||
|
||||
// SelectRole select role.
|
||||
// Enter the role condition by the entity param. And this param is nil, which means selecting all roles.
|
||||
// Get all users that are added to the role by setting the includeUserInfo param to true.
|
||||
func (mt *MetaTable) SelectRole(tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return mt.catalog.SelectRole(mt.ctx, tenant, entity, includeUserInfo)
|
||||
return mt.catalog.ListRole(mt.ctx, tenant, entity, includeUserInfo)
|
||||
}
|
||||
|
||||
// SelectUser select user.
|
||||
// Enter the user condition by the entity param. And this param is nil, which means selecting all users.
|
||||
// Get all roles that are added the user to by setting the includeRoleInfo param to true.
|
||||
func (mt *MetaTable) SelectUser(tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
return mt.catalog.SelectUser(mt.ctx, tenant, entity, includeRoleInfo)
|
||||
return mt.catalog.ListUser(mt.ctx, tenant, entity, includeRoleInfo)
|
||||
}
|
||||
|
||||
// OperatePrivilege grant or revoke privilege by setting the operateType param
|
||||
|
@ -1411,7 +1411,7 @@ func (mt *MetaTable) OperatePrivilege(tenant string, entity *milvuspb.GrantEntit
|
|||
return fmt.Errorf("the operate type in the grant entity is invalid")
|
||||
}
|
||||
|
||||
return mt.catalog.OperatePrivilege(mt.ctx, tenant, entity, operateType)
|
||||
return mt.catalog.AlterGrant(mt.ctx, tenant, entity, operateType)
|
||||
}
|
||||
|
||||
// SelectGrant select grant
|
||||
|
@ -1422,7 +1422,7 @@ func (mt *MetaTable) SelectGrant(tenant string, entity *milvuspb.GrantEntity) ([
|
|||
if entity.Role == nil || funcutil.IsEmptyString(entity.Role.Name) {
|
||||
return entities, fmt.Errorf("the role entity in the grant entity is invalid")
|
||||
}
|
||||
return mt.catalog.SelectGrant(mt.ctx, tenant, entity)
|
||||
return mt.catalog.ListGrant(mt.ctx, tenant, entity)
|
||||
}
|
||||
|
||||
func (mt *MetaTable) ListPolicy(tenant string) ([]string, error) {
|
||||
|
|
|
@ -1087,9 +1087,24 @@ func TestRbacCreateRole(t *testing.T) {
|
|||
mockTxnKV.save = func(key, value string) error {
|
||||
return nil
|
||||
}
|
||||
mockTxnKV.load = func(key string) (string, error) {
|
||||
return "", common.NewKeyNotExistError(key)
|
||||
}
|
||||
err = mt.CreateRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
|
||||
assert.Nil(t, err)
|
||||
|
||||
mockTxnKV.load = func(key string) (string, error) {
|
||||
return "", fmt.Errorf("load error")
|
||||
}
|
||||
err = mt.CreateRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
mockTxnKV.load = func(key string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
err = mt.CreateRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
|
||||
assert.Equal(t, true, common.IsIgnorableError(err))
|
||||
|
||||
mockTxnKV.save = func(key, value string) error {
|
||||
return fmt.Errorf("save error")
|
||||
}
|
||||
|
@ -1134,6 +1149,9 @@ func TestRbacOperateRole(t *testing.T) {
|
|||
err = mt.OperateUserRole(util.DefaultTenant, &milvuspb.UserEntity{Name: "user"}, &milvuspb.RoleEntity{Name: "role"}, milvuspb.OperateUserRoleType(100))
|
||||
assert.NotNil(t, err)
|
||||
|
||||
mockTxnKV.load = func(key string) (string, error) {
|
||||
return "", common.NewKeyNotExistError(key)
|
||||
}
|
||||
err = mt.OperateUserRole(util.DefaultTenant, &milvuspb.UserEntity{Name: "user"}, &milvuspb.RoleEntity{Name: "role"}, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
assert.Nil(t, err)
|
||||
|
||||
|
@ -1146,6 +1164,9 @@ func TestRbacOperateRole(t *testing.T) {
|
|||
mockTxnKV.remove = func(key string) error {
|
||||
return nil
|
||||
}
|
||||
mockTxnKV.load = func(key string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
err = mt.OperateUserRole(util.DefaultTenant, &milvuspb.UserEntity{Name: "user"}, &milvuspb.RoleEntity{Name: "role"}, milvuspb.OperateUserRoleType_RemoveUserFromRole)
|
||||
assert.Nil(t, err)
|
||||
|
||||
|
@ -1369,11 +1390,10 @@ func TestRbacOperatePrivilege(t *testing.T) {
|
|||
return string(grantPrivilegeEntityByte), nil
|
||||
}
|
||||
err = mt.OperatePrivilege(util.DefaultTenant, entity, milvuspb.OperatePrivilegeType_Grant)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, common.IsIgnorableError(err))
|
||||
entity.Grantor.Privilege = &milvuspb.PrivilegeEntity{Name: commonpb.ObjectPrivilege_PrivilegeRelease.String()}
|
||||
err = mt.OperatePrivilege(util.DefaultTenant, entity, milvuspb.OperatePrivilegeType_Revoke)
|
||||
assert.NotNil(t, err)
|
||||
entity.Grantor.Privilege = &milvuspb.PrivilegeEntity{Name: commonpb.ObjectPrivilege_PrivilegeLoad.String()}
|
||||
assert.Equal(t, true, common.IsIgnorableError(err))
|
||||
grantPrivilegeEntity = &milvuspb.GrantPrivilegeEntity{Entities: []*milvuspb.GrantorEntity{
|
||||
{User: &milvuspb.UserEntity{Name: "user2"}, Privilege: &milvuspb.PrivilegeEntity{Name: commonpb.ObjectPrivilege_PrivilegeLoad.String()}},
|
||||
}}
|
||||
|
@ -1383,6 +1403,13 @@ func TestRbacOperatePrivilege(t *testing.T) {
|
|||
}
|
||||
err = mt.OperatePrivilege(util.DefaultTenant, entity, milvuspb.OperatePrivilegeType_Grant)
|
||||
assert.Nil(t, err)
|
||||
grantPrivilegeEntity = &milvuspb.GrantPrivilegeEntity{Entities: []*milvuspb.GrantorEntity{
|
||||
{User: &milvuspb.UserEntity{Name: "user2"}, Privilege: &milvuspb.PrivilegeEntity{Name: commonpb.ObjectPrivilege_PrivilegeRelease.String()}},
|
||||
}}
|
||||
mockTxnKV.load = func(key string) (string, error) {
|
||||
grantPrivilegeEntityByte, _ := proto.Marshal(grantPrivilegeEntity)
|
||||
return string(grantPrivilegeEntityByte), nil
|
||||
}
|
||||
mockTxnKV.remove = func(key string) error {
|
||||
return fmt.Errorf("remove error")
|
||||
}
|
||||
|
|
|
@ -1292,11 +1292,14 @@ func (c *Core) initData() error {
|
|||
|
||||
func (c *Core) initRbac() (initError error) {
|
||||
// create default roles, including admin, public
|
||||
if initError = c.MetaTable.CreateRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: util.RoleAdmin}); initError != nil {
|
||||
return
|
||||
}
|
||||
if initError = c.MetaTable.CreateRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: util.RolePublic}); initError != nil {
|
||||
return
|
||||
for _, role := range util.DefaultRoles {
|
||||
if initError = c.MetaTable.CreateRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: role}); initError != nil {
|
||||
if common.IsIgnorableError(initError) {
|
||||
initError = nil
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// grant privileges for the public role
|
||||
|
@ -1318,6 +1321,10 @@ func (c *Core) initRbac() (initError error) {
|
|||
Privilege: &milvuspb.PrivilegeEntity{Name: globalPrivilege},
|
||||
},
|
||||
}, milvuspb.OperatePrivilegeType_Grant); initError != nil {
|
||||
if common.IsIgnorableError(initError) {
|
||||
initError = nil
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -1331,6 +1338,10 @@ func (c *Core) initRbac() (initError error) {
|
|||
Privilege: &milvuspb.PrivilegeEntity{Name: collectionPrivilege},
|
||||
},
|
||||
}, milvuspb.OperatePrivilegeType_Grant); initError != nil {
|
||||
if common.IsIgnorableError(initError) {
|
||||
initError = nil
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -2973,14 +2984,6 @@ func (c *Core) CreateRole(ctx context.Context, in *milvuspb.CreateRoleRequest) (
|
|||
return errorutil.UnhealthyStatus(code), errorutil.UnhealthyError()
|
||||
}
|
||||
entity := in.Entity
|
||||
_, err := c.MetaTable.SelectRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: entity.Name}, false)
|
||||
if err == nil {
|
||||
errMsg := "role already exists:" + entity.Name
|
||||
return failStatus(commonpb.ErrorCode_CreateRoleFailure, errMsg), errors.New(errMsg)
|
||||
}
|
||||
if !common.IsKeyNotExistError(err) {
|
||||
return failStatus(commonpb.ErrorCode_CreateRoleFailure, err.Error()), err
|
||||
}
|
||||
|
||||
results, err := c.MetaTable.SelectRole(util.DefaultTenant, nil, false)
|
||||
if err != nil {
|
||||
|
@ -3045,6 +3048,9 @@ func (c *Core) DropRole(ctx context.Context, in *milvuspb.DropRoleRequest) (*com
|
|||
for _, roleResult := range roleResults {
|
||||
for index, userEntity := range roleResult.Users {
|
||||
if err = c.MetaTable.OperateUserRole(util.DefaultTenant, &milvuspb.UserEntity{Name: userEntity.Name}, &milvuspb.RoleEntity{Name: roleResult.Role.Name}, milvuspb.OperateUserRoleType_RemoveUserFromRole); err != nil {
|
||||
if common.IsIgnorableError(err) {
|
||||
continue
|
||||
}
|
||||
errMsg := "fail to remove user from role"
|
||||
logger.Error(errMsg, zap.String("role_name", roleResult.Role.Name), zap.String("username", userEntity.Name), zap.Int("current_index", index), zap.Error(err))
|
||||
return failStatus(commonpb.ErrorCode_OperateUserRoleFailure, errMsg), err
|
||||
|
@ -3090,23 +3096,34 @@ func (c *Core) OperateUserRole(ctx context.Context, in *milvuspb.OperateUserRole
|
|||
logger.Error(errMsg, zap.String("username", in.Username), zap.Error(err))
|
||||
return failStatus(commonpb.ErrorCode_OperateUserRoleFailure, errMsg), err
|
||||
}
|
||||
updateCache := true
|
||||
if err := c.MetaTable.OperateUserRole(util.DefaultTenant, &milvuspb.UserEntity{Name: in.Username}, &milvuspb.RoleEntity{Name: in.RoleName}, in.Type); err != nil {
|
||||
errMsg := "fail to operate user to role"
|
||||
logger.Error(errMsg, zap.String("role_name", in.RoleName), zap.String("username", in.Username), zap.Error(err))
|
||||
return failStatus(commonpb.ErrorCode_OperateUserRoleFailure, errMsg), err
|
||||
if !common.IsIgnorableError(err) {
|
||||
errMsg := "fail to operate user to role"
|
||||
logger.Error(errMsg, zap.String("role_name", in.RoleName), zap.String("username", in.Username), zap.Error(err))
|
||||
return failStatus(commonpb.ErrorCode_OperateUserRoleFailure, errMsg), err
|
||||
}
|
||||
updateCache = false
|
||||
}
|
||||
|
||||
var opType int32
|
||||
if in.Type == milvuspb.OperateUserRoleType_AddUserToRole {
|
||||
opType = int32(typeutil.CacheAddUserToRole)
|
||||
} else if in.Type == milvuspb.OperateUserRoleType_RemoveUserFromRole {
|
||||
opType = int32(typeutil.CacheRemoveUserFromRole)
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: opType,
|
||||
OpKey: funcutil.EncodeUserRoleCache(in.Username, in.RoleName),
|
||||
}); err != nil {
|
||||
return failStatus(commonpb.ErrorCode_OperateUserRoleFailure, err.Error()), err
|
||||
if updateCache {
|
||||
var opType int32
|
||||
switch in.Type {
|
||||
case milvuspb.OperateUserRoleType_AddUserToRole:
|
||||
opType = int32(typeutil.CacheAddUserToRole)
|
||||
case milvuspb.OperateUserRoleType_RemoveUserFromRole:
|
||||
opType = int32(typeutil.CacheRemoveUserFromRole)
|
||||
default:
|
||||
errMsg := "invalid operate type for the OperateUserRole api"
|
||||
logger.Error(errMsg, zap.Any("op_type", in.Type))
|
||||
return failStatus(commonpb.ErrorCode_OperateUserRoleFailure, errMsg), errors.New(errMsg)
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: opType,
|
||||
OpKey: funcutil.EncodeUserRoleCache(in.Username, in.RoleName),
|
||||
}); err != nil {
|
||||
return failStatus(commonpb.ErrorCode_OperateUserRoleFailure, err.Error()), err
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debug(method + " success")
|
||||
|
@ -3306,23 +3323,34 @@ func (c *Core) OperatePrivilege(ctx context.Context, in *milvuspb.OperatePrivile
|
|||
if in.Entity.Object.Name == commonpb.ObjectType_Global.String() {
|
||||
in.Entity.ObjectName = util.AnyWord
|
||||
}
|
||||
updateCache := true
|
||||
if err := c.MetaTable.OperatePrivilege(util.DefaultTenant, in.Entity, in.Type); err != nil {
|
||||
errMsg := "fail to operate the privilege"
|
||||
logger.Error(errMsg, zap.Error(err))
|
||||
return failStatus(commonpb.ErrorCode_OperatePrivilegeFailure, errMsg), err
|
||||
if !common.IsIgnorableError(err) {
|
||||
errMsg := "fail to operate the privilege"
|
||||
logger.Error(errMsg, zap.Error(err))
|
||||
return failStatus(commonpb.ErrorCode_OperatePrivilegeFailure, errMsg), err
|
||||
}
|
||||
updateCache = false
|
||||
}
|
||||
|
||||
var opType int32
|
||||
if in.Type == milvuspb.OperatePrivilegeType_Grant {
|
||||
opType = int32(typeutil.CacheGrantPrivilege)
|
||||
} else if in.Type == milvuspb.OperatePrivilegeType_Revoke {
|
||||
opType = int32(typeutil.CacheRevokePrivilege)
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: opType,
|
||||
OpKey: funcutil.PolicyForPrivilege(in.Entity.Role.Name, in.Entity.Object.Name, in.Entity.ObjectName, in.Entity.Grantor.Privilege.Name),
|
||||
}); err != nil {
|
||||
return failStatus(commonpb.ErrorCode_OperatePrivilegeFailure, err.Error()), err
|
||||
if updateCache {
|
||||
var opType int32
|
||||
switch in.Type {
|
||||
case milvuspb.OperatePrivilegeType_Grant:
|
||||
opType = int32(typeutil.CacheGrantPrivilege)
|
||||
case milvuspb.OperatePrivilegeType_Revoke:
|
||||
opType = int32(typeutil.CacheRevokePrivilege)
|
||||
default:
|
||||
errMsg := "invalid operate type for the OperatePrivilege api"
|
||||
logger.Error(errMsg, zap.Any("op_type", in.Type))
|
||||
return failStatus(commonpb.ErrorCode_OperatePrivilegeFailure, errMsg), errors.New(errMsg)
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: opType,
|
||||
OpKey: funcutil.PolicyForPrivilege(in.Entity.Role.Name, in.Entity.Object.Name, in.Entity.ObjectName, in.Entity.Grantor.Privilege.Name),
|
||||
}); err != nil {
|
||||
return failStatus(commonpb.ErrorCode_OperatePrivilegeFailure, err.Error()), err
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debug(method + " success")
|
||||
|
@ -3367,6 +3395,11 @@ func (c *Core) SelectGrant(ctx context.Context, in *milvuspb.SelectGrantRequest)
|
|||
}
|
||||
|
||||
grantEntities, err := c.MetaTable.SelectGrant(util.DefaultTenant, in.Entity)
|
||||
if common.IsKeyNotExistError(err) {
|
||||
return &milvuspb.SelectGrantResponse{
|
||||
Status: succStatus(),
|
||||
}, nil
|
||||
}
|
||||
if err != nil {
|
||||
errMsg := "fail to select the grant"
|
||||
logger.Error(errMsg, zap.Error(err))
|
||||
|
|
|
@ -60,5 +60,6 @@ go test -race -cover ${APPLE_SILICON_FLAG} "${MILVUS_DIR}/distributed/querynode/
|
|||
go test -race -cover ${APPLE_SILICON_FLAG} "${MILVUS_DIR}/rootcoord" -failfast
|
||||
go test -race -cover ${APPLE_SILICON_FLAG} "${MILVUS_DIR}/datacoord/..." -failfast
|
||||
go test -race -cover ${APPLE_SILICON_FLAG} "${MILVUS_DIR}/indexcoord/..." -failfast
|
||||
go test -race -cover ${APPLE_SILICON_FLAG} "${MILVUS_DIR}/metastore/..." -failfast
|
||||
|
||||
echo " Go unittest finished"
|
||||
|
|
|
@ -210,3 +210,43 @@ CREATE TABLE if not exists milvus_meta.credential_users (
|
|||
PRIMARY KEY (id),
|
||||
INDEX idx_tenant_id_username (tenant_id, username)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- role
|
||||
CREATE TABLE if not exists milvus_meta.role (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tenant_id VARCHAR(128) DEFAULT NULL,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
is_deleted BOOL NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP on update current_timestamp,
|
||||
INDEX idx_role_tenant_name (tenant_id, name),
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- user-role
|
||||
CREATE TABLE if not exists milvus_meta.user_role (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tenant_id VARCHAR(128) DEFAULT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
role_id BIGINT NOT NULL,
|
||||
is_deleted BOOL NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP on update current_timestamp,
|
||||
INDEX idx_role_mapping_tenant_user_role (tenant_id, user_id, role_id),
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- grant
|
||||
CREATE TABLE if not exists milvus_meta.grant (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tenant_id VARCHAR(128) DEFAULT NULL,
|
||||
role_id BIGINT NOT NULL,
|
||||
object VARCHAR(128) NOT NULL,
|
||||
object_name VARCHAR(128) NOT NULL,
|
||||
detail TEXT NOT NULL,
|
||||
is_deleted BOOL NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP on update current_timestamp,
|
||||
INDEX idx_grant_principal_resource_tenant (tenant_id, role_id, object, object_name),
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
|
Loading…
Reference in New Issue