mirror of
https://gitee.com/milvus-io/milvus.git
synced 2025-12-06 09:08:43 +08:00
enhance: support rbac with WAL-based DDL framework (#44735)
issue: #43897 - RBAC(Roles/Users/Privileges/Privilege Groups) is implemented by WAL-based DDL framework now. - Support following message type in wal `AlterUser`, `DropUser`, `AlterRole`, `DropRole`, `AlterUserRole`, `DropUserRole`, `AlterPrivilege`, `DropPrivilege`, `AlterPrivilegeGroup`, `DropPrivilegeGroup`, `RestoreRBAC`. - RBAC can be synced by new CDC now. - Refactor some UT for RBAC. --------- Signed-off-by: chyezh <chyezh@outlook.com>
This commit is contained in:
parent
b13b4dabbe
commit
80bb09f7c2
@ -40,8 +40,6 @@ type RootCoordCatalog interface {
|
||||
|
||||
// GetCredential gets the credential info for the username, returns error if no credential exists for this username.
|
||||
GetCredential(ctx context.Context, username string) (*model.Credential, error)
|
||||
// CreateCredential creates credential by Username and EncryptedPassword in crediential. Please make sure credential.Username isn't empty before calling this API. Credentials already exists will be altered.
|
||||
CreateCredential(ctx context.Context, credential *model.Credential) error
|
||||
// AlterCredential does exactly the same as CreateCredential
|
||||
AlterCredential(ctx context.Context, credential *model.Credential) error
|
||||
// DropCredential removes the credential of this username
|
||||
|
||||
@ -346,9 +346,11 @@ func (kc *Catalog) CreateAlias(ctx context.Context, alias *model.Alias, ts typeu
|
||||
return kc.Snapshot.MultiSaveAndRemove(ctx, kvs, []string{oldKBefore210, oldKeyWithoutDb}, ts)
|
||||
}
|
||||
|
||||
func (kc *Catalog) CreateCredential(ctx context.Context, credential *model.Credential) error {
|
||||
func (kc *Catalog) AlterCredential(ctx context.Context, credential *model.Credential) error {
|
||||
k := fmt.Sprintf("%s/%s", CredentialPrefix, credential.Username)
|
||||
v, err := json.Marshal(&internalpb.CredentialInfo{EncryptedPassword: credential.EncryptedPassword})
|
||||
credentialInfo := model.MarshalCredentialModel(credential)
|
||||
credentialInfo.Username = "" // Username is already save in the key, remove it from the value.
|
||||
v, err := json.Marshal(credentialInfo)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error("create credential marshal fail", zap.String("key", k), zap.Error(err))
|
||||
return err
|
||||
@ -359,14 +361,9 @@ func (kc *Catalog) CreateCredential(ctx context.Context, credential *model.Crede
|
||||
log.Ctx(ctx).Error("create credential persist meta fail", zap.String("key", k), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) AlterCredential(ctx context.Context, credential *model.Credential) error {
|
||||
return kc.CreateCredential(ctx, credential)
|
||||
}
|
||||
|
||||
func (kc *Catalog) listPartitionsAfter210(ctx context.Context, collectionID typeutil.UniqueID, ts typeutil.Timestamp) ([]*model.Partition, error) {
|
||||
prefix := BuildPartitionPrefix(collectionID)
|
||||
_, values, err := kc.Snapshot.LoadWithPrefix(ctx, prefix, ts)
|
||||
@ -625,8 +622,9 @@ func (kc *Catalog) GetCredential(ctx context.Context, username string) (*model.C
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unmarshal credential info err:%w", err)
|
||||
}
|
||||
|
||||
return &model.Credential{Username: username, EncryptedPassword: credentialInfo.EncryptedPassword}, nil
|
||||
// we don't save the username in the credential info, so we need to set it manually from path.
|
||||
credentialInfo.Username = username
|
||||
return model.UnmarshalCredentialModel(&credentialInfo), nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) AlterAlias(ctx context.Context, alias *model.Alias, ts typeutil.Timestamp) error {
|
||||
@ -1050,18 +1048,6 @@ func (kc *Catalog) ListCredentialsWithPasswd(ctx context.Context) (map[string]st
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) save(ctx context.Context, k string) error {
|
||||
var err error
|
||||
if _, err = kc.Txn.Load(ctx, k); err != nil && !errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
log.Ctx(ctx).Debug("the key has existed", zap.String("key", k))
|
||||
return common.NewIgnorableError(fmt.Errorf("the key[%s] has existed", k))
|
||||
}
|
||||
return kc.Txn.Save(ctx, k, "")
|
||||
}
|
||||
|
||||
func (kc *Catalog) remove(ctx context.Context, k string) error {
|
||||
var err error
|
||||
if _, err = kc.Txn.Load(ctx, k); err != nil && !errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
@ -1076,11 +1062,7 @@ func (kc *Catalog) remove(ctx context.Context, k string) error {
|
||||
|
||||
func (kc *Catalog) CreateRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error {
|
||||
k := funcutil.HandleTenantForEtcdKey(RolePrefix, tenant, entity.Name)
|
||||
err := kc.save(ctx, k)
|
||||
if err != nil && !common.IsIgnorableError(err) {
|
||||
log.Ctx(ctx).Warn("fail to save the role", zap.String("key", k), zap.Error(err))
|
||||
}
|
||||
return err
|
||||
return kc.Txn.Save(ctx, k, "")
|
||||
}
|
||||
|
||||
func (kc *Catalog) DropRole(ctx context.Context, tenant string, roleName string) error {
|
||||
@ -1112,21 +1094,13 @@ func (kc *Catalog) DropRole(ctx context.Context, tenant string, roleName string)
|
||||
|
||||
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.save(ctx, k)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error("fail to save the user-role", zap.String("key", k), zap.Error(err))
|
||||
}
|
||||
} else if operateType == milvuspb.OperateUserRoleType_RemoveUserFromRole {
|
||||
err = kc.remove(ctx, k)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).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)
|
||||
switch operateType {
|
||||
case milvuspb.OperateUserRoleType_AddUserToRole:
|
||||
return kc.Txn.Save(ctx, k, "")
|
||||
case milvuspb.OperateUserRoleType_RemoveUserFromRole:
|
||||
return kc.Txn.Remove(ctx, k)
|
||||
}
|
||||
return err
|
||||
return fmt.Errorf("invalid operate user role type, operate type: %d", operateType)
|
||||
}
|
||||
|
||||
func (kc *Catalog) ListRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
@ -1593,145 +1567,49 @@ func (kc *Catalog) BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBA
|
||||
}
|
||||
|
||||
func (kc *Catalog) RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error {
|
||||
var err error
|
||||
needRollbackUser := make([]*milvuspb.UserInfo, 0)
|
||||
needRollbackRole := make([]*milvuspb.RoleEntity, 0)
|
||||
needRollbackGrants := make([]*milvuspb.GrantEntity, 0)
|
||||
needRollbackPrivilegeGroups := make([]*milvuspb.PrivilegeGroupInfo, 0)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("failed to restore rbac, try to rollback", zap.Error(err))
|
||||
// roll back role
|
||||
for _, role := range needRollbackRole {
|
||||
err = kc.DropRole(ctx, tenant, role.GetName())
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("failed to rollback roles after restore failed", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// roll back grant
|
||||
for _, grant := range needRollbackGrants {
|
||||
err = kc.AlterGrant(ctx, tenant, grant, milvuspb.OperatePrivilegeType_Revoke)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("failed to rollback grants after restore failed", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
for _, user := range needRollbackUser {
|
||||
// roll back user
|
||||
err = kc.DropCredential(ctx, user.GetUser())
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("failed to rollback users after restore failed", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// roll back privilege group
|
||||
for _, group := range needRollbackPrivilegeGroups {
|
||||
err = kc.DropPrivilegeGroup(ctx, group.GetGroupName())
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("failed to rollback privilege groups after restore failed", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// restore role
|
||||
existRoles, err := kc.ListRole(ctx, tenant, nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existRoleMap := lo.SliceToMap(existRoles, func(entity *milvuspb.RoleResult) (string, struct{}) { return entity.GetRole().GetName(), struct{}{} })
|
||||
for _, role := range meta.GetRoles() {
|
||||
if _, ok := existRoleMap[role.GetName()]; ok {
|
||||
log.Ctx(ctx).Warn("failed to restore, role already exists", zap.String("role", role.GetName()))
|
||||
err = errors.Newf("role [%s] already exists", role.GetName())
|
||||
return err
|
||||
if err := kc.CreateRole(ctx, tenant, role); err != nil {
|
||||
return errors.Wrap(err, "failed to create role")
|
||||
}
|
||||
err = kc.CreateRole(ctx, tenant, role)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
needRollbackRole = append(needRollbackRole, role)
|
||||
}
|
||||
|
||||
// restore privilege group
|
||||
existPrivGroups, err := kc.ListPrivilegeGroups(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existPrivGroupMap := lo.SliceToMap(existPrivGroups, func(entity *milvuspb.PrivilegeGroupInfo) (string, struct{}) { return entity.GetGroupName(), struct{}{} })
|
||||
for _, group := range meta.GetPrivilegeGroups() {
|
||||
if _, ok := existPrivGroupMap[group.GetGroupName()]; ok {
|
||||
log.Ctx(ctx).Warn("failed to restore, privilege group already exists", zap.String("group", group.GetGroupName()))
|
||||
err = errors.Newf("privilege group [%s] already exists", group.GetGroupName())
|
||||
return err
|
||||
if err := kc.SavePrivilegeGroup(ctx, group); err != nil {
|
||||
return errors.Wrap(err, "failed to save privilege group")
|
||||
}
|
||||
err = kc.SavePrivilegeGroup(ctx, group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
needRollbackPrivilegeGroups = append(needRollbackPrivilegeGroups, group)
|
||||
}
|
||||
|
||||
// restore grant, list latest privilege group first
|
||||
existPrivGroups, err = kc.ListPrivilegeGroups(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existPrivGroupMap = lo.SliceToMap(existPrivGroups, func(entity *milvuspb.PrivilegeGroupInfo) (string, struct{}) { return entity.GetGroupName(), struct{}{} })
|
||||
for _, grant := range meta.GetGrants() {
|
||||
privName := grant.GetGrantor().GetPrivilege().GetName()
|
||||
if util.IsPrivilegeNameDefined(privName) {
|
||||
grant.Grantor.Privilege.Name = util.PrivilegeNameForMetastore(privName)
|
||||
} else if _, ok := existPrivGroupMap[privName]; ok {
|
||||
grant.Grantor.Privilege.Name = util.PrivilegeGroupNameForMetastore(privName)
|
||||
} else {
|
||||
log.Ctx(ctx).Warn("failed to restore, privilege group does not exist", zap.String("group", privName))
|
||||
err = errors.Newf("privilege group [%s] does not exist", privName)
|
||||
return err
|
||||
grant.Grantor.Privilege.Name = util.PrivilegeGroupNameForMetastore(privName)
|
||||
}
|
||||
err = kc.AlterGrant(ctx, tenant, grant, milvuspb.OperatePrivilegeType_Grant)
|
||||
if err != nil {
|
||||
return err
|
||||
if err := kc.AlterGrant(ctx, tenant, grant, milvuspb.OperatePrivilegeType_Grant); err != nil {
|
||||
return errors.Wrap(err, "failed to alter grant")
|
||||
}
|
||||
needRollbackGrants = append(needRollbackGrants, grant)
|
||||
}
|
||||
|
||||
// need rollback user
|
||||
existUser, err := kc.ListUser(ctx, tenant, nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existUserMap := lo.SliceToMap(existUser, func(entity *milvuspb.UserResult) (string, struct{}) { return entity.GetUser().GetName(), struct{}{} })
|
||||
for _, user := range meta.GetUsers() {
|
||||
if _, ok := existUserMap[user.GetUser()]; ok {
|
||||
log.Ctx(ctx).Info("failed to restore, user already exists", zap.String("user", user.GetUser()))
|
||||
err = errors.Newf("user [%s] already exists", user.GetUser())
|
||||
return err
|
||||
}
|
||||
// restore user
|
||||
err = kc.CreateCredential(ctx, &model.Credential{
|
||||
if err := kc.AlterCredential(ctx, &model.Credential{
|
||||
Username: user.GetUser(),
|
||||
EncryptedPassword: user.GetPassword(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "failed to alter credential")
|
||||
}
|
||||
needRollbackUser = append(needRollbackUser, user)
|
||||
|
||||
// restore user role mapping
|
||||
entity := &milvuspb.UserEntity{
|
||||
Name: user.GetUser(),
|
||||
}
|
||||
for _, role := range user.GetRoles() {
|
||||
err = kc.AlterUserRole(ctx, tenant, entity, role, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
if err != nil {
|
||||
return err
|
||||
if err := kc.AlterUserRole(ctx, tenant, entity, role, milvuspb.OperateUserRoleType_AddUserToRole); err != nil {
|
||||
return errors.Wrap(err, "failed to alter user role")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) GetPrivilegeGroup(ctx context.Context, groupName string) (*milvuspb.PrivilegeGroupInfo, error) {
|
||||
|
||||
@ -1564,7 +1564,7 @@ func TestRBAC_Credential(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
err := c.CreateCredential(ctx, &model.Credential{
|
||||
err := c.AlterCredential(ctx, &model.Credential{
|
||||
Username: test.user,
|
||||
EncryptedPassword: test.password,
|
||||
})
|
||||
@ -1772,94 +1772,17 @@ func TestRBAC_Role(t *testing.T) {
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test save", func(t *testing.T) {
|
||||
var (
|
||||
kvmock = mocks.NewTxnKV(t)
|
||||
c = NewCatalog(kvmock, nil).(*Catalog)
|
||||
|
||||
notExistKey = "not-exist"
|
||||
errorKey = "error"
|
||||
otherError = errors.New("mock load error")
|
||||
)
|
||||
|
||||
kvmock.EXPECT().Load(mock.Anything, notExistKey).Return("", merr.WrapErrIoKeyNotFound(notExistKey)).Once()
|
||||
kvmock.EXPECT().Load(mock.Anything, errorKey).Return("", otherError).Once()
|
||||
kvmock.EXPECT().Load(mock.Anything, mock.Anything).Return("", nil).Once()
|
||||
kvmock.EXPECT().Save(mock.Anything, mock.Anything, mock.Anything).Call.Return(nil).Once()
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
|
||||
isValid bool
|
||||
key string
|
||||
|
||||
expectedError error
|
||||
ignorable bool
|
||||
}{
|
||||
{"key not exists", true, notExistKey, nil, false},
|
||||
{"other error", false, errorKey, otherError, false},
|
||||
{"ignorable error", false, "key1", &common.IgnorableError{}, true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
err := c.save(ctx, test.key)
|
||||
if test.isValid {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
if test.ignorable {
|
||||
_, ok := err.(*common.IgnorableError)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
t.Run("test CreateRole", func(t *testing.T) {
|
||||
var (
|
||||
kvmock = mocks.NewTxnKV(t)
|
||||
c = NewCatalog(kvmock, nil)
|
||||
|
||||
notExistName = "not-exist"
|
||||
notExistPath = funcutil.HandleTenantForEtcdKey(RolePrefix, tenant, notExistName)
|
||||
errorName = "error"
|
||||
errorPath = funcutil.HandleTenantForEtcdKey(RolePrefix, tenant, errorName)
|
||||
otherError = errors.New("mock load error")
|
||||
)
|
||||
|
||||
kvmock.EXPECT().Load(mock.Anything, notExistPath).Return("", merr.WrapErrIoKeyNotFound(notExistName)).Once()
|
||||
kvmock.EXPECT().Load(mock.Anything, errorPath).Return("", otherError).Once()
|
||||
kvmock.EXPECT().Load(mock.Anything, mock.Anything).Return("", nil).Once()
|
||||
kvmock.EXPECT().Save(mock.Anything, mock.Anything, mock.Anything).Call.Return(nil).Once()
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
|
||||
isValid bool
|
||||
name string
|
||||
|
||||
expectedError error
|
||||
}{
|
||||
{"key not exists", true, notExistName, nil},
|
||||
{"other error", false, errorName, otherError},
|
||||
{"ignorable error", false, "key1", &common.IgnorableError{}},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
err := c.CreateRole(ctx, tenant, &milvuspb.RoleEntity{
|
||||
Name: test.name,
|
||||
})
|
||||
if test.isValid {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
err := c.CreateRole(ctx, tenant, &milvuspb.RoleEntity{
|
||||
Name: "role1",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("test DropRole", func(t *testing.T) {
|
||||
var (
|
||||
@ -1920,58 +1843,17 @@ func TestRBAC_Role(t *testing.T) {
|
||||
c = NewCatalog(kvmock, nil)
|
||||
|
||||
user = "default-user"
|
||||
|
||||
noErrorRoleSave = "no-error-role-save"
|
||||
noErrorRoleSavepath = funcutil.HandleTenantForEtcdKey(RoleMappingPrefix, tenant, fmt.Sprintf("%s/%s", user, noErrorRoleSave))
|
||||
|
||||
errorRoleSave = "error-role-save"
|
||||
errorRoleSavepath = funcutil.HandleTenantForEtcdKey(RoleMappingPrefix, tenant, fmt.Sprintf("%s/%s", user, errorRoleSave))
|
||||
|
||||
errorRoleRemove = "error-role-remove"
|
||||
errorRoleRemovepath = funcutil.HandleTenantForEtcdKey(RoleMappingPrefix, tenant, fmt.Sprintf("%s/%s", user, errorRoleRemove))
|
||||
)
|
||||
kvmock.EXPECT().Save(mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
kvmock.EXPECT().Remove(mock.Anything, mock.Anything).Return(nil)
|
||||
|
||||
// Catalog.save() returns error
|
||||
kvmock.EXPECT().Load(mock.Anything, errorRoleSavepath).Return("", nil)
|
||||
|
||||
// Catalog.save() returns nil
|
||||
kvmock.EXPECT().Load(mock.Anything, noErrorRoleSavepath).Return("", merr.WrapErrIoKeyNotFound(noErrorRoleSavepath))
|
||||
|
||||
// Catalog.remove() returns error
|
||||
kvmock.EXPECT().Load(mock.Anything, errorRoleRemovepath).Return("", errors.New("not exists"))
|
||||
|
||||
// Catalog.remove() returns nil
|
||||
kvmock.EXPECT().Load(mock.Anything, mock.Anything).Return("", nil)
|
||||
|
||||
tests := []struct {
|
||||
description string
|
||||
isValid bool
|
||||
|
||||
role string
|
||||
oType milvuspb.OperateUserRoleType
|
||||
}{
|
||||
{"valid role role1, AddUserToRole", true, noErrorRoleSave, milvuspb.OperateUserRoleType_AddUserToRole},
|
||||
{"invalid role error-role, AddUserToRole", false, errorRoleSave, milvuspb.OperateUserRoleType_AddUserToRole},
|
||||
{"valid role role1, RemoveUserFromRole", true, "role", milvuspb.OperateUserRoleType_RemoveUserFromRole},
|
||||
{"invalid role error-role, RemoveUserFromRole", false, errorRoleRemove, milvuspb.OperateUserRoleType_RemoveUserFromRole},
|
||||
{"invalid operate type 100", false, "role1", milvuspb.OperateUserRoleType(100)},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
err := c.AlterUserRole(ctx, tenant, &milvuspb.UserEntity{Name: user}, &milvuspb.RoleEntity{
|
||||
Name: test.role,
|
||||
}, test.oType)
|
||||
|
||||
if test.isValid {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
err := c.AlterUserRole(ctx, tenant, &milvuspb.UserEntity{Name: user}, &milvuspb.RoleEntity{
|
||||
Name: "role1",
|
||||
}, milvuspb.OperateUserRoleType_RemoveUserFromRole)
|
||||
require.NoError(t, err)
|
||||
err = c.AlterUserRole(ctx, tenant, &milvuspb.UserEntity{Name: user}, &milvuspb.RoleEntity{
|
||||
Name: "role1",
|
||||
}, milvuspb.OperateUserRoleType_AddUserToRole)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("test ListRole", func(t *testing.T) {
|
||||
@ -2816,7 +2698,7 @@ func TestRBAC_Backup(t *testing.T) {
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: "PrivilegeLoad"},
|
||||
},
|
||||
}, milvuspb.OperatePrivilegeType_Grant)
|
||||
c.CreateCredential(ctx, &model.Credential{
|
||||
c.AlterCredential(ctx, &model.Credential{
|
||||
Username: "user1",
|
||||
EncryptedPassword: "passwd",
|
||||
})
|
||||
@ -2940,15 +2822,6 @@ func TestRBAC_Restore(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
User: "user1",
|
||||
Password: "passwd",
|
||||
Roles: []*milvuspb.RoleEntity{
|
||||
{
|
||||
Name: "role2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Roles: []*milvuspb.RoleEntity{
|
||||
{
|
||||
@ -2979,30 +2852,31 @@ func TestRBAC_Restore(t *testing.T) {
|
||||
|
||||
// test restore failed and roll back
|
||||
err = c.RestoreRBAC(ctx, util.DefaultTenant, rbacMeta2)
|
||||
assert.Error(t, err)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// check user
|
||||
users, err = c.ListCredentialsWithPasswd(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, users, 1)
|
||||
assert.Len(t, users, 2)
|
||||
// check role
|
||||
roles, err = c.ListRole(ctx, util.DefaultTenant, nil, false)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, roles, 1)
|
||||
assert.Len(t, roles, 2)
|
||||
// check grant
|
||||
grants, err = c.ListGrant(ctx, util.DefaultTenant, &milvuspb.GrantEntity{
|
||||
Role: roles[0].Role,
|
||||
Role: &milvuspb.RoleEntity{Name: "role2"},
|
||||
DbName: util.AnyWord,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, grants, 1)
|
||||
assert.Equal(t, grants[0].Grantor.Privilege.Name, "Load")
|
||||
assert.Equal(t, "obj_name2", grants[0].ObjectName)
|
||||
assert.Equal(t, "role2", grants[0].Role.Name)
|
||||
assert.Equal(t, "user2", grants[0].Grantor.User.Name)
|
||||
assert.Equal(t, "Load", grants[0].Grantor.Privilege.Name)
|
||||
// check privilege group
|
||||
privGroups, err = c.ListPrivilegeGroups(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, privGroups, 1)
|
||||
assert.Equal(t, "custom_group", privGroups[0].GroupName)
|
||||
assert.Equal(t, "CreateCollection", privGroups[0].Privileges[0].Name)
|
||||
assert.Len(t, privGroups, 2)
|
||||
}
|
||||
|
||||
func TestRBAC_PrivilegeGroup(t *testing.T) {
|
||||
|
||||
@ -8,6 +8,7 @@ type Credential struct {
|
||||
Tenant string
|
||||
IsSuper bool
|
||||
Sha256Password string
|
||||
TimeTick uint64 // the timetick in wal which the credential updates
|
||||
}
|
||||
|
||||
func MarshalCredentialModel(cred *Credential) *internalpb.CredentialInfo {
|
||||
@ -20,5 +21,20 @@ func MarshalCredentialModel(cred *Credential) *internalpb.CredentialInfo {
|
||||
EncryptedPassword: cred.EncryptedPassword,
|
||||
IsSuper: cred.IsSuper,
|
||||
Sha256Password: cred.Sha256Password,
|
||||
TimeTick: cred.TimeTick,
|
||||
}
|
||||
}
|
||||
|
||||
func UnmarshalCredentialModel(cred *internalpb.CredentialInfo) *Credential {
|
||||
if cred == nil {
|
||||
return nil
|
||||
}
|
||||
return &Credential{
|
||||
Username: cred.Username,
|
||||
EncryptedPassword: cred.EncryptedPassword,
|
||||
Tenant: cred.Tenant,
|
||||
IsSuper: cred.IsSuper,
|
||||
Sha256Password: cred.Sha256Password,
|
||||
TimeTick: cred.TimeTick,
|
||||
}
|
||||
}
|
||||
|
||||
104
internal/rootcoord/ddl_callbacks.go
Normal file
104
internal/rootcoord/ddl_callbacks.go
Normal file
@ -0,0 +1,104 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster/broadcast"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster/registry"
|
||||
"github.com/milvus-io/milvus/internal/util/proxyutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/messagespb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message/ce"
|
||||
)
|
||||
|
||||
// RegisterDDLCallbacks registers the ddl callbacks.
|
||||
func RegisterDDLCallbacks(core *Core) {
|
||||
ddlCallback := &DDLCallback{
|
||||
Core: core,
|
||||
}
|
||||
// RBAC
|
||||
ddlCallback.registerRBACCallbacks()
|
||||
}
|
||||
|
||||
// registerRBACCallbacks registers the rbac callbacks.
|
||||
func (c *DDLCallback) registerRBACCallbacks() {
|
||||
registry.RegisterAlterUserV2AckCallback(c.alterUserV2AckCallback)
|
||||
registry.RegisterDropUserV2AckCallback(c.dropUserV2AckCallback)
|
||||
registry.RegisterAlterRoleV2AckCallback(c.alterRoleV2AckCallback)
|
||||
registry.RegisterDropRoleV2AckCallback(c.dropRoleV2AckCallback)
|
||||
registry.RegisterAlterUserRoleV2AckCallback(c.alterUserRoleV2AckCallback)
|
||||
registry.RegisterDropUserRoleV2AckCallback(c.dropUserRoleV2AckCallback)
|
||||
registry.RegisterAlterPrivilegeV2AckCallback(c.alterPrivilegeV2AckCallback)
|
||||
registry.RegisterDropPrivilegeV2AckCallback(c.dropPrivilegeV2AckCallback)
|
||||
registry.RegisterAlterPrivilegeGroupV2AckCallback(c.alterPrivilegeGroupV2AckCallback)
|
||||
registry.RegisterDropPrivilegeGroupV2AckCallback(c.dropPrivilegeGroupV2AckCallback)
|
||||
registry.RegisterRestoreRBACV2AckCallback(c.restoreRBACV2AckCallback)
|
||||
}
|
||||
|
||||
// DDLCallback is the callback of ddl.
|
||||
type DDLCallback struct {
|
||||
*Core
|
||||
}
|
||||
|
||||
// CacheExpirationsGetter is the getter of cache expirations.
|
||||
type CacheExpirationsGetter interface {
|
||||
GetCacheExpirations() *message.CacheExpirations
|
||||
}
|
||||
|
||||
// ExpireCaches handles the cache
|
||||
func (c *DDLCallback) ExpireCaches(ctx context.Context, expirations any, timetick uint64) error {
|
||||
var cacheExpirations *message.CacheExpirations
|
||||
if g, ok := expirations.(CacheExpirationsGetter); ok {
|
||||
cacheExpirations = g.GetCacheExpirations()
|
||||
} else if g, ok := expirations.(*message.CacheExpirations); ok {
|
||||
cacheExpirations = g
|
||||
} else if g, ok := expirations.(*ce.CacheExpirationsBuilder); ok {
|
||||
cacheExpirations = g.Build()
|
||||
} else {
|
||||
panic(fmt.Sprintf("invalid getter type: %T", expirations))
|
||||
}
|
||||
for _, cacheExpiration := range cacheExpirations.CacheExpirations {
|
||||
if err := c.expireCache(ctx, cacheExpiration, timetick); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DDLCallback) expireCache(ctx context.Context, cacheExpiration *message.CacheExpiration, timetick uint64) error {
|
||||
switch cacheExpiration.Cache.(type) {
|
||||
case *messagespb.CacheExpiration_LegacyProxyCollectionMetaCache:
|
||||
legacyProxyCollectionMetaCache := cacheExpiration.GetLegacyProxyCollectionMetaCache()
|
||||
return c.Core.ExpireMetaCache(ctx, legacyProxyCollectionMetaCache.DbName, []string{legacyProxyCollectionMetaCache.CollectionName}, legacyProxyCollectionMetaCache.CollectionId, legacyProxyCollectionMetaCache.PartitionName, timetick, proxyutil.SetMsgType(legacyProxyCollectionMetaCache.MsgType))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// startBroadcastWithRBACLock starts a broadcast for rbac.
|
||||
func startBroadcastWithRBACLock(ctx context.Context) (broadcaster.BroadcastAPI, error) {
|
||||
api, err := broadcast.StartBroadcastWithResourceKeys(ctx, message.NewExclusivePrivilegeResourceKey())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to start broadcast with rbac lock")
|
||||
}
|
||||
return api, nil
|
||||
}
|
||||
137
internal/rootcoord/ddl_callbacks_rbac_credential.go
Normal file
137
internal/rootcoord/ddl_callbacks_rbac_credential.go
Normal file
@ -0,0 +1,137 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
"github.com/milvus-io/milvus/internal/distributed/streaming"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/proxypb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
|
||||
)
|
||||
|
||||
// broadcastAlterUserForCreateCredential broadcasts the alter user message for create credential.
|
||||
func (c *Core) broadcastAlterUserForCreateCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
credInfo.Username = strings.TrimSpace(credInfo.Username)
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfAddCredential(ctx, credInfo); err != nil {
|
||||
return errors.Wrap(err, "failed to check if add credential")
|
||||
}
|
||||
|
||||
msg := message.NewAlterUserMessageBuilderV2().
|
||||
WithHeader(&message.AlterUserMessageHeader{
|
||||
UserEntity: &milvuspb.UserEntity{Name: credInfo.Username},
|
||||
}).
|
||||
WithBody(&message.AlterUserMessageBody{
|
||||
CredentialInfo: credInfo,
|
||||
}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// broadcastAlterUserForUpdateCredential broadcasts the alter user message for update credential.
|
||||
func (c *Core) broadcastAlterUserForUpdateCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
credInfo.Username = strings.TrimSpace(credInfo.Username)
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfUpdateCredential(ctx, credInfo); err != nil {
|
||||
return errors.Wrap(err, "failed to check if update credential")
|
||||
}
|
||||
|
||||
msg := message.NewAlterUserMessageBuilderV2().
|
||||
WithHeader(&message.AlterUserMessageHeader{
|
||||
UserEntity: &milvuspb.UserEntity{Name: credInfo.Username},
|
||||
}).
|
||||
WithBody(&message.AlterUserMessageBody{
|
||||
CredentialInfo: credInfo,
|
||||
}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// alterUserV2AckCallback is the ack callback function for the AlterUserMessageV2 message.
|
||||
func (c *DDLCallback) alterUserV2AckCallback(ctx context.Context, result message.BroadcastResultAlterUserMessageV2) error {
|
||||
// insert to db
|
||||
if err := c.meta.AlterCredential(ctx, result); err != nil {
|
||||
return errors.Wrap(err, "failed to alter credential")
|
||||
}
|
||||
// update proxy's local cache
|
||||
if err := c.UpdateCredCache(ctx, result.Message.MustBody().CredentialInfo); err != nil {
|
||||
return errors.Wrap(err, "failed to update cred cache")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// broadcastDropUserForDeleteCredential broadcasts the drop user message for delete credential.
|
||||
func (c *Core) broadcastDropUserForDeleteCredential(ctx context.Context, in *milvuspb.DeleteCredentialRequest) error {
|
||||
in.Username = strings.TrimSpace(in.Username)
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfDeleteCredential(ctx, in); err != nil {
|
||||
return errors.Wrap(err, "failed to check if delete credential")
|
||||
}
|
||||
|
||||
msg := message.NewDropUserMessageBuilderV2().
|
||||
WithHeader(&message.DropUserMessageHeader{
|
||||
UserName: in.Username,
|
||||
}).
|
||||
WithBody(&message.DropUserMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// dropUserV2AckCallback is the ack callback function for the DeleteCredential message
|
||||
func (c *DDLCallback) dropUserV2AckCallback(ctx context.Context, result message.BroadcastResultDropUserMessageV2) error {
|
||||
if err := c.meta.DeleteCredential(ctx, result); err != nil {
|
||||
return errors.Wrap(err, "failed to delete credential")
|
||||
}
|
||||
if err := c.ExpireCredCache(ctx, result.Message.Header().UserName); err != nil {
|
||||
return errors.Wrap(err, "failed to expire cred cache")
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: int32(typeutil.CacheDeleteUser),
|
||||
OpKey: result.Message.Header().UserName,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "failed to refresh policy info cache")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
106
internal/rootcoord/ddl_callbacks_rbac_credential_test.go
Normal file
106
internal/rootcoord/ddl_callbacks_rbac_credential_test.go
Normal file
@ -0,0 +1,106 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
etcdkv "github.com/milvus-io/milvus/internal/kv/etcd"
|
||||
"github.com/milvus-io/milvus/internal/metastore/kv/rootcoord"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster/registry"
|
||||
kvfactory "github.com/milvus-io/milvus/internal/util/dependency/kv"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/rootcoordpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
)
|
||||
|
||||
func TestDDLCallbacksRBACCredential(t *testing.T) {
|
||||
initStreamingSystem()
|
||||
|
||||
kv, _ := kvfactory.GetEtcdAndPath()
|
||||
path := funcutil.RandomString(10)
|
||||
catalogKV := etcdkv.NewEtcdKV(kv, path)
|
||||
|
||||
testUserName := "user" + funcutil.RandomString(10)
|
||||
|
||||
core := newTestCore(withHealthyCode(),
|
||||
withMeta(&MetaTable{catalog: rootcoord.NewCatalog(catalogKV, nil)}),
|
||||
withValidProxyManager(),
|
||||
)
|
||||
registry.ResetRegistration()
|
||||
RegisterDDLCallbacks(core)
|
||||
|
||||
// Delete a not existed credential should succeed
|
||||
status, err := core.DeleteCredential(context.Background(), &milvuspb.DeleteCredentialRequest{
|
||||
Username: testUserName,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
// Update a not existed credential should return error.
|
||||
status, err = core.UpdateCredential(context.Background(), &internalpb.CredentialInfo{
|
||||
Username: testUserName,
|
||||
EncryptedPassword: "123456",
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
// Create a new credential.
|
||||
status, err = core.CreateCredential(context.Background(), &internalpb.CredentialInfo{
|
||||
Username: testUserName,
|
||||
EncryptedPassword: "123456",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
getCredentialResp, err := core.GetCredential(context.Background(), &rootcoordpb.GetCredentialRequest{
|
||||
Username: testUserName,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(getCredentialResp.Status, err))
|
||||
assert.Equal(t, "123456", getCredentialResp.Password)
|
||||
|
||||
// Create a new credential with same username should return error.
|
||||
status, err = core.CreateCredential(context.Background(), &internalpb.CredentialInfo{
|
||||
Username: testUserName,
|
||||
EncryptedPassword: "123456",
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
// Update the created credential.
|
||||
status, err = core.UpdateCredential(context.Background(), &internalpb.CredentialInfo{
|
||||
Username: testUserName,
|
||||
EncryptedPassword: "1234567",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
getCredentialResp, err = core.GetCredential(context.Background(), &rootcoordpb.GetCredentialRequest{
|
||||
Username: testUserName,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(getCredentialResp.Status, err))
|
||||
assert.Equal(t, "1234567", getCredentialResp.Password)
|
||||
|
||||
// Delete the created credential.
|
||||
status, err = core.DeleteCredential(context.Background(), &milvuspb.DeleteCredentialRequest{
|
||||
Username: testUserName,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
getCredentialResp, err = core.GetCredential(context.Background(), &rootcoordpb.GetCredentialRequest{
|
||||
Username: testUserName,
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(getCredentialResp.Status, err))
|
||||
}
|
||||
199
internal/rootcoord/ddl_callbacks_rbac_privilege.go
Normal file
199
internal/rootcoord/ddl_callbacks_rbac_privilege.go
Normal file
@ -0,0 +1,199 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
|
||||
"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/internal/distributed/streaming"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
)
|
||||
|
||||
func (c *Core) broadcastOperatePrivilege(ctx context.Context, in *milvuspb.OperatePrivilegeRequest) error {
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.operatePrivilegeCommonCheck(ctx, in); err != nil {
|
||||
return errors.Wrap(err, "failed to operate privilege common check")
|
||||
}
|
||||
privName := in.Entity.Grantor.Privilege.Name
|
||||
switch in.Version {
|
||||
case "v2":
|
||||
if err := c.isValidPrivilegeV2(ctx, privName); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.validatePrivilegeGroupParams(ctx, privName, in.Entity.DbName, in.Entity.ObjectName); err != nil {
|
||||
return err
|
||||
}
|
||||
// set up object type for metastore, to be compatible with v1 version
|
||||
in.Entity.Object.Name = util.GetObjectType(privName)
|
||||
default:
|
||||
if err := c.isValidPrivilege(ctx, privName, in.Entity.Object.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
// set up object name if it is global object type and not built in privilege group
|
||||
if in.Entity.Object.Name == commonpb.ObjectType_Global.String() && !util.IsBuiltinPrivilegeGroup(in.Entity.Grantor.Privilege.Name) {
|
||||
in.Entity.ObjectName = util.AnyWord
|
||||
}
|
||||
}
|
||||
|
||||
var msg message.BroadcastMutableMessage
|
||||
switch in.Type {
|
||||
case milvuspb.OperatePrivilegeType_Grant:
|
||||
msg = message.NewAlterPrivilegeMessageBuilderV2().
|
||||
WithHeader(&message.AlterPrivilegeMessageHeader{
|
||||
Entity: in.Entity,
|
||||
}).
|
||||
WithBody(&message.AlterPrivilegeMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
case milvuspb.OperatePrivilegeType_Revoke:
|
||||
msg = message.NewDropPrivilegeMessageBuilderV2().
|
||||
WithHeader(&message.DropPrivilegeMessageHeader{
|
||||
Entity: in.Entity,
|
||||
}).
|
||||
WithBody(&message.DropPrivilegeMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
default:
|
||||
return errors.New("invalid operate privilege type")
|
||||
}
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DDLCallback) alterPrivilegeV2AckCallback(ctx context.Context, result message.BroadcastResultAlterPrivilegeMessageV2) error {
|
||||
return executeOperatePrivilegeTaskSteps(ctx, c.Core, result.Message.Header().Entity, milvuspb.OperatePrivilegeType_Grant)
|
||||
}
|
||||
|
||||
func (c *DDLCallback) dropPrivilegeV2AckCallback(ctx context.Context, result message.BroadcastResultDropPrivilegeMessageV2) error {
|
||||
return executeOperatePrivilegeTaskSteps(ctx, c.Core, result.Message.Header().Entity, milvuspb.OperatePrivilegeType_Revoke)
|
||||
}
|
||||
|
||||
func (c *Core) broadcastCreatePrivilegeGroup(ctx context.Context, in *milvuspb.CreatePrivilegeGroupRequest) error {
|
||||
in.GroupName = strings.TrimSpace(in.GroupName)
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfPrivilegeGroupCreatable(ctx, in); err != nil {
|
||||
return errors.Wrap(err, "failed to check if privilege group creatable")
|
||||
}
|
||||
|
||||
msg := message.NewAlterPrivilegeGroupMessageBuilderV2().
|
||||
WithHeader(&message.AlterPrivilegeGroupMessageHeader{
|
||||
PrivilegeGroupInfo: &milvuspb.PrivilegeGroupInfo{
|
||||
GroupName: in.GroupName,
|
||||
},
|
||||
}).
|
||||
WithBody(&message.AlterPrivilegeGroupMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Core) broadcastOperatePrivilegeGroup(ctx context.Context, in *milvuspb.OperatePrivilegeGroupRequest) error {
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfPrivilegeGroupAlterable(ctx, in); err != nil {
|
||||
return errors.Wrap(err, "failed to check if privilege group alterable")
|
||||
}
|
||||
|
||||
var msg message.BroadcastMutableMessage
|
||||
switch in.Type {
|
||||
case milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup:
|
||||
msg = message.NewAlterPrivilegeGroupMessageBuilderV2().
|
||||
WithHeader(&message.AlterPrivilegeGroupMessageHeader{
|
||||
PrivilegeGroupInfo: &milvuspb.PrivilegeGroupInfo{
|
||||
GroupName: in.GroupName,
|
||||
Privileges: in.Privileges,
|
||||
},
|
||||
}).
|
||||
WithBody(&message.AlterPrivilegeGroupMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
case milvuspb.OperatePrivilegeGroupType_RemovePrivilegesFromGroup:
|
||||
msg = message.NewDropPrivilegeGroupMessageBuilderV2().
|
||||
WithHeader(&message.DropPrivilegeGroupMessageHeader{
|
||||
PrivilegeGroupInfo: &milvuspb.PrivilegeGroupInfo{
|
||||
GroupName: in.GroupName,
|
||||
Privileges: in.Privileges,
|
||||
},
|
||||
}).
|
||||
WithBody(&message.DropPrivilegeGroupMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
default:
|
||||
return errors.New("invalid operate privilege group type")
|
||||
}
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DDLCallback) alterPrivilegeGroupV2AckCallback(ctx context.Context, result message.BroadcastResultAlterPrivilegeGroupMessageV2) error {
|
||||
if len(result.Message.Header().PrivilegeGroupInfo.Privileges) == 0 {
|
||||
return c.meta.CreatePrivilegeGroup(ctx, result.Message.Header().PrivilegeGroupInfo.GroupName)
|
||||
}
|
||||
return executeOperatePrivilegeGroupTaskSteps(ctx, c.Core, result.Message.Header().PrivilegeGroupInfo, milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup)
|
||||
}
|
||||
|
||||
func (c *Core) broadcastDropPrivilegeGroup(ctx context.Context, in *milvuspb.DropPrivilegeGroupRequest) error {
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfPrivilegeGroupDropable(ctx, in); err != nil {
|
||||
return errors.Wrap(err, "failed to check if privilege group dropable")
|
||||
}
|
||||
|
||||
msg := message.NewDropPrivilegeGroupMessageBuilderV2().
|
||||
WithHeader(&message.DropPrivilegeGroupMessageHeader{
|
||||
PrivilegeGroupInfo: &milvuspb.PrivilegeGroupInfo{
|
||||
GroupName: in.GroupName,
|
||||
},
|
||||
}).
|
||||
WithBody(&message.DropPrivilegeGroupMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DDLCallback) dropPrivilegeGroupV2AckCallback(ctx context.Context, result message.BroadcastResultDropPrivilegeGroupMessageV2) error {
|
||||
if len(result.Message.Header().PrivilegeGroupInfo.Privileges) == 0 {
|
||||
return c.meta.DropPrivilegeGroup(ctx, result.Message.Header().PrivilegeGroupInfo.GroupName)
|
||||
}
|
||||
return executeOperatePrivilegeGroupTaskSteps(ctx, c.Core, result.Message.Header().PrivilegeGroupInfo, milvuspb.OperatePrivilegeGroupType_RemovePrivilegesFromGroup)
|
||||
}
|
||||
211
internal/rootcoord/ddl_callbacks_rbac_privilege_test.go
Normal file
211
internal/rootcoord/ddl_callbacks_rbac_privilege_test.go
Normal file
@ -0,0 +1,211 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
etcdkv "github.com/milvus-io/milvus/internal/kv/etcd"
|
||||
"github.com/milvus-io/milvus/internal/metastore/kv/rootcoord"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster/registry"
|
||||
kvfactory "github.com/milvus-io/milvus/internal/util/dependency/kv"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
)
|
||||
|
||||
func TestDDLCallbacksRBACPrivilege(t *testing.T) {
|
||||
initStreamingSystem()
|
||||
|
||||
kv, _ := kvfactory.GetEtcdAndPath()
|
||||
path := funcutil.RandomString(10)
|
||||
catalogKV := etcdkv.NewEtcdKV(kv, path)
|
||||
|
||||
core := newTestCore(withHealthyCode(),
|
||||
withMeta(&MetaTable{catalog: rootcoord.NewCatalog(catalogKV, nil)}),
|
||||
withValidProxyManager(),
|
||||
)
|
||||
registry.ResetRegistration()
|
||||
RegisterDDLCallbacks(core)
|
||||
|
||||
// Create a new role.
|
||||
targetRoleName := "newRole"
|
||||
status, err := core.CreateRole(context.Background(), &milvuspb.CreateRoleRequest{
|
||||
Entity: &milvuspb.RoleEntity{
|
||||
Name: targetRoleName,
|
||||
},
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
targetUserName := "newUser"
|
||||
status, err = core.CreateCredential(context.Background(), &internalpb.CredentialInfo{
|
||||
Username: targetUserName,
|
||||
EncryptedPassword: "123456",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
// Drop not existed privilege should return error.
|
||||
status, err = core.OperatePrivilege(context.Background(), &milvuspb.OperatePrivilegeRequest{
|
||||
Type: milvuspb.OperatePrivilegeType_Revoke,
|
||||
Entity: &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{
|
||||
Name: targetRoleName,
|
||||
},
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
Privilege: &milvuspb.PrivilegeEntity{
|
||||
Name: "not existed",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
entity := &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{
|
||||
Name: targetRoleName,
|
||||
},
|
||||
Object: &milvuspb.ObjectEntity{
|
||||
Name: "Global",
|
||||
},
|
||||
ObjectName: "*",
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
Privilege: &milvuspb.PrivilegeEntity{
|
||||
Name: "DescribeCollection",
|
||||
},
|
||||
User: &milvuspb.UserEntity{
|
||||
Name: targetUserName,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Grant and revoke with v2 version
|
||||
status, err = core.OperatePrivilege(context.Background(), &milvuspb.OperatePrivilegeRequest{
|
||||
Type: milvuspb.OperatePrivilegeType_Grant,
|
||||
Entity: entity,
|
||||
Version: "v2",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
selectGrantResp, err := core.SelectGrant(context.Background(), &milvuspb.SelectGrantRequest{
|
||||
Entity: entity,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(selectGrantResp, err))
|
||||
require.Equal(t, 1, len(selectGrantResp.Entities))
|
||||
|
||||
status, err = core.OperatePrivilege(context.Background(), &milvuspb.OperatePrivilegeRequest{
|
||||
Type: milvuspb.OperatePrivilegeType_Revoke,
|
||||
Entity: entity,
|
||||
Version: "v2",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
selectGrantResp, err = core.SelectGrant(context.Background(), &milvuspb.SelectGrantRequest{
|
||||
Entity: entity,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(selectGrantResp, err))
|
||||
require.Equal(t, 0, len(selectGrantResp.Entities))
|
||||
|
||||
// Grant and revoke with v1 version
|
||||
status, err = core.OperatePrivilege(context.Background(), &milvuspb.OperatePrivilegeRequest{
|
||||
Type: milvuspb.OperatePrivilegeType_Grant,
|
||||
Entity: entity,
|
||||
Version: "v1",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
selectGrantResp, err = core.SelectGrant(context.Background(), &milvuspb.SelectGrantRequest{
|
||||
Entity: entity,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(selectGrantResp, err))
|
||||
require.Equal(t, 1, len(selectGrantResp.Entities))
|
||||
|
||||
status, err = core.OperatePrivilege(context.Background(), &milvuspb.OperatePrivilegeRequest{
|
||||
Type: milvuspb.OperatePrivilegeType_Revoke,
|
||||
Entity: entity,
|
||||
Version: "v1",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
selectGrantResp, err = core.SelectGrant(context.Background(), &milvuspb.SelectGrantRequest{
|
||||
Entity: entity,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(selectGrantResp, err))
|
||||
require.Equal(t, 0, len(selectGrantResp.Entities))
|
||||
|
||||
// Grant and try drop role should return error
|
||||
status, err = core.OperatePrivilege(context.Background(), &milvuspb.OperatePrivilegeRequest{
|
||||
Type: milvuspb.OperatePrivilegeType_Grant,
|
||||
Entity: entity,
|
||||
Version: "v1",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
status, err = core.DropRole(context.Background(), &milvuspb.DropRoleRequest{
|
||||
RoleName: targetRoleName,
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(status, err))
|
||||
}
|
||||
|
||||
func TestDDLCallbacksRBACPrivilegeGroup(t *testing.T) {
|
||||
initStreamingSystem()
|
||||
|
||||
kv, _ := kvfactory.GetEtcdAndPath()
|
||||
path := funcutil.RandomString(10)
|
||||
catalogKV := etcdkv.NewEtcdKV(kv, path)
|
||||
|
||||
core := newTestCore(withHealthyCode(),
|
||||
withMeta(&MetaTable{catalog: rootcoord.NewCatalog(catalogKV, nil)}),
|
||||
withValidProxyManager(),
|
||||
)
|
||||
registry.ResetRegistration()
|
||||
RegisterDDLCallbacks(core)
|
||||
|
||||
groupName := "group1"
|
||||
status, err := core.CreatePrivilegeGroup(context.Background(), &milvuspb.CreatePrivilegeGroupRequest{
|
||||
GroupName: groupName,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
status, err = core.OperatePrivilegeGroup(context.Background(), &milvuspb.OperatePrivilegeGroupRequest{
|
||||
GroupName: groupName,
|
||||
Type: milvuspb.OperatePrivilegeGroupType_RemovePrivilegesFromGroup,
|
||||
Privileges: []*milvuspb.PrivilegeEntity{{Name: "Query"}},
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
status, err = core.OperatePrivilegeGroup(context.Background(), &milvuspb.OperatePrivilegeGroupRequest{
|
||||
GroupName: groupName,
|
||||
Type: milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup,
|
||||
Privileges: []*milvuspb.PrivilegeEntity{{Name: "Query"}},
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
status, err = core.OperatePrivilegeGroup(context.Background(), &milvuspb.OperatePrivilegeGroupRequest{
|
||||
GroupName: groupName,
|
||||
Type: milvuspb.OperatePrivilegeGroupType_RemovePrivilegesFromGroup,
|
||||
Privileges: []*milvuspb.PrivilegeEntity{{Name: "Query"}},
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
status, err = core.DropPrivilegeGroup(context.Background(), &milvuspb.DropPrivilegeGroupRequest{
|
||||
GroupName: groupName,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
}
|
||||
65
internal/rootcoord/ddl_callbacks_rbac_restore.go
Normal file
65
internal/rootcoord/ddl_callbacks_rbac_restore.go
Normal file
@ -0,0 +1,65 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
"github.com/milvus-io/milvus/internal/distributed/streaming"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/proxypb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
|
||||
)
|
||||
|
||||
func (c *Core) broadcastRestoreRBACV2(ctx context.Context, req *milvuspb.RestoreRBACMetaRequest) error {
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfRBACRestorable(ctx, req); err != nil {
|
||||
return errors.Wrap(err, "failed to check if rbac restorable")
|
||||
}
|
||||
|
||||
msg := message.NewRestoreRBACMessageBuilderV2().
|
||||
WithHeader(&message.RestoreRBACMessageHeader{}).
|
||||
WithBody(&message.RestoreRBACMessageBody{
|
||||
RbacMeta: req.GetRBACMeta(),
|
||||
}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DDLCallback) restoreRBACV2AckCallback(ctx context.Context, result message.BroadcastResultRestoreRBACMessageV2) error {
|
||||
meta := result.Message.MustBody().RbacMeta
|
||||
if err := c.meta.RestoreRBAC(ctx, util.DefaultTenant, meta); err != nil {
|
||||
return errors.Wrap(err, "failed to restore rbac meta data")
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: int32(typeutil.CacheRefresh),
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "failed to refresh policy info cache")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
177
internal/rootcoord/ddl_callbacks_rbac_restore_test.go
Normal file
177
internal/rootcoord/ddl_callbacks_rbac_restore_test.go
Normal file
@ -0,0 +1,177 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
etcdkv "github.com/milvus-io/milvus/internal/kv/etcd"
|
||||
"github.com/milvus-io/milvus/internal/metastore/kv/rootcoord"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster/registry"
|
||||
kvfactory "github.com/milvus-io/milvus/internal/util/dependency/kv"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
)
|
||||
|
||||
func TestDDLCallbacksRBACRestore(t *testing.T) {
|
||||
initStreamingSystem()
|
||||
kv, _ := kvfactory.GetEtcdAndPath()
|
||||
path := funcutil.RandomString(10)
|
||||
catalogKV := etcdkv.NewEtcdKV(kv, path)
|
||||
|
||||
core := newTestCore(withHealthyCode(),
|
||||
withMeta(&MetaTable{catalog: rootcoord.NewCatalog(catalogKV, nil)}),
|
||||
withValidProxyManager(),
|
||||
)
|
||||
registry.ResetRegistration()
|
||||
RegisterDDLCallbacks(core)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
rbacMeta := &milvuspb.RBACMeta{
|
||||
Users: []*milvuspb.UserInfo{
|
||||
{
|
||||
User: "user1",
|
||||
Password: "passwd",
|
||||
Roles: []*milvuspb.RoleEntity{
|
||||
{
|
||||
Name: "role1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Roles: []*milvuspb.RoleEntity{
|
||||
{
|
||||
Name: "role1",
|
||||
},
|
||||
},
|
||||
|
||||
Grants: []*milvuspb.GrantEntity{
|
||||
{
|
||||
Role: &milvuspb.RoleEntity{Name: "role1"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "obj1"},
|
||||
ObjectName: "obj_name1",
|
||||
DbName: util.DefaultDBName,
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
User: &milvuspb.UserEntity{Name: "user1"},
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: "Load"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
PrivilegeGroups: []*milvuspb.PrivilegeGroupInfo{
|
||||
{
|
||||
GroupName: "custom_group",
|
||||
Privileges: []*milvuspb.PrivilegeEntity{{Name: "CreateCollection"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
// test restore success
|
||||
status, err := core.RestoreRBAC(ctx, &milvuspb.RestoreRBACMetaRequest{
|
||||
RBACMeta: rbacMeta,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
status, err = core.RestoreRBAC(ctx, &milvuspb.RestoreRBACMetaRequest{
|
||||
RBACMeta: rbacMeta,
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
// check user
|
||||
users, err := core.meta.ListCredentialUsernames(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, users.Usernames, 1)
|
||||
assert.Equal(t, "user1", users.Usernames[0])
|
||||
// check grant
|
||||
userRoles, err := core.meta.ListUserRole(ctx, util.DefaultTenant)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, userRoles, 1)
|
||||
assert.Equal(t, "user1/role1", userRoles[0])
|
||||
policies, err := core.meta.SelectGrant(ctx, util.DefaultTenant, rbacMeta.Grants[0])
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, policies, 1)
|
||||
assert.Equal(t, "obj_name1", policies[0].ObjectName)
|
||||
assert.Equal(t, "role1", policies[0].Role.Name)
|
||||
assert.Equal(t, "user1", policies[0].Grantor.User.Name)
|
||||
assert.Equal(t, "Load", policies[0].Grantor.Privilege.Name)
|
||||
// check privilege group
|
||||
privGroups, err := core.meta.ListPrivilegeGroups(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, privGroups, 1)
|
||||
assert.Equal(t, "custom_group", privGroups[0].GroupName)
|
||||
assert.Equal(t, "CreateCollection", privGroups[0].Privileges[0].Name)
|
||||
|
||||
rbacMeta2 := &milvuspb.RBACMeta{
|
||||
Users: []*milvuspb.UserInfo{
|
||||
{
|
||||
User: "user2",
|
||||
Password: "passwd",
|
||||
Roles: []*milvuspb.RoleEntity{
|
||||
{
|
||||
Name: "role2",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
User: "user1",
|
||||
Password: "passwd",
|
||||
Roles: []*milvuspb.RoleEntity{
|
||||
{
|
||||
Name: "role2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Roles: []*milvuspb.RoleEntity{
|
||||
{
|
||||
Name: "role2",
|
||||
},
|
||||
},
|
||||
|
||||
Grants: []*milvuspb.GrantEntity{
|
||||
{
|
||||
Role: &milvuspb.RoleEntity{Name: "role2"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "obj2"},
|
||||
ObjectName: "obj_name2",
|
||||
DbName: util.DefaultDBName,
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
User: &milvuspb.UserEntity{Name: "user2"},
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: "Load"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
PrivilegeGroups: []*milvuspb.PrivilegeGroupInfo{
|
||||
{
|
||||
GroupName: "custom_group2",
|
||||
Privileges: []*milvuspb.PrivilegeEntity{{Name: "DropCollection"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// test restore failed and roll back
|
||||
status, err = core.RestoreRBAC(ctx, &milvuspb.RestoreRBACMetaRequest{
|
||||
RBACMeta: rbacMeta2,
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(status, err))
|
||||
}
|
||||
170
internal/rootcoord/ddl_callbacks_rbac_role.go
Normal file
170
internal/rootcoord/ddl_callbacks_rbac_role.go
Normal file
@ -0,0 +1,170 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
"github.com/milvus-io/milvus/internal/distributed/streaming"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/proxypb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
|
||||
)
|
||||
|
||||
func (c *Core) broadcastCreateRole(ctx context.Context, in *milvuspb.CreateRoleRequest) error {
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfCreateRole(ctx, in); err != nil {
|
||||
return errors.Wrap(err, "failed to check if create role")
|
||||
}
|
||||
|
||||
msg := message.NewAlterRoleMessageBuilderV2().
|
||||
WithHeader(&message.AlterRoleMessageHeader{
|
||||
RoleEntity: in.GetEntity(),
|
||||
}).
|
||||
WithBody(&message.AlterRoleMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// alterRoleV2AckCallback is the ack callback function for the AlterRoleMessageV2 message.
|
||||
func (c *DDLCallback) alterRoleV2AckCallback(ctx context.Context, result message.BroadcastResultAlterRoleMessageV2) error {
|
||||
return c.meta.CreateRole(ctx, util.DefaultTenant, result.Message.Header().RoleEntity)
|
||||
}
|
||||
|
||||
func (c *Core) broadcastDropRole(ctx context.Context, in *milvuspb.DropRoleRequest) error {
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfDropRole(ctx, in); err != nil {
|
||||
return errors.Wrap(err, "failed to check if drop role")
|
||||
}
|
||||
|
||||
msg := message.NewDropRoleMessageBuilderV2().
|
||||
WithHeader(&message.DropRoleMessageHeader{
|
||||
RoleName: in.RoleName,
|
||||
}).
|
||||
WithBody(&message.DropRoleMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
// dropRoleV2AckCallback is the ack callback function for the DropRoleMessageV2 message.
|
||||
func (c *DDLCallback) dropRoleV2AckCallback(ctx context.Context, result message.BroadcastResultDropRoleMessageV2) error {
|
||||
// There should always be only one message in the msgs slice.
|
||||
msg := result.Message
|
||||
err := c.meta.DropRole(ctx, util.DefaultTenant, msg.Header().RoleName)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to drop role")
|
||||
}
|
||||
if err := c.meta.DropGrant(ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: msg.Header().RoleName}); err != nil {
|
||||
return errors.Wrap(err, "failed to drop grant")
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: int32(typeutil.CacheDropRole),
|
||||
OpKey: msg.Header().RoleName,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "failed to refresh policy info cache")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Core) broadcastOperateUserRole(ctx context.Context, in *milvuspb.OperateUserRoleRequest) error {
|
||||
broadcaster, err := startBroadcastWithRBACLock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer broadcaster.Close()
|
||||
|
||||
if err := c.meta.CheckIfOperateUserRole(ctx, in); err != nil {
|
||||
return errors.Wrap(err, "failed to check if operate user role")
|
||||
}
|
||||
|
||||
var msg message.BroadcastMutableMessage
|
||||
switch in.Type {
|
||||
case milvuspb.OperateUserRoleType_AddUserToRole:
|
||||
msg = message.NewAlterUserRoleMessageBuilderV2().
|
||||
WithHeader(&message.AlterUserRoleMessageHeader{
|
||||
RoleBinding: &message.RoleBinding{
|
||||
UserEntity: &milvuspb.UserEntity{Name: in.Username},
|
||||
RoleEntity: &milvuspb.RoleEntity{Name: in.RoleName},
|
||||
},
|
||||
}).
|
||||
WithBody(&message.AlterUserRoleMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
case milvuspb.OperateUserRoleType_RemoveUserFromRole:
|
||||
msg = message.NewDropUserRoleMessageBuilderV2().
|
||||
WithHeader(&message.DropUserRoleMessageHeader{
|
||||
RoleBinding: &message.RoleBinding{
|
||||
UserEntity: &milvuspb.UserEntity{Name: in.Username},
|
||||
RoleEntity: &milvuspb.RoleEntity{Name: in.RoleName},
|
||||
},
|
||||
}).
|
||||
WithBody(&message.DropUserRoleMessageBody{}).
|
||||
WithBroadcast([]string{streaming.WAL().ControlChannel()}).
|
||||
MustBuildBroadcast()
|
||||
default:
|
||||
return errors.New("invalid operate user role type")
|
||||
}
|
||||
_, err = broadcaster.Broadcast(ctx, msg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DDLCallback) alterUserRoleV2AckCallback(ctx context.Context, result message.BroadcastResultAlterUserRoleMessageV2) error {
|
||||
header := result.Message.Header()
|
||||
if err := c.meta.OperateUserRole(ctx, util.DefaultTenant, header.RoleBinding.UserEntity, header.RoleBinding.RoleEntity, milvuspb.OperateUserRoleType_AddUserToRole); err != nil {
|
||||
return errors.Wrap(err, "failed to operate user role")
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: int32(typeutil.CacheAddUserToRole),
|
||||
OpKey: funcutil.EncodeUserRoleCache(header.RoleBinding.UserEntity.Name, header.RoleBinding.RoleEntity.Name),
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "failed to refresh policy info cache")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DDLCallback) dropUserRoleV2AckCallback(ctx context.Context, result message.BroadcastResultDropUserRoleMessageV2) error {
|
||||
header := result.Message.Header()
|
||||
if err := c.meta.OperateUserRole(ctx, util.DefaultTenant, header.RoleBinding.UserEntity, header.RoleBinding.RoleEntity, milvuspb.OperateUserRoleType_RemoveUserFromRole); err != nil {
|
||||
return errors.Wrap(err, "failed to operate user role")
|
||||
}
|
||||
if err := c.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: int32(typeutil.CacheRemoveUserFromRole),
|
||||
OpKey: funcutil.EncodeUserRoleCache(header.RoleBinding.UserEntity.Name, header.RoleBinding.RoleEntity.Name),
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "failed to refresh policy info cache")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
155
internal/rootcoord/ddl_callbacks_rbac_role_test.go
Normal file
155
internal/rootcoord/ddl_callbacks_rbac_role_test.go
Normal file
@ -0,0 +1,155 @@
|
||||
// Licensed to the LF AI & Data foundation under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
etcdkv "github.com/milvus-io/milvus/internal/kv/etcd"
|
||||
"github.com/milvus-io/milvus/internal/metastore/kv/rootcoord"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster/registry"
|
||||
kvfactory "github.com/milvus-io/milvus/internal/util/dependency/kv"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
|
||||
)
|
||||
|
||||
func TestDDLCallbacksRBACRole(t *testing.T) {
|
||||
initStreamingSystem()
|
||||
|
||||
kv, _ := kvfactory.GetEtcdAndPath()
|
||||
path := funcutil.RandomString(10)
|
||||
catalogKV := etcdkv.NewEtcdKV(kv, path)
|
||||
|
||||
core := newTestCore(withHealthyCode(),
|
||||
withMeta(&MetaTable{catalog: rootcoord.NewCatalog(catalogKV, nil)}),
|
||||
withValidProxyManager(),
|
||||
)
|
||||
registry.ResetRegistration()
|
||||
RegisterDDLCallbacks(core)
|
||||
|
||||
// Test drop builtin role should return error
|
||||
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": "*"}]}}`)
|
||||
err := core.initBuiltinRoles(context.Background())
|
||||
assert.Equal(t, nil, err)
|
||||
assert.True(t, util.IsBuiltinRole(roleDbAdmin))
|
||||
assert.False(t, util.IsBuiltinRole(util.RoleAdmin))
|
||||
resp, err := core.DropRole(context.Background(), &milvuspb.DropRoleRequest{RoleName: roleDbAdmin})
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, int32(1401), resp.Code) // merr.ErrPrivilegeNotPermitted
|
||||
|
||||
// Create a new credential.
|
||||
testUserName := "user" + funcutil.RandomString(10)
|
||||
status, err := core.CreateCredential(context.Background(), &internalpb.CredentialInfo{
|
||||
Username: testUserName,
|
||||
EncryptedPassword: "123456",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
testRoleName := "role" + funcutil.RandomString(10)
|
||||
|
||||
// Drop a not existed role should return error.
|
||||
status, err = core.DropRole(context.Background(), &milvuspb.DropRoleRequest{
|
||||
RoleName: testRoleName,
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
// Operate a not existed role should return error.
|
||||
status, err = core.OperateUserRole(context.Background(), &milvuspb.OperateUserRoleRequest{
|
||||
RoleName: testRoleName,
|
||||
Username: testUserName,
|
||||
Type: milvuspb.OperateUserRoleType_AddUserToRole,
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(status, err))
|
||||
|
||||
// Create a new role.
|
||||
status, err = core.CreateRole(context.Background(), &milvuspb.CreateRoleRequest{
|
||||
Entity: &milvuspb.RoleEntity{
|
||||
Name: testRoleName,
|
||||
},
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
selectRoleResp, err := core.SelectRole(context.Background(), &milvuspb.SelectRoleRequest{
|
||||
Role: &milvuspb.RoleEntity{
|
||||
Name: testRoleName,
|
||||
},
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
assert.Equal(t, 1, len(selectRoleResp.Results))
|
||||
assert.Equal(t, testRoleName, selectRoleResp.Results[0].Role.GetName())
|
||||
|
||||
// Add user to role.
|
||||
status, err = core.OperateUserRole(context.Background(), &milvuspb.OperateUserRoleRequest{
|
||||
RoleName: testRoleName,
|
||||
Username: testUserName,
|
||||
Type: milvuspb.OperateUserRoleType_AddUserToRole,
|
||||
})
|
||||
assert.NoError(t, merr.CheckRPCCall(status, err))
|
||||
selectRoleResp, err = core.SelectRole(context.Background(), &milvuspb.SelectRoleRequest{
|
||||
Role: &milvuspb.RoleEntity{
|
||||
Name: testRoleName,
|
||||
},
|
||||
IncludeUserInfo: true,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
assert.Equal(t, 1, len(selectRoleResp.Results))
|
||||
assert.Equal(t, testRoleName, selectRoleResp.Results[0].Role.GetName())
|
||||
assert.Equal(t, 1, len(selectRoleResp.Results[0].Users))
|
||||
assert.Equal(t, testUserName, selectRoleResp.Results[0].Users[0].GetName())
|
||||
|
||||
// Remove a user from role.
|
||||
status, err = core.OperateUserRole(context.Background(), &milvuspb.OperateUserRoleRequest{
|
||||
RoleName: testRoleName,
|
||||
Username: testUserName,
|
||||
Type: milvuspb.OperateUserRoleType_RemoveUserFromRole,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
selectRoleResp, err = core.SelectRole(context.Background(), &milvuspb.SelectRoleRequest{
|
||||
Role: &milvuspb.RoleEntity{
|
||||
Name: testRoleName,
|
||||
},
|
||||
IncludeUserInfo: true,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
assert.Equal(t, 1, len(selectRoleResp.Results))
|
||||
assert.Equal(t, testRoleName, selectRoleResp.Results[0].Role.GetName())
|
||||
assert.Equal(t, 0, len(selectRoleResp.Results[0].Users))
|
||||
|
||||
// Drop a role with force drop.
|
||||
status, err = core.DropRole(context.Background(), &milvuspb.DropRoleRequest{
|
||||
RoleName: testRoleName,
|
||||
ForceDrop: true,
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
selectRoleResp, err = core.SelectRole(context.Background(), &milvuspb.SelectRoleRequest{
|
||||
Role: &milvuspb.RoleEntity{
|
||||
Name: testRoleName,
|
||||
},
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
assert.Equal(t, 0, len(selectRoleResp.Results))
|
||||
}
|
||||
62
internal/rootcoord/meta_rbac.go
Normal file
62
internal/rootcoord/meta_rbac.go
Normal file
@ -0,0 +1,62 @@
|
||||
package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyUsername = errors.New("username is empty")
|
||||
errUserNotFound = errors.New("user not found")
|
||||
errUserAlreadyExists = errors.New("user already exists")
|
||||
|
||||
errEmptyRoleName = errors.New("role name is empty")
|
||||
errRoleAlreadyExists = errors.New("role already exists")
|
||||
errRoleNotExists = errors.New("role not exists")
|
||||
|
||||
errEmptyRBACMeta = errors.New("rbac meta is empty")
|
||||
errNotCustomPrivilegeGroup = errors.New("not a custom privilege group")
|
||||
|
||||
errEmptyPrivilegeGroupName = errors.New("privilege group name is empty")
|
||||
)
|
||||
|
||||
type RBACChecker interface {
|
||||
// CheckIfAddCredential checks if the credential can be added.
|
||||
// if the credential already exists, it will return errUserAlreadyExists.
|
||||
CheckIfAddCredential(ctx context.Context, req *internalpb.CredentialInfo) error
|
||||
|
||||
// CheckIfUpdateCredential checks if the credential can be updated.
|
||||
// if the credential not exists, it will return errUserNotFound.
|
||||
CheckIfUpdateCredential(ctx context.Context, req *internalpb.CredentialInfo) error
|
||||
|
||||
// CheckIfDeleteCredential checks if the credential can be deleted.
|
||||
// if the credential not exists, it will return errUserNotFound.
|
||||
CheckIfDeleteCredential(ctx context.Context, req *milvuspb.DeleteCredentialRequest) error
|
||||
|
||||
// CheckIfCreateRole checks if the role can be created.
|
||||
// if the role already exists, it will return errRoleAlreadyExists.
|
||||
CheckIfCreateRole(ctx context.Context, req *milvuspb.CreateRoleRequest) error
|
||||
|
||||
// CheckIfDropRole checks if the role can be dropped.
|
||||
// if the role not exists, it will return errRoleNotExists.
|
||||
CheckIfDropRole(ctx context.Context, in *milvuspb.DropRoleRequest) error
|
||||
|
||||
// CheckIfOperateUserRole checks if the user role can be operated.
|
||||
CheckIfOperateUserRole(ctx context.Context, req *milvuspb.OperateUserRoleRequest) error
|
||||
|
||||
// CheckIfPrivilegeGroupCreatable checks if the privilege group can be created.
|
||||
CheckIfPrivilegeGroupCreatable(ctx context.Context, req *milvuspb.CreatePrivilegeGroupRequest) error
|
||||
|
||||
// CheckIfPrivilegeGroupAlterable checks if the privilege group can be altered.
|
||||
CheckIfPrivilegeGroupAlterable(ctx context.Context, req *milvuspb.OperatePrivilegeGroupRequest) error
|
||||
|
||||
// CheckIfPrivilegeGroupDropable checks if the privilege group can be dropped.
|
||||
CheckIfPrivilegeGroupDropable(ctx context.Context, req *milvuspb.DropPrivilegeGroupRequest) error
|
||||
|
||||
// CheckIfRBACRestorable checks if the rbac meta data can be restored.
|
||||
CheckIfRBACRestorable(ctx context.Context, req *milvuspb.RestoreRBACMetaRequest) error
|
||||
}
|
||||
@ -39,8 +39,10 @@ import (
|
||||
pb "github.com/milvus-io/milvus/pkg/v2/proto/etcdpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/rootcoordpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/contextutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/crypto"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
|
||||
@ -48,8 +50,14 @@ import (
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
|
||||
)
|
||||
|
||||
type MetaTableChecker interface {
|
||||
RBACChecker
|
||||
}
|
||||
|
||||
//go:generate mockery --name=IMetaTable --structname=MockIMetaTable --output=./ --filename=mock_meta_table.go --with-expecter --inpackage
|
||||
type IMetaTable interface {
|
||||
MetaTableChecker
|
||||
|
||||
GetDatabaseByID(ctx context.Context, dbID int64, ts Timestamp) (*model.Database, error)
|
||||
GetDatabaseByName(ctx context.Context, dbName string, ts Timestamp) (*model.Database, error)
|
||||
CreateDatabase(ctx context.Context, db *model.Database, ts typeutil.Timestamp) error
|
||||
@ -91,10 +99,10 @@ type IMetaTable interface {
|
||||
IsAlias(ctx context.Context, db, name string) bool
|
||||
ListAliasesByID(ctx context.Context, collID UniqueID) []string
|
||||
|
||||
AddCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error
|
||||
GetCredential(ctx context.Context, username string) (*internalpb.CredentialInfo, error)
|
||||
DeleteCredential(ctx context.Context, username string) error
|
||||
AlterCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error
|
||||
InitCredential(ctx context.Context) error
|
||||
DeleteCredential(ctx context.Context, result message.BroadcastResultDropUserMessageV2) error
|
||||
AlterCredential(ctx context.Context, result message.BroadcastResultAlterUserMessageV2) error
|
||||
ListCredentialUsernames(ctx context.Context) (*milvuspb.ListCredUsersResponse, error)
|
||||
|
||||
CreateRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error
|
||||
@ -1353,47 +1361,103 @@ func (mt *MetaTable) GetGeneralCount(ctx context.Context) int {
|
||||
return mt.generalCnt
|
||||
}
|
||||
|
||||
// AddCredential add credential
|
||||
func (mt *MetaTable) AddCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
if credInfo.Username == "" {
|
||||
return errors.New("username is empty")
|
||||
}
|
||||
func (mt *MetaTable) InitCredential(ctx context.Context) error {
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
|
||||
credInfo, err := mt.catalog.GetCredential(ctx, util.UserRoot)
|
||||
if err != nil && !errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
return err
|
||||
}
|
||||
if credInfo != nil {
|
||||
return nil
|
||||
}
|
||||
encryptedRootPassword, err := crypto.PasswordEncrypt(Params.CommonCfg.DefaultRootPassword.GetValue())
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("RootCoord init user root failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
log.Ctx(ctx).Info("RootCoord init user root")
|
||||
err = mt.catalog.AlterCredential(ctx, &model.Credential{
|
||||
Username: util.UserRoot,
|
||||
EncryptedPassword: encryptedRootPassword,
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("RootCoord init user root failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mt *MetaTable) CheckIfAddCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
if funcutil.IsEmptyString(credInfo.GetUsername()) {
|
||||
return errEmptyUsername
|
||||
}
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
usernames, err := mt.catalog.ListCredentials(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(usernames) >= Params.ProxyCfg.MaxUserNum.GetAsInt() {
|
||||
// check if the username already exists.
|
||||
for _, username := range usernames {
|
||||
if username == credInfo.GetUsername() {
|
||||
return errUserAlreadyExists
|
||||
}
|
||||
}
|
||||
|
||||
// check if the number of users has reached the limit.
|
||||
maxUserNum := Params.ProxyCfg.MaxUserNum.GetAsInt()
|
||||
if len(usernames) >= maxUserNum {
|
||||
errMsg := "unable to add user because the number of users has reached the limit"
|
||||
log.Ctx(ctx).Error(errMsg, zap.Int("max_user_num", Params.ProxyCfg.MaxUserNum.GetAsInt()))
|
||||
log.Ctx(ctx).Error(errMsg, zap.Int("maxUserNum", maxUserNum))
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if origin, _ := mt.catalog.GetCredential(ctx, credInfo.Username); origin != nil {
|
||||
return fmt.Errorf("user already exists: %s", credInfo.Username)
|
||||
func (mt *MetaTable) CheckIfUpdateCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
if funcutil.IsEmptyString(credInfo.GetUsername()) {
|
||||
return errEmptyUsername
|
||||
}
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
credential := &model.Credential{
|
||||
Username: credInfo.Username,
|
||||
EncryptedPassword: credInfo.EncryptedPassword,
|
||||
// check if the number of credential exists.
|
||||
if _, err := mt.catalog.GetCredential(ctx, credInfo.GetUsername()); err != nil {
|
||||
if errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
return errUserNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
return mt.catalog.CreateCredential(ctx, credential)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AlterCredential update credential
|
||||
func (mt *MetaTable) AlterCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
if credInfo.Username == "" {
|
||||
return errors.New("username is empty")
|
||||
}
|
||||
func (mt *MetaTable) AlterCredential(ctx context.Context, result message.BroadcastResultAlterUserMessageV2) error {
|
||||
body := result.Message.MustBody()
|
||||
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
|
||||
existsCredential, err := mt.catalog.GetCredential(ctx, body.CredentialInfo.Username)
|
||||
if err != nil && !errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
return err
|
||||
}
|
||||
// if the credential already exists and the version is not greater than the current timetick.
|
||||
if existsCredential != nil && existsCredential.TimeTick >= result.GetControlChannelResult().TimeTick {
|
||||
log.Info("credential already exists and the version is not greater than the current timetick",
|
||||
zap.String("username", body.CredentialInfo.Username),
|
||||
zap.Uint64("incoming", result.GetControlChannelResult().TimeTick),
|
||||
zap.Uint64("current", existsCredential.TimeTick),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
credential := &model.Credential{
|
||||
Username: credInfo.Username,
|
||||
EncryptedPassword: credInfo.EncryptedPassword,
|
||||
Username: body.CredentialInfo.Username,
|
||||
EncryptedPassword: body.CredentialInfo.EncryptedPassword,
|
||||
TimeTick: result.GetControlChannelResult().TimeTick,
|
||||
}
|
||||
return mt.catalog.AlterCredential(ctx, credential)
|
||||
}
|
||||
@ -1407,12 +1471,42 @@ func (mt *MetaTable) GetCredential(ctx context.Context, username string) (*inter
|
||||
return model.MarshalCredentialModel(credential), err
|
||||
}
|
||||
|
||||
func (mt *MetaTable) CheckIfDeleteCredential(ctx context.Context, req *milvuspb.DeleteCredentialRequest) error {
|
||||
if funcutil.IsEmptyString(req.GetUsername()) {
|
||||
return errEmptyUsername
|
||||
}
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
// check if the number of credential exists.
|
||||
if _, err := mt.catalog.GetCredential(ctx, req.GetUsername()); err != nil {
|
||||
if errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
return errUserNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteCredential delete credential
|
||||
func (mt *MetaTable) DeleteCredential(ctx context.Context, username string) error {
|
||||
func (mt *MetaTable) DeleteCredential(ctx context.Context, result message.BroadcastResultDropUserMessageV2) error {
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
|
||||
return mt.catalog.DropCredential(ctx, username)
|
||||
existsCredential, err := mt.catalog.GetCredential(ctx, result.Message.Header().UserName)
|
||||
if err != nil && !errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
return err
|
||||
}
|
||||
// if the credential already exists and the version is not greater than the current timetick.
|
||||
if existsCredential != nil && existsCredential.TimeTick >= result.GetControlChannelResult().TimeTick {
|
||||
log.Info("credential already exists and the version is not greater than the current timetick",
|
||||
zap.String("username", result.Message.Header().UserName),
|
||||
zap.Uint64("incoming", result.GetControlChannelResult().TimeTick),
|
||||
zap.Uint64("current", existsCredential.TimeTick),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return mt.catalog.DropCredential(ctx, result.Message.Header().UserName)
|
||||
}
|
||||
|
||||
// ListCredentialUsernames list credential usernames
|
||||
@ -1427,23 +1521,23 @@ func (mt *MetaTable) ListCredentialUsernames(ctx context.Context) (*milvuspb.Lis
|
||||
return &milvuspb.ListCredUsersResponse{Usernames: usernames}, nil
|
||||
}
|
||||
|
||||
// CreateRole create role
|
||||
func (mt *MetaTable) CreateRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error {
|
||||
if funcutil.IsEmptyString(entity.Name) {
|
||||
return errors.New("the role name in the role info is empty")
|
||||
// CheckIfCreateRole checks if the role can be created.
|
||||
func (mt *MetaTable) CheckIfCreateRole(ctx context.Context, in *milvuspb.CreateRoleRequest) error {
|
||||
if funcutil.IsEmptyString(in.GetEntity().GetName()) {
|
||||
return errEmptyRoleName
|
||||
}
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
results, err := mt.catalog.ListRole(ctx, tenant, nil, false)
|
||||
results, err := mt.catalog.ListRole(ctx, util.DefaultTenant, nil, false)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("fail to list roles", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
for _, result := range results {
|
||||
if result.GetRole().GetName() == entity.Name {
|
||||
log.Ctx(ctx).Info("role already exists", zap.String("role", entity.Name))
|
||||
return common.NewIgnorableError(errors.Newf("role [%s] already exists", entity))
|
||||
if result.GetRole().GetName() == in.GetEntity().GetName() {
|
||||
log.Ctx(ctx).Info("role already exists", zap.String("role", in.GetEntity().GetName()))
|
||||
return errRoleAlreadyExists
|
||||
}
|
||||
}
|
||||
if len(results) >= Params.ProxyCfg.MaxRoleNum.GetAsInt() {
|
||||
@ -1451,10 +1545,51 @@ func (mt *MetaTable) CreateRole(ctx context.Context, tenant string, entity *milv
|
||||
log.Ctx(ctx).Warn(errMsg, zap.Int("max_role_num", Params.ProxyCfg.MaxRoleNum.GetAsInt()))
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateRole create role
|
||||
func (mt *MetaTable) CreateRole(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error {
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
|
||||
return mt.catalog.CreateRole(ctx, tenant, entity)
|
||||
}
|
||||
|
||||
func (mt *MetaTable) CheckIfDropRole(ctx context.Context, in *milvuspb.DropRoleRequest) error {
|
||||
if funcutil.IsEmptyString(in.GetRoleName()) {
|
||||
return errEmptyRoleName
|
||||
}
|
||||
if util.IsBuiltinRole(in.GetRoleName()) {
|
||||
return merr.WrapErrPrivilegeNotPermitted("the role[%s] is a builtin role, which can't be dropped", in.GetRoleName())
|
||||
}
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
if _, err := mt.catalog.ListRole(ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: in.GetRoleName()}, false); err != nil {
|
||||
if errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
return errRoleNotExists
|
||||
}
|
||||
return err
|
||||
}
|
||||
if in.GetForceDrop() {
|
||||
return nil
|
||||
}
|
||||
|
||||
grantEntities, err := mt.catalog.ListGrant(ctx, util.DefaultTenant, &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: in.GetRoleName()},
|
||||
DbName: "*",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(grantEntities) != 0 {
|
||||
errMsg := "fail to drop the role that it has privileges. Use REVOKE API to revoke privileges"
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DropRole drop role info
|
||||
func (mt *MetaTable) DropRole(ctx context.Context, tenant string, roleName string) error {
|
||||
mt.permissionLock.Lock()
|
||||
@ -1463,15 +1598,33 @@ func (mt *MetaTable) DropRole(ctx context.Context, tenant string, roleName strin
|
||||
return mt.catalog.DropRole(ctx, tenant, roleName)
|
||||
}
|
||||
|
||||
// OperateUserRole operate the relationship between a user and a role, including adding a user to a role and removing a user from a role
|
||||
func (mt *MetaTable) OperateUserRole(ctx context.Context, tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error {
|
||||
if funcutil.IsEmptyString(userEntity.Name) {
|
||||
func (mt *MetaTable) CheckIfOperateUserRole(ctx context.Context, req *milvuspb.OperateUserRoleRequest) error {
|
||||
if funcutil.IsEmptyString(req.GetUsername()) {
|
||||
return errors.New("username in the user entity is empty")
|
||||
}
|
||||
if funcutil.IsEmptyString(roleEntity.Name) {
|
||||
if funcutil.IsEmptyString(req.GetRoleName()) {
|
||||
return errors.New("role name in the role entity is empty")
|
||||
}
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
if _, err := mt.catalog.ListRole(ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: req.RoleName}, false); err != nil {
|
||||
if errors.Is(err, merr.ErrIoKeyNotFound) {
|
||||
return errRoleNotExists
|
||||
}
|
||||
return err
|
||||
}
|
||||
if req.Type != milvuspb.OperateUserRoleType_RemoveUserFromRole {
|
||||
if _, err := mt.catalog.ListUser(ctx, util.DefaultTenant, &milvuspb.UserEntity{Name: req.Username}, false); err != nil {
|
||||
errMsg := "not found the user, maybe the user isn't existed or internal system error"
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OperateUserRole operate the relationship between a user and a role, including adding a user to a role and removing a user from a role
|
||||
func (mt *MetaTable) OperateUserRole(ctx context.Context, tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error {
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
|
||||
@ -1584,6 +1737,72 @@ func (mt *MetaTable) BackupRBAC(ctx context.Context, tenant string) (*milvuspb.R
|
||||
return mt.catalog.BackupRBAC(ctx, tenant)
|
||||
}
|
||||
|
||||
func (mt *MetaTable) CheckIfRBACRestorable(ctx context.Context, req *milvuspb.RestoreRBACMetaRequest) error {
|
||||
meta := req.GetRBACMeta()
|
||||
if len(meta.GetRoles()) == 0 && len(meta.GetPrivilegeGroups()) == 0 && len(meta.GetGrants()) == 0 && len(meta.GetUsers()) == 0 {
|
||||
return errEmptyRBACMeta
|
||||
}
|
||||
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
// check if role already exists
|
||||
existRoles, err := mt.catalog.ListRole(ctx, util.DefaultTenant, nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existRoleMap := lo.SliceToMap(existRoles, func(entity *milvuspb.RoleResult) (string, struct{}) { return entity.GetRole().GetName(), struct{}{} })
|
||||
existRoleAfterRestoreMap := lo.SliceToMap(existRoles, func(entity *milvuspb.RoleResult) (string, struct{}) { return entity.GetRole().GetName(), struct{}{} })
|
||||
for _, role := range meta.GetRoles() {
|
||||
if _, ok := existRoleMap[role.GetName()]; ok {
|
||||
return errors.Newf("role [%s] already exists", role.GetName())
|
||||
}
|
||||
existRoleAfterRestoreMap[role.GetName()] = struct{}{}
|
||||
}
|
||||
|
||||
// check if privilege group already exists
|
||||
existPrivGroups, err := mt.catalog.ListPrivilegeGroups(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existPrivGroupMap := lo.SliceToMap(existPrivGroups, func(entity *milvuspb.PrivilegeGroupInfo) (string, struct{}) { return entity.GetGroupName(), struct{}{} })
|
||||
existPrivGroupAfterRestoreMap := lo.SliceToMap(existPrivGroups, func(entity *milvuspb.PrivilegeGroupInfo) (string, struct{}) { return entity.GetGroupName(), struct{}{} })
|
||||
for _, group := range meta.GetPrivilegeGroups() {
|
||||
if _, ok := existPrivGroupMap[group.GetGroupName()]; ok {
|
||||
return errors.Newf("privilege group [%s] already exists", group.GetGroupName())
|
||||
}
|
||||
existPrivGroupAfterRestoreMap[group.GetGroupName()] = struct{}{}
|
||||
}
|
||||
|
||||
// check if grant can be restored
|
||||
for _, grant := range meta.GetGrants() {
|
||||
privName := grant.GetGrantor().GetPrivilege().GetName()
|
||||
if _, ok := existPrivGroupAfterRestoreMap[privName]; !ok && !util.IsPrivilegeNameDefined(privName) {
|
||||
return errors.Newf("privilege [%s] does not exist", privName)
|
||||
}
|
||||
}
|
||||
|
||||
// check if user can be restored
|
||||
existUser, err := mt.catalog.ListUser(ctx, util.DefaultTenant, nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existUserMap := lo.SliceToMap(existUser, func(entity *milvuspb.UserResult) (string, struct{}) { return entity.GetUser().GetName(), struct{}{} })
|
||||
for _, user := range meta.GetUsers() {
|
||||
if _, ok := existUserMap[user.GetUser()]; ok {
|
||||
return errors.Newf("user [%s] already exists", user.GetUser())
|
||||
}
|
||||
|
||||
// check if user-role can be restored
|
||||
for _, role := range user.GetRoles() {
|
||||
if _, ok := existRoleAfterRestoreMap[role.GetName()]; !ok {
|
||||
return errors.Newf("role [%s] does not exist", role.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mt *MetaTable) RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error {
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
@ -1605,23 +1824,30 @@ func (mt *MetaTable) IsCustomPrivilegeGroup(ctx context.Context, groupName strin
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (mt *MetaTable) CreatePrivilegeGroup(ctx context.Context, groupName string) error {
|
||||
if funcutil.IsEmptyString(groupName) {
|
||||
return errors.New("the privilege group name is empty")
|
||||
func (mt *MetaTable) CheckIfPrivilegeGroupCreatable(ctx context.Context, req *milvuspb.CreatePrivilegeGroupRequest) error {
|
||||
if funcutil.IsEmptyString(req.GetGroupName()) {
|
||||
return errEmptyPrivilegeGroupName
|
||||
}
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
definedByUsers, err := mt.IsCustomPrivilegeGroup(ctx, groupName)
|
||||
definedByUsers, err := mt.IsCustomPrivilegeGroup(ctx, req.GetGroupName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if definedByUsers {
|
||||
return merr.WrapErrParameterInvalidMsg("privilege group name [%s] is defined by users", groupName)
|
||||
return merr.WrapErrParameterInvalidMsg("privilege group name [%s] is defined by users", req.GetGroupName())
|
||||
}
|
||||
if util.IsPrivilegeNameDefined(groupName) {
|
||||
return merr.WrapErrParameterInvalidMsg("privilege group name [%s] is defined by built in privileges or privilege groups in system", groupName)
|
||||
if util.IsPrivilegeNameDefined(req.GetGroupName()) {
|
||||
return merr.WrapErrParameterInvalidMsg("privilege group name [%s] is defined by built in privileges or privilege groups in system", req.GetGroupName())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mt *MetaTable) CreatePrivilegeGroup(ctx context.Context, groupName string) error {
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
|
||||
data := &milvuspb.PrivilegeGroupInfo{
|
||||
GroupName: groupName,
|
||||
Privileges: make([]*milvuspb.PrivilegeEntity, 0),
|
||||
@ -1629,20 +1855,21 @@ func (mt *MetaTable) CreatePrivilegeGroup(ctx context.Context, groupName string)
|
||||
return mt.catalog.SavePrivilegeGroup(ctx, data)
|
||||
}
|
||||
|
||||
func (mt *MetaTable) DropPrivilegeGroup(ctx context.Context, groupName string) error {
|
||||
if funcutil.IsEmptyString(groupName) {
|
||||
return errors.New("the privilege group name is empty")
|
||||
func (mt *MetaTable) CheckIfPrivilegeGroupDropable(ctx context.Context, req *milvuspb.DropPrivilegeGroupRequest) error {
|
||||
if funcutil.IsEmptyString(req.GetGroupName()) {
|
||||
return errEmptyPrivilegeGroupName
|
||||
}
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
definedByUsers, err := mt.IsCustomPrivilegeGroup(ctx, groupName)
|
||||
definedByUsers, err := mt.IsCustomPrivilegeGroup(ctx, req.GetGroupName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !definedByUsers {
|
||||
return nil
|
||||
return errNotCustomPrivilegeGroup
|
||||
}
|
||||
|
||||
// check if the group is used by any role
|
||||
roles, err := mt.catalog.ListRole(ctx, util.DefaultTenant, nil, false)
|
||||
if err != nil {
|
||||
@ -1660,11 +1887,18 @@ func (mt *MetaTable) DropPrivilegeGroup(ctx context.Context, groupName string) e
|
||||
return err
|
||||
}
|
||||
for _, grant := range grants {
|
||||
if grant.Grantor.Privilege.Name == groupName {
|
||||
return errors.Newf("privilege group [%s] is used by role [%s], Use REVOKE API to revoke it first", groupName, role.GetName())
|
||||
if grant.Grantor.Privilege.Name == req.GetGroupName() {
|
||||
return errors.Newf("privilege group [%s] is used by role [%s], Use REVOKE API to revoke it first", req.GetGroupName(), role.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mt *MetaTable) DropPrivilegeGroup(ctx context.Context, groupName string) error {
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
|
||||
return mt.catalog.DropPrivilegeGroup(ctx, groupName)
|
||||
}
|
||||
|
||||
@ -1675,43 +1909,55 @@ func (mt *MetaTable) ListPrivilegeGroups(ctx context.Context) ([]*milvuspb.Privi
|
||||
return mt.catalog.ListPrivilegeGroups(ctx)
|
||||
}
|
||||
|
||||
func (mt *MetaTable) OperatePrivilegeGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity, operateType milvuspb.OperatePrivilegeGroupType) error {
|
||||
if funcutil.IsEmptyString(groupName) {
|
||||
return errors.New("the privilege group name is empty")
|
||||
// CheckIfPrivilegeGroupAlterable checks if the privilege group can be altered.
|
||||
func (mt *MetaTable) CheckIfPrivilegeGroupAlterable(ctx context.Context, req *milvuspb.OperatePrivilegeGroupRequest) error {
|
||||
if funcutil.IsEmptyString(req.GetGroupName()) {
|
||||
return errEmptyPrivilegeGroupName
|
||||
}
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
if util.IsBuiltinPrivilegeGroup(groupName) {
|
||||
return merr.WrapErrParameterInvalidMsg("the privilege group name [%s] is defined by built in privilege groups in system", groupName)
|
||||
}
|
||||
|
||||
// validate input params
|
||||
definedByUsers, err := mt.IsCustomPrivilegeGroup(ctx, groupName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !definedByUsers {
|
||||
return merr.WrapErrParameterInvalidMsg("there is no privilege group name [%s] to operate", groupName)
|
||||
}
|
||||
groups, err := mt.catalog.ListPrivilegeGroups(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range privileges {
|
||||
currenctGroups := lo.SliceToMap(groups, func(group *milvuspb.PrivilegeGroupInfo) (string, []*milvuspb.PrivilegeEntity) {
|
||||
return group.GroupName, group.Privileges
|
||||
})
|
||||
// check if the privilege group is defined by users
|
||||
if _, ok := currenctGroups[req.GroupName]; !ok {
|
||||
return merr.WrapErrParameterInvalidMsg("there is no privilege group name [%s] defined in system to operate", req.GroupName)
|
||||
}
|
||||
|
||||
if len(req.Privileges) == 0 {
|
||||
return merr.WrapErrParameterInvalidMsg("privileges is empty when alter the privilege group")
|
||||
}
|
||||
// check if the new incoming privileges are defined by users or built in
|
||||
for _, p := range req.Privileges {
|
||||
if util.IsPrivilegeNameDefined(p.Name) {
|
||||
continue
|
||||
}
|
||||
for _, group := range groups {
|
||||
// add privileges for custom privilege group
|
||||
if group.GroupName == p.Name {
|
||||
privileges = append(privileges, group.Privileges...)
|
||||
} else {
|
||||
return merr.WrapErrParameterInvalidMsg("there is no privilege name or privilege group name [%s] defined in system to operate", p.Name)
|
||||
}
|
||||
if _, ok := currenctGroups[p.Name]; !ok {
|
||||
return merr.WrapErrParameterInvalidMsg("there is no privilege name or privilege group name [%s] defined in system to operate", p.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if req.Type == milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup {
|
||||
// Check if all privileges are the same privilege level
|
||||
privilegeLevels := lo.SliceToMap(lo.Union(req.Privileges, currenctGroups[req.GroupName]), func(p *milvuspb.PrivilegeEntity) (string, struct{}) {
|
||||
return util.GetPrivilegeLevel(p.Name), struct{}{}
|
||||
})
|
||||
if len(privilegeLevels) > 1 {
|
||||
return merr.WrapErrParameterInvalidMsg("privileges are not the same privilege level")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mt *MetaTable) OperatePrivilegeGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity, operateType milvuspb.OperatePrivilegeGroupType) error {
|
||||
mt.permissionLock.Lock()
|
||||
defer mt.permissionLock.Unlock()
|
||||
|
||||
// merge with current privileges
|
||||
group, err := mt.catalog.GetPrivilegeGroup(ctx, groupName)
|
||||
if err != nil {
|
||||
|
||||
@ -28,31 +28,80 @@ import (
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
|
||||
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
memkv "github.com/milvus-io/milvus/internal/kv/mem"
|
||||
etcdkv "github.com/milvus-io/milvus/internal/kv/etcd"
|
||||
"github.com/milvus-io/milvus/internal/metastore/kv/rootcoord"
|
||||
"github.com/milvus-io/milvus/internal/metastore/mocks"
|
||||
"github.com/milvus-io/milvus/internal/metastore/model"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/balancer/channel"
|
||||
mocktso "github.com/milvus-io/milvus/internal/tso/mocks"
|
||||
"github.com/milvus-io/milvus/pkg/v2/common"
|
||||
kvfactory "github.com/milvus-io/milvus/internal/util/dependency/kv"
|
||||
pb "github.com/milvus-io/milvus/pkg/v2/proto/etcdpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
|
||||
)
|
||||
|
||||
func generateMetaTable(t *testing.T) *MetaTable {
|
||||
return &MetaTable{catalog: rootcoord.NewCatalog(memkv.NewMemoryKV(), nil)}
|
||||
func generateMetaTable(_ *testing.T) *MetaTable {
|
||||
kv, _ := kvfactory.GetEtcdAndPath()
|
||||
path := funcutil.RandomString(10)
|
||||
catalogKV := etcdkv.NewEtcdKV(kv, path)
|
||||
return &MetaTable{catalog: rootcoord.NewCatalog(catalogKV, nil)}
|
||||
}
|
||||
|
||||
func TestRbacAddCredential(t *testing.T) {
|
||||
func buildAlterUserMessage(credInfo *internalpb.CredentialInfo, timetick uint64) message.BroadcastResultAlterUserMessageV2 {
|
||||
msg := message.NewAlterUserMessageBuilderV2().
|
||||
WithHeader(&message.AlterUserMessageHeader{
|
||||
UserEntity: &milvuspb.UserEntity{
|
||||
Name: credInfo.Username,
|
||||
},
|
||||
}).
|
||||
WithBody(&message.AlterUserMessageBody{
|
||||
CredentialInfo: credInfo,
|
||||
}).
|
||||
WithBroadcast([]string{funcutil.GetControlChannel("by-dev-rootcoord-dml_1")}).
|
||||
MustBuildBroadcast()
|
||||
return message.BroadcastResultAlterUserMessageV2{
|
||||
Message: message.MustAsBroadcastAlterUserMessageV2(msg),
|
||||
Results: map[string]*message.AppendResult{
|
||||
funcutil.GetControlChannel("by-dev-rootcoord-dml_1"): {TimeTick: timetick},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func buildDropUserMessage(credInfo *internalpb.CredentialInfo, timetick uint64) message.BroadcastResultDropUserMessageV2 {
|
||||
msg := message.NewDropUserMessageBuilderV2().
|
||||
WithHeader(&message.DropUserMessageHeader{
|
||||
UserName: credInfo.Username,
|
||||
}).
|
||||
WithBody(&message.DropUserMessageBody{}).
|
||||
WithBroadcast([]string{funcutil.GetControlChannel("by-dev-rootcoord-dml_1")}).
|
||||
MustBuildBroadcast()
|
||||
return message.BroadcastResultDropUserMessageV2{
|
||||
Message: message.MustAsBroadcastDropUserMessageV2(msg),
|
||||
Results: map[string]*message.AppendResult{
|
||||
funcutil.GetControlChannel("by-dev-rootcoord-dml_1"): {TimeTick: timetick},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestRbacCredential(t *testing.T) {
|
||||
mt := generateMetaTable(t)
|
||||
err := mt.AddCredential(context.TODO(), &internalpb.CredentialInfo{
|
||||
Username: "user1",
|
||||
|
||||
username := "user" + funcutil.RandomString(10)
|
||||
credInfo := &internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
Tenant: util.DefaultTenant,
|
||||
})
|
||||
}
|
||||
err := mt.CheckIfAddCredential(context.TODO(), credInfo)
|
||||
require.NoError(t, err)
|
||||
err = mt.AlterCredential(context.TODO(), buildAlterUserMessage(credInfo, 1))
|
||||
require.NoError(t, err)
|
||||
// idempotency
|
||||
err = mt.AlterCredential(context.TODO(), buildAlterUserMessage(credInfo, 1))
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@ -63,7 +112,7 @@ func TestRbacAddCredential(t *testing.T) {
|
||||
}{
|
||||
{"Empty username", false, &internalpb.CredentialInfo{Username: ""}},
|
||||
{"exceed MaxUserNum", true, &internalpb.CredentialInfo{Username: "user3", Tenant: util.DefaultTenant}},
|
||||
{"user exist", false, &internalpb.CredentialInfo{Username: "user1", Tenant: util.DefaultTenant}},
|
||||
{"user exist", false, &internalpb.CredentialInfo{Username: username, Tenant: util.DefaultTenant}},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@ -74,10 +123,39 @@ func TestRbacAddCredential(t *testing.T) {
|
||||
paramtable.Get().Save(Params.ProxyCfg.MaxUserNum.Key, "3")
|
||||
}
|
||||
defer paramtable.Get().Reset(Params.ProxyCfg.MaxUserNum.Key)
|
||||
err := mt.AddCredential(context.TODO(), test.info)
|
||||
err := mt.CheckIfAddCredential(context.TODO(), test.info)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
// should be ignored if timetick is too low.
|
||||
err = mt.AlterCredential(context.TODO(), buildAlterUserMessage(credInfo, 0))
|
||||
require.NoError(t, err)
|
||||
newCred, err := mt.GetCredential(context.TODO(), credInfo.Username)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newCred.TimeTick, uint64(1))
|
||||
|
||||
err = mt.AlterCredential(context.TODO(), buildAlterUserMessage(credInfo, 2))
|
||||
require.NoError(t, err)
|
||||
newCred, err = mt.GetCredential(context.TODO(), credInfo.Username)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newCred.TimeTick, uint64(2))
|
||||
|
||||
// should be ignored if timetick is too low.
|
||||
err = mt.DeleteCredential(context.TODO(), buildDropUserMessage(credInfo, 2))
|
||||
require.NoError(t, err)
|
||||
newCred, err = mt.GetCredential(context.TODO(), credInfo.Username)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, newCred.TimeTick, uint64(2))
|
||||
|
||||
err = mt.DeleteCredential(context.TODO(), buildDropUserMessage(credInfo, 3))
|
||||
require.NoError(t, err)
|
||||
newCred, err = mt.GetCredential(context.TODO(), credInfo.Username)
|
||||
require.ErrorIs(t, err, merr.ErrIoKeyNotFound)
|
||||
require.Nil(t, newCred)
|
||||
|
||||
err = mt.DeleteCredential(context.TODO(), buildDropUserMessage(credInfo, 0))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRbacCreateRole(t *testing.T) {
|
||||
@ -85,7 +163,11 @@ func TestRbacCreateRole(t *testing.T) {
|
||||
|
||||
paramtable.Get().Save(Params.ProxyCfg.MaxRoleNum.Key, "2")
|
||||
defer paramtable.Get().Reset(Params.ProxyCfg.MaxRoleNum.Key)
|
||||
err := mt.CreateRole(context.TODO(), util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
|
||||
err := mt.CheckIfCreateRole(context.TODO(), &milvuspb.CreateRoleRequest{Entity: &milvuspb.RoleEntity{Name: "role1"}})
|
||||
require.NoError(t, err)
|
||||
err = mt.CreateRole(context.TODO(), util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
|
||||
require.NoError(t, err)
|
||||
err = mt.CheckIfCreateRole(context.TODO(), &milvuspb.CreateRoleRequest{Entity: &milvuspb.RoleEntity{Name: "role2"}})
|
||||
require.NoError(t, err)
|
||||
err = mt.CreateRole(context.TODO(), util.DefaultTenant, &milvuspb.RoleEntity{Name: "role2"})
|
||||
require.NoError(t, err)
|
||||
@ -101,14 +183,14 @@ func TestRbacCreateRole(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
err := mt.CreateRole(context.TODO(), util.DefaultTenant, test.inEntity)
|
||||
err := mt.CheckIfCreateRole(context.TODO(), &milvuspb.CreateRoleRequest{Entity: test.inEntity})
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
t.Run("role has existed", func(t *testing.T) {
|
||||
err := mt.CreateRole(context.TODO(), util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
|
||||
err := mt.CheckIfCreateRole(context.TODO(), &milvuspb.CreateRoleRequest{Entity: &milvuspb.RoleEntity{Name: "role1"}})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, common.IsIgnorableError(err))
|
||||
assert.True(t, errors.Is(err, errRoleAlreadyExists))
|
||||
})
|
||||
|
||||
{
|
||||
@ -120,7 +202,7 @@ func TestRbacCreateRole(t *testing.T) {
|
||||
mock.Anything,
|
||||
).Return(nil, errors.New("error mock list role"))
|
||||
mockMt := &MetaTable{catalog: mockCata}
|
||||
err := mockMt.CreateRole(context.TODO(), util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
|
||||
err := mockMt.CheckIfCreateRole(context.TODO(), &milvuspb.CreateRoleRequest{Entity: &milvuspb.RoleEntity{Name: "role1"}})
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
@ -128,24 +210,21 @@ func TestRbacCreateRole(t *testing.T) {
|
||||
func TestRbacDropRole(t *testing.T) {
|
||||
mt := generateMetaTable(t)
|
||||
|
||||
err := mt.CreateRole(context.TODO(), util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
|
||||
// drop a exist role
|
||||
roleExist := "role" + funcutil.RandomString(10)
|
||||
err := mt.CreateRole(context.TODO(), util.DefaultTenant, &milvuspb.RoleEntity{Name: roleExist})
|
||||
require.NoError(t, err)
|
||||
err = mt.CheckIfDropRole(context.TODO(), &milvuspb.DropRoleRequest{RoleName: roleExist})
|
||||
require.NoError(t, err)
|
||||
err = mt.DropRole(context.TODO(), util.DefaultTenant, roleExist)
|
||||
require.NoError(t, err)
|
||||
// idempotency
|
||||
mt.DropRole(context.TODO(), util.DefaultTenant, roleExist)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
roleName string
|
||||
|
||||
description string
|
||||
}{
|
||||
{"role1", "drop role1"},
|
||||
{"role_not_exists", "drop not exist role"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
err := mt.DropRole(context.TODO(), util.DefaultTenant, test.roleName)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
// drop a not exist role
|
||||
err = mt.CheckIfDropRole(context.TODO(), &milvuspb.DropRoleRequest{RoleName: "role_not_exist"})
|
||||
require.ErrorIs(t, err, errRoleNotExists)
|
||||
}
|
||||
|
||||
func TestRbacOperateRole(t *testing.T) {
|
||||
@ -169,7 +248,11 @@ func TestRbacOperateRole(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
err := mt.OperateUserRole(context.TODO(), util.DefaultTenant, &milvuspb.UserEntity{Name: test.user}, &milvuspb.RoleEntity{Name: test.role}, test.oType)
|
||||
err := mt.CheckIfOperateUserRole(context.TODO(), &milvuspb.OperateUserRoleRequest{
|
||||
Username: test.user,
|
||||
RoleName: test.role,
|
||||
Type: test.oType,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
@ -191,7 +274,7 @@ func TestRbacSelect(t *testing.T) {
|
||||
}
|
||||
|
||||
for user, rs := range userRoles {
|
||||
err := mt.catalog.CreateCredential(context.TODO(), &model.Credential{
|
||||
err := mt.catalog.AlterCredential(context.TODO(), &model.Credential{
|
||||
Username: user,
|
||||
Tenant: util.DefaultTenant,
|
||||
})
|
||||
@ -2226,23 +2309,55 @@ func TestMetaTable_PrivilegeGroup(t *testing.T) {
|
||||
aliases: newNameDb(),
|
||||
catalog: catalog,
|
||||
}
|
||||
err := mt.CreatePrivilegeGroup(context.TODO(), "pg1")
|
||||
err := mt.CheckIfPrivilegeGroupCreatable(context.TODO(), &milvuspb.CreatePrivilegeGroupRequest{
|
||||
GroupName: "pg1",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
err = mt.CreatePrivilegeGroup(context.TODO(), "")
|
||||
err = mt.CheckIfPrivilegeGroupCreatable(context.TODO(), &milvuspb.CreatePrivilegeGroupRequest{
|
||||
GroupName: "",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
err = mt.CreatePrivilegeGroup(context.TODO(), "Insert")
|
||||
err = mt.CheckIfPrivilegeGroupCreatable(context.TODO(), &milvuspb.CreatePrivilegeGroupRequest{
|
||||
GroupName: "Insert",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
err = mt.CreatePrivilegeGroup(context.TODO(), "pg2")
|
||||
err = mt.CheckIfPrivilegeGroupCreatable(context.TODO(), &milvuspb.CreatePrivilegeGroupRequest{
|
||||
GroupName: "pg2",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
err = mt.DropPrivilegeGroup(context.TODO(), "")
|
||||
err = mt.CreatePrivilegeGroup(context.TODO(), "pg1")
|
||||
assert.NoError(t, err)
|
||||
// idempotency
|
||||
err = mt.CreatePrivilegeGroup(context.TODO(), "pg1")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = mt.CheckIfPrivilegeGroupDropable(context.TODO(), &milvuspb.DropPrivilegeGroupRequest{
|
||||
GroupName: "",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
err = mt.CheckIfPrivilegeGroupDropable(context.TODO(), &milvuspb.DropPrivilegeGroupRequest{
|
||||
GroupName: "pg1",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
err = mt.DropPrivilegeGroup(context.TODO(), "pg1")
|
||||
assert.NoError(t, err)
|
||||
err = mt.OperatePrivilegeGroup(context.TODO(), "", []*milvuspb.PrivilegeEntity{}, milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup)
|
||||
err = mt.CheckIfPrivilegeGroupAlterable(context.TODO(), &milvuspb.OperatePrivilegeGroupRequest{
|
||||
GroupName: "",
|
||||
Privileges: []*milvuspb.PrivilegeEntity{},
|
||||
Type: milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
err = mt.OperatePrivilegeGroup(context.TODO(), "ClusterReadOnly", []*milvuspb.PrivilegeEntity{}, milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup)
|
||||
err = mt.CheckIfPrivilegeGroupAlterable(context.TODO(), &milvuspb.OperatePrivilegeGroupRequest{
|
||||
GroupName: "ClusterReadOnly",
|
||||
Privileges: []*milvuspb.PrivilegeEntity{},
|
||||
Type: milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
err = mt.OperatePrivilegeGroup(context.TODO(), "pg3", []*milvuspb.PrivilegeEntity{}, milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup)
|
||||
err = mt.CheckIfPrivilegeGroupAlterable(context.TODO(), &milvuspb.OperatePrivilegeGroupRequest{
|
||||
GroupName: "pg3",
|
||||
Privileges: []*milvuspb.PrivilegeEntity{},
|
||||
Type: milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
_, err = mt.GetPrivilegeGroupRoles(context.TODO(), "")
|
||||
assert.Error(t, err)
|
||||
|
||||
@ -44,6 +44,7 @@ import (
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/proxypb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/querypb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/metricsinfo"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/paramtable"
|
||||
@ -56,6 +57,8 @@ const (
|
||||
TestRootCoordID = 200
|
||||
)
|
||||
|
||||
var _ IMetaTable = &mockMetaTable{}
|
||||
|
||||
// TODO: remove mockMetaTable, use mockery instead
|
||||
type mockMetaTable struct {
|
||||
IMetaTable
|
||||
@ -83,8 +86,8 @@ type mockMetaTable struct {
|
||||
RenameCollectionFunc func(ctx context.Context, oldName string, newName string, ts Timestamp) error
|
||||
AddCredentialFunc func(ctx context.Context, credInfo *internalpb.CredentialInfo) error
|
||||
GetCredentialFunc func(ctx context.Context, username string) (*internalpb.CredentialInfo, error)
|
||||
DeleteCredentialFunc func(ctx context.Context, username string) error
|
||||
AlterCredentialFunc func(ctx context.Context, credInfo *internalpb.CredentialInfo) error
|
||||
DeleteCredentialFunc func(ctx context.Context, msg message.BroadcastResultDropUserMessageV2) error
|
||||
AlterCredentialFunc func(ctx context.Context, msg message.BroadcastResultAlterUserMessageV2) error
|
||||
ListCredentialUsernamesFunc func(ctx context.Context) (*milvuspb.ListCredUsersResponse, error)
|
||||
CreateRoleFunc func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error
|
||||
DropRoleFunc func(ctx context.Context, tenant string, roleName string) error
|
||||
@ -205,12 +208,12 @@ func (m mockMetaTable) GetCredential(ctx context.Context, username string) (*int
|
||||
return m.GetCredentialFunc(ctx, username)
|
||||
}
|
||||
|
||||
func (m mockMetaTable) DeleteCredential(ctx context.Context, username string) error {
|
||||
return m.DeleteCredentialFunc(ctx, username)
|
||||
func (m mockMetaTable) DeleteCredential(ctx context.Context, msg message.BroadcastResultDropUserMessageV2) error {
|
||||
return m.DeleteCredentialFunc(ctx, msg)
|
||||
}
|
||||
|
||||
func (m mockMetaTable) AlterCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
return m.AlterCredentialFunc(ctx, credInfo)
|
||||
func (m mockMetaTable) AlterCredential(ctx context.Context, msg message.BroadcastResultAlterUserMessageV2) error {
|
||||
return m.AlterCredentialFunc(ctx, msg)
|
||||
}
|
||||
|
||||
func (m mockMetaTable) ListCredentialUsernames(ctx context.Context) (*milvuspb.ListCredUsersResponse, error) {
|
||||
@ -373,12 +376,17 @@ func newMockTsoAllocator() *tso.MockAllocator {
|
||||
|
||||
type mockProxy struct {
|
||||
types.ProxyClient
|
||||
UpdateCredentialCacheFunc func(ctx context.Context, request *proxypb.UpdateCredCacheRequest) (*commonpb.Status, error)
|
||||
InvalidateCollectionMetaCacheFunc func(ctx context.Context, request *proxypb.InvalidateCollMetaCacheRequest) (*commonpb.Status, error)
|
||||
InvalidateCredentialCacheFunc func(ctx context.Context, request *proxypb.InvalidateCredCacheRequest) (*commonpb.Status, error)
|
||||
RefreshPolicyInfoCacheFunc func(ctx context.Context, request *proxypb.RefreshPolicyInfoCacheRequest) (*commonpb.Status, error)
|
||||
GetComponentStatesFunc func(ctx context.Context) (*milvuspb.ComponentStates, error)
|
||||
}
|
||||
|
||||
func (m mockProxy) UpdateCredentialCache(ctx context.Context, request *proxypb.UpdateCredCacheRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
|
||||
return m.UpdateCredentialCacheFunc(ctx, request)
|
||||
}
|
||||
|
||||
func (m mockProxy) InvalidateCollectionMetaCache(ctx context.Context, request *proxypb.InvalidateCollMetaCacheRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
|
||||
return m.InvalidateCollectionMetaCacheFunc(ctx, request)
|
||||
}
|
||||
@ -426,9 +434,18 @@ func withValidProxyManager() Opt {
|
||||
return func(c *Core) {
|
||||
c.proxyClientManager = proxyutil.NewProxyClientManager(proxyutil.DefaultProxyCreator)
|
||||
p := newMockProxy()
|
||||
p.UpdateCredentialCacheFunc = func(ctx context.Context, request *proxypb.UpdateCredCacheRequest) (*commonpb.Status, error) {
|
||||
return merr.Success(), nil
|
||||
}
|
||||
p.InvalidateCredentialCacheFunc = func(ctx context.Context, request *proxypb.InvalidateCredCacheRequest) (*commonpb.Status, error) {
|
||||
return merr.Success(), nil
|
||||
}
|
||||
p.InvalidateCollectionMetaCacheFunc = func(ctx context.Context, request *proxypb.InvalidateCollMetaCacheRequest) (*commonpb.Status, error) {
|
||||
return merr.Success(), nil
|
||||
}
|
||||
p.RefreshPolicyInfoCacheFunc = func(ctx context.Context, request *proxypb.RefreshPolicyInfoCacheRequest) (*commonpb.Status, error) {
|
||||
return merr.Success(), nil
|
||||
}
|
||||
p.GetComponentStatesFunc = func(ctx context.Context) (*milvuspb.ComponentStates, error) {
|
||||
return &milvuspb.ComponentStates{
|
||||
State: &milvuspb.ComponentInfo{StateCode: commonpb.StateCode_Healthy},
|
||||
@ -509,10 +526,10 @@ func withInvalidMeta() Opt {
|
||||
meta.GetCredentialFunc = func(ctx context.Context, username string) (*internalpb.CredentialInfo, error) {
|
||||
return nil, errors.New("error mock GetCredential")
|
||||
}
|
||||
meta.DeleteCredentialFunc = func(ctx context.Context, username string) error {
|
||||
meta.DeleteCredentialFunc = func(ctx context.Context, msg message.BroadcastResultDropUserMessageV2) error {
|
||||
return errors.New("error mock DeleteCredential")
|
||||
}
|
||||
meta.AlterCredentialFunc = func(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
meta.AlterCredentialFunc = func(ctx context.Context, msg message.BroadcastResultAlterUserMessageV2) error {
|
||||
return errors.New("error mock AlterCredential")
|
||||
}
|
||||
meta.ListCredentialUsernamesFunc = func(ctx context.Context) (*milvuspb.ListCredUsersResponse, error) {
|
||||
|
||||
@ -8,6 +8,10 @@ import (
|
||||
etcdpb "github.com/milvus-io/milvus/pkg/v2/proto/etcdpb"
|
||||
internalpb "github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
|
||||
message "github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
|
||||
messagespb "github.com/milvus-io/milvus/pkg/v2/proto/messagespb"
|
||||
|
||||
milvuspb "github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
@ -77,53 +81,6 @@ func (_c *IMetaTable_AddCollection_Call) RunAndReturn(run func(context.Context,
|
||||
return _c
|
||||
}
|
||||
|
||||
// AddCredential provides a mock function with given fields: ctx, credInfo
|
||||
func (_m *IMetaTable) AddCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
ret := _m.Called(ctx, credInfo)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for AddCredential")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *internalpb.CredentialInfo) error); ok {
|
||||
r0 = rf(ctx, credInfo)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_AddCredential_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddCredential'
|
||||
type IMetaTable_AddCredential_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// AddCredential is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - credInfo *internalpb.CredentialInfo
|
||||
func (_e *IMetaTable_Expecter) AddCredential(ctx interface{}, credInfo interface{}) *IMetaTable_AddCredential_Call {
|
||||
return &IMetaTable_AddCredential_Call{Call: _e.mock.On("AddCredential", ctx, credInfo)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_AddCredential_Call) Run(run func(ctx context.Context, credInfo *internalpb.CredentialInfo)) *IMetaTable_AddCredential_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*internalpb.CredentialInfo))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_AddCredential_Call) Return(_a0 error) *IMetaTable_AddCredential_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_AddCredential_Call) RunAndReturn(run func(context.Context, *internalpb.CredentialInfo) error) *IMetaTable_AddCredential_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// AddPartition provides a mock function with given fields: ctx, partition
|
||||
func (_m *IMetaTable) AddPartition(ctx context.Context, partition *model.Partition) error {
|
||||
ret := _m.Called(ctx, partition)
|
||||
@ -271,17 +228,17 @@ func (_c *IMetaTable_AlterCollection_Call) RunAndReturn(run func(context.Context
|
||||
return _c
|
||||
}
|
||||
|
||||
// AlterCredential provides a mock function with given fields: ctx, credInfo
|
||||
func (_m *IMetaTable) AlterCredential(ctx context.Context, credInfo *internalpb.CredentialInfo) error {
|
||||
ret := _m.Called(ctx, credInfo)
|
||||
// AlterCredential provides a mock function with given fields: ctx, result
|
||||
func (_m *IMetaTable) AlterCredential(ctx context.Context, result message.BroadcastResult[*messagespb.AlterUserMessageHeader, *messagespb.AlterUserMessageBody]) error {
|
||||
ret := _m.Called(ctx, result)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for AlterCredential")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *internalpb.CredentialInfo) error); ok {
|
||||
r0 = rf(ctx, credInfo)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, message.BroadcastResult[*messagespb.AlterUserMessageHeader, *messagespb.AlterUserMessageBody]) error); ok {
|
||||
r0 = rf(ctx, result)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@ -296,14 +253,14 @@ type IMetaTable_AlterCredential_Call struct {
|
||||
|
||||
// AlterCredential is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - credInfo *internalpb.CredentialInfo
|
||||
func (_e *IMetaTable_Expecter) AlterCredential(ctx interface{}, credInfo interface{}) *IMetaTable_AlterCredential_Call {
|
||||
return &IMetaTable_AlterCredential_Call{Call: _e.mock.On("AlterCredential", ctx, credInfo)}
|
||||
// - result message.BroadcastResult[*messagespb.AlterUserMessageHeader,*messagespb.AlterUserMessageBody]
|
||||
func (_e *IMetaTable_Expecter) AlterCredential(ctx interface{}, result interface{}) *IMetaTable_AlterCredential_Call {
|
||||
return &IMetaTable_AlterCredential_Call{Call: _e.mock.On("AlterCredential", ctx, result)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_AlterCredential_Call) Run(run func(ctx context.Context, credInfo *internalpb.CredentialInfo)) *IMetaTable_AlterCredential_Call {
|
||||
func (_c *IMetaTable_AlterCredential_Call) Run(run func(ctx context.Context, result message.BroadcastResult[*messagespb.AlterUserMessageHeader, *messagespb.AlterUserMessageBody])) *IMetaTable_AlterCredential_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*internalpb.CredentialInfo))
|
||||
run(args[0].(context.Context), args[1].(message.BroadcastResult[*messagespb.AlterUserMessageHeader, *messagespb.AlterUserMessageBody]))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
@ -313,7 +270,7 @@ func (_c *IMetaTable_AlterCredential_Call) Return(_a0 error) *IMetaTable_AlterCr
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_AlterCredential_Call) RunAndReturn(run func(context.Context, *internalpb.CredentialInfo) error) *IMetaTable_AlterCredential_Call {
|
||||
func (_c *IMetaTable_AlterCredential_Call) RunAndReturn(run func(context.Context, message.BroadcastResult[*messagespb.AlterUserMessageHeader, *messagespb.AlterUserMessageBody]) error) *IMetaTable_AlterCredential_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
@ -525,6 +482,476 @@ func (_c *IMetaTable_ChangePartitionState_Call) RunAndReturn(run func(context.Co
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfAddCredential provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfAddCredential(ctx context.Context, req *internalpb.CredentialInfo) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfAddCredential")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *internalpb.CredentialInfo) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfAddCredential_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfAddCredential'
|
||||
type IMetaTable_CheckIfAddCredential_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfAddCredential is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *internalpb.CredentialInfo
|
||||
func (_e *IMetaTable_Expecter) CheckIfAddCredential(ctx interface{}, req interface{}) *IMetaTable_CheckIfAddCredential_Call {
|
||||
return &IMetaTable_CheckIfAddCredential_Call{Call: _e.mock.On("CheckIfAddCredential", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfAddCredential_Call) Run(run func(ctx context.Context, req *internalpb.CredentialInfo)) *IMetaTable_CheckIfAddCredential_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*internalpb.CredentialInfo))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfAddCredential_Call) Return(_a0 error) *IMetaTable_CheckIfAddCredential_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfAddCredential_Call) RunAndReturn(run func(context.Context, *internalpb.CredentialInfo) error) *IMetaTable_CheckIfAddCredential_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfCreateRole provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfCreateRole(ctx context.Context, req *milvuspb.CreateRoleRequest) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfCreateRole")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.CreateRoleRequest) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfCreateRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfCreateRole'
|
||||
type IMetaTable_CheckIfCreateRole_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfCreateRole is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *milvuspb.CreateRoleRequest
|
||||
func (_e *IMetaTable_Expecter) CheckIfCreateRole(ctx interface{}, req interface{}) *IMetaTable_CheckIfCreateRole_Call {
|
||||
return &IMetaTable_CheckIfCreateRole_Call{Call: _e.mock.On("CheckIfCreateRole", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfCreateRole_Call) Run(run func(ctx context.Context, req *milvuspb.CreateRoleRequest)) *IMetaTable_CheckIfCreateRole_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.CreateRoleRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfCreateRole_Call) Return(_a0 error) *IMetaTable_CheckIfCreateRole_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfCreateRole_Call) RunAndReturn(run func(context.Context, *milvuspb.CreateRoleRequest) error) *IMetaTable_CheckIfCreateRole_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfDeleteCredential provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfDeleteCredential(ctx context.Context, req *milvuspb.DeleteCredentialRequest) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfDeleteCredential")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.DeleteCredentialRequest) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfDeleteCredential_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfDeleteCredential'
|
||||
type IMetaTable_CheckIfDeleteCredential_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfDeleteCredential is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *milvuspb.DeleteCredentialRequest
|
||||
func (_e *IMetaTable_Expecter) CheckIfDeleteCredential(ctx interface{}, req interface{}) *IMetaTable_CheckIfDeleteCredential_Call {
|
||||
return &IMetaTable_CheckIfDeleteCredential_Call{Call: _e.mock.On("CheckIfDeleteCredential", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfDeleteCredential_Call) Run(run func(ctx context.Context, req *milvuspb.DeleteCredentialRequest)) *IMetaTable_CheckIfDeleteCredential_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.DeleteCredentialRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfDeleteCredential_Call) Return(_a0 error) *IMetaTable_CheckIfDeleteCredential_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfDeleteCredential_Call) RunAndReturn(run func(context.Context, *milvuspb.DeleteCredentialRequest) error) *IMetaTable_CheckIfDeleteCredential_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfDropRole provides a mock function with given fields: ctx, in
|
||||
func (_m *IMetaTable) CheckIfDropRole(ctx context.Context, in *milvuspb.DropRoleRequest) error {
|
||||
ret := _m.Called(ctx, in)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfDropRole")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.DropRoleRequest) error); ok {
|
||||
r0 = rf(ctx, in)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfDropRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfDropRole'
|
||||
type IMetaTable_CheckIfDropRole_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfDropRole is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - in *milvuspb.DropRoleRequest
|
||||
func (_e *IMetaTable_Expecter) CheckIfDropRole(ctx interface{}, in interface{}) *IMetaTable_CheckIfDropRole_Call {
|
||||
return &IMetaTable_CheckIfDropRole_Call{Call: _e.mock.On("CheckIfDropRole", ctx, in)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfDropRole_Call) Run(run func(ctx context.Context, in *milvuspb.DropRoleRequest)) *IMetaTable_CheckIfDropRole_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.DropRoleRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfDropRole_Call) Return(_a0 error) *IMetaTable_CheckIfDropRole_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfDropRole_Call) RunAndReturn(run func(context.Context, *milvuspb.DropRoleRequest) error) *IMetaTable_CheckIfDropRole_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfOperateUserRole provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfOperateUserRole(ctx context.Context, req *milvuspb.OperateUserRoleRequest) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfOperateUserRole")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.OperateUserRoleRequest) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfOperateUserRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfOperateUserRole'
|
||||
type IMetaTable_CheckIfOperateUserRole_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfOperateUserRole is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *milvuspb.OperateUserRoleRequest
|
||||
func (_e *IMetaTable_Expecter) CheckIfOperateUserRole(ctx interface{}, req interface{}) *IMetaTable_CheckIfOperateUserRole_Call {
|
||||
return &IMetaTable_CheckIfOperateUserRole_Call{Call: _e.mock.On("CheckIfOperateUserRole", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfOperateUserRole_Call) Run(run func(ctx context.Context, req *milvuspb.OperateUserRoleRequest)) *IMetaTable_CheckIfOperateUserRole_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.OperateUserRoleRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfOperateUserRole_Call) Return(_a0 error) *IMetaTable_CheckIfOperateUserRole_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfOperateUserRole_Call) RunAndReturn(run func(context.Context, *milvuspb.OperateUserRoleRequest) error) *IMetaTable_CheckIfOperateUserRole_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfPrivilegeGroupAlterable provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfPrivilegeGroupAlterable(ctx context.Context, req *milvuspb.OperatePrivilegeGroupRequest) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfPrivilegeGroupAlterable")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.OperatePrivilegeGroupRequest) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfPrivilegeGroupAlterable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfPrivilegeGroupAlterable'
|
||||
type IMetaTable_CheckIfPrivilegeGroupAlterable_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfPrivilegeGroupAlterable is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *milvuspb.OperatePrivilegeGroupRequest
|
||||
func (_e *IMetaTable_Expecter) CheckIfPrivilegeGroupAlterable(ctx interface{}, req interface{}) *IMetaTable_CheckIfPrivilegeGroupAlterable_Call {
|
||||
return &IMetaTable_CheckIfPrivilegeGroupAlterable_Call{Call: _e.mock.On("CheckIfPrivilegeGroupAlterable", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupAlterable_Call) Run(run func(ctx context.Context, req *milvuspb.OperatePrivilegeGroupRequest)) *IMetaTable_CheckIfPrivilegeGroupAlterable_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.OperatePrivilegeGroupRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupAlterable_Call) Return(_a0 error) *IMetaTable_CheckIfPrivilegeGroupAlterable_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupAlterable_Call) RunAndReturn(run func(context.Context, *milvuspb.OperatePrivilegeGroupRequest) error) *IMetaTable_CheckIfPrivilegeGroupAlterable_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfPrivilegeGroupCreatable provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfPrivilegeGroupCreatable(ctx context.Context, req *milvuspb.CreatePrivilegeGroupRequest) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfPrivilegeGroupCreatable")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.CreatePrivilegeGroupRequest) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfPrivilegeGroupCreatable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfPrivilegeGroupCreatable'
|
||||
type IMetaTable_CheckIfPrivilegeGroupCreatable_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfPrivilegeGroupCreatable is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *milvuspb.CreatePrivilegeGroupRequest
|
||||
func (_e *IMetaTable_Expecter) CheckIfPrivilegeGroupCreatable(ctx interface{}, req interface{}) *IMetaTable_CheckIfPrivilegeGroupCreatable_Call {
|
||||
return &IMetaTable_CheckIfPrivilegeGroupCreatable_Call{Call: _e.mock.On("CheckIfPrivilegeGroupCreatable", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupCreatable_Call) Run(run func(ctx context.Context, req *milvuspb.CreatePrivilegeGroupRequest)) *IMetaTable_CheckIfPrivilegeGroupCreatable_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.CreatePrivilegeGroupRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupCreatable_Call) Return(_a0 error) *IMetaTable_CheckIfPrivilegeGroupCreatable_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupCreatable_Call) RunAndReturn(run func(context.Context, *milvuspb.CreatePrivilegeGroupRequest) error) *IMetaTable_CheckIfPrivilegeGroupCreatable_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfPrivilegeGroupDropable provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfPrivilegeGroupDropable(ctx context.Context, req *milvuspb.DropPrivilegeGroupRequest) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfPrivilegeGroupDropable")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.DropPrivilegeGroupRequest) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfPrivilegeGroupDropable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfPrivilegeGroupDropable'
|
||||
type IMetaTable_CheckIfPrivilegeGroupDropable_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfPrivilegeGroupDropable is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *milvuspb.DropPrivilegeGroupRequest
|
||||
func (_e *IMetaTable_Expecter) CheckIfPrivilegeGroupDropable(ctx interface{}, req interface{}) *IMetaTable_CheckIfPrivilegeGroupDropable_Call {
|
||||
return &IMetaTable_CheckIfPrivilegeGroupDropable_Call{Call: _e.mock.On("CheckIfPrivilegeGroupDropable", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupDropable_Call) Run(run func(ctx context.Context, req *milvuspb.DropPrivilegeGroupRequest)) *IMetaTable_CheckIfPrivilegeGroupDropable_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.DropPrivilegeGroupRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupDropable_Call) Return(_a0 error) *IMetaTable_CheckIfPrivilegeGroupDropable_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfPrivilegeGroupDropable_Call) RunAndReturn(run func(context.Context, *milvuspb.DropPrivilegeGroupRequest) error) *IMetaTable_CheckIfPrivilegeGroupDropable_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfRBACRestorable provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfRBACRestorable(ctx context.Context, req *milvuspb.RestoreRBACMetaRequest) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfRBACRestorable")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreRBACMetaRequest) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfRBACRestorable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfRBACRestorable'
|
||||
type IMetaTable_CheckIfRBACRestorable_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfRBACRestorable is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *milvuspb.RestoreRBACMetaRequest
|
||||
func (_e *IMetaTable_Expecter) CheckIfRBACRestorable(ctx interface{}, req interface{}) *IMetaTable_CheckIfRBACRestorable_Call {
|
||||
return &IMetaTable_CheckIfRBACRestorable_Call{Call: _e.mock.On("CheckIfRBACRestorable", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfRBACRestorable_Call) Run(run func(ctx context.Context, req *milvuspb.RestoreRBACMetaRequest)) *IMetaTable_CheckIfRBACRestorable_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.RestoreRBACMetaRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfRBACRestorable_Call) Return(_a0 error) *IMetaTable_CheckIfRBACRestorable_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfRBACRestorable_Call) RunAndReturn(run func(context.Context, *milvuspb.RestoreRBACMetaRequest) error) *IMetaTable_CheckIfRBACRestorable_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CheckIfUpdateCredential provides a mock function with given fields: ctx, req
|
||||
func (_m *IMetaTable) CheckIfUpdateCredential(ctx context.Context, req *internalpb.CredentialInfo) error {
|
||||
ret := _m.Called(ctx, req)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CheckIfUpdateCredential")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *internalpb.CredentialInfo) error); ok {
|
||||
r0 = rf(ctx, req)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_CheckIfUpdateCredential_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckIfUpdateCredential'
|
||||
type IMetaTable_CheckIfUpdateCredential_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// CheckIfUpdateCredential is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - req *internalpb.CredentialInfo
|
||||
func (_e *IMetaTable_Expecter) CheckIfUpdateCredential(ctx interface{}, req interface{}) *IMetaTable_CheckIfUpdateCredential_Call {
|
||||
return &IMetaTable_CheckIfUpdateCredential_Call{Call: _e.mock.On("CheckIfUpdateCredential", ctx, req)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfUpdateCredential_Call) Run(run func(ctx context.Context, req *internalpb.CredentialInfo)) *IMetaTable_CheckIfUpdateCredential_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*internalpb.CredentialInfo))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfUpdateCredential_Call) Return(_a0 error) *IMetaTable_CheckIfUpdateCredential_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_CheckIfUpdateCredential_Call) RunAndReturn(run func(context.Context, *internalpb.CredentialInfo) error) *IMetaTable_CheckIfUpdateCredential_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// CreateAlias provides a mock function with given fields: ctx, dbName, alias, collectionName, ts
|
||||
func (_m *IMetaTable) CreateAlias(ctx context.Context, dbName string, alias string, collectionName string, ts uint64) error {
|
||||
ret := _m.Called(ctx, dbName, alias, collectionName, ts)
|
||||
@ -718,17 +1145,17 @@ func (_c *IMetaTable_CreateRole_Call) RunAndReturn(run func(context.Context, str
|
||||
return _c
|
||||
}
|
||||
|
||||
// DeleteCredential provides a mock function with given fields: ctx, username
|
||||
func (_m *IMetaTable) DeleteCredential(ctx context.Context, username string) error {
|
||||
ret := _m.Called(ctx, username)
|
||||
// DeleteCredential provides a mock function with given fields: ctx, result
|
||||
func (_m *IMetaTable) DeleteCredential(ctx context.Context, result message.BroadcastResult[*messagespb.DropUserMessageHeader, *messagespb.DropUserMessageBody]) error {
|
||||
ret := _m.Called(ctx, result)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteCredential")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, username)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, message.BroadcastResult[*messagespb.DropUserMessageHeader, *messagespb.DropUserMessageBody]) error); ok {
|
||||
r0 = rf(ctx, result)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
@ -743,14 +1170,14 @@ type IMetaTable_DeleteCredential_Call struct {
|
||||
|
||||
// DeleteCredential is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - username string
|
||||
func (_e *IMetaTable_Expecter) DeleteCredential(ctx interface{}, username interface{}) *IMetaTable_DeleteCredential_Call {
|
||||
return &IMetaTable_DeleteCredential_Call{Call: _e.mock.On("DeleteCredential", ctx, username)}
|
||||
// - result message.BroadcastResult[*messagespb.DropUserMessageHeader,*messagespb.DropUserMessageBody]
|
||||
func (_e *IMetaTable_Expecter) DeleteCredential(ctx interface{}, result interface{}) *IMetaTable_DeleteCredential_Call {
|
||||
return &IMetaTable_DeleteCredential_Call{Call: _e.mock.On("DeleteCredential", ctx, result)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_DeleteCredential_Call) Run(run func(ctx context.Context, username string)) *IMetaTable_DeleteCredential_Call {
|
||||
func (_c *IMetaTable_DeleteCredential_Call) Run(run func(ctx context.Context, result message.BroadcastResult[*messagespb.DropUserMessageHeader, *messagespb.DropUserMessageBody])) *IMetaTable_DeleteCredential_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
run(args[0].(context.Context), args[1].(message.BroadcastResult[*messagespb.DropUserMessageHeader, *messagespb.DropUserMessageBody]))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
@ -760,7 +1187,7 @@ func (_c *IMetaTable_DeleteCredential_Call) Return(_a0 error) *IMetaTable_Delete
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_DeleteCredential_Call) RunAndReturn(run func(context.Context, string) error) *IMetaTable_DeleteCredential_Call {
|
||||
func (_c *IMetaTable_DeleteCredential_Call) RunAndReturn(run func(context.Context, message.BroadcastResult[*messagespb.DropUserMessageHeader, *messagespb.DropUserMessageBody]) error) *IMetaTable_DeleteCredential_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
@ -1676,6 +2103,52 @@ func (_c *IMetaTable_GetPrivilegeGroupRoles_Call) RunAndReturn(run func(context.
|
||||
return _c
|
||||
}
|
||||
|
||||
// InitCredential provides a mock function with given fields: ctx
|
||||
func (_m *IMetaTable) InitCredential(ctx context.Context) error {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for InitCredential")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// IMetaTable_InitCredential_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InitCredential'
|
||||
type IMetaTable_InitCredential_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// InitCredential is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *IMetaTable_Expecter) InitCredential(ctx interface{}) *IMetaTable_InitCredential_Call {
|
||||
return &IMetaTable_InitCredential_Call{Call: _e.mock.On("InitCredential", ctx)}
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_InitCredential_Call) Run(run func(ctx context.Context)) *IMetaTable_InitCredential_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_InitCredential_Call) Return(_a0 error) *IMetaTable_InitCredential_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *IMetaTable_InitCredential_Call) RunAndReturn(run func(context.Context) error) *IMetaTable_InitCredential_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// IsAlias provides a mock function with given fields: ctx, db, name
|
||||
func (_m *IMetaTable) IsAlias(ctx context.Context, db string, name string) bool {
|
||||
ret := _m.Called(ctx, db, name)
|
||||
|
||||
@ -35,171 +35,64 @@ import (
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/typeutil"
|
||||
)
|
||||
|
||||
func executeDeleteCredentialTaskSteps(ctx context.Context, core *Core, username string) error {
|
||||
redoTask := newBaseRedoTask(core.stepExecutor)
|
||||
redoTask.AddSyncStep(NewSimpleStep("delete credential meta data", func(ctx context.Context) ([]nestedStep, error) {
|
||||
err := core.meta.DeleteCredential(ctx, username)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("delete credential meta data failed", zap.String("username", username), zap.Error(err))
|
||||
}
|
||||
return nil, err
|
||||
}))
|
||||
redoTask.AddAsyncStep(NewSimpleStep("delete credential cache", func(ctx context.Context) ([]nestedStep, error) {
|
||||
err := core.ExpireCredCache(ctx, username)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("delete credential cache failed", zap.String("username", username), zap.Error(err))
|
||||
}
|
||||
return nil, err
|
||||
}))
|
||||
redoTask.AddAsyncStep(NewSimpleStep("delete user role cache for the user", func(ctx context.Context) ([]nestedStep, error) {
|
||||
err := core.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: int32(typeutil.CacheDeleteUser),
|
||||
OpKey: username,
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("delete user role cache failed for the user", zap.String("username", username), zap.Error(err))
|
||||
}
|
||||
return nil, err
|
||||
}))
|
||||
|
||||
return redoTask.Execute(ctx)
|
||||
}
|
||||
|
||||
func executeDropRoleTaskSteps(ctx context.Context, core *Core, roleName string, foreDrop bool) error {
|
||||
redoTask := newBaseRedoTask(core.stepExecutor)
|
||||
redoTask.AddSyncStep(NewSimpleStep("drop role meta data", func(ctx context.Context) ([]nestedStep, error) {
|
||||
err := core.meta.DropRole(ctx, util.DefaultTenant, roleName)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("drop role mata data failed", zap.String("role_name", roleName), zap.Error(err))
|
||||
}
|
||||
return nil, err
|
||||
}))
|
||||
redoTask.AddAsyncStep(NewSimpleStep("drop the privilege list of this role", func(ctx context.Context) ([]nestedStep, error) {
|
||||
if !foreDrop {
|
||||
return nil, nil
|
||||
}
|
||||
err := core.meta.DropGrant(ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: roleName})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("drop the privilege list failed for the role", zap.String("role_name", roleName), zap.Error(err))
|
||||
}
|
||||
return nil, err
|
||||
}))
|
||||
redoTask.AddAsyncStep(NewSimpleStep("drop role cache", func(ctx context.Context) ([]nestedStep, error) {
|
||||
err := core.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: int32(typeutil.CacheDropRole),
|
||||
OpKey: roleName,
|
||||
})
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("delete user role cache failed for the role", zap.String("role_name", roleName), zap.Error(err))
|
||||
}
|
||||
return nil, err
|
||||
}))
|
||||
return redoTask.Execute(ctx)
|
||||
}
|
||||
|
||||
func executeOperateUserRoleTaskSteps(ctx context.Context, core *Core, in *milvuspb.OperateUserRoleRequest) error {
|
||||
username := in.Username
|
||||
roleName := in.RoleName
|
||||
operateType := in.Type
|
||||
redoTask := newBaseRedoTask(core.stepExecutor)
|
||||
redoTask.AddSyncStep(NewSimpleStep("operate user role meta data", func(ctx context.Context) ([]nestedStep, error) {
|
||||
err := core.meta.OperateUserRole(ctx, util.DefaultTenant, &milvuspb.UserEntity{Name: username}, &milvuspb.RoleEntity{Name: roleName}, operateType)
|
||||
if err != nil && !common.IsIgnorableError(err) {
|
||||
log.Ctx(ctx).Warn("operate user role mata data failed",
|
||||
zap.String("username", username), zap.String("role_name", roleName),
|
||||
zap.Any("operate_type", operateType),
|
||||
zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}))
|
||||
redoTask.AddAsyncStep(NewSimpleStep("operate user role cache", func(ctx context.Context) ([]nestedStep, error) {
|
||||
var opType int32
|
||||
switch operateType {
|
||||
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"
|
||||
log.Ctx(ctx).Warn(errMsg,
|
||||
zap.String("username", username), zap.String("role_name", roleName),
|
||||
zap.Any("operate_type", operateType),
|
||||
)
|
||||
return nil, nil
|
||||
}
|
||||
if err := core.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: opType,
|
||||
OpKey: funcutil.EncodeUserRoleCache(username, roleName),
|
||||
}); err != nil {
|
||||
log.Ctx(ctx).Warn("fail to refresh policy info cache",
|
||||
zap.String("username", username), zap.String("role_name", roleName),
|
||||
zap.Any("operate_type", operateType),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}))
|
||||
return redoTask.Execute(ctx)
|
||||
}
|
||||
|
||||
func executeOperatePrivilegeTaskSteps(ctx context.Context, core *Core, in *milvuspb.OperatePrivilegeRequest) error {
|
||||
privName := in.Entity.Grantor.Privilege.Name
|
||||
redoTask := newBaseRedoTask(core.stepExecutor)
|
||||
redoTask.AddSyncStep(NewSimpleStep("operate privilege meta data", func(ctx context.Context) ([]nestedStep, error) {
|
||||
func executeOperatePrivilegeTaskSteps(ctx context.Context, core *Core, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error {
|
||||
privName := entity.Grantor.Privilege.Name
|
||||
if err := func() error {
|
||||
// set up privilege name for metastore
|
||||
dbPrivName, err := core.getMetastorePrivilegeName(ctx, privName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
in.Entity.Grantor.Privilege.Name = dbPrivName
|
||||
entity.Grantor.Privilege.Name = dbPrivName
|
||||
|
||||
err = core.meta.OperatePrivilege(ctx, util.DefaultTenant, in.Entity, in.Type)
|
||||
err = core.meta.OperatePrivilege(ctx, util.DefaultTenant, entity, operateType)
|
||||
if err != nil && !common.IsIgnorableError(err) {
|
||||
log.Ctx(ctx).Warn("fail to operate the privilege", zap.Any("in", in), zap.Error(err))
|
||||
return nil, err
|
||||
log.Ctx(ctx).Warn("fail to operate the privilege", zap.Any("in", entity), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
return nil, nil
|
||||
}))
|
||||
redoTask.AddAsyncStep(NewSimpleStep("operate privilege cache", func(ctx context.Context) ([]nestedStep, error) {
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "failed to operate the privilege")
|
||||
}
|
||||
|
||||
if err := func() error {
|
||||
// set back to expand privilege group
|
||||
in.Entity.Grantor.Privilege.Name = privName
|
||||
entity.Grantor.Privilege.Name = privName
|
||||
var opType int32
|
||||
switch in.Type {
|
||||
switch operateType {
|
||||
case milvuspb.OperatePrivilegeType_Grant:
|
||||
opType = int32(typeutil.CacheGrantPrivilege)
|
||||
case milvuspb.OperatePrivilegeType_Revoke:
|
||||
opType = int32(typeutil.CacheRevokePrivilege)
|
||||
default:
|
||||
log.Ctx(ctx).Warn("invalid operate type for the OperatePrivilege api", zap.Any("in", in))
|
||||
return nil, nil
|
||||
log.Ctx(ctx).Warn("invalid operate type for the OperatePrivilege api", zap.Any("operate_type", operateType))
|
||||
return errors.New("invalid operate type for the OperatePrivilege api")
|
||||
}
|
||||
grants := []*milvuspb.GrantEntity{in.Entity}
|
||||
grants := []*milvuspb.GrantEntity{entity}
|
||||
|
||||
allGroups, err := core.getDefaultAndCustomPrivilegeGroups(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
groups := lo.SliceToMap(allGroups, func(group *milvuspb.PrivilegeGroupInfo) (string, []*milvuspb.PrivilegeEntity) {
|
||||
return group.GroupName, group.Privileges
|
||||
})
|
||||
expandGrants, err := core.expandPrivilegeGroups(ctx, grants, groups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// if there is same grant in the other privilege groups, the grant should not be removed from the cache
|
||||
if in.Type == milvuspb.OperatePrivilegeType_Revoke {
|
||||
if operateType == milvuspb.OperatePrivilegeType_Revoke {
|
||||
metaGrants, err := core.meta.SelectGrant(ctx, util.DefaultTenant, &milvuspb.GrantEntity{
|
||||
Role: in.Entity.Role,
|
||||
DbName: in.Entity.DbName,
|
||||
Role: entity.Role,
|
||||
DbName: entity.DbName,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
metaExpandGrants, err := core.expandPrivilegeGroups(ctx, metaGrants, groups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
expandGrants = lo.Filter(expandGrants, func(g1 *milvuspb.GrantEntity, _ int) bool {
|
||||
return !lo.ContainsBy(metaExpandGrants, func(g2 *milvuspb.GrantEntity) bool {
|
||||
@ -212,45 +105,23 @@ func executeOperatePrivilegeTaskSteps(ctx context.Context, core *Core, in *milvu
|
||||
OpType: opType,
|
||||
OpKey: funcutil.PolicyForPrivileges(expandGrants),
|
||||
}); err != nil {
|
||||
log.Ctx(ctx).Warn("fail to refresh policy info cache", zap.Any("in", in), zap.Error(err))
|
||||
return nil, err
|
||||
log.Ctx(ctx).Warn("fail to refresh policy info cache", zap.Any("in", entity), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}))
|
||||
|
||||
return redoTask.Execute(ctx)
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "failed to refresh policy info cache")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func executeRestoreRBACTaskSteps(ctx context.Context, core *Core, in *milvuspb.RestoreRBACMetaRequest) error {
|
||||
redoTask := newBaseRedoTask(core.stepExecutor)
|
||||
redoTask.AddSyncStep(NewSimpleStep("restore rbac meta data", func(ctx context.Context) ([]nestedStep, error) {
|
||||
if err := core.meta.RestoreRBAC(ctx, util.DefaultTenant, in.RBACMeta); err != nil {
|
||||
log.Ctx(ctx).Warn("fail to restore rbac meta data", zap.Any("in", in), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}))
|
||||
redoTask.AddAsyncStep(NewSimpleStep("operate privilege cache", func(ctx context.Context) ([]nestedStep, error) {
|
||||
if err := core.proxyClientManager.RefreshPolicyInfoCache(ctx, &proxypb.RefreshPolicyInfoCacheRequest{
|
||||
OpType: int32(typeutil.CacheRefresh),
|
||||
}); err != nil {
|
||||
log.Ctx(ctx).Warn("fail to refresh policy info cache", zap.Any("in", in), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}))
|
||||
|
||||
return redoTask.Execute(ctx)
|
||||
}
|
||||
|
||||
func executeOperatePrivilegeGroupTaskSteps(ctx context.Context, core *Core, in *milvuspb.OperatePrivilegeGroupRequest) error {
|
||||
redoTask := newBaseRedoTask(core.stepExecutor)
|
||||
redoTask.AddSyncStep(NewSimpleStep("operate privilege group", func(ctx context.Context) ([]nestedStep, error) {
|
||||
func executeOperatePrivilegeGroupTaskSteps(ctx context.Context, core *Core, in *milvuspb.PrivilegeGroupInfo, operateType milvuspb.OperatePrivilegeGroupType) error {
|
||||
if err := func() error {
|
||||
groups, err := core.meta.ListPrivilegeGroups(ctx)
|
||||
if err != nil && !common.IsIgnorableError(err) {
|
||||
log.Ctx(ctx).Warn("fail to list privilege groups", zap.Error(err))
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
currGroups := lo.SliceToMap(groups, func(group *milvuspb.PrivilegeGroupInfo) (string, []*milvuspb.PrivilegeEntity) {
|
||||
return group.GroupName, group.Privileges
|
||||
@ -259,34 +130,25 @@ func executeOperatePrivilegeGroupTaskSteps(ctx context.Context, core *Core, in *
|
||||
// get roles granted to the group
|
||||
roles, err := core.meta.GetPrivilegeGroupRoles(ctx, in.GroupName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
newGroups := make(map[string][]*milvuspb.PrivilegeEntity)
|
||||
for k, v := range currGroups {
|
||||
if k != in.GroupName {
|
||||
newGroups[k] = v
|
||||
continue
|
||||
}
|
||||
switch in.Type {
|
||||
switch operateType {
|
||||
case milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup:
|
||||
newPrivs := lo.Union(v, in.Privileges)
|
||||
newGroups[k] = lo.UniqBy(newPrivs, func(p *milvuspb.PrivilegeEntity) string {
|
||||
return p.Name
|
||||
})
|
||||
|
||||
// check if privileges are the same privilege level
|
||||
privilegeLevels := lo.SliceToMap(newPrivs, func(p *milvuspb.PrivilegeEntity) (string, struct{}) {
|
||||
return util.GetPrivilegeLevel(p.Name), struct{}{}
|
||||
})
|
||||
if len(privilegeLevels) > 1 {
|
||||
return nil, errors.New("privileges are not the same privilege level")
|
||||
}
|
||||
case milvuspb.OperatePrivilegeGroupType_RemovePrivilegesFromGroup:
|
||||
newPrivs, _ := lo.Difference(v, in.Privileges)
|
||||
newGroups[k] = newPrivs
|
||||
default:
|
||||
return nil, errors.New("invalid operate type")
|
||||
return errors.New("invalid operate type")
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,15 +168,15 @@ func executeOperatePrivilegeGroupTaskSteps(ctx context.Context, core *Core, in *
|
||||
DbName: util.AnyWord,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
currGrants, err := core.expandPrivilegeGroups(ctx, grants, currGroups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
newGrants, err := core.expandPrivilegeGroups(ctx, grants, newGroups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
toRevoke := lo.Filter(currGrants, func(item *milvuspb.GrantEntity, _ int) bool {
|
||||
@ -340,7 +202,7 @@ func executeOperatePrivilegeGroupTaskSteps(ctx context.Context, core *Core, in *
|
||||
OpKey: funcutil.PolicyForPrivileges(rolesToRevoke),
|
||||
}); err != nil {
|
||||
log.Ctx(ctx).Warn("fail to refresh policy info cache for revoke privileges in operate privilege group", zap.Any("in", in), zap.Error(err))
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -351,19 +213,16 @@ func executeOperatePrivilegeGroupTaskSteps(ctx context.Context, core *Core, in *
|
||||
OpKey: funcutil.PolicyForPrivileges(rolesToGrant),
|
||||
}); err != nil {
|
||||
log.Ctx(ctx).Warn("fail to refresh policy info cache for grants privilege in operate privilege group", zap.Any("in", in), zap.Error(err))
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}))
|
||||
|
||||
redoTask.AddSyncStep(NewSimpleStep("operate privilege group meta data", func(ctx context.Context) ([]nestedStep, error) {
|
||||
err := core.meta.OperatePrivilegeGroup(ctx, in.GroupName, in.Privileges, in.Type)
|
||||
if err != nil && !common.IsIgnorableError(err) {
|
||||
log.Ctx(ctx).Warn("fail to operate privilege group", zap.Error(err))
|
||||
}
|
||||
return nil, err
|
||||
}))
|
||||
|
||||
return redoTask.Execute(ctx)
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "failed to refresh policy info cache")
|
||||
}
|
||||
if err := core.meta.OperatePrivilegeGroup(ctx, in.GroupName, in.Privileges, operateType); err != nil && !common.IsIgnorableError(err) {
|
||||
log.Ctx(ctx).Warn("fail to operate privilege group", zap.Error(err))
|
||||
return errors.Wrap(err, "failed to operate privilege group")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -62,7 +62,6 @@ import (
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/commonpbutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/contextutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/crypto"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/expr"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
@ -488,6 +487,7 @@ func (c *Core) Init() error {
|
||||
|
||||
c.initOnce.Do(func() {
|
||||
initError = c.initInternal()
|
||||
RegisterDDLCallbacks(c)
|
||||
})
|
||||
log.Info("RootCoord init successfully")
|
||||
|
||||
@ -495,22 +495,7 @@ func (c *Core) Init() error {
|
||||
}
|
||||
|
||||
func (c *Core) initCredentials(initCtx context.Context) error {
|
||||
credInfo, _ := c.meta.GetCredential(initCtx, util.UserRoot)
|
||||
if credInfo == nil {
|
||||
encryptedRootPassword, err := crypto.PasswordEncrypt(Params.CommonCfg.DefaultRootPassword.GetValue())
|
||||
if err != nil {
|
||||
log.Ctx(initCtx).Warn("RootCoord init user root failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
log.Ctx(initCtx).Info("RootCoord init user root")
|
||||
err = c.meta.AddCredential(initCtx, &internalpb.CredentialInfo{Username: util.UserRoot, EncryptedPassword: encryptedRootPassword})
|
||||
if err != nil {
|
||||
log.Ctx(initCtx).Warn("RootCoord init user root failed", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
return c.meta.InitCredential(initCtx)
|
||||
}
|
||||
|
||||
func (c *Core) initRbac(initCtx context.Context) error {
|
||||
@ -531,7 +516,7 @@ func (c *Core) initRbac(initCtx context.Context) error {
|
||||
}
|
||||
|
||||
if Params.RoleCfg.Enabled.GetAsBool() {
|
||||
return c.initBuiltinRoles()
|
||||
return c.initBuiltinRoles(initCtx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -580,22 +565,22 @@ func (c *Core) initPublicRolePrivilege(initCtx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Core) initBuiltinRoles() error {
|
||||
log := log.Ctx(c.ctx)
|
||||
func (c *Core) initBuiltinRoles(ctx context.Context) error {
|
||||
log := log.Ctx(ctx)
|
||||
rolePrivilegesMap := Params.RoleCfg.Roles.GetAsRoleDetails()
|
||||
for role, privilegesJSON := range rolePrivilegesMap {
|
||||
err := c.meta.CreateRole(c.ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: role})
|
||||
err := c.meta.CreateRole(ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: role})
|
||||
if err != nil && !common.IsIgnorableError(err) {
|
||||
log.Error("create a builtin role fail", zap.String("roleName", role), zap.Error(err))
|
||||
return errors.Wrapf(err, "failed to create a builtin role: %s", role)
|
||||
}
|
||||
for _, privilege := range privilegesJSON[util.RoleConfigPrivileges] {
|
||||
privilegeName, err := c.getMetastorePrivilegeName(c.ctx, privilege[util.RoleConfigPrivilege])
|
||||
privilegeName, err := c.getMetastorePrivilegeName(ctx, privilege[util.RoleConfigPrivilege])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get metastore privilege name for: %s", privilege[util.RoleConfigPrivilege])
|
||||
}
|
||||
|
||||
err = c.meta.OperatePrivilege(c.ctx, util.DefaultTenant, &milvuspb.GrantEntity{
|
||||
err = c.meta.OperatePrivilege(ctx, util.DefaultTenant, &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: role},
|
||||
Object: &milvuspb.ObjectEntity{Name: privilege[util.RoleConfigObjectType]},
|
||||
ObjectName: privilege[util.RoleConfigObjectName],
|
||||
@ -2193,20 +2178,14 @@ func (c *Core) CreateCredential(ctx context.Context, credInfo *internalpb.Creden
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
// insert to db
|
||||
err := c.meta.AddCredential(ctx, credInfo)
|
||||
if err != nil {
|
||||
ctxLog.Warn("CreateCredential save credential failed", zap.Error(err))
|
||||
if err := c.broadcastAlterUserForCreateCredential(ctx, credInfo); err != nil {
|
||||
ctxLog.Warn("CreateCredential failed", zap.Error(err))
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
if errors.Is(err, errUserAlreadyExists) {
|
||||
return merr.StatusWithErrorCode(errors.Errorf("user already exists: %s", credInfo.Username), commonpb.ErrorCode_CreateCredentialFailure), nil
|
||||
}
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_CreateCredentialFailure), nil
|
||||
}
|
||||
// update proxy's local cache
|
||||
err = c.UpdateCredCache(ctx, credInfo)
|
||||
if err != nil {
|
||||
ctxLog.Warn("CreateCredential add cache failed", zap.Error(err))
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
}
|
||||
ctxLog.Debug("CreateCredential success")
|
||||
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
|
||||
metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
|
||||
@ -2254,21 +2233,12 @@ func (c *Core) UpdateCredential(ctx context.Context, credInfo *internalpb.Creden
|
||||
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
// update data on storage
|
||||
err := c.meta.AlterCredential(ctx, credInfo)
|
||||
if err != nil {
|
||||
ctxLog.Warn("UpdateCredential save credential failed", zap.Error(err))
|
||||
|
||||
if err := c.broadcastAlterUserForUpdateCredential(ctx, credInfo); err != nil {
|
||||
ctxLog.Warn("UpdateCredential append message failed", zap.Error(err))
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_UpdateCredentialFailure), nil
|
||||
}
|
||||
// update proxy's local cache
|
||||
err = c.UpdateCredCache(ctx, credInfo)
|
||||
if err != nil {
|
||||
ctxLog.Warn("UpdateCredential update cache failed", zap.Error(err))
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_UpdateCredentialFailure), nil
|
||||
}
|
||||
ctxLog.Debug("UpdateCredential success")
|
||||
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
|
||||
metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
|
||||
@ -2285,27 +2255,25 @@ func (c *Core) DeleteCredential(ctx context.Context, in *milvuspb.DeleteCredenti
|
||||
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
var status *commonpb.Status
|
||||
defer func() {
|
||||
if status.Code != 0 {
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
|
||||
// user not found will not report to the client to achieve idempotent
|
||||
if err := c.broadcastDropUserForDeleteCredential(ctx, in); err != nil {
|
||||
if errors.Is(err, errUserNotFound) {
|
||||
ctxLog.Info("DeleteCredential user not found, ignored")
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
|
||||
metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
|
||||
return merr.Success(), nil
|
||||
}
|
||||
}()
|
||||
|
||||
err := executeDeleteCredentialTaskSteps(ctx, c, in.Username)
|
||||
if err != nil {
|
||||
errMsg := "fail to execute task when deleting the user"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
status = merr.StatusWithErrorCode(errors.New(errMsg), commonpb.ErrorCode_DeleteCredentialFailure)
|
||||
return status, nil
|
||||
ctxLog.Warn("DeleteCredential append message failed", zap.Error(err))
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_DeleteCredentialFailure), nil
|
||||
}
|
||||
ctxLog.Debug("DeleteCredential success")
|
||||
|
||||
ctxLog.Debug("DeleteCredential success")
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
|
||||
metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
|
||||
metrics.RootCoordNumOfCredentials.Dec()
|
||||
status = merr.Success()
|
||||
return status, nil
|
||||
return merr.Success(), nil
|
||||
}
|
||||
|
||||
// ListCredUsers list all usernames
|
||||
@ -2352,12 +2320,13 @@ func (c *Core) CreateRole(ctx context.Context, in *milvuspb.CreateRoleRequest) (
|
||||
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
entity := in.Entity
|
||||
|
||||
err := c.meta.CreateRole(ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: entity.Name})
|
||||
if err != nil {
|
||||
errMsg := "fail to create role"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
if err := c.broadcastCreateRole(ctx, in); err != nil {
|
||||
ctxLog.Warn("fail to create role", zap.Error(err))
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
if errors.Is(err, errRoleAlreadyExists) {
|
||||
return merr.StatusWithErrorCode(errors.Newf("role [%s] already exists", in.GetEntity()), commonpb.ErrorCode_CreateRoleFailure), nil
|
||||
}
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_CreateRoleFailure), nil
|
||||
}
|
||||
|
||||
@ -2365,7 +2334,6 @@ func (c *Core) CreateRole(ctx context.Context, in *milvuspb.CreateRoleRequest) (
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
|
||||
metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
|
||||
metrics.RootCoordNumOfRoles.Inc()
|
||||
|
||||
return merr.Success(), nil
|
||||
}
|
||||
|
||||
@ -2386,32 +2354,13 @@ 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(ctx, 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))
|
||||
return merr.StatusWithErrorCode(errors.New(errMsg), commonpb.ErrorCode_DropRoleFailure), nil
|
||||
}
|
||||
|
||||
if !in.ForceDrop {
|
||||
grantEntities, err := c.meta.SelectGrant(ctx, util.DefaultTenant, &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: in.RoleName},
|
||||
DbName: "*",
|
||||
})
|
||||
if len(grantEntities) != 0 {
|
||||
errMsg := "fail to drop the role that it has privileges. Use REVOKE API to revoke privileges"
|
||||
ctxLog.Warn(errMsg, zap.Any("grants", grantEntities), zap.Error(err))
|
||||
return merr.StatusWithErrorCode(errors.New(errMsg), commonpb.ErrorCode_DropRoleFailure), nil
|
||||
if err := c.broadcastDropRole(ctx, in); err != nil {
|
||||
ctxLog.Warn("fail to drop role", zap.Error(err))
|
||||
if errors.Is(err, errRoleNotExists) {
|
||||
return merr.StatusWithErrorCode(errors.New("not found the role, maybe the role isn't existed or internal system error"), commonpb.ErrorCode_DropRoleFailure), nil
|
||||
}
|
||||
}
|
||||
err := executeDropRoleTaskSteps(ctx, c, in.RoleName, in.ForceDrop)
|
||||
if err != nil {
|
||||
errMsg := "fail to execute task when dropping the role"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
return merr.StatusWithErrorCode(errors.New(errMsg), commonpb.ErrorCode_DropRoleFailure), nil
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_DropRoleFailure), nil
|
||||
}
|
||||
|
||||
ctxLog.Debug(method+" success", zap.String("role_name", in.RoleName))
|
||||
@ -2438,27 +2387,15 @@ func (c *Core) OperateUserRole(ctx context.Context, in *milvuspb.OperateUserRole
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
if _, err := c.meta.SelectRole(ctx, 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))
|
||||
return merr.StatusWithErrorCode(errors.New(errMsg), commonpb.ErrorCode_OperateUserRoleFailure), nil
|
||||
}
|
||||
if in.Type != milvuspb.OperateUserRoleType_RemoveUserFromRole {
|
||||
if _, err := c.meta.SelectUser(ctx, util.DefaultTenant, &milvuspb.UserEntity{Name: in.Username}, false); err != nil {
|
||||
errMsg := "not found the user, maybe the user isn't existed or internal system error"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
return merr.StatusWithErrorCode(errors.New(errMsg), commonpb.ErrorCode_OperateUserRoleFailure), nil
|
||||
if err := c.broadcastOperateUserRole(ctx, in); err != nil {
|
||||
ctxLog.Warn("fail to operate the user and role", zap.Error(err))
|
||||
if errors.Is(err, errRoleNotExists) {
|
||||
return merr.StatusWithErrorCode(errors.New("not found the role, maybe the role isn't existed or internal system error"), commonpb.ErrorCode_OperateUserRoleFailure), nil
|
||||
}
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperateUserRoleFailure), nil
|
||||
}
|
||||
|
||||
err := executeOperateUserRoleTaskSteps(ctx, c, in)
|
||||
if err != nil {
|
||||
errMsg := "fail to execute task when operate the user and role"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
return merr.StatusWithErrorCode(errors.New(errMsg), commonpb.ErrorCode_OperateUserRoleFailure), nil
|
||||
}
|
||||
|
||||
ctxLog.Debug(method + " success")
|
||||
ctxLog.Info(method + " success")
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
|
||||
metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
|
||||
return merr.Success(), nil
|
||||
@ -2558,14 +2495,14 @@ func (c *Core) SelectUser(ctx context.Context, in *milvuspb.SelectUserRequest) (
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Core) isValidRole(entity *milvuspb.RoleEntity) error {
|
||||
func (c *Core) isValidRole(ctx context.Context, entity *milvuspb.RoleEntity) error {
|
||||
if entity == nil {
|
||||
return errors.New("the role entity is nil")
|
||||
}
|
||||
if entity.Name == "" {
|
||||
return errors.New("the name in the role entity is empty")
|
||||
}
|
||||
if _, err := c.meta.SelectRole(c.ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: entity.Name}, false); err != nil {
|
||||
if _, err := c.meta.SelectRole(ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: entity.Name}, false); err != nil {
|
||||
log.Warn("fail to select the role", zap.String("role_name", entity.Name), zap.Error(err))
|
||||
return errors.New("not found the role, maybe the role isn't existed or internal system error")
|
||||
}
|
||||
@ -2642,36 +2579,11 @@ func (c *Core) OperatePrivilege(ctx context.Context, in *milvuspb.OperatePrivile
|
||||
ctxLog := log.Ctx(ctx).With(zap.String("role", typeutil.RootCoordRole), zap.Any("in", in))
|
||||
ctxLog.Debug(method)
|
||||
|
||||
if err := c.operatePrivilegeCommonCheck(ctx, in); err != nil {
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeFailure), nil
|
||||
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
privName := in.Entity.Grantor.Privilege.Name
|
||||
switch in.Version {
|
||||
case "v2":
|
||||
if err := c.isValidPrivilegeV2(ctx, privName); err != nil {
|
||||
ctxLog.Error("", zap.Error(err))
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeFailure), nil
|
||||
}
|
||||
if err := c.validatePrivilegeGroupParams(ctx, privName, in.Entity.DbName, in.Entity.ObjectName); err != nil {
|
||||
ctxLog.Error("", zap.Error(err))
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeFailure), nil
|
||||
}
|
||||
// set up object type for metastore, to be compatible with v1 version
|
||||
in.Entity.Object.Name = util.GetObjectType(privName)
|
||||
default:
|
||||
if err := c.isValidPrivilege(ctx, privName, in.Entity.Object.Name); err != nil {
|
||||
ctxLog.Error("", zap.Error(err))
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeFailure), nil
|
||||
}
|
||||
// set up object name if it is global object type and not built in privilege group
|
||||
if in.Entity.Object.Name == commonpb.ObjectType_Global.String() && !util.IsBuiltinPrivilegeGroup(in.Entity.Grantor.Privilege.Name) {
|
||||
in.Entity.ObjectName = util.AnyWord
|
||||
}
|
||||
}
|
||||
|
||||
err := executeOperatePrivilegeTaskSteps(ctx, c, in)
|
||||
if err != nil {
|
||||
if err := c.broadcastOperatePrivilege(ctx, in); err != nil {
|
||||
errMsg := "fail to execute task when operating the privilege"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeFailure), nil
|
||||
@ -2684,9 +2596,6 @@ func (c *Core) OperatePrivilege(ctx context.Context, in *milvuspb.OperatePrivile
|
||||
}
|
||||
|
||||
func (c *Core) operatePrivilegeCommonCheck(ctx context.Context, in *milvuspb.OperatePrivilegeRequest) error {
|
||||
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Type != milvuspb.OperatePrivilegeType_Grant && in.Type != milvuspb.OperatePrivilegeType_Revoke {
|
||||
errMsg := fmt.Sprintf("invalid operate privilege type, current type: %s, valid value: [%s, %s]", in.Type, milvuspb.OperatePrivilegeType_Grant, milvuspb.OperatePrivilegeType_Revoke)
|
||||
return errors.New(errMsg)
|
||||
@ -2698,7 +2607,7 @@ func (c *Core) operatePrivilegeCommonCheck(ctx context.Context, in *milvuspb.Ope
|
||||
if err := c.isValidObject(in.Entity.Object); err != nil {
|
||||
return errors.New("the object entity in the request is nil or invalid")
|
||||
}
|
||||
if err := c.isValidRole(in.Entity.Role); err != nil {
|
||||
if err := c.isValidRole(ctx, in.Entity.Role); err != nil {
|
||||
return err
|
||||
}
|
||||
entity := in.Entity.Grantor
|
||||
@ -2798,7 +2707,7 @@ func (c *Core) SelectGrant(ctx context.Context, in *milvuspb.SelectGrantRequest)
|
||||
Status: merr.StatusWithErrorCode(errors.New(errMsg), commonpb.ErrorCode_SelectGrantFailure),
|
||||
}, nil
|
||||
}
|
||||
if err := c.isValidRole(in.Entity.Role); err != nil {
|
||||
if err := c.isValidRole(ctx, in.Entity.Role); err != nil {
|
||||
ctxLog.Warn("", zap.Error(err))
|
||||
return &milvuspb.SelectGrantResponse{
|
||||
Status: merr.StatusWithErrorCode(err, commonpb.ErrorCode_SelectGrantFailure),
|
||||
@ -2939,8 +2848,11 @@ func (c *Core) RestoreRBAC(ctx context.Context, in *milvuspb.RestoreRBACMetaRequ
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
err := executeRestoreRBACTaskSteps(ctx, c, in)
|
||||
if err != nil {
|
||||
if err := c.broadcastRestoreRBACV2(ctx, in); err != nil {
|
||||
if errors.Is(err, errEmptyRBACMeta) {
|
||||
ctxLog.Info("restoring rbac meta is empty, skip restore", zap.Error(err))
|
||||
return merr.Success(), nil
|
||||
}
|
||||
errMsg := "fail to execute task when restore rbac meta data"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeFailure), nil
|
||||
@ -3092,12 +3004,12 @@ func (c *Core) CreatePrivilegeGroup(ctx context.Context, in *milvuspb.CreatePriv
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_CreatePrivilegeGroupFailure), nil
|
||||
}
|
||||
|
||||
if err := c.meta.CreatePrivilegeGroup(ctx, in.GroupName); err != nil {
|
||||
if err := c.broadcastCreatePrivilegeGroup(ctx, in); err != nil {
|
||||
ctxLog.Warn("fail to create privilege group", zap.Error(err))
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_CreatePrivilegeGroupFailure), nil
|
||||
}
|
||||
|
||||
ctxLog.Debug(method + " success")
|
||||
ctxLog.Info(method + " success")
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
|
||||
metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
|
||||
metrics.RootCoordNumOfPrivilegeGroups.Inc()
|
||||
@ -3115,12 +3027,16 @@ func (c *Core) DropPrivilegeGroup(ctx context.Context, in *milvuspb.DropPrivileg
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_DropPrivilegeGroupFailure), nil
|
||||
}
|
||||
|
||||
if err := c.meta.DropPrivilegeGroup(ctx, in.GroupName); err != nil {
|
||||
if err := c.broadcastDropPrivilegeGroup(ctx, in); err != nil {
|
||||
if errors.Is(err, errNotCustomPrivilegeGroup) {
|
||||
ctxLog.Info("privilege group is not custom privilege group, skip drop", zap.Error(err))
|
||||
return merr.Success(), nil
|
||||
}
|
||||
ctxLog.Warn("fail to drop privilege group", zap.Error(err))
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_DropPrivilegeGroupFailure), nil
|
||||
}
|
||||
|
||||
ctxLog.Debug(method + " success")
|
||||
ctxLog.Info(method + " success")
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
|
||||
metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
|
||||
metrics.RootCoordNumOfPrivilegeGroups.Desc()
|
||||
@ -3171,8 +3087,7 @@ func (c *Core) OperatePrivilegeGroup(ctx context.Context, in *milvuspb.OperatePr
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
err := executeOperatePrivilegeGroupTaskSteps(ctx, c, in)
|
||||
if err != nil {
|
||||
if err := c.broadcastOperatePrivilegeGroup(ctx, in); err != nil {
|
||||
errMsg := "fail to execute task when operate privilege group"
|
||||
ctxLog.Warn(errMsg, zap.Error(err))
|
||||
return merr.StatusWithErrorCode(err, commonpb.ErrorCode_OperatePrivilegeGroupFailure), nil
|
||||
|
||||
@ -30,15 +30,22 @@ 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/internal/distributed/streaming"
|
||||
"github.com/milvus-io/milvus/internal/metastore/model"
|
||||
"github.com/milvus-io/milvus/internal/mocks/distributed/mock_streaming"
|
||||
"github.com/milvus-io/milvus/internal/mocks/streamingcoord/server/mock_broadcaster"
|
||||
mockrootcoord "github.com/milvus-io/milvus/internal/rootcoord/mocks"
|
||||
"github.com/milvus-io/milvus/internal/util/proxyutil"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster/broadcast"
|
||||
"github.com/milvus-io/milvus/internal/streamingcoord/server/broadcaster/registry"
|
||||
"github.com/milvus-io/milvus/internal/util/sessionutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/common"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/etcdpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/proxypb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/proto/rootcoordpb"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/util/types"
|
||||
"github.com/milvus-io/milvus/pkg/v2/streaming/walimpls/impls/walimplstest"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
||||
@ -51,15 +58,39 @@ import (
|
||||
func TestMain(m *testing.M) {
|
||||
paramtable.Init()
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
parameters := []string{"tikv", "etcd"}
|
||||
var code int
|
||||
for _, v := range parameters {
|
||||
paramtable.Get().Save(paramtable.Get().MetaStoreCfg.MetaStoreType.Key, v)
|
||||
code = m.Run()
|
||||
}
|
||||
code := m.Run()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
func initStreamingSystem() {
|
||||
t := common.NewEmptyMockT()
|
||||
wal := mock_streaming.NewMockWALAccesser(t)
|
||||
wal.EXPECT().ControlChannel().Return(funcutil.GetControlChannel("by-dev-rootcoord-dml_0"))
|
||||
streaming.SetWALForTest(wal)
|
||||
|
||||
bapi := mock_broadcaster.NewMockBroadcastAPI(t)
|
||||
bapi.EXPECT().Broadcast(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, msg message.BroadcastMutableMessage) (*types.BroadcastAppendResult, error) {
|
||||
results := make(map[string]*message.AppendResult)
|
||||
for _, vchannel := range msg.BroadcastHeader().VChannels {
|
||||
results[vchannel] = &message.AppendResult{
|
||||
MessageID: walimplstest.NewTestMessageID(1),
|
||||
TimeTick: tsoutil.ComposeTSByTime(time.Now(), 0),
|
||||
LastConfirmedMessageID: walimplstest.NewTestMessageID(1),
|
||||
}
|
||||
}
|
||||
registry.CallMessageAckCallback(context.Background(), msg, results)
|
||||
return &types.BroadcastAppendResult{}, nil
|
||||
})
|
||||
bapi.EXPECT().Close().Return()
|
||||
|
||||
mb := mock_broadcaster.NewMockBroadcaster(t)
|
||||
mb.EXPECT().WithResourceKeys(mock.Anything, mock.Anything).Return(bapi, nil)
|
||||
mb.EXPECT().Close().Return()
|
||||
broadcast.Release()
|
||||
broadcast.ResetBroadcaster()
|
||||
broadcast.Register(mb)
|
||||
}
|
||||
|
||||
func TestRootCoord_CreateDatabase(t *testing.T) {
|
||||
t.Run("not healthy", func(t *testing.T) {
|
||||
c := newTestCore(withAbnormalCode())
|
||||
@ -1733,345 +1764,6 @@ func TestRootCoord_DescribeDatabase(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestRootCoord_RBACError(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
c := newTestCore(withHealthyCode(), withInvalidMeta())
|
||||
t.Run("create credential failed", func(t *testing.T) {
|
||||
resp, err := c.CreateCredential(ctx, &internalpb.CredentialInfo{Username: "foo", EncryptedPassword: "bar"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
})
|
||||
t.Run("get credential failed", func(t *testing.T) {
|
||||
resp, err := c.GetCredential(ctx, &rootcoordpb.GetCredentialRequest{Username: "foo"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
})
|
||||
t.Run("update credential failed", func(t *testing.T) {
|
||||
resp, err := c.UpdateCredential(ctx, &internalpb.CredentialInfo{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
})
|
||||
t.Run("delete credential failed", func(t *testing.T) {
|
||||
resp, err := c.DeleteCredential(ctx, &milvuspb.DeleteCredentialRequest{Username: "foo"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
})
|
||||
t.Run("list credential failed", func(t *testing.T) {
|
||||
resp, err := c.ListCredUsers(ctx, &milvuspb.ListCredUsersRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
})
|
||||
t.Run("create role failed", func(t *testing.T) {
|
||||
resp, err := c.CreateRole(ctx, &milvuspb.CreateRoleRequest{Entity: &milvuspb.RoleEntity{Name: "foo"}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
})
|
||||
t.Run("drop role failed", func(t *testing.T) {
|
||||
resp, err := c.DropRole(ctx, &milvuspb.DropRoleRequest{RoleName: "foo"})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
})
|
||||
t.Run("operate user role failed", func(t *testing.T) {
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.SelectRoleFunc = func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
mockMeta.SelectUserFunc = func(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
resp, err := c.OperateUserRole(ctx, &milvuspb.OperateUserRoleRequest{RoleName: "foo", Username: "bar", Type: milvuspb.OperateUserRoleType_AddUserToRole})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
mockMeta.SelectRoleFunc = func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
mockMeta.SelectUserFunc = func(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
})
|
||||
t.Run("select role failed", func(t *testing.T) {
|
||||
{
|
||||
resp, err := c.SelectRole(ctx, &milvuspb.SelectRoleRequest{Role: &milvuspb.RoleEntity{Name: "foo"}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
{
|
||||
resp, err := c.SelectRole(ctx, &milvuspb.SelectRoleRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
})
|
||||
t.Run("select user failed", func(t *testing.T) {
|
||||
{
|
||||
resp, err := c.SelectUser(ctx, &milvuspb.SelectUserRequest{User: &milvuspb.UserEntity{Name: "foo"}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
{
|
||||
resp, err := c.SelectUser(ctx, &milvuspb.SelectUserRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
})
|
||||
t.Run("operate privilege failed", func(t *testing.T) {
|
||||
{
|
||||
resp, err := c.OperatePrivilege(ctx, &milvuspb.OperatePrivilegeRequest{Type: milvuspb.OperatePrivilegeType(100)})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
}
|
||||
{
|
||||
resp, err := c.OperatePrivilege(ctx, &milvuspb.OperatePrivilegeRequest{Type: milvuspb.OperatePrivilegeType_Grant})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
}
|
||||
{
|
||||
resp, err := c.OperatePrivilege(ctx, &milvuspb.OperatePrivilegeRequest{Entity: &milvuspb.GrantEntity{Object: &milvuspb.ObjectEntity{Name: "CollectionErr"}}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
}
|
||||
{
|
||||
resp, err := c.OperatePrivilege(ctx, &milvuspb.OperatePrivilegeRequest{Entity: &milvuspb.GrantEntity{Object: &milvuspb.ObjectEntity{Name: "Collection"}, Role: &milvuspb.RoleEntity{Name: "foo"}}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
}
|
||||
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.SelectRoleFunc = func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
mockMeta.ListPrivilegeGroupsFunc = func(ctx context.Context) ([]*milvuspb.PrivilegeGroupInfo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
{
|
||||
resp, err := c.OperatePrivilege(ctx, &milvuspb.OperatePrivilegeRequest{Entity: &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
User: &milvuspb.UserEntity{Name: "root"},
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: "Insert"},
|
||||
},
|
||||
}, Type: milvuspb.OperatePrivilegeType_Grant})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
}
|
||||
mockMeta.IsCustomPrivilegeGroupFunc = func(ctx context.Context, groupName string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
mockMeta.SelectUserFunc = func(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
resp, err := c.OperatePrivilege(ctx, &milvuspb.OperatePrivilegeRequest{Entity: &milvuspb.GrantEntity{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
Object: &milvuspb.ObjectEntity{Name: "Collection"},
|
||||
ObjectName: "col1",
|
||||
Grantor: &milvuspb.GrantorEntity{
|
||||
User: &milvuspb.UserEntity{Name: "root"},
|
||||
Privilege: &milvuspb.PrivilegeEntity{Name: "Insert"},
|
||||
},
|
||||
}, Type: milvuspb.OperatePrivilegeType_Grant})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.ErrorCode)
|
||||
mockMeta.SelectRoleFunc = func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
mockMeta.SelectUserFunc = func(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("operate privilege group failed", func(t *testing.T) {
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.ListPrivilegeGroupsFunc = func(ctx context.Context) ([]*milvuspb.PrivilegeGroupInfo, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
mockMeta.CreatePrivilegeGroupFunc = func(ctx context.Context, groupName string) error {
|
||||
return errors.New("mock error")
|
||||
}
|
||||
mockMeta.GetPrivilegeGroupRolesFunc = func(ctx context.Context, groupName string) ([]*milvuspb.RoleEntity, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
{
|
||||
resp, err := c.OperatePrivilegeGroup(ctx, &milvuspb.OperatePrivilegeGroupRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetErrorCode())
|
||||
}
|
||||
{
|
||||
resp, err := c.ListPrivilegeGroups(ctx, &milvuspb.ListPrivilegeGroupsRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
{
|
||||
resp, err := c.OperatePrivilegeGroup(ctx, &milvuspb.OperatePrivilegeGroupRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetErrorCode())
|
||||
}
|
||||
{
|
||||
resp, err := c.CreatePrivilegeGroup(ctx, &milvuspb.CreatePrivilegeGroupRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetErrorCode())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("select grant failed", func(t *testing.T) {
|
||||
{
|
||||
resp, err := c.SelectGrant(ctx, &milvuspb.SelectGrantRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
{
|
||||
resp, err := c.SelectGrant(ctx, &milvuspb.SelectGrantRequest{Entity: &milvuspb.GrantEntity{Role: &milvuspb.RoleEntity{Name: "foo"}}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.SelectRoleFunc = func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
{
|
||||
resp, err := c.SelectGrant(ctx, &milvuspb.SelectGrantRequest{Entity: &milvuspb.GrantEntity{Role: &milvuspb.RoleEntity{Name: "foo"}, Object: &milvuspb.ObjectEntity{Name: "CollectionFoo"}}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
{
|
||||
resp, err := c.SelectGrant(ctx, &milvuspb.SelectGrantRequest{Entity: &milvuspb.GrantEntity{Role: &milvuspb.RoleEntity{Name: "foo"}, Object: &milvuspb.ObjectEntity{Name: "Collection"}}})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
mockMeta.SelectRoleFunc = func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("select grant success", func(t *testing.T) {
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.SelectRoleFunc = func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return []*milvuspb.RoleResult{
|
||||
{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
mockMeta.SelectGrantFunc = func(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) {
|
||||
return []*milvuspb.GrantEntity{
|
||||
{
|
||||
Role: &milvuspb.RoleEntity{Name: "foo"},
|
||||
},
|
||||
}, merr.ErrIoKeyNotFound
|
||||
}
|
||||
|
||||
{
|
||||
resp, err := c.SelectGrant(ctx, &milvuspb.SelectGrantRequest{Entity: &milvuspb.GrantEntity{Role: &milvuspb.RoleEntity{Name: "foo"}, Object: &milvuspb.ObjectEntity{Name: "Collection"}, ObjectName: "fir"}})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(resp.GetEntities()))
|
||||
assert.Equal(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
}
|
||||
|
||||
mockMeta.SelectRoleFunc = func(ctx context.Context, tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
|
||||
mockMeta.SelectGrantFunc = func(ctx context.Context, tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) {
|
||||
return nil, errors.New("mock error")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("list policy failed", func(t *testing.T) {
|
||||
resp, err := c.ListPolicy(ctx, &internalpb.ListPolicyRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
|
||||
mockMeta := c.meta.(*mockMetaTable)
|
||||
mockMeta.ListPolicyFunc = func(ctx context.Context, tenant string) ([]*milvuspb.GrantEntity, error) {
|
||||
return []*milvuspb.GrantEntity{{
|
||||
ObjectName: "*",
|
||||
Object: &milvuspb.ObjectEntity{
|
||||
Name: "Global",
|
||||
},
|
||||
Role: &milvuspb.RoleEntity{Name: "role"},
|
||||
Grantor: &milvuspb.GrantorEntity{Privilege: &milvuspb.PrivilegeEntity{Name: "CustomGroup"}},
|
||||
}}, nil
|
||||
}
|
||||
resp, err = c.ListPolicy(ctx, &internalpb.ListPolicyRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
mockMeta.ListPrivilegeGroupsFunc = func(ctx context.Context) ([]*milvuspb.PrivilegeGroupInfo, error) {
|
||||
return []*milvuspb.PrivilegeGroupInfo{
|
||||
{
|
||||
GroupName: "CollectionAdmin",
|
||||
Privileges: []*milvuspb.PrivilegeEntity{{Name: "CreateCollection"}},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
resp, err = c.ListPolicy(ctx, &internalpb.ListPolicyRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
mockMeta.IsCustomPrivilegeGroupFunc = func(ctx context.Context, groupName string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
resp, err = c.ListPolicy(ctx, &internalpb.ListPolicyRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, resp.GetStatus().GetErrorCode())
|
||||
mockMeta.ListPolicyFunc = func(ctx context.Context, tenant string) ([]*milvuspb.GrantEntity, error) {
|
||||
return []*milvuspb.GrantEntity{}, errors.New("mock error")
|
||||
}
|
||||
mockMeta.ListPrivilegeGroupsFunc = func(ctx context.Context) ([]*milvuspb.PrivilegeGroupInfo, error) {
|
||||
return []*milvuspb.PrivilegeGroupInfo{}, errors.New("mock error")
|
||||
}
|
||||
mockMeta.IsCustomPrivilegeGroupFunc = func(ctx context.Context, groupName string) (bool, error) {
|
||||
return false, errors.New("mock error")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error {
|
||||
return nil
|
||||
}
|
||||
mockMeta.OperatePrivilegeFunc = func(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error {
|
||||
return nil
|
||||
}
|
||||
mockMeta.ListPrivilegeGroupsFunc = func(ctx context.Context) ([]*milvuspb.PrivilegeGroupInfo, error) {
|
||||
return nil, 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(ctx context.Context, 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(ctx context.Context, tenant string, entity *milvuspb.RoleEntity) error {
|
||||
return nil
|
||||
}
|
||||
mockMeta.OperatePrivilegeFunc = func(ctx context.Context, 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{}
|
||||
@ -2171,25 +1863,6 @@ func TestCore_BackupRBAC(t *testing.T) {
|
||||
assert.False(t, merr.Ok(resp.GetStatus()))
|
||||
}
|
||||
|
||||
func TestCore_RestoreRBAC(t *testing.T) {
|
||||
meta := mockrootcoord.NewIMetaTable(t)
|
||||
c := newTestCore(withHealthyCode(), withMeta(meta))
|
||||
mockProxyClientManager := proxyutil.NewMockProxyClientManager(t)
|
||||
mockProxyClientManager.EXPECT().RefreshPolicyInfoCache(mock.Anything, mock.Anything).Return(nil).Maybe()
|
||||
c.proxyClientManager = mockProxyClientManager
|
||||
|
||||
meta.EXPECT().RestoreRBAC(mock.Anything, mock.Anything, mock.Anything).Return(nil)
|
||||
resp, err := c.RestoreRBAC(context.Background(), &milvuspb.RestoreRBACMetaRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, merr.Ok(resp))
|
||||
|
||||
meta.ExpectedCalls = nil
|
||||
meta.EXPECT().RestoreRBAC(mock.Anything, mock.Anything, mock.Anything).Return(errors.New("mock error"))
|
||||
resp, err = c.RestoreRBAC(context.Background(), &milvuspb.RestoreRBACMetaRequest{})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, merr.Ok(resp))
|
||||
}
|
||||
|
||||
func TestCore_getMetastorePrivilegeName(t *testing.T) {
|
||||
meta := mockrootcoord.NewIMetaTable(t)
|
||||
c := newTestCore(withHealthyCode(), withMeta(meta))
|
||||
|
||||
@ -259,13 +259,13 @@ message ChannelTimeTickMsg {
|
||||
}
|
||||
|
||||
message CredentialInfo {
|
||||
string username = 1;
|
||||
string username = 1; // not save in metadata.
|
||||
// encrypted by bcrypt (for higher security level)
|
||||
string encrypted_password = 2;
|
||||
string tenant = 3;
|
||||
bool is_super = 4;
|
||||
string tenant = 3 [deprecated=true]; // not used.
|
||||
bool is_super = 4 [deprecated=true]; // not used.
|
||||
// encrypted by sha256 (for good performance in cache mapping)
|
||||
string sha256_password = 5;
|
||||
string sha256_password = 5; // not save in metadata.
|
||||
uint64 time_tick = 6; // the timetick in wal which the credential updates
|
||||
}
|
||||
|
||||
|
||||
@ -2470,14 +2470,16 @@ type CredentialInfo struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` // not save in metadata.
|
||||
// encrypted by bcrypt (for higher security level)
|
||||
EncryptedPassword string `protobuf:"bytes,2,opt,name=encrypted_password,json=encryptedPassword,proto3" json:"encrypted_password,omitempty"`
|
||||
Tenant string `protobuf:"bytes,3,opt,name=tenant,proto3" json:"tenant,omitempty"`
|
||||
IsSuper bool `protobuf:"varint,4,opt,name=is_super,json=isSuper,proto3" json:"is_super,omitempty"`
|
||||
// Deprecated: Marked as deprecated in internal.proto.
|
||||
Tenant string `protobuf:"bytes,3,opt,name=tenant,proto3" json:"tenant,omitempty"` // not used.
|
||||
// Deprecated: Marked as deprecated in internal.proto.
|
||||
IsSuper bool `protobuf:"varint,4,opt,name=is_super,json=isSuper,proto3" json:"is_super,omitempty"` // not used.
|
||||
// encrypted by sha256 (for good performance in cache mapping)
|
||||
Sha256Password string `protobuf:"bytes,5,opt,name=sha256_password,json=sha256Password,proto3" json:"sha256_password,omitempty"`
|
||||
TimeTick uint64 `protobuf:"varint,6,opt,name=time_tick,json=timeTick,proto3" json:"time_tick,omitempty"` // the timetick in wal which the credential updates
|
||||
Sha256Password string `protobuf:"bytes,5,opt,name=sha256_password,json=sha256Password,proto3" json:"sha256_password,omitempty"` // not save in metadata.
|
||||
TimeTick uint64 `protobuf:"varint,6,opt,name=time_tick,json=timeTick,proto3" json:"time_tick,omitempty"` // the timetick in wal which the credential updates
|
||||
}
|
||||
|
||||
func (x *CredentialInfo) Reset() {
|
||||
@ -2526,6 +2528,7 @@ func (x *CredentialInfo) GetEncryptedPassword() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Deprecated: Marked as deprecated in internal.proto.
|
||||
func (x *CredentialInfo) GetTenant() string {
|
||||
if x != nil {
|
||||
return x.Tenant
|
||||
@ -2533,6 +2536,7 @@ func (x *CredentialInfo) GetTenant() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Deprecated: Marked as deprecated in internal.proto.
|
||||
func (x *CredentialInfo) GetIsSuper() bool {
|
||||
if x != nil {
|
||||
return x.IsSuper
|
||||
@ -4485,283 +4489,284 @@ var file_internal_proto_rawDesc = []byte{
|
||||
0x28, 0x04, 0x52, 0x0a, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x12, 0x2b,
|
||||
0x0a, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||
0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x64, 0x65, 0x66, 0x61, 0x75,
|
||||
0x6c, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xd4, 0x01, 0x0a, 0x0e,
|
||||
0x6c, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xdc, 0x01, 0x0a, 0x0e,
|
||||
0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x65, 0x6e,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65,
|
||||
0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x53, 0x75, 0x70, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f,
|
||||
0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x50, 0x61, 0x73,
|
||||
0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69,
|
||||
0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69,
|
||||
0x63, 0x6b, 0x22, 0x45, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x73, 0x67, 0x42,
|
||||
0x61, 0x73, 0x65, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x22, 0xdf, 0x01, 0x0a, 0x12, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f,
|
||||
0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x6f, 0x6c,
|
||||
0x69, 0x63, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72,
|
||||
0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73,
|
||||
0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x76, 0x69,
|
||||
0x6c, 0x65, 0x67, 0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x50, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67,
|
||||
0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x76,
|
||||
0x69, 0x6c, 0x65, 0x67, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x67, 0x0a, 0x19, 0x53,
|
||||
0x68, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x73, 0x67,
|
||||
0x42, 0x61, 0x73, 0x65, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61,
|
||||
0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74,
|
||||
0x74, 0x65, 0x72, 0x6e, 0x22, 0x9a, 0x01, 0x0a, 0x1a, 0x53, 0x68, 0x6f, 0x77, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61,
|
||||
0x69, 0x72, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x22, 0x45, 0x0a, 0x04, 0x52, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x0a, 0x02, 0x72, 0x74, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x52, 0x61,
|
||||
0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x02, 0x72, 0x74, 0x12, 0x0c, 0x0a, 0x01, 0x72, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x01, 0x72, 0x22, 0x32, 0x0a, 0x0a, 0x49, 0x6d, 0x70, 0x6f,
|
||||
0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18,
|
||||
0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x22, 0xb7, 0x03, 0x0a,
|
||||
0x15, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x04, 0x64, 0x62, 0x49, 0x44, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01, 0x52, 0x04, 0x64, 0x62, 0x49, 0x44, 0x12, 0x22,
|
||||
0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x44, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x70,
|
||||
0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28,
|
||||
0x03, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12,
|
||||
0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73,
|
||||
0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e,
|
||||
0x61, 0x6d, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68,
|
||||
0x65, 0x6d, 0x61, 0x12, 0x37, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x07,
|
||||
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e,
|
||||
0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x06, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x74,
|
||||
0x65, 0x6e, 0x61, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x73, 0x75, 0x70, 0x65,
|
||||
0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x07, 0x69, 0x73, 0x53,
|
||||
0x75, 0x70, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x68, 0x61, 0x32, 0x35, 0x36, 0x5f, 0x70,
|
||||
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73,
|
||||
0x68, 0x61, 0x32, 0x35, 0x36, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x1b, 0x0a,
|
||||
0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x69, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04,
|
||||
0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x22, 0x45, 0x0a, 0x11, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x30, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
|
||||
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72,
|
||||
0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74,
|
||||
0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28,
|
||||
0x04, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0xee, 0x01, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61,
|
||||
0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x37, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x46,
|
||||
0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x6f, 0x70,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69,
|
||||
0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
|
||||
0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x07,
|
||||
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5b, 0x0a, 0x0e, 0x49, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
|
||||
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a,
|
||||
0x6f, 0x62, 0x49, 0x44, 0x22, 0x49, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62,
|
||||
0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x22,
|
||||
0x81, 0x02, 0x0a, 0x12, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x50, 0x72,
|
||||
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67,
|
||||
0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67,
|
||||
0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65,
|
||||
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6d,
|
||||
0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61,
|
||||
0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12,
|
||||
0x23, 0x0a, 0x0d, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x77, 0x73,
|
||||
0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64,
|
||||
0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x6f,
|
||||
0x77, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52,
|
||||
0x6f, 0x77, 0x73, 0x22, 0xc6, 0x03, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06,
|
||||
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x49, 0x6d,
|
||||
0x70, 0x6f, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74,
|
||||
0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70,
|
||||
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70,
|
||||
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65,
|
||||
0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d,
|
||||
0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74,
|
||||
0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x52, 0x0a, 0x0f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x70, 0x72,
|
||||
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29,
|
||||
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73,
|
||||
0x6b, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x50,
|
||||
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6d, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0c, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x09, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x54, 0x0a, 0x1a,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62,
|
||||
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x64, 0x62, 0x49, 0x44, 0x12, 0x22,
|
||||
0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x44, 0x22, 0x56, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x86, 0x02, 0x0a, 0x13, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
|
||||
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x49, 0x44,
|
||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x73, 0x12,
|
||||
0x3d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32,
|
||||
0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69,
|
||||
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4a, 0x6f,
|
||||
0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x07, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x72,
|
||||
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61,
|
||||
0x6d, 0x65, 0x73, 0x22, 0x74, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e,
|
||||
0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a,
|
||||
0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64,
|
||||
0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x67,
|
||||
0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0a, 0x73,
|
||||
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x73, 0x22, 0x3f, 0x0a, 0x0b, 0x46, 0x69, 0x65,
|
||||
0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x65, 0x6c,
|
||||
0x64, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x66, 0x69, 0x65, 0x6c, 0x64,
|
||||
0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f, 0x67, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x03, 0x52, 0x06, 0x6c, 0x6f, 0x67, 0x49, 0x44, 0x73, 0x22, 0x82, 0x04, 0x0a, 0x0b, 0x53,
|
||||
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65,
|
||||
0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73,
|
||||
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c,
|
||||
0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b,
|
||||
0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x76, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x76, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75,
|
||||
0x6d, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75,
|
||||
0x6d, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x37, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x37,
|
||||
0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e,
|
||||
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c,
|
||||
0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x73, 0x6f,
|
||||
0x72, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x53, 0x6f,
|
||||
0x72, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x6c,
|
||||
0x6f, 0x67, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
|
||||
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
|
||||
0x6c, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x0a, 0x69,
|
||||
0x6e, 0x73, 0x65, 0x72, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x64, 0x65, 0x6c,
|
||||
0x74, 0x61, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e,
|
||||
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f,
|
||||
0x67, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x41, 0x0a, 0x0a,
|
||||
0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69,
|
||||
0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x09, 0x73, 0x74, 0x61, 0x74, 0x73, 0x4c, 0x6f, 0x67, 0x73, 0x22,
|
||||
0x96, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73,
|
||||
0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x73, 0x67, 0x42, 0x61, 0x73, 0x65, 0x52, 0x04, 0x62, 0x61, 0x73,
|
||||
0x65, 0x22, 0xdf, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75,
|
||||
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a,
|
||||
0x0c, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x02, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x73,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x03,
|
||||
0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12,
|
||||
0x52, 0x0a, 0x10, 0x70, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x5f, 0x67, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
|
||||
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
|
||||
0x50, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x0f, 0x70, 0x72, 0x69, 0x76, 0x69, 0x6c, 0x65, 0x67, 0x65, 0x47, 0x72, 0x6f,
|
||||
0x75, 0x70, 0x73, 0x22, 0x67, 0x0a, 0x19, 0x53, 0x68, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x30, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
|
||||
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x73, 0x67, 0x42, 0x61, 0x73, 0x65, 0x52, 0x04, 0x62, 0x61,
|
||||
0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x22, 0x9a, 0x01, 0x0a,
|
||||
0x1a, 0x53, 0x68, 0x6f, 0x77, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69,
|
||||
0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f,
|
||||
0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x12, 0x46, 0x0a, 0x0c, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x73,
|
||||
0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x53,
|
||||
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x73, 0x65, 0x67, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x22, 0x4a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x51,
|
||||
0x75, 0x6f, 0x74, 0x61, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x73, 0x67, 0x42, 0x61, 0x73, 0x65, 0x52, 0x04,
|
||||
0x62, 0x61, 0x73, 0x65, 0x22, 0x71, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61,
|
||||
0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f,
|
||||
0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x74, 0x72,
|
||||
0x69, 0x63, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x2a, 0x45, 0x0a, 0x09, 0x52, 0x61, 0x74, 0x65, 0x53,
|
||||
0x63, 0x6f, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x10,
|
||||
0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x10, 0x01, 0x12,
|
||||
0x0e, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x02, 0x12,
|
||||
0x0d, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x03, 0x2a, 0xc4,
|
||||
0x01, 0x0a, 0x08, 0x52, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x44,
|
||||
0x44, 0x4c, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x00, 0x12, 0x10,
|
||||
0x0a, 0x0c, 0x44, 0x44, 0x4c, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x01,
|
||||
0x12, 0x0c, 0x0a, 0x08, 0x44, 0x44, 0x4c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x10, 0x02, 0x12, 0x0c,
|
||||
0x0a, 0x08, 0x44, 0x44, 0x4c, 0x46, 0x6c, 0x75, 0x73, 0x68, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d,
|
||||
0x44, 0x44, 0x4c, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x04, 0x12,
|
||||
0x0d, 0x0a, 0x09, 0x44, 0x4d, 0x4c, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x10, 0x05, 0x12, 0x0d,
|
||||
0x0a, 0x09, 0x44, 0x4d, 0x4c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x10, 0x06, 0x12, 0x0f, 0x0a,
|
||||
0x0b, 0x44, 0x4d, 0x4c, 0x42, 0x75, 0x6c, 0x6b, 0x4c, 0x6f, 0x61, 0x64, 0x10, 0x07, 0x12, 0x0d,
|
||||
0x0a, 0x09, 0x44, 0x51, 0x4c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x10, 0x08, 0x12, 0x0c, 0x0a,
|
||||
0x08, 0x44, 0x51, 0x4c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x10, 0x09, 0x12, 0x0d, 0x0a, 0x09, 0x44,
|
||||
0x4d, 0x4c, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x10, 0x0a, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x44,
|
||||
0x4c, 0x44, 0x42, 0x10, 0x0b, 0x2a, 0x83, 0x01, 0x0a, 0x0e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74,
|
||||
0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65,
|
||||
0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x10, 0x01, 0x12,
|
||||
0x10, 0x0a, 0x0c, 0x50, 0x72, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x10,
|
||||
0x02, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x10, 0x03,
|
||||
0x12, 0x0a, 0x0a, 0x06, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09,
|
||||
0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x49,
|
||||
0x6e, 0x64, 0x65, 0x78, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x69, 0x6e, 0x67, 0x10, 0x06, 0x12, 0x0b,
|
||||
0x0a, 0x07, 0x53, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x10, 0x07, 0x42, 0x35, 0x5a, 0x33, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73,
|
||||
0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x76,
|
||||
0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
||||
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x12, 0x47, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65,
|
||||
0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x45, 0x0a, 0x04, 0x52, 0x61, 0x74,
|
||||
0x65, 0x12, 0x2f, 0x0a, 0x02, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e,
|
||||
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x02,
|
||||
0x72, 0x74, 0x12, 0x0c, 0x0a, 0x01, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x01, 0x72,
|
||||
0x22, 0x32, 0x0a, 0x0a, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x0e,
|
||||
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70,
|
||||
0x61, 0x74, 0x68, 0x73, 0x22, 0xb7, 0x03, 0x0a, 0x15, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x16,
|
||||
0x0a, 0x04, 0x64, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x42, 0x02, 0x18, 0x01,
|
||||
0x52, 0x04, 0x64, 0x62, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x44, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0c, 0x70, 0x61, 0x72, 0x74, 0x69,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e,
|
||||
0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c,
|
||||
0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x3d, 0x0a, 0x06,
|
||||
0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6d,
|
||||
0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x63, 0x68, 0x65,
|
||||
0x6d, 0x61, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68,
|
||||
0x65, 0x6d, 0x61, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x37, 0x0a, 0x05, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c,
|
||||
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6c, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
|
||||
0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x56,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||
0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49,
|
||||
0x44, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0xee,
|
||||
0x01, 0x0a, 0x0d, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x74,
|
||||
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x66, 0x69, 0x6c,
|
||||
0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75,
|
||||
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
||||
0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c,
|
||||
0x65, 0x73, 0x12, 0x3b, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22,
|
||||
0x5b, 0x0a, 0x0e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06,
|
||||
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0x49, 0x0a, 0x18,
|
||||
0x47, 0x65, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x22, 0x81, 0x02, 0x0a, 0x12, 0x49, 0x6d, 0x70, 0x6f,
|
||||
0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1b,
|
||||
0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08,
|
||||
0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73,
|
||||
0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
|
||||
0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d,
|
||||
0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x69, 0x6d,
|
||||
0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c,
|
||||
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a, 0x0a,
|
||||
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x6f, 0x77, 0x73, 0x22, 0xc6, 0x03, 0x0a, 0x19,
|
||||
0x47, 0x65, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
|
||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76,
|
||||
0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e,
|
||||
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x3b,
|
||||
0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e,
|
||||
0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72,
|
||||
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61,
|
||||
0x73, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12,
|
||||
0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x70,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0c, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x52, 0x0a,
|
||||
0x0f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73,
|
||||
0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x49,
|
||||
0x6d, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73,
|
||||
0x73, 0x52, 0x0e, 0x74, 0x61, 0x73, 0x6b, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65,
|
||||
0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x6f,
|
||||
0x77, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74,
|
||||
0x65, 0x64, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
|
||||
0x72, 0x6f, 0x77, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61,
|
||||
0x6c, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x22, 0x54, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6f,
|
||||
0x72, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x04, 0x64, 0x62, 0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x22, 0x56, 0x0a, 0x12, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61,
|
||||
0x6d, 0x65, 0x22, 0x86, 0x02, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72,
|
||||
0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c,
|
||||
0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
||||
0x16, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x06, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x73, 0x12, 0x3d, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e,
|
||||
0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x06,
|
||||
0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
|
||||
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x73,
|
||||
0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x05,
|
||||
0x20, 0x03, 0x28, 0x03, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73,
|
||||
0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x74, 0x0a, 0x16, 0x47,
|
||||
0x65, 0x74, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a,
|
||||
0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
|
||||
0x44, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x73, 0x18,
|
||||
0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0a, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44,
|
||||
0x73, 0x22, 0x3f, 0x0a, 0x0b, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x07, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f,
|
||||
0x67, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x06, 0x6c, 0x6f, 0x67, 0x49,
|
||||
0x44, 0x73, 0x22, 0x82, 0x04, 0x0a, 0x0b, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44,
|
||||
0x12, 0x22, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x43, 0x68, 0x61, 0x6e, 0x6e,
|
||||
0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x43, 0x68, 0x61, 0x6e, 0x6e,
|
||||
0x65, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6e, 0x75, 0x6d, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6e, 0x75, 0x6d, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x37, 0x0a,
|
||||
0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x6d,
|
||||
0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52,
|
||||
0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18,
|
||||
0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x67, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12,
|
||||
0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x73, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x53, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x0b,
|
||||
0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42,
|
||||
0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x4c, 0x6f, 0x67,
|
||||
0x73, 0x12, 0x41, 0x0a, 0x0a, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18,
|
||||
0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x46, 0x69,
|
||||
0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x74, 0x61,
|
||||
0x4c, 0x6f, 0x67, 0x73, 0x12, 0x41, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x73, 0x5f, 0x6c, 0x6f,
|
||||
0x67, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75,
|
||||
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
||||
0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x42, 0x69, 0x6e, 0x6c, 0x6f, 0x67, 0x52, 0x09, 0x73, 0x74,
|
||||
0x61, 0x74, 0x73, 0x4c, 0x6f, 0x67, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x53,
|
||||
0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x46, 0x0a, 0x0c, 0x73, 0x65, 0x67, 0x6d,
|
||||
0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22,
|
||||
0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x69, 0x6e,
|
||||
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x52, 0x0c, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x73,
|
||||
0x22, 0x4a, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x4d, 0x65, 0x74, 0x72,
|
||||
0x69, 0x63, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x62, 0x61,
|
||||
0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75,
|
||||
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d,
|
||||
0x73, 0x67, 0x42, 0x61, 0x73, 0x65, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x22, 0x71, 0x0a, 0x17,
|
||||
0x47, 0x65, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x0c,
|
||||
0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0b, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x2a,
|
||||
0x45, 0x0a, 0x09, 0x52, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07,
|
||||
0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x61, 0x74,
|
||||
0x61, 0x62, 0x61, 0x73, 0x65, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x10, 0x03, 0x2a, 0xc4, 0x01, 0x0a, 0x08, 0x52, 0x61, 0x74, 0x65, 0x54,
|
||||
0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x44, 0x4c, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x44, 0x4c, 0x50, 0x61, 0x72,
|
||||
0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x44, 0x4c, 0x49,
|
||||
0x6e, 0x64, 0x65, 0x78, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x44, 0x4c, 0x46, 0x6c, 0x75,
|
||||
0x73, 0x68, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x44, 0x4c, 0x43, 0x6f, 0x6d, 0x70, 0x61,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x4d, 0x4c, 0x49, 0x6e,
|
||||
0x73, 0x65, 0x72, 0x74, 0x10, 0x05, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x4d, 0x4c, 0x44, 0x65, 0x6c,
|
||||
0x65, 0x74, 0x65, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x4d, 0x4c, 0x42, 0x75, 0x6c, 0x6b,
|
||||
0x4c, 0x6f, 0x61, 0x64, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x51, 0x4c, 0x53, 0x65, 0x61,
|
||||
0x72, 0x63, 0x68, 0x10, 0x08, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x51, 0x4c, 0x51, 0x75, 0x65, 0x72,
|
||||
0x79, 0x10, 0x09, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x4d, 0x4c, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74,
|
||||
0x10, 0x0a, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x44, 0x4c, 0x44, 0x42, 0x10, 0x0b, 0x2a, 0x83, 0x01,
|
||||
0x0a, 0x0e, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65,
|
||||
0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x65,
|
||||
0x6e, 0x64, 0x69, 0x6e, 0x67, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x72, 0x65, 0x49, 0x6d,
|
||||
0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x49, 0x6d, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x61, 0x69, 0x6c,
|
||||
0x65, 0x64, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65,
|
||||
0x64, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x75, 0x69, 0x6c,
|
||||
0x64, 0x69, 0x6e, 0x67, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x6f, 0x72, 0x74, 0x69, 0x6e,
|
||||
0x67, 0x10, 0x07, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x6d, 0x69, 0x6c, 0x76, 0x75, 0x73, 0x2d, 0x69, 0x6f, 0x2f, 0x6d, 0x69, 0x6c, 0x76,
|
||||
0x75, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
|
||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user