mirror of
https://github.com/milvus-io/milvus.git
synced 2026-07-21 10:15:43 +00:00
feat: [RBAC] support user description in credentials (#50186)
- Wire credential descriptions through create/update/read paths, including proxy, HTTP v2, Go SDK options, length validation, optional update presence handling, and internal credential proto/model persistence. - Preserve existing encrypted passwords and descriptions during RootCoord credential updates when either field is omitted, reject all-empty or partial direct password updates, and keep sha256 passwords cache-only. - Skip auth-cache refresh for description-only credential updates so existing authentication state is not blanked, while still refreshing caches for password updates. - Return persisted user descriptions from select_user and HTTP v2 describe_user, including include_role_info=false, and reuse already-loaded credential rows in user listing and RBAC backup to avoid duplicate etcd reads while ignoring malformed credential keys. - Use the upstream milvus-proto go-api/v3 version that includes the credential description proto change; the temporary fork replaces in root, pkg, client, and tests/go_client modules have been removed. design doc: docs/design-docs/design_docs/20260601-rbac-user-description.md related: #50179 --------- Signed-off-by: shaoting-huang <shaoting.huang@zilliz.com>
This commit is contained in:
+1
-1
@@ -30,4 +30,4 @@ unittest:
|
||||
|
||||
generate-mockery:
|
||||
@echo "Generating mockery Milvus service server"
|
||||
@../bin/mockery --srcpkg=github.com/milvus-io/milvus-proto/go-api/v2/milvuspb --name=MilvusServiceServer --filename=mock_milvus_server_test.go --output=milvusclient --outpkg=milvusclient --with-expecter
|
||||
@../bin/mockery --srcpkg=github.com/milvus-io/milvus-proto/go-api/v3/milvuspb --name=MilvusServiceServer --filename=mock_milvus_server_test.go --output=milvusclient --outpkg=milvusclient --with-expecter
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
package entity
|
||||
|
||||
type User struct {
|
||||
UserName string
|
||||
Roles []string
|
||||
UserName string
|
||||
Roles []string
|
||||
Description string
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ require (
|
||||
github.com/cockroachdb/errors v1.9.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e
|
||||
github.com/milvus-io/milvus/pkg/v3 v3.0.0-beta
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.23
|
||||
github.com/samber/lo v1.52.0
|
||||
|
||||
+2
-2
@@ -222,8 +222,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f h1:W+paUzc+AA381Rydx2DJffoQuM4l+efVqO+2i9GdfMw=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f/go.mod h1:rbKpv5JToISTKTTLl0duL5r6wbYnjJ9SsD0QgXMzKy0=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e h1:axPnOhjsWqqxk0dOQRSIU2mdg52Kyl/8E6iDFZy/IpE=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e/go.mod h1:rbKpv5JToISTKTTLl0duL5r6wbYnjJ9SsD0QgXMzKy0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
||||
@@ -6,11 +6,8 @@ import (
|
||||
context "context"
|
||||
|
||||
commonpb "github.com/milvus-io/milvus-proto/go-api/v3/commonpb"
|
||||
|
||||
federpb "github.com/milvus-io/milvus-proto/go-api/v3/federpb"
|
||||
|
||||
milvuspb "github.com/milvus-io/milvus-proto/go-api/v3/milvuspb"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
@@ -794,6 +791,65 @@ func (_c *MilvusServiceServer_AlterIndex_Call) RunAndReturn(run func(context.Con
|
||||
return _c
|
||||
}
|
||||
|
||||
// AlterRole provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MilvusServiceServer) AlterRole(_a0 context.Context, _a1 *milvuspb.AlterRoleRequest) (*commonpb.Status, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for AlterRole")
|
||||
}
|
||||
|
||||
var r0 *commonpb.Status
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AlterRoleRequest) (*commonpb.Status, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AlterRoleRequest) *commonpb.Status); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*commonpb.Status)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.AlterRoleRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MilvusServiceServer_AlterRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AlterRole'
|
||||
type MilvusServiceServer_AlterRole_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// AlterRole is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *milvuspb.AlterRoleRequest
|
||||
func (_e *MilvusServiceServer_Expecter) AlterRole(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_AlterRole_Call {
|
||||
return &MilvusServiceServer_AlterRole_Call{Call: _e.mock.On("AlterRole", _a0, _a1)}
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_AlterRole_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.AlterRoleRequest)) *MilvusServiceServer_AlterRole_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.AlterRoleRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_AlterRole_Call) Return(_a0 *commonpb.Status, _a1 error) *MilvusServiceServer_AlterRole_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_AlterRole_Call) RunAndReturn(run func(context.Context, *milvuspb.AlterRoleRequest) (*commonpb.Status, error)) *MilvusServiceServer_AlterRole_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// BackupRBAC provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MilvusServiceServer) BackupRBAC(_a0 context.Context, _a1 *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
@@ -3247,6 +3303,65 @@ func (_c *MilvusServiceServer_DumpMessages_Call) RunAndReturn(run func(*milvuspb
|
||||
return _c
|
||||
}
|
||||
|
||||
// ExportSnapshot provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MilvusServiceServer) ExportSnapshot(_a0 context.Context, _a1 *milvuspb.ExportSnapshotRequest) (*milvuspb.ExportSnapshotResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ExportSnapshot")
|
||||
}
|
||||
|
||||
var r0 *milvuspb.ExportSnapshotResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.ExportSnapshotRequest) (*milvuspb.ExportSnapshotResponse, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.ExportSnapshotRequest) *milvuspb.ExportSnapshotResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*milvuspb.ExportSnapshotResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.ExportSnapshotRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MilvusServiceServer_ExportSnapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExportSnapshot'
|
||||
type MilvusServiceServer_ExportSnapshot_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ExportSnapshot is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *milvuspb.ExportSnapshotRequest
|
||||
func (_e *MilvusServiceServer_Expecter) ExportSnapshot(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_ExportSnapshot_Call {
|
||||
return &MilvusServiceServer_ExportSnapshot_Call{Call: _e.mock.On("ExportSnapshot", _a0, _a1)}
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_ExportSnapshot_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.ExportSnapshotRequest)) *MilvusServiceServer_ExportSnapshot_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.ExportSnapshotRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_ExportSnapshot_Call) Return(_a0 *milvuspb.ExportSnapshotResponse, _a1 error) *MilvusServiceServer_ExportSnapshot_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_ExportSnapshot_Call) RunAndReturn(run func(context.Context, *milvuspb.ExportSnapshotRequest) (*milvuspb.ExportSnapshotResponse, error)) *MilvusServiceServer_ExportSnapshot_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Flush provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MilvusServiceServer) Flush(_a0 context.Context, _a1 *milvuspb.FlushRequest) (*milvuspb.FlushResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
@@ -6787,6 +6902,65 @@ func (_c *MilvusServiceServer_ReplicateMessage_Call) RunAndReturn(run func(conte
|
||||
return _c
|
||||
}
|
||||
|
||||
// RestoreExternalSnapshot provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MilvusServiceServer) RestoreExternalSnapshot(_a0 context.Context, _a1 *milvuspb.RestoreExternalSnapshotRequest) (*milvuspb.RestoreExternalSnapshotResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RestoreExternalSnapshot")
|
||||
}
|
||||
|
||||
var r0 *milvuspb.RestoreExternalSnapshotResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreExternalSnapshotRequest) (*milvuspb.RestoreExternalSnapshotResponse, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreExternalSnapshotRequest) *milvuspb.RestoreExternalSnapshotResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*milvuspb.RestoreExternalSnapshotResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.RestoreExternalSnapshotRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MilvusServiceServer_RestoreExternalSnapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestoreExternalSnapshot'
|
||||
type MilvusServiceServer_RestoreExternalSnapshot_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RestoreExternalSnapshot is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *milvuspb.RestoreExternalSnapshotRequest
|
||||
func (_e *MilvusServiceServer_Expecter) RestoreExternalSnapshot(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_RestoreExternalSnapshot_Call {
|
||||
return &MilvusServiceServer_RestoreExternalSnapshot_Call{Call: _e.mock.On("RestoreExternalSnapshot", _a0, _a1)}
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_RestoreExternalSnapshot_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.RestoreExternalSnapshotRequest)) *MilvusServiceServer_RestoreExternalSnapshot_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.RestoreExternalSnapshotRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_RestoreExternalSnapshot_Call) Return(_a0 *milvuspb.RestoreExternalSnapshotResponse, _a1 error) *MilvusServiceServer_RestoreExternalSnapshot_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MilvusServiceServer_RestoreExternalSnapshot_Call) RunAndReturn(run func(context.Context, *milvuspb.RestoreExternalSnapshotRequest) (*milvuspb.RestoreExternalSnapshotResponse, error)) *MilvusServiceServer_RestoreExternalSnapshot_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RestoreRBAC provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MilvusServiceServer) RestoreRBAC(_a0 context.Context, _a1 *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
@@ -53,8 +53,9 @@ func (c *Client) DescribeUser(ctx context.Context, opt DescribeUserOption, callO
|
||||
}
|
||||
result := resp.GetResults()[0]
|
||||
user = &entity.User{
|
||||
UserName: result.GetUser().GetName(),
|
||||
Roles: lo.Map(result.GetRoles(), func(r *milvuspb.RoleEntity, _ int) string { return r.GetName() }),
|
||||
UserName: result.GetUser().GetName(),
|
||||
Roles: lo.Map(result.GetRoles(), func(r *milvuspb.RoleEntity, _ int) string { return r.GetName() }),
|
||||
Description: result.GetDescription(),
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -67,14 +67,16 @@ type CreateUserOption interface {
|
||||
}
|
||||
|
||||
type createUserOption struct {
|
||||
userName string
|
||||
password string
|
||||
userName string
|
||||
password string
|
||||
description *string
|
||||
}
|
||||
|
||||
func (opt *createUserOption) Request() *milvuspb.CreateCredentialRequest {
|
||||
return &milvuspb.CreateCredentialRequest{
|
||||
Username: opt.userName,
|
||||
Password: crypto.Base64Encode(opt.password),
|
||||
Username: opt.userName,
|
||||
Password: crypto.Base64Encode(opt.password),
|
||||
Description: opt.description,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +87,11 @@ func NewCreateUserOption(userName, password string) *createUserOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (opt *createUserOption) WithDescription(description string) *createUserOption {
|
||||
opt.description = &description
|
||||
return opt
|
||||
}
|
||||
|
||||
type UpdatePasswordOption interface {
|
||||
Request() *milvuspb.UpdateCredentialRequest
|
||||
}
|
||||
@@ -93,6 +100,7 @@ type updatePasswordOption struct {
|
||||
userName string
|
||||
oldPassword string
|
||||
newPassword string
|
||||
description *string
|
||||
}
|
||||
|
||||
func (opt *updatePasswordOption) Request() *milvuspb.UpdateCredentialRequest {
|
||||
@@ -100,6 +108,7 @@ func (opt *updatePasswordOption) Request() *milvuspb.UpdateCredentialRequest {
|
||||
Username: opt.userName,
|
||||
OldPassword: crypto.Base64Encode(opt.oldPassword),
|
||||
NewPassword: crypto.Base64Encode(opt.newPassword),
|
||||
Description: opt.description,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +120,11 @@ func NewUpdatePasswordOption(userName, oldPassword, newPassword string) *updateP
|
||||
}
|
||||
}
|
||||
|
||||
func (opt *updatePasswordOption) WithDescription(description string) *updatePasswordOption {
|
||||
opt.description = &description
|
||||
return opt
|
||||
}
|
||||
|
||||
type DropUserOption interface {
|
||||
Request() *milvuspb.DeleteCredentialRequest
|
||||
}
|
||||
|
||||
@@ -65,12 +65,14 @@ func (s *UserSuite) TestDescribeUser() {
|
||||
userName := fmt.Sprintf("user_%s", s.randString(5))
|
||||
|
||||
s.Run("success", func() {
|
||||
description := "go sdk user description"
|
||||
s.mock.EXPECT().SelectUser(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, r *milvuspb.SelectUserRequest) (*milvuspb.SelectUserResponse, error) {
|
||||
s.Equal(userName, r.GetUser().GetName())
|
||||
return &milvuspb.SelectUserResponse{
|
||||
Results: []*milvuspb.UserResult{
|
||||
{
|
||||
User: &milvuspb.UserEntity{Name: userName},
|
||||
User: &milvuspb.UserEntity{Name: userName},
|
||||
Description: description,
|
||||
Roles: []*milvuspb.RoleEntity{
|
||||
{Name: "role1"},
|
||||
{Name: "role2"},
|
||||
@@ -84,6 +86,7 @@ func (s *UserSuite) TestDescribeUser() {
|
||||
s.NoError(err)
|
||||
s.Equal(userName, user.UserName)
|
||||
s.Equal([]string{"role1", "role2"}, user.Roles)
|
||||
s.Equal(description, user.Description)
|
||||
})
|
||||
|
||||
s.Run("failure", func() {
|
||||
@@ -101,13 +104,15 @@ func (s *UserSuite) TestCreateUser() {
|
||||
s.Run("success", func() {
|
||||
userName := fmt.Sprintf("user_%s", s.randString(5))
|
||||
password := s.randString(12)
|
||||
description := "go sdk create description"
|
||||
s.mock.EXPECT().CreateCredential(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ccr *milvuspb.CreateCredentialRequest) (*commonpb.Status, error) {
|
||||
s.Equal(userName, ccr.GetUsername())
|
||||
s.Equal(crypto.Base64Encode(password), ccr.GetPassword())
|
||||
s.Equal(description, ccr.GetDescription())
|
||||
return merr.Success(), nil
|
||||
}).Once()
|
||||
|
||||
err := s.client.CreateUser(ctx, NewCreateUserOption(userName, password))
|
||||
err := s.client.CreateUser(ctx, NewCreateUserOption(userName, password).WithDescription(description))
|
||||
s.NoError(err)
|
||||
})
|
||||
}
|
||||
@@ -120,14 +125,31 @@ func (s *UserSuite) TestUpdatePassword() {
|
||||
userName := fmt.Sprintf("user_%s", s.randString(5))
|
||||
oldPassword := s.randString(12)
|
||||
newPassword := s.randString(12)
|
||||
description := "go sdk update description"
|
||||
s.mock.EXPECT().UpdateCredential(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ucr *milvuspb.UpdateCredentialRequest) (*commonpb.Status, error) {
|
||||
s.Equal(userName, ucr.GetUsername())
|
||||
s.Equal(crypto.Base64Encode(oldPassword), ucr.GetOldPassword())
|
||||
s.Equal(crypto.Base64Encode(newPassword), ucr.GetNewPassword())
|
||||
s.Equal(description, ucr.GetDescription())
|
||||
return merr.Success(), nil
|
||||
}).Once()
|
||||
|
||||
err := s.client.UpdatePassword(ctx, NewUpdatePasswordOption(userName, oldPassword, newPassword))
|
||||
err := s.client.UpdatePassword(ctx, NewUpdatePasswordOption(userName, oldPassword, newPassword).WithDescription(description))
|
||||
s.NoError(err)
|
||||
})
|
||||
|
||||
s.Run("description only", func() {
|
||||
userName := fmt.Sprintf("user_%s", s.randString(5))
|
||||
description := "go sdk description only update"
|
||||
s.mock.EXPECT().UpdateCredential(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, ucr *milvuspb.UpdateCredentialRequest) (*commonpb.Status, error) {
|
||||
s.Equal(userName, ucr.GetUsername())
|
||||
s.Empty(ucr.GetOldPassword())
|
||||
s.Empty(ucr.GetNewPassword())
|
||||
s.Equal(description, ucr.GetDescription())
|
||||
return merr.Success(), nil
|
||||
}).Once()
|
||||
|
||||
err := s.client.UpdatePassword(ctx, NewUpdatePasswordOption(userName, "", "").WithDescription(description))
|
||||
s.NoError(err)
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
# MEP: RBAC User Description
|
||||
|
||||
- **Created:** 2026-06-01
|
||||
- **Author(s):** @shaoting-huang
|
||||
- **Status:** Under Review
|
||||
- **Component:** Proxy | Coordinator
|
||||
- **Related Issues:** #50179
|
||||
- **Released:** Milvus release version, if applicable
|
||||
|
||||
## Summary
|
||||
|
||||
Milvus RBAC users can carry an optional human-readable description. The field is
|
||||
accepted on user creation, returned by user read APIs, and can be edited through
|
||||
the existing credential update API without requiring a password change.
|
||||
|
||||
**GitHub Issue**: https://github.com/milvus-io/milvus/issues/50179
|
||||
|
||||
## Motivation
|
||||
|
||||
RBAC users are currently identified only by username and role bindings. Operators
|
||||
need a lightweight place to record who owns a user, what integration it belongs
|
||||
to, or why it exists. The description must be editable without rotating the
|
||||
password, and password rotation must not erase the description.
|
||||
|
||||
## Goals
|
||||
|
||||
- Persist a user description together with credential metadata.
|
||||
- Return the description from user describe and select flows, including when
|
||||
role information is not requested.
|
||||
- Allow description-only updates through `UpdateCredential`.
|
||||
- Preserve the existing password when only the description changes.
|
||||
- Preserve the existing description when only the password changes.
|
||||
- Avoid invalidating or blanking proxy authentication cache entries during
|
||||
description-only updates.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Add a new RPC for user description edits.
|
||||
- Change RBAC authorization semantics. A caller with `PrivilegeUpdateUser` can
|
||||
update a description without knowing the target user's password.
|
||||
- Add user descriptions to RBAC backup and restore. The current proto dependency
|
||||
does not add description to `UserInfo`.
|
||||
|
||||
## Public Interfaces
|
||||
|
||||
The milvus-proto dependency adds optional description fields to the existing
|
||||
credential requests and user read result:
|
||||
|
||||
```protobuf
|
||||
message CreateCredentialRequest {
|
||||
optional string description = 6;
|
||||
}
|
||||
|
||||
message UpdateCredentialRequest {
|
||||
optional string description = 7;
|
||||
}
|
||||
|
||||
message UserResult {
|
||||
UserEntity user = 1;
|
||||
repeated RoleEntity roles = 2;
|
||||
string description = 3;
|
||||
}
|
||||
```
|
||||
|
||||
Milvus internal credential messages add the same optional field so the WAL body
|
||||
can distinguish "field not provided" from "set description to empty string":
|
||||
|
||||
```protobuf
|
||||
message CredentialInfo {
|
||||
string username = 1;
|
||||
string encrypted_password = 2;
|
||||
string sha256_password = 5;
|
||||
uint64 time_tick = 6;
|
||||
optional string description = 7;
|
||||
}
|
||||
```
|
||||
|
||||
`proxy.maxUserDescriptionLength` limits the byte length of the description. The
|
||||
default is 1024 bytes.
|
||||
|
||||
## Design Details
|
||||
|
||||
### Data Flow
|
||||
|
||||
#### Create User
|
||||
|
||||
1. Proxy validates username, password, and description length.
|
||||
2. Proxy encrypts the password, computes the SHA256 cache value, and sends
|
||||
`CredentialInfo` with `description` to RootCoord.
|
||||
3. RootCoord broadcasts an alter-user WAL message.
|
||||
4. The WAL ack callback writes the credential metadata and updates proxy auth
|
||||
caches because a password is present.
|
||||
|
||||
#### Update Password
|
||||
|
||||
1. Proxy enters the password update path only when `new_password` is provided.
|
||||
2. Proxy decodes and validates the old and new passwords, verifies the old
|
||||
password unless the caller is a configured super user, then sends the new
|
||||
encrypted password and SHA256 cache value.
|
||||
3. RootCoord performs a read-modify-write merge. If the incoming message does
|
||||
not carry `description`, the existing description is preserved.
|
||||
4. The WAL ack callback updates proxy auth caches because the body carries a
|
||||
non-empty SHA256 password.
|
||||
|
||||
#### Update Description Only
|
||||
|
||||
1. Proxy validates description length and skips the password block because
|
||||
`new_password` is absent.
|
||||
2. Proxy sends `CredentialInfo` with `description` and no password fields.
|
||||
3. RootCoord merges the incoming metadata with the existing credential. Because
|
||||
the incoming encrypted password is empty, the existing encrypted password is
|
||||
preserved.
|
||||
4. The WAL ack callback skips proxy auth cache updates because no SHA256
|
||||
password is present.
|
||||
|
||||
#### Read User
|
||||
|
||||
`Catalog.getUserResult` loads the credential before the role-info early return
|
||||
and copies `Credential.Description` into `UserResult.Description`. This makes
|
||||
both `include_role_info=true` and `include_role_info=false` return the field.
|
||||
|
||||
## Storage Model
|
||||
|
||||
`model.Credential` stores `Description` in the same JSON payload as the encrypted
|
||||
password and timetick. `Sha256Password` remains cache-only and is not persisted
|
||||
by the RootCoord merge path.
|
||||
|
||||
Proxy enforces the description length before the request reaches RootCoord, so an
|
||||
oversized description is rejected before it can increase the etcd credential
|
||||
value. RootCoord keeps the existing credential validation shape and does not
|
||||
duplicate proxy-side username, password, or description length checks.
|
||||
|
||||
HTTP v2 user create and update requests pass the optional description through to
|
||||
the same gRPC credential APIs. HTTP v2 user describe preserves the existing role
|
||||
list response and includes the description in the response object.
|
||||
|
||||
## Compatibility, Deprecation, and Migration Plan
|
||||
|
||||
The description field is optional. Existing credential records unmarshal with an
|
||||
empty description. Existing clients that do not send descriptions continue to
|
||||
create and update credentials as before.
|
||||
|
||||
This Milvus PR temporarily uses a git-based `replace` for the milvus-proto
|
||||
branch that defines the API fields. During coordinated landing, the replace is
|
||||
removed and the dependency is switched to the upstream milvus-proto version that
|
||||
contains those fields.
|
||||
|
||||
No deprecation or data migration is required.
|
||||
|
||||
## Test Plan
|
||||
|
||||
- Proxy unit tests cover create with description, description length rejection,
|
||||
description-only update, password-plus-description update, empty update
|
||||
rejection, and empty-string description clearing.
|
||||
- RootCoord unit tests cover read-modify-write preservation and proxy auth cache
|
||||
behavior, including malformed password updates.
|
||||
- Metastore tests cover credential marshal/unmarshal and user result readback.
|
||||
- HTTP v2 tests cover create, description-only update, and describe response
|
||||
propagation.
|
||||
- CI runs package tests, static check, and Go-only builds against the coordinated
|
||||
milvus-proto dependency.
|
||||
|
||||
## Rejected Alternatives
|
||||
|
||||
- Add a new update-description RPC. Rejected because the existing
|
||||
`UpdateCredential` API already owns credential metadata updates and can model
|
||||
password and description as independently optional fields.
|
||||
- Store descriptions in a separate metadata key. Rejected because credentials
|
||||
already have a versioned WAL update path and catalog record. A separate key
|
||||
would add another consistency edge without reducing update complexity.
|
||||
- Update proxy auth caches on every credential metadata edit. Rejected because a
|
||||
description-only update carries no SHA256 password and would blank cached
|
||||
authentication state.
|
||||
@@ -69,8 +69,7 @@ require (
|
||||
github.com/hamba/avro/v2 v2.29.0
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||
github.com/magiconair/properties v1.8.7
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.18
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e
|
||||
github.com/milvus-io/milvus/client/v2 v2.6.2
|
||||
github.com/milvus-io/milvus/pkg/v3 v3.0.0-beta
|
||||
github.com/shirou/gopsutil/v4 v4.25.10
|
||||
|
||||
@@ -795,10 +795,8 @@ github.com/milvus-io/cgosymbolizer v0.0.0-20250318084424-114f4050c3a6 h1:YHMFI6L
|
||||
github.com/milvus-io/cgosymbolizer v0.0.0-20250318084424-114f4050c3a6/go.mod h1:DvXTE/K/RtHehxU8/GtDs4vFtfw64jJ3PaCnFri8CRg=
|
||||
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b h1:TfeY0NxYxZzUfIfYe5qYDBzt4ZYRqzUjTR6CvUzjat8=
|
||||
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.18 h1:4EaGTuDn0yv9BtQ23l2Wube7d8XcLA4+z2sQsgRkYK0=
|
||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.6.18/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f h1:W+paUzc+AA381Rydx2DJffoQuM4l+efVqO+2i9GdfMw=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f/go.mod h1:rbKpv5JToISTKTTLl0duL5r6wbYnjJ9SsD0QgXMzKy0=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e h1:axPnOhjsWqqxk0dOQRSIU2mdg52Kyl/8E6iDFZy/IpE=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e/go.mod h1:rbKpv5JToISTKTTLl0duL5r6wbYnjJ9SsD0QgXMzKy0=
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
|
||||
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
|
||||
|
||||
@@ -2663,14 +2663,18 @@ func (h *HandlersV2) describeUser(ctx context.Context, c *gin.Context, anyReq an
|
||||
})
|
||||
if err == nil {
|
||||
roleNames := []string{}
|
||||
description := ""
|
||||
for _, userRole := range resp.(*milvuspb.SelectUserResponse).Results {
|
||||
if userRole.User.Name == userName {
|
||||
description = userRole.GetDescription()
|
||||
for _, role := range userRole.Roles {
|
||||
roleNames = append(roleNames, role.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
HTTPReturn(c, http.StatusOK, wrapperReturnList(roleNames))
|
||||
result := wrapperReturnList(roleNames)
|
||||
result[HTTPReturnDescription] = description
|
||||
HTTPReturn(c, http.StatusOK, result)
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
@@ -2678,8 +2682,9 @@ func (h *HandlersV2) describeUser(ctx context.Context, c *gin.Context, anyReq an
|
||||
func (h *HandlersV2) createUser(ctx context.Context, c *gin.Context, anyReq any, dbName string) (interface{}, error) {
|
||||
httpReq := anyReq.(*PasswordReq)
|
||||
req := &milvuspb.CreateCredentialRequest{
|
||||
Username: httpReq.UserName,
|
||||
Password: crypto.Base64Encode(httpReq.Password),
|
||||
Username: httpReq.UserName,
|
||||
Password: crypto.Base64Encode(httpReq.Password),
|
||||
Description: httpReq.Description,
|
||||
}
|
||||
resp, err := wrapperProxy(ctx, c, req, h.checkAuth, false, "/milvus.proto.milvus.MilvusService/CreateCredential", func(reqCtx context.Context, req any) (interface{}, error) {
|
||||
return h.proxy.CreateCredential(reqCtx, req.(*milvuspb.CreateCredentialRequest))
|
||||
@@ -2694,8 +2699,11 @@ func (h *HandlersV2) updateUser(ctx context.Context, c *gin.Context, anyReq any,
|
||||
httpReq := anyReq.(*NewPasswordReq)
|
||||
req := &milvuspb.UpdateCredentialRequest{
|
||||
Username: httpReq.UserName,
|
||||
OldPassword: crypto.Base64Encode(httpReq.Password),
|
||||
NewPassword: crypto.Base64Encode(httpReq.NewPassword),
|
||||
Description: httpReq.Description,
|
||||
}
|
||||
if httpReq.NewPassword != "" {
|
||||
req.OldPassword = crypto.Base64Encode(httpReq.Password)
|
||||
req.NewPassword = crypto.Base64Encode(httpReq.NewPassword)
|
||||
}
|
||||
resp, err := wrapperProxy(ctx, c, req, h.checkAuth, false, "/milvus.proto.milvus.MilvusService/UpdateCredential", func(reqCtx context.Context, req any) (interface{}, error) {
|
||||
return h.proxy.UpdateCredential(reqCtx, req.(*milvuspb.UpdateCredentialRequest))
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
@@ -44,6 +45,7 @@ import (
|
||||
"github.com/milvus-io/milvus/pkg/v3/common"
|
||||
"github.com/milvus-io/milvus/pkg/v3/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/crypto"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/paramtable"
|
||||
)
|
||||
@@ -2879,6 +2881,79 @@ func TestMethodPost(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserDescriptionV2(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
description := "用户描述"
|
||||
mp := mocks.NewMockProxy(t)
|
||||
mp.EXPECT().
|
||||
CreateCredential(mock.Anything, mock.MatchedBy(func(req *milvuspb.CreateCredentialRequest) bool {
|
||||
return req.GetUsername() == util.UserRoot &&
|
||||
req.GetPassword() == crypto.Base64Encode("Milvus") &&
|
||||
req.Description != nil &&
|
||||
req.GetDescription() == description
|
||||
})).
|
||||
Return(commonSuccessStatus, nil).
|
||||
Once()
|
||||
mp.EXPECT().
|
||||
UpdateCredential(mock.Anything, mock.MatchedBy(func(req *milvuspb.UpdateCredentialRequest) bool {
|
||||
return req.GetUsername() == util.UserRoot &&
|
||||
req.GetOldPassword() == "" &&
|
||||
req.GetNewPassword() == "" &&
|
||||
req.Description != nil &&
|
||||
req.GetDescription() == description
|
||||
})).
|
||||
Return(commonSuccessStatus, nil).
|
||||
Once()
|
||||
mp.EXPECT().
|
||||
SelectUser(mock.Anything, mock.Anything).
|
||||
Return(&milvuspb.SelectUserResponse{
|
||||
Status: &StatusSuccess,
|
||||
Results: []*milvuspb.UserResult{
|
||||
{
|
||||
User: &milvuspb.UserEntity{Name: util.UserRoot},
|
||||
Roles: []*milvuspb.RoleEntity{{Name: util.RoleAdmin}},
|
||||
Description: description,
|
||||
},
|
||||
},
|
||||
}, nil).
|
||||
Once()
|
||||
|
||||
testEngine := initHTTPServerV2(mp, false)
|
||||
for _, testcase := range []struct {
|
||||
path string
|
||||
body string
|
||||
}{
|
||||
{
|
||||
path: versionalV2(UserCategory, CreateAction),
|
||||
body: `{"userName":"` + util.UserRoot + `","password":"Milvus","description":"` + description + `"}`,
|
||||
},
|
||||
{
|
||||
path: versionalV2(UserCategory, UpdatePasswordAction),
|
||||
body: `{"userName":"` + util.UserRoot + `","description":"` + description + `"}`,
|
||||
},
|
||||
{
|
||||
path: versionalV2(UserCategory, DescribeAction),
|
||||
body: `{"userName":"` + util.UserRoot + `"}`,
|
||||
},
|
||||
} {
|
||||
t.Run(testcase.path, func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodPost, testcase.path, bytes.NewReader([]byte(testcase.body)))
|
||||
w := httptest.NewRecorder()
|
||||
testEngine.ServeHTTP(w, req)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
resp := map[string]interface{}{}
|
||||
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
||||
assert.Equal(t, float64(0), resp[HTTPReturnCode])
|
||||
if testcase.path == versionalV2(UserCategory, DescribeAction) {
|
||||
assert.Equal(t, description, resp[HTTPReturnDescription])
|
||||
assert.Equal(t, []interface{}{util.RoleAdmin}, resp[HTTPReturnData])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func validateTestCases(t *testing.T, testEngine *gin.Engine, queryTestCases []requestBodyTestCase, allowInt64 bool) {
|
||||
for i, testcase := range queryTestCases {
|
||||
t.Run(testcase.path, func(t *testing.T) {
|
||||
|
||||
@@ -519,14 +519,16 @@ type TimestampGetter interface {
|
||||
GetTimestamp() uint64
|
||||
}
|
||||
type PasswordReq struct {
|
||||
UserName string `json:"userName" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
UserName string `json:"userName" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
type NewPasswordReq struct {
|
||||
UserName string `json:"userName" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
NewPassword string `json:"newPassword" binding:"required"`
|
||||
UserName string `json:"userName" binding:"required"`
|
||||
Password string `json:"password"`
|
||||
NewPassword string `json:"newPassword"`
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
type UserRoleReq struct {
|
||||
|
||||
@@ -90,7 +90,6 @@ type RootCoordCatalog interface {
|
||||
// MigrateGrantCollectionName migrates all grants from oldName to newName when a collection is renamed.
|
||||
MigrateGrantCollectionName(ctx context.Context, tenant string, oldDBName string, oldName string, newDBName string, newName string) error
|
||||
|
||||
ListCredentialsWithPasswd(ctx context.Context) (map[string]string, error)
|
||||
BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBACMeta, error)
|
||||
RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error
|
||||
|
||||
|
||||
@@ -360,7 +360,8 @@ func (kc *Catalog) CreateAlias(ctx context.Context, alias *model.Alias, ts typeu
|
||||
func (kc *Catalog) AlterCredential(ctx context.Context, credential *model.Credential) error {
|
||||
k := fmt.Sprintf("%s/%s", CredentialPrefix, credential.Username)
|
||||
credentialInfo := model.MarshalCredentialModel(credential)
|
||||
credentialInfo.Username = "" // Username is already save in the key, remove it from the value.
|
||||
credentialInfo.Username = "" // Username is already save in the key, remove it from the value.
|
||||
credentialInfo.Sha256Password = "" // Sha256Password is cache-only, do not persist it.
|
||||
v, err := json.Marshal(credentialInfo)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error("create credential marshal fail", zap.String("key", k), zap.Error(err))
|
||||
@@ -1129,37 +1130,45 @@ func (kc *Catalog) ListAliases(ctx context.Context, dbID int64, ts typeutil.Time
|
||||
}
|
||||
|
||||
func (kc *Catalog) ListCredentials(ctx context.Context) ([]string, error) {
|
||||
users, err := kc.ListCredentialsWithPasswd(ctx)
|
||||
credentials, err := kc.listCredentials(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lo.Keys(users), nil
|
||||
return lo.Map(credentials, func(credential *model.Credential, _ int) string {
|
||||
return credential.Username
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) ListCredentialsWithPasswd(ctx context.Context) (map[string]string, error) {
|
||||
func (kc *Catalog) listCredentials(ctx context.Context) ([]*model.Credential, error) {
|
||||
keys, values, err := kc.Txn.LoadWithPrefix(ctx, CredentialPrefix+"/")
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Error("list all credential usernames fail", zap.String("prefix", CredentialPrefix), zap.Error(err))
|
||||
log.Ctx(ctx).Error("list all credentials fail", zap.String("prefix", CredentialPrefix), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users := make(map[string]string)
|
||||
credentials := make([]*model.Credential, 0, len(keys))
|
||||
prefix := CredentialPrefix + "/"
|
||||
for i := range keys {
|
||||
username := typeutil.After(keys[i], UserSubPrefix+"/")
|
||||
if len(username) == 0 {
|
||||
log.Ctx(ctx).Warn("no username extract from path:", zap.String("path", keys[i]))
|
||||
prefixPos := strings.Index(keys[i], prefix)
|
||||
if prefixPos < 0 {
|
||||
log.Ctx(ctx).Warn("invalid credential key", zap.String("path", keys[i]), zap.String("prefix", prefix))
|
||||
continue
|
||||
}
|
||||
credential := &internalpb.CredentialInfo{}
|
||||
err := json.Unmarshal([]byte(values[i]), credential)
|
||||
if err != nil {
|
||||
username := keys[i][prefixPos+len(prefix):]
|
||||
if len(username) == 0 || strings.Contains(username, "/") {
|
||||
log.Ctx(ctx).Warn("invalid credential key", zap.String("path", keys[i]), zap.String("prefix", prefix))
|
||||
continue
|
||||
}
|
||||
credentialInfo := &internalpb.CredentialInfo{}
|
||||
if err := json.Unmarshal([]byte(values[i]), credentialInfo); err != nil {
|
||||
log.Ctx(ctx).Error("credential unmarshal fail", zap.String("key", keys[i]), zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
users[username] = credential.EncryptedPassword
|
||||
credentialInfo.Username = username
|
||||
credentials = append(credentials, model.UnmarshalCredentialModel(credentialInfo))
|
||||
}
|
||||
|
||||
return users, nil
|
||||
return credentials, nil
|
||||
}
|
||||
|
||||
func (kc *Catalog) remove(ctx context.Context, k string) error {
|
||||
@@ -1302,13 +1311,17 @@ func (kc *Catalog) getRolesByUsername(ctx context.Context, tenant string, userna
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
// getUserResult get the user result by the username. And never return the error because the error means the user isn't added to a role.
|
||||
func (kc *Catalog) getUserResult(ctx context.Context, tenant string, username string, includeRoleInfo bool) (*milvuspb.UserResult, error) {
|
||||
result := &milvuspb.UserResult{User: &milvuspb.UserEntity{Name: username}}
|
||||
// getUserResult gets the user result from a loaded credential.
|
||||
func (kc *Catalog) getUserResult(ctx context.Context, tenant string, credential *model.Credential, includeRoleInfo bool) (*milvuspb.UserResult, error) {
|
||||
result := &milvuspb.UserResult{
|
||||
User: &milvuspb.UserEntity{Name: credential.Username},
|
||||
Description: credential.Description,
|
||||
}
|
||||
|
||||
if !includeRoleInfo {
|
||||
return result, nil
|
||||
}
|
||||
roleNames, err := kc.getRolesByUsername(ctx, tenant, username)
|
||||
roleNames, err := kc.getRolesByUsername(ctx, tenant, credential.Username)
|
||||
if err != nil {
|
||||
log.Ctx(ctx).Warn("fail to get roles by the username", zap.Error(err))
|
||||
return result, err
|
||||
@@ -1323,40 +1336,33 @@ func (kc *Catalog) getUserResult(ctx context.Context, tenant string, username st
|
||||
|
||||
func (kc *Catalog) ListUser(ctx context.Context, tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) {
|
||||
var (
|
||||
usernames []string
|
||||
err error
|
||||
results []*milvuspb.UserResult
|
||||
credentials []*model.Credential
|
||||
err error
|
||||
)
|
||||
|
||||
appendUserResult := func(username string) error {
|
||||
result, err := kc.getUserResult(ctx, tenant, username, includeRoleInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results = append(results, result)
|
||||
return nil
|
||||
}
|
||||
|
||||
if entity == nil {
|
||||
usernames, err = kc.ListCredentials(ctx)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
} else {
|
||||
if funcutil.IsEmptyString(entity.Name) {
|
||||
return results, merr.WrapErrParameterInvalidMsg("username in the user entity is empty")
|
||||
}
|
||||
_, err = kc.GetCredential(ctx, entity.Name)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
usernames = append(usernames, entity.Name)
|
||||
}
|
||||
for _, username := range usernames {
|
||||
err = appendUserResult(username)
|
||||
credentials, err = kc.listCredentials(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if funcutil.IsEmptyString(entity.Name) {
|
||||
return nil, merr.WrapErrParameterInvalidMsg("username in the user entity is empty")
|
||||
}
|
||||
credential, err := kc.GetCredential(ctx, entity.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
credentials = []*model.Credential{credential}
|
||||
}
|
||||
|
||||
results := make([]*milvuspb.UserResult, 0, len(credentials))
|
||||
for _, credential := range credentials {
|
||||
result, err := kc.getUserResult(ctx, tenant, credential, includeRoleInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
@@ -1987,14 +1993,20 @@ func (kc *Catalog) ListUserRole(ctx context.Context, tenant string) ([]string, e
|
||||
}
|
||||
|
||||
func (kc *Catalog) BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBACMeta, error) {
|
||||
users, err := kc.ListUser(ctx, tenant, nil, true)
|
||||
credentials, err := kc.listCredentials(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
credentials, err := kc.ListCredentialsWithPasswd(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
users := make([]*milvuspb.UserResult, 0, len(credentials))
|
||||
credentialPasswords := make(map[string]string, len(credentials))
|
||||
for _, credential := range credentials {
|
||||
credentialPasswords[credential.Username] = credential.EncryptedPassword
|
||||
user, err := kc.getUserResult(ctx, tenant, credential, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
userInfos := lo.FilterMap(users, func(entity *milvuspb.UserResult, _ int) (*milvuspb.UserInfo, bool) {
|
||||
@@ -2004,7 +2016,7 @@ func (kc *Catalog) BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBA
|
||||
}
|
||||
return &milvuspb.UserInfo{
|
||||
User: userName,
|
||||
Password: credentials[userName],
|
||||
Password: credentialPasswords[userName],
|
||||
Roles: entity.GetRoles(),
|
||||
}, true
|
||||
})
|
||||
|
||||
@@ -1607,6 +1607,133 @@ func getUserInfoMetaString(username string) string {
|
||||
return string(validBytes)
|
||||
}
|
||||
|
||||
func TestGetUserResultIncludesDescriptionWithoutRoleInfo(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
tenant := util.DefaultTenant
|
||||
username := "user-with-description"
|
||||
description := "stored description"
|
||||
|
||||
kvmock := mocks.NewTxnKV(t)
|
||||
c := NewCatalog(kvmock).(*Catalog)
|
||||
credential := &model.Credential{
|
||||
Username: username,
|
||||
Description: description,
|
||||
}
|
||||
|
||||
result, err := c.getUserResult(ctx, tenant, credential, false)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, username, result.GetUser().GetName())
|
||||
assert.Equal(t, description, result.GetDescription())
|
||||
assert.Empty(t, result.GetRoles())
|
||||
}
|
||||
|
||||
func TestListUserReturnsCredentialLoadError(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
tenant := util.DefaultTenant
|
||||
username := "user-with-credential-load-error"
|
||||
credentialKey := fmt.Sprintf("%s/%s", CredentialPrefix, username)
|
||||
expectedErr := errors.New("credential load failed")
|
||||
|
||||
kvmock := mocks.NewTxnKV(t)
|
||||
c := NewCatalog(kvmock).(*Catalog)
|
||||
kvmock.EXPECT().Load(mock.Anything, credentialKey).Return("", expectedErr)
|
||||
|
||||
results, err := c.ListUser(ctx, tenant, &milvuspb.UserEntity{Name: username}, false)
|
||||
|
||||
require.ErrorIs(t, err, expectedErr)
|
||||
assert.Empty(t, results)
|
||||
}
|
||||
|
||||
func TestListUserSingleUserReusesLoadedCredentialDescription(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
tenant := util.DefaultTenant
|
||||
username := "user-with-description"
|
||||
description := "single user description"
|
||||
credentialKey := fmt.Sprintf("%s/%s", CredentialPrefix, username)
|
||||
credentialValue, err := json.Marshal(&internalpb.CredentialInfo{Description: &description})
|
||||
require.NoError(t, err)
|
||||
|
||||
kvmock := mocks.NewTxnKV(t)
|
||||
c := NewCatalog(kvmock).(*Catalog)
|
||||
kvmock.EXPECT().Load(mock.Anything, credentialKey).Return(string(credentialValue), nil).Once()
|
||||
|
||||
results, err := c.ListUser(ctx, tenant, &milvuspb.UserEntity{Name: username}, false)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, results, 1)
|
||||
assert.Equal(t, username, results[0].GetUser().GetName())
|
||||
assert.Equal(t, description, results[0].GetDescription())
|
||||
assert.Empty(t, results[0].GetRoles())
|
||||
}
|
||||
|
||||
func TestListUserAllUsersReusesLoadedCredentialDescriptions(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
tenant := util.DefaultTenant
|
||||
user1Description := "first user"
|
||||
user2Description := "second user"
|
||||
ghostDescription := "ghost user"
|
||||
user1Credential, err := json.Marshal(&internalpb.CredentialInfo{Description: &user1Description})
|
||||
require.NoError(t, err)
|
||||
user2Credential, err := json.Marshal(&internalpb.CredentialInfo{Description: &user2Description})
|
||||
require.NoError(t, err)
|
||||
ghostCredential, err := json.Marshal(&internalpb.CredentialInfo{Description: &ghostDescription})
|
||||
require.NoError(t, err)
|
||||
|
||||
kvmock := mocks.NewTxnKV(t)
|
||||
c := NewCatalog(kvmock).(*Catalog)
|
||||
kvmock.EXPECT().LoadWithPrefix(mock.Anything, CredentialPrefix+"/").Return(
|
||||
[]string{
|
||||
fmt.Sprintf("%s/%s", CredentialPrefix, "user1"),
|
||||
fmt.Sprintf("%s/%s", CredentialPrefix, "user2"),
|
||||
fmt.Sprintf("%s/%s/%s", CredentialPrefix, UserSubPrefix, "ghost"),
|
||||
},
|
||||
[]string{string(user1Credential), string(user2Credential), string(ghostCredential)},
|
||||
nil,
|
||||
)
|
||||
|
||||
results, err := c.ListUser(ctx, tenant, nil, false)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, results, 2)
|
||||
assert.Equal(t, "user1", results[0].GetUser().GetName())
|
||||
assert.Equal(t, user1Description, results[0].GetDescription())
|
||||
assert.Empty(t, results[0].GetRoles())
|
||||
assert.Equal(t, "user2", results[1].GetUser().GetName())
|
||||
assert.Equal(t, user2Description, results[1].GetDescription())
|
||||
assert.Empty(t, results[1].GetRoles())
|
||||
}
|
||||
|
||||
func TestBackupRBACReusesLoadedCredentials(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
tenant := util.DefaultTenant
|
||||
username := "user-with-password"
|
||||
password := "encrypted-password"
|
||||
credentialValue, err := json.Marshal(&internalpb.CredentialInfo{EncryptedPassword: password})
|
||||
require.NoError(t, err)
|
||||
|
||||
var credentialPrefixLoads int
|
||||
kvmock := mocks.NewTxnKV(t)
|
||||
c := NewCatalog(kvmock).(*Catalog)
|
||||
kvmock.EXPECT().LoadWithPrefix(mock.Anything, mock.Anything).RunAndReturn(
|
||||
func(ctx context.Context, key string) ([]string, []string, error) {
|
||||
if key == CredentialPrefix+"/" {
|
||||
credentialPrefixLoads++
|
||||
return []string{fmt.Sprintf("%s/%s", CredentialPrefix, username)}, []string{string(credentialValue)}, nil
|
||||
}
|
||||
return nil, nil, nil
|
||||
})
|
||||
|
||||
backup, err := c.BackupRBAC(ctx, tenant)
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, credentialPrefixLoads)
|
||||
require.Len(t, backup.GetUsers(), 1)
|
||||
assert.Equal(t, username, backup.GetUsers()[0].GetUser())
|
||||
assert.Equal(t, password, backup.GetUsers()[0].GetPassword())
|
||||
assert.Empty(t, backup.GetUsers()[0].GetRoles())
|
||||
}
|
||||
|
||||
func TestRBAC_Credential(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
@@ -1711,6 +1838,32 @@ func TestRBAC_Credential(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("test AlterCredential does not persist sha256 password", func(t *testing.T) {
|
||||
var (
|
||||
kvmock = mocks.NewTxnKV(t)
|
||||
c = NewCatalog(kvmock)
|
||||
)
|
||||
|
||||
kvmock.EXPECT().
|
||||
Save(mock.Anything, fmt.Sprintf("%s/%s", CredentialPrefix, "user1"), mock.MatchedBy(func(value string) bool {
|
||||
credential := &internalpb.CredentialInfo{}
|
||||
require.NoError(t, json.Unmarshal([]byte(value), credential))
|
||||
return credential.GetEncryptedPassword() == "password" &&
|
||||
credential.GetSha256Password() == "" &&
|
||||
credential.GetDescription() == "description"
|
||||
})).
|
||||
Return(nil)
|
||||
|
||||
description := "description"
|
||||
err := c.AlterCredential(ctx, &model.Credential{
|
||||
Username: "user1",
|
||||
EncryptedPassword: "password",
|
||||
Sha256Password: "sha256-password",
|
||||
Description: description,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("test DropCredential", func(t *testing.T) {
|
||||
var (
|
||||
kvmock = mocks.NewTxnKV(t)
|
||||
@@ -1780,6 +1933,8 @@ func TestRBAC_Credential(t *testing.T) {
|
||||
|
||||
// Return valid keys if count==0
|
||||
// return error if count!=0
|
||||
credentialValue, err := json.Marshal(&internalpb.CredentialInfo{EncryptedPassword: crypto.Base64Encode("passwd")})
|
||||
require.NoError(t, err)
|
||||
kvmock.EXPECT().LoadWithPrefix(mock.Anything, mock.Anything).Call.Return(
|
||||
func(ctx context.Context, key string) []string {
|
||||
cmu.RLock()
|
||||
@@ -1789,6 +1944,7 @@ func TestRBAC_Credential(t *testing.T) {
|
||||
fmt.Sprintf("%s/%s", CredentialPrefix, "user1"),
|
||||
fmt.Sprintf("%s/%s", CredentialPrefix, "user2"),
|
||||
fmt.Sprintf("%s/%s", CredentialPrefix, "user3"),
|
||||
fmt.Sprintf("%s/%s/%s", CredentialPrefix, UserSubPrefix, "ghost"),
|
||||
"random",
|
||||
}
|
||||
}
|
||||
@@ -1797,13 +1953,13 @@ func TestRBAC_Credential(t *testing.T) {
|
||||
func(ctx context.Context, key string) []string {
|
||||
cmu.RLock()
|
||||
defer cmu.RUnlock()
|
||||
passwd, _ := json.Marshal(&model.Credential{EncryptedPassword: crypto.Base64Encode("passwd")})
|
||||
if count == 0 {
|
||||
return []string{
|
||||
string(passwd),
|
||||
string(passwd),
|
||||
string(passwd),
|
||||
string(passwd),
|
||||
string(credentialValue),
|
||||
string(credentialValue),
|
||||
string(credentialValue),
|
||||
string(credentialValue),
|
||||
string(credentialValue),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -2119,11 +2275,12 @@ func TestRBAC_Role(t *testing.T) {
|
||||
kvmock = mocks.NewTxnKV(t)
|
||||
c = NewCatalog(kvmock).(*Catalog)
|
||||
|
||||
invalidUser = "invalid-user"
|
||||
invalidUserKey = funcutil.HandleTenantForEtcdPrefix(RoleMappingPrefix, tenant, invalidUser)
|
||||
invalidUser = "invalid-user"
|
||||
invalidRoleUser = "invalid-role-user"
|
||||
invalidRoleUserKey = funcutil.HandleTenantForEtcdPrefix(RoleMappingPrefix, tenant, invalidRoleUser)
|
||||
)
|
||||
// returns error for invalidUserKey
|
||||
kvmock.EXPECT().LoadWithPrefix(mock.Anything, invalidUserKey).Call.Return(
|
||||
// returns error for invalidRoleUserKey
|
||||
kvmock.EXPECT().LoadWithPrefix(mock.Anything, invalidRoleUserKey).Call.Return(
|
||||
nil, nil, errors.New("Mock load with prefix wrong"))
|
||||
|
||||
// Returns keys for RoleMappingPrefix/tenant/user1/ (with trailing slash after the fix)
|
||||
@@ -2136,6 +2293,9 @@ func TestRBAC_Role(t *testing.T) {
|
||||
user1Key + "role3/error",
|
||||
}
|
||||
}, nil, nil)
|
||||
kvmock.EXPECT().Load(mock.Anything, fmt.Sprintf("%s/%s", CredentialPrefix, "user1")).Return(getUserInfoMetaString("user1"), nil).Maybe()
|
||||
kvmock.EXPECT().Load(mock.Anything, fmt.Sprintf("%s/%s", CredentialPrefix, invalidUser)).Return("", errors.New("mock load credential error")).Maybe()
|
||||
kvmock.EXPECT().Load(mock.Anything, fmt.Sprintf("%s/%s", CredentialPrefix, invalidRoleUser)).Return(getUserInfoMetaString(invalidRoleUser), nil).Maybe()
|
||||
|
||||
// Returns keys for CredentialPrefix
|
||||
var loadCredentialPrefixReturn atomic.Bool
|
||||
@@ -2143,7 +2303,7 @@ func TestRBAC_Role(t *testing.T) {
|
||||
func(ctx context.Context, key string) []string {
|
||||
if loadCredentialPrefixReturn.Load() {
|
||||
return []string{
|
||||
fmt.Sprintf("%s/%s/%s", CredentialPrefix, UserSubPrefix, "user1"),
|
||||
fmt.Sprintf("%s/%s", CredentialPrefix, "user1"),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -2168,20 +2328,19 @@ func TestRBAC_Role(t *testing.T) {
|
||||
description string
|
||||
isValid bool
|
||||
|
||||
user string
|
||||
credential *model.Credential
|
||||
includeRoleInfo bool
|
||||
}{
|
||||
{"valid user1 not include RoleInfo", true, "user1", false},
|
||||
{"valid user1 include RoleInfo", true, "user1", true},
|
||||
{"invalid user not include RoleInfo", true, invalidUser, false},
|
||||
{"invalid user include RoleInfo", false, invalidUser, true},
|
||||
{"valid user1 not include RoleInfo", true, &model.Credential{Username: "user1"}, false},
|
||||
{"valid user1 include RoleInfo", true, &model.Credential{Username: "user1"}, true},
|
||||
{"invalid role user include RoleInfo", false, &model.Credential{Username: invalidRoleUser}, true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.description, func(t *testing.T) {
|
||||
res, err := c.getUserResult(ctx, tenant, test.user, test.includeRoleInfo)
|
||||
res, err := c.getUserResult(ctx, tenant, test.credential, test.includeRoleInfo)
|
||||
|
||||
assert.Equal(t, test.user, res.GetUser().GetName())
|
||||
assert.Equal(t, test.credential.Username, res.GetUser().GetName())
|
||||
|
||||
if test.isValid {
|
||||
assert.NoError(t, err)
|
||||
@@ -2231,6 +2390,7 @@ func TestRBAC_Role(t *testing.T) {
|
||||
{true, true, &milvuspb.UserEntity{Name: "user1"}, false, "valid entity user1 not include RoleInfo"},
|
||||
{true, true, &milvuspb.UserEntity{Name: "user1"}, true, "valid entity user1 include RoleInfo"},
|
||||
{false, true, &milvuspb.UserEntity{Name: invalidUser}, true, "invalid entity invalidUser include RoleInfo"},
|
||||
{false, true, &milvuspb.UserEntity{Name: invalidRoleUser}, true, "invalid entity invalidRoleUser include RoleInfo"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -3282,10 +3442,11 @@ func TestRBAC_Restore(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// check user
|
||||
users, err := c.ListCredentialsWithPasswd(ctx)
|
||||
credentials, err := c.(*Catalog).listCredentials(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, users, 1)
|
||||
assert.Equal(t, users["user1"], "passwd")
|
||||
assert.Len(t, credentials, 1)
|
||||
assert.Equal(t, "user1", credentials[0].Username)
|
||||
assert.Equal(t, "passwd", credentials[0].EncryptedPassword)
|
||||
// check role
|
||||
roles, err := c.ListRole(ctx, util.DefaultTenant, nil, false)
|
||||
assert.NoError(t, err)
|
||||
@@ -3353,9 +3514,9 @@ func TestRBAC_Restore(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// check user
|
||||
users, err = c.ListCredentialsWithPasswd(ctx)
|
||||
credentials, err = c.(*Catalog).listCredentials(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, users, 2)
|
||||
assert.Len(t, credentials, 2)
|
||||
// check role
|
||||
roles, err = c.ListRole(ctx, util.DefaultTenant, nil, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -5,18 +5,13 @@ package mocks
|
||||
import (
|
||||
context "context"
|
||||
|
||||
msgpb "github.com/milvus-io/milvus-proto/go-api/v3/msgpb"
|
||||
metastore "github.com/milvus-io/milvus/internal/metastore"
|
||||
model "github.com/milvus-io/milvus/internal/metastore/model"
|
||||
datapb "github.com/milvus-io/milvus/pkg/v3/proto/datapb"
|
||||
indexpb "github.com/milvus-io/milvus/pkg/v3/proto/indexpb"
|
||||
|
||||
internalpb "github.com/milvus-io/milvus/pkg/v3/proto/internalpb"
|
||||
|
||||
metastore "github.com/milvus-io/milvus/internal/metastore"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
model "github.com/milvus-io/milvus/internal/metastore/model"
|
||||
|
||||
msgpb "github.com/milvus-io/milvus-proto/go-api/v3/msgpb"
|
||||
)
|
||||
|
||||
// DataCoordCatalog is an autogenerated mock type for the DataCoordCatalog type
|
||||
|
||||
@@ -5,9 +5,8 @@ package mocks
|
||||
import (
|
||||
context "context"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
querypb "github.com/milvus-io/milvus/pkg/v3/proto/querypb"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// QueryCoordCatalog is an autogenerated mock type for the QueryCoordCatalog type
|
||||
|
||||
@@ -5,14 +5,11 @@ package mocks
|
||||
import (
|
||||
context "context"
|
||||
|
||||
metastore "github.com/milvus-io/milvus/internal/metastore"
|
||||
internalpb "github.com/milvus-io/milvus/pkg/v3/proto/internalpb"
|
||||
|
||||
milvuspb "github.com/milvus-io/milvus-proto/go-api/v3/milvuspb"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
metastore "github.com/milvus-io/milvus/internal/metastore"
|
||||
model "github.com/milvus-io/milvus/internal/metastore/model"
|
||||
internalpb "github.com/milvus-io/milvus/pkg/v3/proto/internalpb"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// RootCoordCatalog is an autogenerated mock type for the RootCoordCatalog type
|
||||
@@ -1655,64 +1652,6 @@ func (_c *RootCoordCatalog_ListCredentials_Call) RunAndReturn(run func(context.C
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListCredentialsWithPasswd provides a mock function with given fields: ctx
|
||||
func (_m *RootCoordCatalog) ListCredentialsWithPasswd(ctx context.Context) (map[string]string, error) {
|
||||
ret := _m.Called(ctx)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListCredentialsWithPasswd")
|
||||
}
|
||||
|
||||
var r0 map[string]string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context) (map[string]string, error)); ok {
|
||||
return rf(ctx)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context) map[string]string); ok {
|
||||
r0 = rf(ctx)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(map[string]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
|
||||
r1 = rf(ctx)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RootCoordCatalog_ListCredentialsWithPasswd_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListCredentialsWithPasswd'
|
||||
type RootCoordCatalog_ListCredentialsWithPasswd_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ListCredentialsWithPasswd is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
func (_e *RootCoordCatalog_Expecter) ListCredentialsWithPasswd(ctx interface{}) *RootCoordCatalog_ListCredentialsWithPasswd_Call {
|
||||
return &RootCoordCatalog_ListCredentialsWithPasswd_Call{Call: _e.mock.On("ListCredentialsWithPasswd", ctx)}
|
||||
}
|
||||
|
||||
func (_c *RootCoordCatalog_ListCredentialsWithPasswd_Call) Run(run func(ctx context.Context)) *RootCoordCatalog_ListCredentialsWithPasswd_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *RootCoordCatalog_ListCredentialsWithPasswd_Call) Return(_a0 map[string]string, _a1 error) *RootCoordCatalog_ListCredentialsWithPasswd_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *RootCoordCatalog_ListCredentialsWithPasswd_Call) RunAndReturn(run func(context.Context) (map[string]string, error)) *RootCoordCatalog_ListCredentialsWithPasswd_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// ListDatabases provides a mock function with given fields: ctx, ts
|
||||
func (_m *RootCoordCatalog) ListDatabases(ctx context.Context, ts uint64) ([]*model.Database, error) {
|
||||
ret := _m.Called(ctx, ts)
|
||||
|
||||
@@ -8,6 +8,7 @@ type Credential struct {
|
||||
Tenant string
|
||||
IsSuper bool
|
||||
Sha256Password string
|
||||
Description string
|
||||
TimeTick uint64 // the timetick in wal which the credential updates
|
||||
}
|
||||
|
||||
@@ -21,6 +22,7 @@ func MarshalCredentialModel(cred *Credential) *internalpb.CredentialInfo {
|
||||
EncryptedPassword: cred.EncryptedPassword,
|
||||
IsSuper: cred.IsSuper,
|
||||
Sha256Password: cred.Sha256Password,
|
||||
Description: &cred.Description,
|
||||
TimeTick: cred.TimeTick,
|
||||
}
|
||||
}
|
||||
@@ -35,6 +37,7 @@ func UnmarshalCredentialModel(cred *internalpb.CredentialInfo) *Credential {
|
||||
Tenant: cred.Tenant,
|
||||
IsSuper: cred.IsSuper,
|
||||
Sha256Password: cred.Sha256Password,
|
||||
Description: cred.GetDescription(),
|
||||
TimeTick: cred.TimeTick,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,17 @@ var (
|
||||
Tenant: "tenant-1",
|
||||
IsSuper: true,
|
||||
Sha256Password: "xxxx",
|
||||
Description: "description",
|
||||
}
|
||||
|
||||
description = "description"
|
||||
credentialPb = &internalpb.CredentialInfo{
|
||||
Username: "user",
|
||||
EncryptedPassword: "password",
|
||||
Tenant: "tenant-1",
|
||||
IsSuper: true,
|
||||
Sha256Password: "xxxx",
|
||||
Description: &description,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
+181
-10
@@ -6,19 +6,13 @@ import (
|
||||
context "context"
|
||||
|
||||
commonpb "github.com/milvus-io/milvus-proto/go-api/v3/commonpb"
|
||||
|
||||
federpb "github.com/milvus-io/milvus-proto/go-api/v3/federpb"
|
||||
|
||||
internalpb "github.com/milvus-io/milvus/pkg/v3/proto/internalpb"
|
||||
|
||||
milvuspb "github.com/milvus-io/milvus-proto/go-api/v3/milvuspb"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
datapb "github.com/milvus-io/milvus/pkg/v3/proto/datapb"
|
||||
proxypb "github.com/milvus-io/milvus/pkg/v3/proto/proxypb"
|
||||
|
||||
types "github.com/milvus-io/milvus/internal/types"
|
||||
datapb "github.com/milvus-io/milvus/pkg/v3/proto/datapb"
|
||||
internalpb "github.com/milvus-io/milvus/pkg/v3/proto/internalpb"
|
||||
proxypb "github.com/milvus-io/milvus/pkg/v3/proto/proxypb"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockProxy is an autogenerated mock type for the ProxyComponent type
|
||||
@@ -860,6 +854,65 @@ func (_c *MockProxy_AlterIndex_Call) RunAndReturn(run func(context.Context, *mil
|
||||
return _c
|
||||
}
|
||||
|
||||
// AlterRole provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockProxy) AlterRole(_a0 context.Context, _a1 *milvuspb.AlterRoleRequest) (*commonpb.Status, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for AlterRole")
|
||||
}
|
||||
|
||||
var r0 *commonpb.Status
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AlterRoleRequest) (*commonpb.Status, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AlterRoleRequest) *commonpb.Status); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*commonpb.Status)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.AlterRoleRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockProxy_AlterRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AlterRole'
|
||||
type MockProxy_AlterRole_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// AlterRole is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *milvuspb.AlterRoleRequest
|
||||
func (_e *MockProxy_Expecter) AlterRole(_a0 interface{}, _a1 interface{}) *MockProxy_AlterRole_Call {
|
||||
return &MockProxy_AlterRole_Call{Call: _e.mock.On("AlterRole", _a0, _a1)}
|
||||
}
|
||||
|
||||
func (_c *MockProxy_AlterRole_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.AlterRoleRequest)) *MockProxy_AlterRole_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.AlterRoleRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProxy_AlterRole_Call) Return(_a0 *commonpb.Status, _a1 error) *MockProxy_AlterRole_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProxy_AlterRole_Call) RunAndReturn(run func(context.Context, *milvuspb.AlterRoleRequest) (*commonpb.Status, error)) *MockProxy_AlterRole_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// BackupRBAC provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockProxy) BackupRBAC(_a0 context.Context, _a1 *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
@@ -3549,6 +3602,65 @@ func (_c *MockProxy_DumpMessages_Call) RunAndReturn(run func(*milvuspb.DumpMessa
|
||||
return _c
|
||||
}
|
||||
|
||||
// ExportSnapshot provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockProxy) ExportSnapshot(_a0 context.Context, _a1 *milvuspb.ExportSnapshotRequest) (*milvuspb.ExportSnapshotResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ExportSnapshot")
|
||||
}
|
||||
|
||||
var r0 *milvuspb.ExportSnapshotResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.ExportSnapshotRequest) (*milvuspb.ExportSnapshotResponse, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.ExportSnapshotRequest) *milvuspb.ExportSnapshotResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*milvuspb.ExportSnapshotResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.ExportSnapshotRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockProxy_ExportSnapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExportSnapshot'
|
||||
type MockProxy_ExportSnapshot_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// ExportSnapshot is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *milvuspb.ExportSnapshotRequest
|
||||
func (_e *MockProxy_Expecter) ExportSnapshot(_a0 interface{}, _a1 interface{}) *MockProxy_ExportSnapshot_Call {
|
||||
return &MockProxy_ExportSnapshot_Call{Call: _e.mock.On("ExportSnapshot", _a0, _a1)}
|
||||
}
|
||||
|
||||
func (_c *MockProxy_ExportSnapshot_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.ExportSnapshotRequest)) *MockProxy_ExportSnapshot_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.ExportSnapshotRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProxy_ExportSnapshot_Call) Return(_a0 *milvuspb.ExportSnapshotResponse, _a1 error) *MockProxy_ExportSnapshot_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProxy_ExportSnapshot_Call) RunAndReturn(run func(context.Context, *milvuspb.ExportSnapshotRequest) (*milvuspb.ExportSnapshotResponse, error)) *MockProxy_ExportSnapshot_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// Flush provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockProxy) Flush(_a0 context.Context, _a1 *milvuspb.FlushRequest) (*milvuspb.FlushResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
@@ -8166,6 +8278,65 @@ func (_c *MockProxy_ReplicateMessage_Call) RunAndReturn(run func(context.Context
|
||||
return _c
|
||||
}
|
||||
|
||||
// RestoreExternalSnapshot provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockProxy) RestoreExternalSnapshot(_a0 context.Context, _a1 *milvuspb.RestoreExternalSnapshotRequest) (*milvuspb.RestoreExternalSnapshotResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RestoreExternalSnapshot")
|
||||
}
|
||||
|
||||
var r0 *milvuspb.RestoreExternalSnapshotResponse
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreExternalSnapshotRequest) (*milvuspb.RestoreExternalSnapshotResponse, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreExternalSnapshotRequest) *milvuspb.RestoreExternalSnapshotResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*milvuspb.RestoreExternalSnapshotResponse)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.RestoreExternalSnapshotRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockProxy_RestoreExternalSnapshot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestoreExternalSnapshot'
|
||||
type MockProxy_RestoreExternalSnapshot_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// RestoreExternalSnapshot is a helper method to define mock.On call
|
||||
// - _a0 context.Context
|
||||
// - _a1 *milvuspb.RestoreExternalSnapshotRequest
|
||||
func (_e *MockProxy_Expecter) RestoreExternalSnapshot(_a0 interface{}, _a1 interface{}) *MockProxy_RestoreExternalSnapshot_Call {
|
||||
return &MockProxy_RestoreExternalSnapshot_Call{Call: _e.mock.On("RestoreExternalSnapshot", _a0, _a1)}
|
||||
}
|
||||
|
||||
func (_c *MockProxy_RestoreExternalSnapshot_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.RestoreExternalSnapshotRequest)) *MockProxy_RestoreExternalSnapshot_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(*milvuspb.RestoreExternalSnapshotRequest))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProxy_RestoreExternalSnapshot_Call) Return(_a0 *milvuspb.RestoreExternalSnapshotResponse, _a1 error) *MockProxy_RestoreExternalSnapshot_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockProxy_RestoreExternalSnapshot_Call) RunAndReturn(run func(context.Context, *milvuspb.RestoreExternalSnapshotRequest) (*milvuspb.RestoreExternalSnapshotResponse, error)) *MockProxy_RestoreExternalSnapshot_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// RestoreRBAC provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockProxy) RestoreRBAC(_a0 context.Context, _a1 *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
// 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 proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v3/commonpb"
|
||||
"github.com/milvus-io/milvus-proto/go-api/v3/milvuspb"
|
||||
"github.com/milvus-io/milvus/internal/mocks"
|
||||
"github.com/milvus-io/milvus/pkg/v3/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/crypto"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/paramtable"
|
||||
)
|
||||
|
||||
func TestCreateCredentialPassesDescription(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
description := "created user description"
|
||||
mixCoord := mocks.NewMockMixCoordClient(t)
|
||||
mixCoord.EXPECT().
|
||||
CreateCredential(mock.Anything, mock.MatchedBy(func(cred *internalpb.CredentialInfo) bool {
|
||||
return cred.GetUsername() == "desc_user" &&
|
||||
cred.Description != nil &&
|
||||
cred.GetDescription() == description &&
|
||||
cred.GetEncryptedPassword() != "" &&
|
||||
cred.GetSha256Password() != ""
|
||||
})).
|
||||
Return(merr.Success(), nil)
|
||||
|
||||
node := &Proxy{mixCoord: mixCoord}
|
||||
node.UpdateStateCode(commonpb.StateCode_Healthy)
|
||||
|
||||
status, err := node.CreateCredential(context.Background(), &milvuspb.CreateCredentialRequest{
|
||||
Username: "desc_user",
|
||||
Password: crypto.Base64Encode("password"),
|
||||
Description: &description,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
||||
}
|
||||
|
||||
func TestCreateCredentialRejectsOverLimitDescription(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
mixCoord := mocks.NewMockMixCoordClient(t)
|
||||
mixCoord.On("CreateCredential", mock.Anything, mock.Anything).Return(merr.Success(), nil).Maybe()
|
||||
node := &Proxy{mixCoord: mixCoord}
|
||||
node.UpdateStateCode(commonpb.StateCode_Healthy)
|
||||
|
||||
description := strings.Repeat("x", 1025)
|
||||
status, err := node.CreateCredential(context.Background(), &milvuspb.CreateCredentialRequest{
|
||||
Username: "desc_user",
|
||||
Password: crypto.Base64Encode("password"),
|
||||
Description: &description,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
||||
mixCoord.AssertNotCalled(t, "CreateCredential", mock.Anything, mock.Anything)
|
||||
}
|
||||
|
||||
func TestUpdateCredentialDescriptionOnlySkipsPasswordVerification(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
description := "updated user description"
|
||||
mixCoord := mocks.NewMockMixCoordClient(t)
|
||||
mixCoord.EXPECT().
|
||||
UpdateCredential(mock.Anything, mock.MatchedBy(func(cred *internalpb.CredentialInfo) bool {
|
||||
return cred.GetUsername() == "desc_user" &&
|
||||
cred.Description != nil &&
|
||||
cred.GetDescription() == description &&
|
||||
cred.GetEncryptedPassword() == "" &&
|
||||
cred.GetSha256Password() == ""
|
||||
})).
|
||||
Return(merr.Success(), nil)
|
||||
|
||||
node := &Proxy{mixCoord: mixCoord}
|
||||
node.UpdateStateCode(commonpb.StateCode_Healthy)
|
||||
|
||||
status, err := node.UpdateCredential(context.Background(), &milvuspb.UpdateCredentialRequest{
|
||||
Username: "desc_user",
|
||||
Description: &description,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
||||
}
|
||||
|
||||
func TestUpdateCredentialClearsDescriptionOnly(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
description := ""
|
||||
mixCoord := mocks.NewMockMixCoordClient(t)
|
||||
mixCoord.EXPECT().
|
||||
UpdateCredential(mock.Anything, mock.MatchedBy(func(cred *internalpb.CredentialInfo) bool {
|
||||
return cred.GetUsername() == "desc_user" &&
|
||||
cred.Description != nil &&
|
||||
cred.GetDescription() == description &&
|
||||
cred.GetEncryptedPassword() == "" &&
|
||||
cred.GetSha256Password() == ""
|
||||
})).
|
||||
Return(merr.Success(), nil)
|
||||
|
||||
node := &Proxy{mixCoord: mixCoord}
|
||||
node.UpdateStateCode(commonpb.StateCode_Healthy)
|
||||
|
||||
status, err := node.UpdateCredential(context.Background(), &milvuspb.UpdateCredentialRequest{
|
||||
Username: "desc_user",
|
||||
Description: &description,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
||||
}
|
||||
|
||||
func TestUpdateCredentialRejectsEmptyUpdate(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
mixCoord := mocks.NewMockMixCoordClient(t)
|
||||
mixCoord.On("UpdateCredential", mock.Anything, mock.Anything).Return(merr.Success(), nil).Maybe()
|
||||
node := &Proxy{mixCoord: mixCoord}
|
||||
node.UpdateStateCode(commonpb.StateCode_Healthy)
|
||||
|
||||
status, err := node.UpdateCredential(context.Background(), &milvuspb.UpdateCredentialRequest{
|
||||
Username: "desc_user",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
||||
assert.Contains(t, status.GetReason(), "must update either password or description")
|
||||
mixCoord.AssertNotCalled(t, "UpdateCredential", mock.Anything, mock.Anything)
|
||||
}
|
||||
|
||||
func TestUpdateCredentialPasswordAndDescription(t *testing.T) {
|
||||
paramtable.Init()
|
||||
require.NoError(t, paramtable.Get().Save(Params.CommonCfg.SuperUsers.Key, "root"))
|
||||
defer paramtable.Get().Reset(Params.CommonCfg.SuperUsers.Key)
|
||||
|
||||
description := "updated user description"
|
||||
mixCoord := mocks.NewMockMixCoordClient(t)
|
||||
mixCoord.EXPECT().
|
||||
UpdateCredential(mock.Anything, mock.MatchedBy(func(cred *internalpb.CredentialInfo) bool {
|
||||
return cred.GetUsername() == "desc_user" &&
|
||||
cred.Description != nil &&
|
||||
cred.GetDescription() == description &&
|
||||
cred.GetEncryptedPassword() != "" &&
|
||||
cred.GetSha256Password() == crypto.SHA256("new_password", "desc_user")
|
||||
})).
|
||||
Return(merr.Success(), nil)
|
||||
|
||||
node := &Proxy{mixCoord: mixCoord}
|
||||
node.UpdateStateCode(commonpb.StateCode_Healthy)
|
||||
|
||||
status, err := node.UpdateCredential(GetContext(context.Background(), "root:password"), &milvuspb.UpdateCredentialRequest{
|
||||
Username: "desc_user",
|
||||
OldPassword: crypto.Base64Encode("old_password"),
|
||||
NewPassword: crypto.Base64Encode("new_password"),
|
||||
Description: &description,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
||||
}
|
||||
|
||||
func TestUpdateCredentialRejectsOverLimitDescription(t *testing.T) {
|
||||
paramtable.Init()
|
||||
require.NoError(t, paramtable.Get().Save(Params.CommonCfg.SuperUsers.Key, "root"))
|
||||
defer paramtable.Get().Reset(Params.CommonCfg.SuperUsers.Key)
|
||||
|
||||
mixCoord := mocks.NewMockMixCoordClient(t)
|
||||
mixCoord.On("UpdateCredential", mock.Anything, mock.Anything).Return(merr.Success(), nil).Maybe()
|
||||
node := &Proxy{mixCoord: mixCoord}
|
||||
node.UpdateStateCode(commonpb.StateCode_Healthy)
|
||||
|
||||
description := strings.Repeat("x", 1025)
|
||||
status, err := node.UpdateCredential(GetContext(context.Background(), "root:password"), &milvuspb.UpdateCredentialRequest{
|
||||
Username: "desc_user",
|
||||
OldPassword: crypto.Base64Encode("old_password"),
|
||||
NewPassword: crypto.Base64Encode("new_password"),
|
||||
Description: &description,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
||||
mixCoord.AssertNotCalled(t, "UpdateCredential", mock.Anything, mock.Anything)
|
||||
}
|
||||
|
||||
func TestUpdateCredentialPasswordValidationErrors(t *testing.T) {
|
||||
paramtable.Init()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
oldPassword string
|
||||
newPassword string
|
||||
reason string
|
||||
}{
|
||||
{
|
||||
name: "invalid old password base64",
|
||||
oldPassword: "not-base64!!",
|
||||
newPassword: crypto.Base64Encode("new_password"),
|
||||
reason: "decode old password failed",
|
||||
},
|
||||
{
|
||||
name: "invalid new password base64",
|
||||
oldPassword: crypto.Base64Encode("old_password"),
|
||||
newPassword: "not-base64!!",
|
||||
reason: "decode password failed",
|
||||
},
|
||||
{
|
||||
name: "invalid new password length",
|
||||
oldPassword: crypto.Base64Encode("old_password"),
|
||||
newPassword: crypto.Base64Encode("short"),
|
||||
reason: "invalid password length",
|
||||
},
|
||||
{
|
||||
name: "old password verification failed",
|
||||
oldPassword: crypto.Base64Encode("old_password"),
|
||||
newPassword: crypto.Base64Encode("new_password"),
|
||||
reason: "old password not correct",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
mixCoord := mocks.NewMockMixCoordClient(t)
|
||||
mixCoord.On("UpdateCredential", mock.Anything, mock.Anything).Return(merr.Success(), nil).Maybe()
|
||||
node := &Proxy{mixCoord: mixCoord}
|
||||
node.UpdateStateCode(commonpb.StateCode_Healthy)
|
||||
|
||||
status, err := node.UpdateCredential(context.Background(), &milvuspb.UpdateCredentialRequest{
|
||||
Username: "desc_user",
|
||||
OldPassword: test.oldPassword,
|
||||
NewPassword: test.newPassword,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, commonpb.ErrorCode_Success, status.GetErrorCode())
|
||||
assert.Contains(t, status.GetReason(), test.reason)
|
||||
mixCoord.AssertNotCalled(t, "UpdateCredential", mock.Anything, mock.Anything)
|
||||
})
|
||||
}
|
||||
}
|
||||
+54
-38
@@ -5483,6 +5483,9 @@ func (node *Proxy) CreateCredential(ctx context.Context, req *milvuspb.CreateCre
|
||||
if err := ValidateUsername(username); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
if err := ValidateUserDescription(req.GetDescription()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
rawPassword, err := crypto.Base64Decode(req.Password)
|
||||
if err != nil {
|
||||
log.Error("decode password fail",
|
||||
@@ -5511,6 +5514,7 @@ func (node *Proxy) CreateCredential(ctx context.Context, req *milvuspb.CreateCre
|
||||
Username: req.Username,
|
||||
EncryptedPassword: encryptedPassword,
|
||||
Sha256Password: crypto.SHA256(rawPassword, req.Username),
|
||||
Description: req.Description,
|
||||
}
|
||||
result, err := node.mixCoord.CreateCredential(ctx, credInfo)
|
||||
if err != nil { // for error like conntext timeout etc.
|
||||
@@ -5533,57 +5537,69 @@ func (node *Proxy) UpdateCredential(ctx context.Context, req *milvuspb.UpdateCre
|
||||
if err := merr.CheckHealthy(node.GetStateCode()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
rawOldPassword, err := crypto.Base64Decode(req.OldPassword)
|
||||
if err != nil {
|
||||
log.Error("decode old password fail",
|
||||
zap.Error(err))
|
||||
err = merr.WrapErrParameterInvalidErr(err, "decode old password failed")
|
||||
if err := ValidateUserDescription(req.GetDescription()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
rawNewPassword, err := crypto.Base64Decode(req.NewPassword)
|
||||
if err != nil {
|
||||
log.Error("decode password fail",
|
||||
zap.Error(err))
|
||||
err = merr.WrapErrParameterInvalidErr(err, "decode password failed")
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
// valid new password
|
||||
if err = ValidatePassword(rawNewPassword); err != nil {
|
||||
log.Error("illegal password",
|
||||
zap.Error(err))
|
||||
if req.GetNewPassword() == "" && req.Description == nil {
|
||||
err := merr.WrapErrParameterInvalidMsg("must update either password or description")
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
skipPasswordVerify := false
|
||||
if currentUser, _ := GetCurUserFromContext(ctx); currentUser != "" {
|
||||
for _, s := range Params.CommonCfg.SuperUsers.GetAsStrings() {
|
||||
if s == currentUser {
|
||||
skipPasswordVerify = true
|
||||
updateCredReq := &internalpb.CredentialInfo{
|
||||
Username: req.Username,
|
||||
Description: req.Description,
|
||||
}
|
||||
|
||||
if req.GetNewPassword() != "" {
|
||||
rawOldPassword, err := crypto.Base64Decode(req.OldPassword)
|
||||
if err != nil {
|
||||
log.Error("decode old password fail",
|
||||
zap.Error(err))
|
||||
err = merr.WrapErrParameterInvalidErr(err, "decode old password failed")
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
rawNewPassword, err := crypto.Base64Decode(req.NewPassword)
|
||||
if err != nil {
|
||||
log.Error("decode password fail",
|
||||
zap.Error(err))
|
||||
err = merr.WrapErrParameterInvalidErr(err, "decode password failed")
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
// valid new password
|
||||
if err = ValidatePassword(rawNewPassword); err != nil {
|
||||
log.Error("illegal password",
|
||||
zap.Error(err))
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
skipPasswordVerify := false
|
||||
if currentUser, _ := GetCurUserFromContext(ctx); currentUser != "" {
|
||||
for _, s := range Params.CommonCfg.SuperUsers.GetAsStrings() {
|
||||
if s == currentUser {
|
||||
skipPasswordVerify = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !skipPasswordVerify && !passwordVerify(ctx, req.Username, rawOldPassword, privilege.GetPrivilegeCache()) {
|
||||
err := merr.WrapErrPrivilegeNotAuthenticated("old password not correct for %s", req.GetUsername())
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
// update meta data
|
||||
encryptedPassword, err := crypto.PasswordEncrypt(rawNewPassword)
|
||||
if err != nil {
|
||||
log.Error("encrypt password fail",
|
||||
zap.Error(err))
|
||||
err = merr.WrapErrServiceInternalErr(err, "encrypt password failed")
|
||||
return merr.Status(err), nil
|
||||
if !skipPasswordVerify && !passwordVerify(ctx, req.Username, rawOldPassword, privilege.GetPrivilegeCache()) {
|
||||
err := merr.WrapErrPrivilegeNotAuthenticated("old password not correct for %s", req.GetUsername())
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
// update meta data
|
||||
encryptedPassword, err := crypto.PasswordEncrypt(rawNewPassword)
|
||||
if err != nil {
|
||||
log.Error("encrypt password fail",
|
||||
zap.Error(err))
|
||||
err = merr.WrapErrServiceInternalErr(err, "encrypt password failed")
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
updateCredReq.Sha256Password = crypto.SHA256(rawNewPassword, req.Username)
|
||||
updateCredReq.EncryptedPassword = encryptedPassword
|
||||
}
|
||||
if req.Base == nil {
|
||||
req.Base = &commonpb.MsgBase{}
|
||||
}
|
||||
req.Base.MsgType = commonpb.MsgType_UpdateCredential
|
||||
updateCredReq := &internalpb.CredentialInfo{
|
||||
Username: req.Username,
|
||||
Sha256Password: crypto.SHA256(rawNewPassword, req.Username),
|
||||
EncryptedPassword: encryptedPassword,
|
||||
}
|
||||
result, err := node.mixCoord.UpdateCredential(ctx, updateCredReq)
|
||||
if err != nil { // for error like conntext timeout etc.
|
||||
log.Error("update credential fail",
|
||||
|
||||
@@ -1486,6 +1486,13 @@ func ValidateUsername(username string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateUserDescription(description string) error {
|
||||
if len(description) > Params.ProxyCfg.MaxUserDescriptionLength.GetAsInt() {
|
||||
return merr.WrapErrParameterInvalidMsg("invalid user description with length %d, the length of user description must be less than or equal to %s", len(description), Params.ProxyCfg.MaxUserDescriptionLength.GetValue())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidatePassword(password string) error {
|
||||
if len(password) < Params.ProxyCfg.MinPasswordLength.GetAsInt() || len(password) > Params.ProxyCfg.MaxPasswordLength.GetAsInt() {
|
||||
return merr.WrapErrParameterInvalidRange(Params.ProxyCfg.MinPasswordLength.GetAsInt(),
|
||||
|
||||
@@ -88,8 +88,10 @@ func (c *DDLCallback) alterUserV2AckCallback(ctx context.Context, result message
|
||||
return merr.Wrap(err, "failed to alter credential")
|
||||
}
|
||||
// update proxy's local cache
|
||||
if err := c.UpdateCredCache(ctx, result.Message.MustBody().CredentialInfo); err != nil {
|
||||
return merr.Wrap(err, "failed to update cred cache")
|
||||
if result.Message.MustBody().CredentialInfo.GetSha256Password() != "" {
|
||||
if err := c.UpdateCredCache(ctx, result.Message.MustBody().CredentialInfo); err != nil {
|
||||
return merr.Wrap(err, "failed to update cred cache")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -18,14 +18,20 @@ package rootcoord
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/v3/commonpb"
|
||||
"github.com/milvus-io/milvus-proto/go-api/v3/milvuspb"
|
||||
"github.com/milvus-io/milvus/internal/util/proxyutil"
|
||||
"github.com/milvus-io/milvus/pkg/v3/proto/internalpb"
|
||||
"github.com/milvus-io/milvus/pkg/v3/proto/proxypb"
|
||||
"github.com/milvus-io/milvus/pkg/v3/proto/rootcoordpb"
|
||||
"github.com/milvus-io/milvus/pkg/v3/streaming/util/message"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/merr"
|
||||
)
|
||||
@@ -70,6 +76,7 @@ func TestDDLCallbacksRBACCredential(t *testing.T) {
|
||||
status, err = core.UpdateCredential(context.Background(), &internalpb.CredentialInfo{
|
||||
Username: testUserName,
|
||||
EncryptedPassword: "1234567",
|
||||
Sha256Password: "1234567-sha256",
|
||||
})
|
||||
require.NoError(t, merr.CheckRPCCall(status, err))
|
||||
getCredentialResp, err = core.GetCredential(context.Background(), &rootcoordpb.GetCredentialRequest{
|
||||
@@ -88,3 +95,81 @@ func TestDDLCallbacksRBACCredential(t *testing.T) {
|
||||
})
|
||||
require.Error(t, merr.CheckRPCCall(getCredentialResp.Status, err))
|
||||
}
|
||||
|
||||
func TestAlterUserV2AckCallbackSkipsCredentialCacheForDescriptionOnlyUpdate(t *testing.T) {
|
||||
description := "description only"
|
||||
var updateCacheCalls atomic.Int32
|
||||
|
||||
meta := newMockMetaTable()
|
||||
meta.AlterCredentialFunc = func(ctx context.Context, msg message.BroadcastResultAlterUserMessageV2) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
core := newTestCore(withMeta(meta))
|
||||
core.proxyClientManager = proxyutil.NewProxyClientManager(proxyutil.DefaultProxyCreator)
|
||||
proxy := newMockProxy()
|
||||
proxy.UpdateCredentialCacheFunc = func(ctx context.Context, request *proxypb.UpdateCredCacheRequest) (*commonpb.Status, error) {
|
||||
updateCacheCalls.Add(1)
|
||||
return merr.Success(), nil
|
||||
}
|
||||
core.proxyClientManager.GetProxyClients().Insert(TestProxyID, proxy)
|
||||
|
||||
err := (&DDLCallback{Core: core}).alterUserV2AckCallback(context.Background(), buildAlterUserMessage(&internalpb.CredentialInfo{
|
||||
Username: "desc_user",
|
||||
Description: &description,
|
||||
}, 1))
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Zero(t, updateCacheCalls.Load())
|
||||
}
|
||||
|
||||
func TestAlterUserV2AckCallbackUpdatesCredentialCacheForPasswordUpdate(t *testing.T) {
|
||||
var updateCacheCalls atomic.Int32
|
||||
|
||||
meta := newMockMetaTable()
|
||||
meta.AlterCredentialFunc = func(ctx context.Context, msg message.BroadcastResultAlterUserMessageV2) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
core := newTestCore(withMeta(meta))
|
||||
core.proxyClientManager = proxyutil.NewProxyClientManager(proxyutil.DefaultProxyCreator)
|
||||
proxy := newMockProxy()
|
||||
proxy.UpdateCredentialCacheFunc = func(ctx context.Context, request *proxypb.UpdateCredCacheRequest) (*commonpb.Status, error) {
|
||||
updateCacheCalls.Add(1)
|
||||
assert.Equal(t, "desc_user", request.GetUsername())
|
||||
assert.Equal(t, "sha256", request.GetPassword())
|
||||
return merr.Success(), nil
|
||||
}
|
||||
core.proxyClientManager.GetProxyClients().Insert(TestProxyID, proxy)
|
||||
|
||||
err := (&DDLCallback{Core: core}).alterUserV2AckCallback(context.Background(), buildAlterUserMessage(&internalpb.CredentialInfo{
|
||||
Username: "desc_user",
|
||||
Sha256Password: "sha256",
|
||||
}, 1))
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int32(1), updateCacheCalls.Load())
|
||||
}
|
||||
|
||||
func TestAlterUserV2AckCallbackReturnsCredentialCacheError(t *testing.T) {
|
||||
meta := newMockMetaTable()
|
||||
meta.AlterCredentialFunc = func(ctx context.Context, msg message.BroadcastResultAlterUserMessageV2) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
core := newTestCore(withMeta(meta))
|
||||
core.proxyClientManager = proxyutil.NewProxyClientManager(proxyutil.DefaultProxyCreator)
|
||||
proxy := newMockProxy()
|
||||
proxy.UpdateCredentialCacheFunc = func(ctx context.Context, request *proxypb.UpdateCredCacheRequest) (*commonpb.Status, error) {
|
||||
return nil, errors.New("cache update failed")
|
||||
}
|
||||
core.proxyClientManager.GetProxyClients().Insert(TestProxyID, proxy)
|
||||
|
||||
err := (&DDLCallback{Core: core}).alterUserV2AckCallback(context.Background(), buildAlterUserMessage(&internalpb.CredentialInfo{
|
||||
Username: "desc_user",
|
||||
Sha256Password: "sha256",
|
||||
}, 1))
|
||||
|
||||
require.Error(t, err)
|
||||
assert.ErrorContains(t, err, "failed to update cred cache")
|
||||
}
|
||||
|
||||
@@ -1741,6 +1741,14 @@ func (mt *MetaTable) CheckIfUpdateCredential(ctx context.Context, credInfo *inte
|
||||
if funcutil.IsEmptyString(credInfo.GetUsername()) {
|
||||
return merr.WrapErrParameterInvalidMsg("username is empty")
|
||||
}
|
||||
hasEncryptedPassword := credInfo.GetEncryptedPassword() != ""
|
||||
hasSha256Password := credInfo.GetSha256Password() != ""
|
||||
if hasEncryptedPassword != hasSha256Password {
|
||||
return merr.WrapErrParameterInvalidMsg("credential password update must include both encrypted and sha256 password")
|
||||
}
|
||||
if !hasEncryptedPassword && !hasSha256Password && credInfo.Description == nil {
|
||||
return merr.WrapErrParameterInvalidMsg("credential update must change password or description")
|
||||
}
|
||||
mt.permissionLock.RLock()
|
||||
defer mt.permissionLock.RUnlock()
|
||||
|
||||
@@ -1774,9 +1782,20 @@ func (mt *MetaTable) AlterCredential(ctx context.Context, result message.Broadca
|
||||
)
|
||||
return nil
|
||||
}
|
||||
encryptedPassword := body.CredentialInfo.EncryptedPassword
|
||||
description := body.CredentialInfo.GetDescription()
|
||||
if existsCredential != nil {
|
||||
if encryptedPassword == "" {
|
||||
encryptedPassword = existsCredential.EncryptedPassword
|
||||
}
|
||||
if body.CredentialInfo.Description == nil {
|
||||
description = existsCredential.Description
|
||||
}
|
||||
}
|
||||
credential := &model.Credential{
|
||||
Username: body.CredentialInfo.Username,
|
||||
EncryptedPassword: body.CredentialInfo.EncryptedPassword,
|
||||
EncryptedPassword: encryptedPassword,
|
||||
Description: description,
|
||||
TimeTick: result.GetControlChannelResult().TimeTick,
|
||||
}
|
||||
return mt.catalog.AlterCredential(ctx, credential)
|
||||
|
||||
@@ -162,6 +162,90 @@ func TestRbacCredential(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRbacCredentialAlterCredentialMergesPartialUpdates(t *testing.T) {
|
||||
mt := generateMetaTable(t)
|
||||
|
||||
ptr := func(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
username := "user" + funcutil.RandomString(10)
|
||||
err := mt.AlterCredential(context.TODO(), buildAlterUserMessage(&internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
EncryptedPassword: "old-password",
|
||||
Description: ptr("initial description"),
|
||||
}, 1))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mt.AlterCredential(context.TODO(), buildAlterUserMessage(&internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
EncryptedPassword: "new-password",
|
||||
}, 2))
|
||||
require.NoError(t, err)
|
||||
cred, err := mt.GetCredential(context.TODO(), username)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "new-password", cred.GetEncryptedPassword())
|
||||
assert.Equal(t, "initial description", cred.GetDescription())
|
||||
|
||||
err = mt.AlterCredential(context.TODO(), buildAlterUserMessage(&internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
Description: ptr("updated description"),
|
||||
}, 3))
|
||||
require.NoError(t, err)
|
||||
cred, err = mt.GetCredential(context.TODO(), username)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "new-password", cred.GetEncryptedPassword())
|
||||
assert.Equal(t, "updated description", cred.GetDescription())
|
||||
|
||||
err = mt.AlterCredential(context.TODO(), buildAlterUserMessage(&internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
Description: ptr(""),
|
||||
}, 4))
|
||||
require.NoError(t, err)
|
||||
cred, err = mt.GetCredential(context.TODO(), username)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "new-password", cred.GetEncryptedPassword())
|
||||
assert.Equal(t, "", cred.GetDescription())
|
||||
}
|
||||
|
||||
func TestRbacCredentialRejectsInconsistentPasswordUpdate(t *testing.T) {
|
||||
mt := generateMetaTable(t)
|
||||
|
||||
username := "user" + funcutil.RandomString(10)
|
||||
err := mt.AlterCredential(context.TODO(), buildAlterUserMessage(&internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
EncryptedPassword: "old-password",
|
||||
}, 1))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mt.CheckIfUpdateCredential(context.TODO(), &internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
EncryptedPassword: "new-password",
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.ErrorContains(t, err, "must include both encrypted and sha256 password")
|
||||
|
||||
err = mt.CheckIfUpdateCredential(context.TODO(), &internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
Sha256Password: "sha256",
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.ErrorContains(t, err, "must include both encrypted and sha256 password")
|
||||
|
||||
description := "description-only update"
|
||||
err = mt.CheckIfUpdateCredential(context.TODO(), &internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
Description: &description,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mt.CheckIfUpdateCredential(context.TODO(), &internalpb.CredentialInfo{
|
||||
Username: username,
|
||||
})
|
||||
require.Error(t, err)
|
||||
assert.ErrorContains(t, err, "credential update must change password or description")
|
||||
}
|
||||
|
||||
func TestRbacCreateRole(t *testing.T) {
|
||||
mt := generateMetaTable(t)
|
||||
|
||||
|
||||
@@ -2199,7 +2199,6 @@ func (c *Core) CreateCredential(ctx context.Context, credInfo *internalpb.Creden
|
||||
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
if err := c.broadcastAlterUserForCreateCredential(ctx, credInfo); err != nil {
|
||||
ctxLog.Warn("CreateCredential failed", zap.Error(err))
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
@@ -2255,7 +2254,6 @@ func (c *Core) UpdateCredential(ctx context.Context, credInfo *internalpb.Creden
|
||||
if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
|
||||
return merr.Status(err), nil
|
||||
}
|
||||
|
||||
if err := c.broadcastAlterUserForUpdateCredential(ctx, credInfo); err != nil {
|
||||
ctxLog.Warn("UpdateCredential append message failed", zap.Error(err))
|
||||
metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.FailLabel).Inc()
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ require (
|
||||
github.com/jolestar/go-commons-pool/v2 v2.1.2
|
||||
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12
|
||||
github.com/klauspost/compress v1.18.0
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260514121806-9b60a053353f
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e
|
||||
github.com/minio/minio-go/v7 v7.0.73
|
||||
github.com/panjf2000/ants/v2 v2.11.3
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
|
||||
+2
-2
@@ -498,8 +498,8 @@ github.com/milvus-io/cgosymbolizer v0.0.0-20250318084424-114f4050c3a6 h1:YHMFI6L
|
||||
github.com/milvus-io/cgosymbolizer v0.0.0-20250318084424-114f4050c3a6/go.mod h1:DvXTE/K/RtHehxU8/GtDs4vFtfw64jJ3PaCnFri8CRg=
|
||||
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b h1:TfeY0NxYxZzUfIfYe5qYDBzt4ZYRqzUjTR6CvUzjat8=
|
||||
github.com/milvus-io/gorocksdb v0.0.0-20220624081344-8c5f4212846b/go.mod h1:iwW+9cWfIzzDseEBCCeDSN5SD16Tidvy8cwQ7ZY8Qj4=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260514121806-9b60a053353f h1:Z2paGeFL0i1a3Dqw82DwRwZ2ix3FtyKU7+u6rR7jbUs=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260514121806-9b60a053353f/go.mod h1:rbKpv5JToISTKTTLl0duL5r6wbYnjJ9SsD0QgXMzKy0=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e h1:axPnOhjsWqqxk0dOQRSIU2mdg52Kyl/8E6iDFZy/IpE=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e/go.mod h1:rbKpv5JToISTKTTLl0duL5r6wbYnjJ9SsD0QgXMzKy0=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.73 h1:qr2vi96Qm7kZ4v7LLebjte+MQh621fFWnv93p12htEo=
|
||||
|
||||
@@ -329,6 +329,7 @@ message CredentialInfo {
|
||||
// encrypted by sha256 (for good performance in cache mapping)
|
||||
string sha256_password = 5; // not save in metadata.
|
||||
uint64 time_tick = 6; // the timetick in wal which the credential updates
|
||||
optional string description = 7;
|
||||
}
|
||||
|
||||
message ListPolicyRequest {
|
||||
|
||||
+308
-295
@@ -2945,8 +2945,9 @@ type CredentialInfo struct {
|
||||
// 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"` // 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
|
||||
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
|
||||
Description *string `protobuf:"bytes,7,opt,name=description,proto3,oneof" json:"description,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CredentialInfo) Reset() {
|
||||
@@ -3025,6 +3026,13 @@ func (x *CredentialInfo) GetTimeTick() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CredentialInfo) GetDescription() string {
|
||||
if x != nil && x.Description != nil {
|
||||
return *x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ListPolicyRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -5292,7 +5300,7 @@ var file_internal_proto_rawDesc = []byte{
|
||||
0x20, 0x03, 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, 0xdc, 0x01,
|
||||
0x61, 0x75, 0x6c, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x93, 0x02,
|
||||
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,
|
||||
@@ -5306,304 +5314,308 @@ var file_internal_proto_rawDesc = []byte{
|
||||
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,
|
||||
0x28, 0x04, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x54, 0x69, 0x63, 0x6b, 0x12, 0x25, 0x0a, 0x0b,
|
||||
0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||
0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
|
||||
0x69, 0x6f, 0x6e, 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, 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,
|
||||
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, 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, 0xc8, 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, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 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, 0x22, 0x6d, 0x0a, 0x10, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70,
|
||||
0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12,
|
||||
0x21, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61,
|
||||
0x6d, 0x65, 0x22, 0x7a, 0x0a, 0x17, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a,
|
||||
0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x27, 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, 0x6c, 0x65, 0x52, 0x65, 0x73,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5d,
|
||||
0x0a, 0x10, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x7a, 0x6b, 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, 0x17, 0x0a, 0x07, 0x64, 0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x62, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x5a, 0x0a,
|
||||
0x11, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x7a, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
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, 0xc8, 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, 0x10, 0x0a, 0x03, 0x65, 0x7a, 0x6b, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x7a, 0x6b, 0x2a, 0x59, 0x0a, 0x0a, 0x53, 0x65, 0x61,
|
||||
0x72, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55,
|
||||
0x4c, 0x54, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x50, 0x55, 0x52, 0x45, 0x5f, 0x41, 0x4e, 0x4e,
|
||||
0x5f, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x4e, 0x4f, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45,
|
||||
0x52, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x50, 0x55, 0x52, 0x45, 0x5f, 0x41, 0x4e, 0x4e, 0x5f,
|
||||
0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x57, 0x49, 0x54, 0x48, 0x5f, 0x46, 0x49, 0x4c, 0x54,
|
||||
0x45, 0x52, 0x10, 0x02, 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, 0xc8, 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, 0x11, 0x0a, 0x09, 0x44, 0x4d, 0x4c, 0x55,
|
||||
0x70, 0x73, 0x65, 0x72, 0x74, 0x10, 0x0a, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x44,
|
||||
0x44, 0x4c, 0x44, 0x42, 0x10, 0x0b, 0x2a, 0xa4, 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, 0x12, 0x0f, 0x0a, 0x0b,
|
||||
0x55, 0x6e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x10, 0x08, 0x12, 0x0e, 0x0a,
|
||||
0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x10, 0x09, 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, 0x33, 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,
|
||||
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, 0x1f,
|
||||
0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 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, 0x22, 0x6d, 0x0a, 0x10, 0x46, 0x69,
|
||||
0x6c, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67,
|
||||
0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x7a, 0x0a, 0x17, 0x53, 0x79, 0x6e,
|
||||
0x63, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 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, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x0a, 0x10, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45,
|
||||
0x7a, 0x6b, 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, 0x17, 0x0a, 0x07, 0x64,
|
||||
0x62, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x62,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x22, 0x5a, 0x0a, 0x11, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x45, 0x7a,
|
||||
0x6b, 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, 0x10,
|
||||
0x0a, 0x03, 0x65, 0x7a, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x65, 0x7a, 0x6b,
|
||||
0x2a, 0x59, 0x0a, 0x0a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b,
|
||||
0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x50,
|
||||
0x55, 0x52, 0x45, 0x5f, 0x41, 0x4e, 0x4e, 0x5f, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x4e,
|
||||
0x4f, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x50, 0x55,
|
||||
0x52, 0x45, 0x5f, 0x41, 0x4e, 0x4e, 0x5f, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x57, 0x49,
|
||||
0x54, 0x48, 0x5f, 0x46, 0x49, 0x4c, 0x54, 0x45, 0x52, 0x10, 0x02, 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, 0xc8, 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,
|
||||
0x11, 0x0a, 0x09, 0x44, 0x4d, 0x4c, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x10, 0x0a, 0x1a, 0x02,
|
||||
0x08, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x44, 0x4c, 0x44, 0x42, 0x10, 0x0b, 0x2a, 0xa4, 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, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x6e, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74,
|
||||
0x65, 0x64, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x69,
|
||||
0x6e, 0x67, 0x10, 0x09, 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, 0x33, 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 (
|
||||
@@ -6434,6 +6446,7 @@ func file_internal_proto_init() {
|
||||
}
|
||||
}
|
||||
}
|
||||
file_internal_proto_msgTypes[28].OneofWrappers = []interface{}{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
|
||||
@@ -2053,6 +2053,7 @@ type proxyConfig struct {
|
||||
MaxNameLength ParamItem `refreshable:"true"`
|
||||
MaxCollectionDescriptionLength ParamItem `refreshable:"true"`
|
||||
MaxUsernameLength ParamItem `refreshable:"true"`
|
||||
MaxUserDescriptionLength ParamItem `refreshable:"true"`
|
||||
MinPasswordLength ParamItem `refreshable:"true"`
|
||||
MaxPasswordLength ParamItem `refreshable:"true"`
|
||||
MaxFieldNum ParamItem `refreshable:"true"`
|
||||
@@ -2175,6 +2176,14 @@ func (p *proxyConfig) init(base *BaseTable) {
|
||||
}
|
||||
p.MaxUsernameLength.Init(base.mgr)
|
||||
|
||||
p.MaxUserDescriptionLength = ParamItem{
|
||||
Key: "proxy.maxUserDescriptionLength",
|
||||
DefaultValue: "1024",
|
||||
Version: "2.6.19",
|
||||
PanicIfEmpty: true,
|
||||
}
|
||||
p.MaxUserDescriptionLength.Init(base.mgr)
|
||||
|
||||
p.MaxPasswordLength = ParamItem{
|
||||
Key: "proxy.maxPasswordLength",
|
||||
DefaultValue: "72", // bcrypt max length
|
||||
|
||||
@@ -236,6 +236,7 @@ func TestComponentParam(t *testing.T) {
|
||||
t.Logf("MsgStreamTimeTickBufSize: %d", Params.MsgStreamTimeTickBufSize.GetAsInt64())
|
||||
|
||||
t.Logf("MaxNameLength: %d", Params.MaxNameLength.GetAsInt64())
|
||||
assert.Equal(t, 1024, Params.MaxUserDescriptionLength.GetAsInt())
|
||||
|
||||
t.Logf("MaxFieldNum: %d", Params.MaxFieldNum.GetAsInt64())
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ go 1.26.4
|
||||
require (
|
||||
github.com/apache/arrow/go/v17 v17.0.0
|
||||
github.com/cockroachdb/errors v1.9.1
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e
|
||||
github.com/milvus-io/milvus/client/v2 v2.0.0-20241125024034-0b9edb62a92d
|
||||
github.com/milvus-io/milvus/pkg/v3 v3.0.0-beta
|
||||
github.com/minio/minio-go/v7 v7.0.73
|
||||
|
||||
@@ -245,8 +245,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f h1:W+paUzc+AA381Rydx2DJffoQuM4l+efVqO+2i9GdfMw=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260526093827-489331a5a41f/go.mod h1:rbKpv5JToISTKTTLl0duL5r6wbYnjJ9SsD0QgXMzKy0=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e h1:axPnOhjsWqqxk0dOQRSIU2mdg52Kyl/8E6iDFZy/IpE=
|
||||
github.com/milvus-io/milvus-proto/go-api/v3 v3.0.0-20260612100615-43795e8f8f6e/go.mod h1:rbKpv5JToISTKTTLl0duL5r6wbYnjJ9SsD0QgXMzKy0=
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
|
||||
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/milvus-io/milvus-proto/go-api/v3/commonpb"
|
||||
"github.com/milvus-io/milvus-proto/go-api/v3/milvuspb"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/crypto"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/v3/util/paramtable"
|
||||
"github.com/milvus-io/milvus/tests/integration"
|
||||
@@ -107,6 +108,76 @@ func (s *RBACBasicTestSuite) TestDropRole() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RBACBasicTestSuite) TestCredentialDescriptionRoundTrip() {
|
||||
rootCtx := GetContext(context.Background(), defaultAuth)
|
||||
userName := fmt.Sprintf("desc_user_%d", rand.Int31n(1000000))
|
||||
oldPassword := "old_password"
|
||||
newPassword := "new_password"
|
||||
description := "CJK user description \xe6\x9d\x83\xe9\x99\x90\xe7\x94\xa8\xe6\x88\xb7"
|
||||
updatedDescription := "updated description \xe6\x9b\xb4\xe6\x96\xb0"
|
||||
|
||||
resp, err := s.Cluster.MilvusClient.CreateCredential(rootCtx, &milvuspb.CreateCredentialRequest{
|
||||
Username: userName,
|
||||
Password: crypto.Base64Encode(oldPassword),
|
||||
Description: &description,
|
||||
})
|
||||
s.NoError(err)
|
||||
s.True(merr.Ok(resp))
|
||||
defer s.Cluster.MilvusClient.DeleteCredential(rootCtx, &milvuspb.DeleteCredentialRequest{Username: userName}) //nolint
|
||||
|
||||
selectResp, err := s.Cluster.MilvusClient.SelectUser(rootCtx, &milvuspb.SelectUserRequest{
|
||||
User: &milvuspb.UserEntity{Name: userName},
|
||||
IncludeRoleInfo: false,
|
||||
})
|
||||
s.NoError(err)
|
||||
s.True(merr.Ok(selectResp.GetStatus()))
|
||||
s.Len(selectResp.GetResults(), 1)
|
||||
s.Equal(description, selectResp.GetResults()[0].GetDescription())
|
||||
|
||||
updateResp, err := s.Cluster.MilvusClient.UpdateCredential(rootCtx, &milvuspb.UpdateCredentialRequest{
|
||||
Username: userName,
|
||||
Description: &updatedDescription,
|
||||
})
|
||||
s.NoError(err)
|
||||
s.True(merr.Ok(updateResp))
|
||||
|
||||
oldUserCtx := GetContext(context.Background(), fmt.Sprintf("%s:%s", userName, oldPassword))
|
||||
authResp, err := s.Cluster.MilvusClient.ShowCollections(oldUserCtx, &milvuspb.ShowCollectionsRequest{})
|
||||
s.NoError(err)
|
||||
s.True(merr.Ok(authResp.GetStatus()))
|
||||
|
||||
selectResp, err = s.Cluster.MilvusClient.SelectUser(rootCtx, &milvuspb.SelectUserRequest{
|
||||
User: &milvuspb.UserEntity{Name: userName},
|
||||
IncludeRoleInfo: false,
|
||||
})
|
||||
s.NoError(err)
|
||||
s.True(merr.Ok(selectResp.GetStatus()))
|
||||
s.Len(selectResp.GetResults(), 1)
|
||||
s.Equal(updatedDescription, selectResp.GetResults()[0].GetDescription())
|
||||
|
||||
updateResp, err = s.Cluster.MilvusClient.UpdateCredential(rootCtx, &milvuspb.UpdateCredentialRequest{
|
||||
Username: userName,
|
||||
OldPassword: crypto.Base64Encode(oldPassword),
|
||||
NewPassword: crypto.Base64Encode(newPassword),
|
||||
})
|
||||
s.NoError(err)
|
||||
s.True(merr.Ok(updateResp))
|
||||
|
||||
newUserCtx := GetContext(context.Background(), fmt.Sprintf("%s:%s", userName, newPassword))
|
||||
authResp, err = s.Cluster.MilvusClient.ShowCollections(newUserCtx, &milvuspb.ShowCollectionsRequest{})
|
||||
s.NoError(err)
|
||||
s.True(merr.Ok(authResp.GetStatus()))
|
||||
|
||||
selectResp, err = s.Cluster.MilvusClient.SelectUser(rootCtx, &milvuspb.SelectUserRequest{
|
||||
User: &milvuspb.UserEntity{Name: userName},
|
||||
IncludeRoleInfo: false,
|
||||
})
|
||||
s.NoError(err)
|
||||
s.True(merr.Ok(selectResp.GetStatus()))
|
||||
s.Len(selectResp.GetResults(), 1)
|
||||
s.Equal(updatedDescription, selectResp.GetResults()[0].GetDescription())
|
||||
}
|
||||
|
||||
func TestRBAC(t *testing.T) {
|
||||
suite.Run(t, new(RBACBasicTestSuite))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user