mirror of https://github.com/milvus-io/milvus.git
enhance: add 3 builtin roles (#28961)
issue: #28960 [milvus-proto #212](https://github.com/milvus-io/milvus-proto/issues/212) add new configuration: builtinRoles user can define roles in config file: `milvus.yaml` there is an example: 1. db_ro, only have read privileges, include load 2. db_rw, read and write privileges, include create/drop/rename collection 3. db_admin, not only read and write privileges, but also user administration Signed-off-by: PowderLi <min.li@zilliz.com>pull/29293/head
parent
a602171d06
commit
bcd6865b29
2
go.mod
2
go.mod
|
@ -23,7 +23,7 @@ require (
|
|||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||
github.com/klauspost/compress v1.16.7
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231114080011-9a495865219e
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231208092431-02cbad30332f
|
||||
github.com/milvus-io/milvus/pkg v0.0.1
|
||||
github.com/minio/minio-go/v7 v7.0.61
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -583,6 +583,8 @@ github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b h1:TfeY0NxYxZz
|
|||
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231114080011-9a495865219e h1:IH1WAXwEF8vbwahPdupi4zzRNWViT4B7fZzIjtRLpG4=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231114080011-9a495865219e/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231208092431-02cbad30332f h1:0cAMN9OsgBxlEUY8i1e1ocrBZ/cpu/Kdguz4JWz9fUc=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231208092431-02cbad30332f/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
|
||||
github.com/milvus-io/milvus-storage/go v0.0.0-20231109072809-1cd7b0866092 h1:UYJ7JB+QlMOoFHNdd8mUa3/lV63t9dnBX7ILXmEEWPY=
|
||||
github.com/milvus-io/milvus-storage/go v0.0.0-20231109072809-1cd7b0866092/go.mod h1:GPETMcTZq1gLY1WA6Na5kiNAKnq8SEMMiVKUZrM3sho=
|
||||
github.com/milvus-io/pulsar-client-go v0.6.10 h1:eqpJjU+/QX0iIhEo3nhOqMNXL+TyInAs1IAHZCrCM/A=
|
||||
|
|
|
@ -821,6 +821,11 @@ func (s *Server) CreateIndex(ctx context.Context, request *milvuspb.CreateIndexR
|
|||
return s.proxy.CreateIndex(ctx, request)
|
||||
}
|
||||
|
||||
func (s *Server) AlterIndex(ctx context.Context, request *milvuspb.AlterIndexRequest) (*commonpb.Status, error) {
|
||||
// Todo
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DropIndex notifies Proxy to drop index
|
||||
func (s *Server) DropIndex(ctx context.Context, request *milvuspb.DropIndexRequest) (*commonpb.Status, error) {
|
||||
return s.proxy.DropIndex(ctx, request)
|
||||
|
@ -865,6 +870,11 @@ func (s *Server) Search(ctx context.Context, request *milvuspb.SearchRequest) (*
|
|||
return s.proxy.Search(ctx, request)
|
||||
}
|
||||
|
||||
func (s *Server) SearchV2(ctx context.Context, request *milvuspb.SearchRequestV2) (*milvuspb.SearchResults, error) {
|
||||
// Todo
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *Server) Flush(ctx context.Context, request *milvuspb.FlushRequest) (*milvuspb.FlushResponse, error) {
|
||||
return s.proxy.Flush(ctx, request)
|
||||
}
|
||||
|
|
|
@ -639,6 +639,11 @@ func (_c *MockProxy_CreateIndex_Call) RunAndReturn(run func(context.Context, *mi
|
|||
return _c
|
||||
}
|
||||
|
||||
func (_m *MockProxy) AlterIndex(_a0 context.Context, _a1 *milvuspb.AlterIndexRequest) (*commonpb.Status, error) {
|
||||
// Todo
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// CreatePartition provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockProxy) CreatePartition(_a0 context.Context, _a1 *milvuspb.CreatePartitionRequest) (*commonpb.Status, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
@ -4555,6 +4560,11 @@ func (_c *MockProxy_Search_Call) RunAndReturn(run func(context.Context, *milvusp
|
|||
return _c
|
||||
}
|
||||
|
||||
func (_m *MockProxy) SearchV2(_a0 context.Context, _a1 *milvuspb.SearchRequestV2) (*milvuspb.SearchResults, error) {
|
||||
// Todo
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SelectGrant provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockProxy) SelectGrant(_a0 context.Context, _a1 *milvuspb.SelectGrantRequest) (*milvuspb.SelectGrantResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
|
|
@ -1814,6 +1814,11 @@ func (node *Proxy) CreateIndex(ctx context.Context, request *milvuspb.CreateInde
|
|||
return cit.result, nil
|
||||
}
|
||||
|
||||
func (node *Proxy) AlterIndex(ctx context.Context, request *milvuspb.AlterIndexRequest) (*commonpb.Status, error) {
|
||||
// Todo
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// DescribeIndex get the meta information of index, such as index state, index id and etc.
|
||||
func (node *Proxy) DescribeIndex(ctx context.Context, request *milvuspb.DescribeIndexRequest) (*milvuspb.DescribeIndexResponse, error) {
|
||||
if err := merr.CheckHealthy(node.GetStateCode()); err != nil {
|
||||
|
@ -2649,6 +2654,11 @@ func (node *Proxy) Search(ctx context.Context, request *milvuspb.SearchRequest)
|
|||
return qt.result, nil
|
||||
}
|
||||
|
||||
func (node *Proxy) SearchV2(ctx context.Context, request *milvuspb.SearchRequestV2) (*milvuspb.SearchResults, error) {
|
||||
// Todo
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (node *Proxy) getVectorPlaceholderGroupForSearchByPks(ctx context.Context, request *milvuspb.SearchRequest) ([]byte, error) {
|
||||
placeholderGroup := &commonpb.PlaceholderGroup{}
|
||||
err := proto.Unmarshal(request.PlaceholderGroup, placeholderGroup)
|
||||
|
@ -4223,7 +4233,7 @@ func (node *Proxy) DropRole(ctx context.Context, req *milvuspb.DropRoleRequest)
|
|||
return merr.Status(err), nil
|
||||
}
|
||||
if IsDefaultRole(req.RoleName) {
|
||||
err := merr.WrapErrPrivilegeNotPermitted("the role[%s] is a default role, which can't be droped", req.GetRoleName())
|
||||
err := merr.WrapErrPrivilegeNotPermitted("the role[%s] is a default role, which can't be dropped", req.GetRoleName())
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
result, err := node.rootCoord.DropRole(ctx, req)
|
||||
|
|
|
@ -168,7 +168,7 @@ func PrivilegeInterceptor(ctx context.Context, req interface{}) (context.Context
|
|||
}
|
||||
|
||||
log.Info("permission deny", zap.Strings("roles", roleNames))
|
||||
return ctx, status.Error(codes.PermissionDenied, fmt.Sprintf("%s: permission deny", objectPrivilege))
|
||||
return ctx, status.Error(codes.PermissionDenied, fmt.Sprintf("%s: permission deny to %s", objectPrivilege, username))
|
||||
}
|
||||
|
||||
// isCurUserObject Determine whether it is an Object of type User that operates on its own user information,
|
||||
|
|
|
@ -613,6 +613,43 @@ func (c *Core) initRbac() error {
|
|||
return errors.Wrap(err, "failed to grant collection privilege")
|
||||
}
|
||||
}
|
||||
if Params.RoleCfg.Enabled.GetAsBool() {
|
||||
return c.initBuiltinRoles()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Core) initBuiltinRoles() error {
|
||||
rolePrivilegesMap := Params.RoleCfg.Roles.GetAsRoleDetails()
|
||||
for role, privilegesJSON := range rolePrivilegesMap {
|
||||
err := c.meta.CreateRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: role})
|
||||
if err != nil && !common.IsIgnorableError(err) {
|
||||
log.Error("create a builtin role fail", zap.Any("error", err), zap.String("roleName", role))
|
||||
return errors.Wrapf(err, "failed to create a builtin role: %s", role)
|
||||
}
|
||||
for _, privilege := range privilegesJSON[util.RoleConfigPrivileges] {
|
||||
privilegeName := privilege[util.RoleConfigPrivilege]
|
||||
if !util.IsAnyWord(privilege[util.RoleConfigPrivilege]) {
|
||||
privilegeName = util.PrivilegeNameForMetastore(privilege[util.RoleConfigPrivilege])
|
||||
}
|
||||
err := c.meta.OperatePrivilege(util.DefaultTenant, &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: role},
|
||||
Object: &milvuspb.ObjectEntity{Name: privilege[util.RoleConfigObjectType]},
|
||||
ObjectName: privilege[util.RoleConfigObjectName],
|
||||
DbName: privilege[util.RoleConfigDBName],
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
User: &milvuspb.UserEntity{Name: util.UserRoot},
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: privilegeName},
|
||||
},
|
||||
}, milvuspb.OperatePrivilegeType_Grant)
|
||||
if err != nil && !common.IsIgnorableError(err) {
|
||||
log.Error("grant privilege to builtin role fail", zap.Any("error", err), zap.String("roleName", role), zap.Any("privilege", privilege))
|
||||
return errors.Wrapf(err, "failed to grant privilege: <%s, %s, %s> of db: %s to role: %s", privilege[util.RoleConfigObjectType], privilege[util.RoleConfigObjectName], privilege[util.RoleConfigPrivilege], privilege[util.RoleConfigDBName], role)
|
||||
}
|
||||
}
|
||||
util.BuiltinRoles = append(util.BuiltinRoles, role)
|
||||
log.Info("init a builtin role successfully", zap.String("roleName", role))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -2268,6 +2305,10 @@ func (c *Core) DropRole(ctx context.Context, in *milvuspb.DropRoleRequest) (*com
|
|||
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
for util.IsBuiltinRole(in.GetRoleName()) {
|
||||
err := merr.WrapErrPrivilegeNotPermitted("the role[%s] is a builtin role, which can't be dropped", in.GetRoleName())
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
if _, err := c.meta.SelectRole(util.DefaultTenant, &milvuspb.RoleEntity{Name: in.RoleName}, false); err != nil {
|
||||
errMsg := "not found the role, maybe the role isn't existed or internal system error"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
|
|
|
@ -49,6 +49,7 @@ import (
|
|||
"github.com/milvus-io/milvus/internal/util/importutil"
|
||||
"github.com/milvus-io/milvus/internal/util/sessionutil"
|
||||
"github.com/milvus-io/milvus/pkg/common"
|
||||
"github.com/milvus-io/milvus/pkg/util"
|
||||
"github.com/milvus-io/milvus/pkg/util/etcd"
|
||||
"github.com/milvus-io/milvus/pkg/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/util/merr"
|
||||
|
@ -2087,6 +2088,51 @@ func TestRootCoord_RBACError(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestRootCoord_BuiltinRoles(t *testing.T) {
|
||||
roleDbAdmin := "db_admin"
|
||||
paramtable.Init()
|
||||
paramtable.Get().Save(paramtable.Get().RoleCfg.Enabled.Key, "true")
|
||||
paramtable.Get().Save(paramtable.Get().RoleCfg.Roles.Key, `{"`+roleDbAdmin+`": {"privileges": [{"object_type": "Global", "object_name": "*", "privilege": "CreateCollection", "db_name": "*"}]}}`)
|
||||
t.Run("init builtin roles success", func(t *testing.T) {
|
||||
c := newTestCore(withHealthyCode(), withInvalidMeta())
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.CreateRoleFunc = func(tenant string, entity *milvuspb.RoleEntity) error {
|
||||
return nil
|
||||
}
|
||||
mockMeta.OperatePrivilegeFunc = func(tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error {
|
||||
return nil
|
||||
}
|
||||
err := c.initBuiltinRoles()
|
||||
assert.Equal(t, nil, err)
|
||||
assert.True(t, util.IsBuiltinRole(roleDbAdmin))
|
||||
assert.False(t, util.IsBuiltinRole(util.RoleAdmin))
|
||||
resp, err := c.DropRole(context.Background(), &milvuspb.DropRoleRequest{RoleName: roleDbAdmin})
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, int32(1401), resp.Code) // merr.ErrPrivilegeNotPermitted
|
||||
})
|
||||
t.Run("init builtin roles fail to create role", func(t *testing.T) {
|
||||
c := newTestCore(withHealthyCode(), withInvalidMeta())
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.CreateRoleFunc = func(tenant string, entity *milvuspb.RoleEntity) error {
|
||||
return merr.ErrPrivilegeNotPermitted
|
||||
}
|
||||
err := c.initBuiltinRoles()
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("init builtin roles fail to operate privileg", func(t *testing.T) {
|
||||
c := newTestCore(withHealthyCode(), withInvalidMeta())
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.CreateRoleFunc = func(tenant string, entity *milvuspb.RoleEntity) error {
|
||||
return nil
|
||||
}
|
||||
mockMeta.OperatePrivilegeFunc = func(tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error {
|
||||
return merr.ErrPrivilegeNotPermitted
|
||||
}
|
||||
err := c.initBuiltinRoles()
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCore_Stop(t *testing.T) {
|
||||
t.Run("abnormal stop before component is ready", func(t *testing.T) {
|
||||
c := &Core{}
|
||||
|
|
|
@ -13,7 +13,7 @@ require (
|
|||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||
github.com/klauspost/compress v1.16.5
|
||||
github.com/lingdor/stackerror v0.0.0-20191119040541-976d8885ed76
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231114080011-9a495865219e
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231208092431-02cbad30332f
|
||||
github.com/nats-io/nats-server/v2 v2.9.17
|
||||
github.com/nats-io/nats.go v1.24.0
|
||||
github.com/panjf2000/ants/v2 v2.7.2
|
||||
|
|
|
@ -481,6 +481,8 @@ github.com/milvus-io/milvus-proto/go-api/v2 v2.3.2-0.20231008032233-5d64d443769d
|
|||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.2-0.20231008032233-5d64d443769d/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231114080011-9a495865219e h1:IH1WAXwEF8vbwahPdupi4zzRNWViT4B7fZzIjtRLpG4=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231114080011-9a495865219e/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231208092431-02cbad30332f h1:0cAMN9OsgBxlEUY8i1e1ocrBZ/cpu/Kdguz4JWz9fUc=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20231208092431-02cbad30332f/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
|
||||
github.com/milvus-io/pulsar-client-go v0.6.10 h1:eqpJjU+/QX0iIhEo3nhOqMNXL+TyInAs1IAHZCrCM/A=
|
||||
github.com/milvus-io/pulsar-client-go v0.6.10/go.mod h1:lQqCkgwDF8YFYjKA+zOheTk1tev2B+bKj5j7+nm8M1w=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
|
|
|
@ -61,6 +61,12 @@ const (
|
|||
|
||||
IdentifierKey = "identifier"
|
||||
HeaderDBName = "dbName"
|
||||
|
||||
RoleConfigPrivileges = "privileges"
|
||||
RoleConfigObjectType = "object_type"
|
||||
RoleConfigObjectName = "object_name"
|
||||
RoleConfigDBName = "db_name"
|
||||
RoleConfigPrivilege = "privilege"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -70,6 +76,7 @@ const (
|
|||
|
||||
var (
|
||||
DefaultRoles = []string{RoleAdmin, RolePublic}
|
||||
BuiltinRoles = []string{}
|
||||
|
||||
ObjectPrivileges = map[string][]string{
|
||||
commonpb.ObjectType_Collection.String(): {
|
||||
|
@ -118,6 +125,12 @@ var (
|
|||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateDatabase.String()),
|
||||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropDatabase.String()),
|
||||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeListDatabases.String()),
|
||||
|
||||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreatePartition.String()),
|
||||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropPartition.String()),
|
||||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeShowPartitions.String()),
|
||||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeHasPartition.String()),
|
||||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeGetFlushState.String()),
|
||||
},
|
||||
commonpb.ObjectType_User.String(): {
|
||||
MetaStore2API(commonpb.ObjectPrivilege_PrivilegeUpdateUser.String()),
|
||||
|
@ -169,3 +182,12 @@ func PrivilegeNameForMetastore(name string) string {
|
|||
func IsAnyWord(word string) bool {
|
||||
return word == AnyWord
|
||||
}
|
||||
|
||||
func IsBuiltinRole(roleName string) bool {
|
||||
for _, builtinRole := range BuiltinRoles {
|
||||
if builtinRole == roleName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import (
|
|||
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
|
||||
"github.com/milvus-io/milvus/pkg/util"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
)
|
||||
|
||||
|
@ -93,6 +94,34 @@ func MapToJSON(m map[string]string) []byte {
|
|||
return bs
|
||||
}
|
||||
|
||||
func JSONToRoleDetails(mStr string) (map[string](map[string]([](map[string]string))), error) {
|
||||
buffer := make(map[string](map[string]([](map[string]string))), 0)
|
||||
err := json.Unmarshal([]byte(mStr), &buffer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unmarshal `builtinRoles.Roles` failed, %w", err)
|
||||
}
|
||||
ret := make(map[string](map[string]([](map[string]string))), 0)
|
||||
for role, privilegesJSON := range buffer {
|
||||
ret[role] = make(map[string]([](map[string]string)), 0)
|
||||
privilegesArray := make([]map[string]string, 0)
|
||||
for _, privileges := range privilegesJSON[util.RoleConfigPrivileges] {
|
||||
privilegesArray = append(privilegesArray, map[string]string{
|
||||
util.RoleConfigObjectType: privileges[util.RoleConfigObjectType],
|
||||
util.RoleConfigObjectName: privileges[util.RoleConfigObjectName],
|
||||
util.RoleConfigPrivilege: privileges[util.RoleConfigPrivilege],
|
||||
util.RoleConfigDBName: privileges[util.RoleConfigDBName],
|
||||
})
|
||||
}
|
||||
ret[role]["privileges"] = privilegesArray
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func RoleDetailsToJSON(m map[string](map[string]([](map[string]string)))) []byte {
|
||||
bs, _ := json.Marshal(m)
|
||||
return bs
|
||||
}
|
||||
|
||||
const (
|
||||
// PulsarMaxMessageSizeKey is the key of config item
|
||||
PulsarMaxMessageSizeKey = "maxMessageSize"
|
||||
|
|
|
@ -33,6 +33,7 @@ import (
|
|||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
"github.com/milvus-io/milvus/pkg/util"
|
||||
)
|
||||
|
||||
func Test_CheckGrpcReady(t *testing.T) {
|
||||
|
@ -89,6 +90,25 @@ func Test_ParseIndexParamsMap(t *testing.T) {
|
|||
assert.NotEqual(t, err, nil)
|
||||
}
|
||||
|
||||
func Test_ParseBuiltinRolesMap(t *testing.T) {
|
||||
t.Run("correct format", func(t *testing.T) {
|
||||
builtinRoles := `{"db_admin": {"privileges": [{"object_type": "Global", "object_name": "*", "privilege": "CreateCollection", "db_name": "*"}]}}`
|
||||
rolePrivilegesMap, err := JSONToRoleDetails(builtinRoles)
|
||||
assert.Nil(t, err)
|
||||
for role, privilegesJSON := range rolePrivilegesMap {
|
||||
assert.Contains(t, []string{"db_admin", "db_rw", "db_ro"}, role)
|
||||
for _, privileges := range privilegesJSON[util.RoleConfigPrivileges] {
|
||||
assert.Equal(t, privileges[util.RoleConfigObjectType], "Global")
|
||||
}
|
||||
}
|
||||
})
|
||||
t.Run("wrong format", func(t *testing.T) {
|
||||
builtinRoles := `{"db_admin": {"privileges": [{"object_type": "Global", "object_name": "*", "privilege": "CreateCollection", "db_name": "*"}]}`
|
||||
_, err := JSONToRoleDetails(builtinRoles)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetAttrByKeyFromRepeatedKV(t *testing.T) {
|
||||
kvs := []*commonpb.KeyValuePair{
|
||||
{Key: "Key1", Value: "Value1"},
|
||||
|
|
|
@ -20,7 +20,7 @@ func Test_GetPrivilegeExtObj(t *testing.T) {
|
|||
assert.Equal(t, commonpb.ObjectPrivilege_PrivilegeLoad, privilegeExt.ObjectPrivilege)
|
||||
assert.Equal(t, int32(3), privilegeExt.ObjectNameIndex)
|
||||
|
||||
request2 := &milvuspb.CreatePartitionRequest{}
|
||||
request2 := &milvuspb.GetPartitionStatisticsRequest{}
|
||||
_, err = GetPrivilegeExtObj(request2)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ type ComponentParam struct {
|
|||
IndexNodeCfg indexNodeConfig
|
||||
HTTPCfg httpConfig
|
||||
LogCfg logConfig
|
||||
RoleCfg roleConfig
|
||||
|
||||
RootCoordGrpcServerCfg GrpcServerConfig
|
||||
ProxyGrpcServerCfg GrpcServerConfig
|
||||
|
@ -116,6 +117,7 @@ func (p *ComponentParam) init(bt *BaseTable) {
|
|||
p.IndexNodeCfg.init(bt)
|
||||
p.HTTPCfg.init(bt)
|
||||
p.LogCfg.init(bt)
|
||||
p.RoleCfg.init(bt)
|
||||
|
||||
p.RootCoordGrpcServerCfg.Init("rootCoord", bt)
|
||||
p.ProxyGrpcServerCfg.Init("proxy", bt)
|
||||
|
|
|
@ -141,6 +141,10 @@ func (pi *ParamItem) GetAsJSONMap() map[string]string {
|
|||
return getAndConvert(pi.GetValue(), funcutil.JSONToMap, nil)
|
||||
}
|
||||
|
||||
func (pi *ParamItem) GetAsRoleDetails() map[string](map[string]([](map[string]string))) {
|
||||
return getAndConvert(pi.GetValue(), funcutil.JSONToRoleDetails, nil)
|
||||
}
|
||||
|
||||
type CompositeParamItem struct {
|
||||
Items []*ParamItem
|
||||
Format func(map[string]string) string
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package paramtable
|
||||
|
||||
import (
|
||||
"github.com/milvus-io/milvus/pkg/config"
|
||||
"github.com/milvus-io/milvus/pkg/util/funcutil"
|
||||
)
|
||||
|
||||
type roleConfig struct {
|
||||
Enabled ParamItem `refreshable:"false"`
|
||||
Roles ParamItem `refreshable:"false"`
|
||||
}
|
||||
|
||||
func (p *roleConfig) init(base *BaseTable) {
|
||||
p.Enabled = ParamItem{
|
||||
Key: "builtinRoles.enable",
|
||||
DefaultValue: "false",
|
||||
Version: "2.3.4",
|
||||
Doc: "Whether to init builtin roles",
|
||||
Export: true,
|
||||
}
|
||||
p.Enabled.Init(base.mgr)
|
||||
|
||||
p.Roles = ParamItem{
|
||||
Key: "builtinRoles.roles",
|
||||
DefaultValue: `{}`,
|
||||
Version: "2.3.4",
|
||||
Doc: "what builtin roles should be init",
|
||||
Export: true,
|
||||
}
|
||||
p.Roles.Init(base.mgr)
|
||||
|
||||
p.panicIfNotValid(base.mgr)
|
||||
}
|
||||
|
||||
func (p *roleConfig) panicIfNotValid(mgr *config.Manager) {
|
||||
if p.Enabled.GetAsBool() {
|
||||
m := p.Roles.GetAsRoleDetails()
|
||||
if m == nil {
|
||||
panic("builtinRoles.roles not invalid, should be json format")
|
||||
}
|
||||
|
||||
j := funcutil.RoleDetailsToJSON(m)
|
||||
mgr.SetConfig("builtinRoles.roles", string(j))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package paramtable
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/milvus-io/milvus/pkg/config"
|
||||
)
|
||||
|
||||
func TestRoleConfig_Init(t *testing.T) {
|
||||
params := ComponentParam{}
|
||||
params.Init(NewBaseTable(SkipRemote(true)))
|
||||
cfg := ¶ms.RoleCfg
|
||||
assert.Equal(t, cfg.Enabled.GetAsBool(), false)
|
||||
assert.Equal(t, cfg.Roles.GetValue(), "{}")
|
||||
assert.Equal(t, len(cfg.Roles.GetAsJSONMap()), 0)
|
||||
}
|
||||
|
||||
func TestRoleConfig_Invalid(t *testing.T) {
|
||||
t.Run("valid roles", func(t *testing.T) {
|
||||
mgr := config.NewManager()
|
||||
mgr.SetConfig("builtinRoles.enable", "true")
|
||||
mgr.SetConfig("builtinRoles.roles", `{"db_admin": {"privileges": [{"object_type": "Global", "object_name": "*", "privilege": "CreateCollection", "db_name": "*"}]}}`)
|
||||
p := &roleConfig{
|
||||
Enabled: ParamItem{
|
||||
Key: "builtinRoles.enable",
|
||||
},
|
||||
Roles: ParamItem{
|
||||
Key: "builtinRoles.roles",
|
||||
},
|
||||
}
|
||||
p.Enabled.Init(mgr)
|
||||
p.Roles.Init(mgr)
|
||||
assert.NotPanics(t, func() {
|
||||
p.panicIfNotValid(mgr)
|
||||
})
|
||||
})
|
||||
t.Run("invalid roles", func(t *testing.T) {
|
||||
mgr := config.NewManager()
|
||||
mgr.SetConfig("builtinRoles.enable", "true")
|
||||
mgr.SetConfig("builtinRoles.roles", `{"db_admin": {"privileges": {"object_type": "Global", "object_name": "*", "privilege": "CreateCollection", "db_name": "*"}}}`)
|
||||
p := &roleConfig{
|
||||
Enabled: ParamItem{
|
||||
Key: "builtinRoles.enable",
|
||||
},
|
||||
Roles: ParamItem{
|
||||
Key: "builtinRoles.roles",
|
||||
},
|
||||
}
|
||||
p.Enabled.Init(mgr)
|
||||
p.Roles.Init(mgr)
|
||||
assert.Panics(t, func() {
|
||||
p.panicIfNotValid(mgr)
|
||||
})
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue