mirror of https://github.com/milvus-io/milvus.git
				
				
				
			enhance: Add BackupRBAC/RestoreRBAC API to enable rbac backup (#35444)
issue: #35443 --------- Signed-off-by: Wei Liu <wei.liu@zilliz.com>pull/35507/head
							parent
							
								
									1275005fc1
								
							
						
					
					
						commit
						1d49358f82
					
				
							
								
								
									
										4
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										4
									
								
								go.mod
								
								
								
								
							| 
						 | 
				
			
			@ -22,7 +22,7 @@ require (
 | 
			
		|||
	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
 | 
			
		||||
	github.com/klauspost/compress v1.17.7
 | 
			
		||||
	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
 | 
			
		||||
	github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240717062137-3ffb1db01632
 | 
			
		||||
	github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240815113856-e2789dca8b59
 | 
			
		||||
	github.com/minio/minio-go/v7 v7.0.61
 | 
			
		||||
	github.com/pingcap/log v1.1.1-0.20221015072633-39906604fb81
 | 
			
		||||
	github.com/prometheus/client_golang v1.14.0
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +57,7 @@ require (
 | 
			
		|||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/bits-and-blooms/bitset v1.10.0
 | 
			
		||||
	github.com/bytedance/sonic v1.9.1
 | 
			
		||||
	github.com/cenkalti/backoff/v4 v4.2.1
 | 
			
		||||
	github.com/cockroachdb/redact v1.1.3
 | 
			
		||||
	github.com/greatroar/blobloom v0.0.0-00010101000000-000000000000
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +92,6 @@ require (
 | 
			
		|||
	github.com/benbjohnson/clock v1.1.0 // indirect
 | 
			
		||||
	github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b // indirect
 | 
			
		||||
	github.com/beorn7/perks v1.0.1 // indirect
 | 
			
		||||
	github.com/bytedance/sonic v1.9.1 // indirect
 | 
			
		||||
	github.com/campoy/embedmd v1.0.0 // indirect
 | 
			
		||||
	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 | 
			
		||||
	github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										4
									
								
								go.sum
								
								
								
								
							| 
						 | 
				
			
			@ -598,8 +598,8 @@ github.com/milvus-io/cgosymbolizer v0.0.0-20240722103217-b7dee0e50119 h1:9VXijWu
 | 
			
		|||
github.com/milvus-io/cgosymbolizer v0.0.0-20240722103217-b7dee0e50119/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.3.4-0.20240717062137-3ffb1db01632 h1:CXig0DNtUsCLzchCFe3PR2KgOdobbz9gK2nSV7195PM=
 | 
			
		||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240717062137-3ffb1db01632/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
 | 
			
		||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240815113856-e2789dca8b59 h1:mKekr0GmCKMpIQh9OJ67TlKVKxDt08600ltARc/JUXY=
 | 
			
		||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240815113856-e2789dca8b59/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
 | 
			
		||||
github.com/milvus-io/pulsar-client-go v0.6.10 h1:eqpJjU+/QX0iIhEo3nhOqMNXL+TyInAs1IAHZCrCM/A=
 | 
			
		||||
github.com/milvus-io/pulsar-client-go v0.6.10/go.mod h1:lQqCkgwDF8YFYjKA+zOheTk1tev2B+bKj5j7+nm8M1w=
 | 
			
		||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -624,6 +624,14 @@ func (m *mockRootCoordClient) GetMetrics(ctx context.Context, req *milvuspb.GetM
 | 
			
		|||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *mockRootCoordClient) BackupRBAC(ctx context.Context, req *milvuspb.BackupRBACMetaRequest, opts ...grpc.CallOption) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	panic("not implemented") // TODO: Implement
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *mockRootCoordClient) RestoreRBAC(ctx context.Context, req *milvuspb.RestoreRBACMetaRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
 | 
			
		||||
	panic("not implemented") // TODO: Implement
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type mockCompactionTrigger struct {
 | 
			
		||||
	methods map[string]interface{}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1145,6 +1145,14 @@ func (s *Server) SelectGrant(ctx context.Context, req *milvuspb.SelectGrantReque
 | 
			
		|||
	return s.proxy.SelectGrant(ctx, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) BackupRBAC(ctx context.Context, req *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	return s.proxy.BackupRBAC(ctx, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) RestoreRBAC(ctx context.Context, req *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error) {
 | 
			
		||||
	return s.proxy.RestoreRBAC(ctx, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) RefreshPolicyInfoCache(ctx context.Context, req *proxypb.RefreshPolicyInfoCacheRequest) (*commonpb.Status, error) {
 | 
			
		||||
	return s.proxy.RefreshPolicyInfoCache(ctx, req)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -682,3 +682,27 @@ func (c *Client) AlterDatabase(ctx context.Context, request *rootcoordpb.AlterDa
 | 
			
		|||
		return client.AlterDatabase(ctx, request)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) BackupRBAC(ctx context.Context, in *milvuspb.BackupRBACMetaRequest, opts ...grpc.CallOption) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	in = typeutil.Clone(in)
 | 
			
		||||
	commonpbutil.UpdateMsgBase(
 | 
			
		||||
		in.GetBase(),
 | 
			
		||||
		commonpbutil.FillMsgBaseFromClient(paramtable.GetNodeID(), commonpbutil.WithTargetID(c.sess.ServerID)),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return wrapGrpcCall(ctx, c, func(client rootcoordpb.RootCoordClient) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
		return client.BackupRBAC(ctx, in)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) RestoreRBAC(ctx context.Context, in *milvuspb.RestoreRBACMetaRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
 | 
			
		||||
	in = typeutil.Clone(in)
 | 
			
		||||
	commonpbutil.UpdateMsgBase(
 | 
			
		||||
		in.GetBase(),
 | 
			
		||||
		commonpbutil.FillMsgBaseFromClient(paramtable.GetNodeID(), commonpbutil.WithTargetID(c.sess.ServerID)),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return wrapGrpcCall(ctx, c, func(client rootcoordpb.RootCoordClient) (*commonpb.Status, error) {
 | 
			
		||||
		return client.RestoreRBAC(ctx, in)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -533,3 +533,11 @@ func (s *Server) AlterCollection(ctx context.Context, request *milvuspb.AlterCol
 | 
			
		|||
func (s *Server) RenameCollection(ctx context.Context, request *milvuspb.RenameCollectionRequest) (*commonpb.Status, error) {
 | 
			
		||||
	return s.rootCoord.RenameCollection(ctx, request)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) BackupRBAC(ctx context.Context, request *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	return s.rootCoord.BackupRBAC(ctx, request)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) RestoreRBAC(ctx context.Context, request *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error) {
 | 
			
		||||
	return s.rootCoord.RestoreRBAC(ctx, request)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,6 +82,10 @@ type RootCoordCatalog interface {
 | 
			
		|||
	// For example []string{"user1/role1"}
 | 
			
		||||
	ListUserRole(ctx context.Context, tenant string) ([]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
 | 
			
		||||
 | 
			
		||||
	Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/cockroachdb/errors"
 | 
			
		||||
	"github.com/samber/lo"
 | 
			
		||||
	"go.uber.org/zap"
 | 
			
		||||
	"google.golang.org/protobuf/proto"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -740,23 +741,37 @@ func (kc *Catalog) ListAliases(ctx context.Context, dbID int64, ts typeutil.Time
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (kc *Catalog) ListCredentials(ctx context.Context) ([]string, error) {
 | 
			
		||||
	keys, _, err := kc.Txn.LoadWithPrefix(CredentialPrefix)
 | 
			
		||||
	users, err := kc.ListCredentialsWithPasswd(ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return lo.Keys(users), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (kc *Catalog) ListCredentialsWithPasswd(ctx context.Context) (map[string]string, error) {
 | 
			
		||||
	keys, values, err := kc.Txn.LoadWithPrefix(CredentialPrefix)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("list all credential usernames fail", zap.String("prefix", CredentialPrefix), zap.Error(err))
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var usernames []string
 | 
			
		||||
	for _, path := range keys {
 | 
			
		||||
		username := typeutil.After(path, UserSubPrefix+"/")
 | 
			
		||||
	users := make(map[string]string)
 | 
			
		||||
	for i := range keys {
 | 
			
		||||
		username := typeutil.After(keys[i], UserSubPrefix+"/")
 | 
			
		||||
		if len(username) == 0 {
 | 
			
		||||
			log.Warn("no username extract from path:", zap.String("path", path))
 | 
			
		||||
			log.Warn("no username extract from path:", zap.String("path", keys[i]))
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		usernames = append(usernames, username)
 | 
			
		||||
		credential := &internalpb.CredentialInfo{}
 | 
			
		||||
		err := json.Unmarshal([]byte(values[i]), credential)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Error("credential unmarshal fail", zap.String("key", keys[i]), zap.Error(err))
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		users[username] = credential.EncryptedPassword
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return usernames, nil
 | 
			
		||||
	return users, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (kc *Catalog) save(k string) error {
 | 
			
		||||
| 
						 | 
				
			
			@ -1210,6 +1225,161 @@ func (kc *Catalog) ListUserRole(ctx context.Context, tenant string) ([]string, e
 | 
			
		|||
	return userRoles, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (kc *Catalog) BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBACMeta, error) {
 | 
			
		||||
	users, err := kc.ListUser(ctx, tenant, nil, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	credentials, err := kc.ListCredentialsWithPasswd(ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	userInfos := lo.FilterMap(users, func(entity *milvuspb.UserResult, _ int) (*milvuspb.UserInfo, bool) {
 | 
			
		||||
		userName := entity.GetUser().GetName()
 | 
			
		||||
		if userName == util.UserRoot {
 | 
			
		||||
			return nil, false
 | 
			
		||||
		}
 | 
			
		||||
		return &milvuspb.UserInfo{
 | 
			
		||||
			User:     userName,
 | 
			
		||||
			Password: credentials[userName],
 | 
			
		||||
			Roles:    entity.GetRoles(),
 | 
			
		||||
		}, true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	roles, err := kc.ListRole(ctx, tenant, nil, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	roleEntity := lo.FilterMap(roles, func(entity *milvuspb.RoleResult, _ int) (*milvuspb.RoleEntity, bool) {
 | 
			
		||||
		roleName := entity.GetRole().GetName()
 | 
			
		||||
		if roleName == util.RoleAdmin || roleName == util.RolePublic {
 | 
			
		||||
			return nil, false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return entity.GetRole(), true
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	grantsEntity := make([]*milvuspb.GrantEntity, 0)
 | 
			
		||||
	for _, role := range roleEntity {
 | 
			
		||||
		grants, err := kc.ListGrant(ctx, tenant, &milvuspb.GrantEntity{
 | 
			
		||||
			Role:   role,
 | 
			
		||||
			DbName: util.AnyWord,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		grantsEntity = append(grantsEntity, grants...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &milvuspb.RBACMeta{
 | 
			
		||||
		Users:  userInfos,
 | 
			
		||||
		Roles:  roleEntity,
 | 
			
		||||
		Grants: grantsEntity,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (kc *Catalog) RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	needRollbackUser := make([]*milvuspb.UserInfo, 0)
 | 
			
		||||
	needRollbackRole := make([]*milvuspb.RoleEntity, 0)
 | 
			
		||||
	needRollbackGrants := make([]*milvuspb.GrantEntity, 0)
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Warn("failed to restore rbac, try to rollback", zap.Error(err))
 | 
			
		||||
			// roll back role
 | 
			
		||||
			for _, role := range needRollbackRole {
 | 
			
		||||
				err = kc.DropRole(ctx, tenant, role.Name)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Warn("failed to rollback roles after restore failed", zap.Error(err))
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// roll back grant
 | 
			
		||||
			for _, grant := range needRollbackGrants {
 | 
			
		||||
				err = kc.AlterGrant(ctx, tenant, grant, milvuspb.OperatePrivilegeType_Revoke)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Warn("failed to rollback grants after restore failed", zap.Error(err))
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for _, user := range needRollbackUser {
 | 
			
		||||
				// roll back user
 | 
			
		||||
				err = kc.DropCredential(ctx, user.User)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Warn("failed to rollback users after restore failed", zap.Error(err))
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// restore role
 | 
			
		||||
	existRoles, err := kc.ListRole(ctx, tenant, nil, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	existRoleMap := lo.SliceToMap(existRoles, func(entity *milvuspb.RoleResult) (string, struct{}) { return entity.GetRole().GetName(), struct{}{} })
 | 
			
		||||
	for _, role := range meta.Roles {
 | 
			
		||||
		if _, ok := existRoleMap[role.GetName()]; ok {
 | 
			
		||||
			log.Warn("failed to restore, role already exists", zap.String("role", role.GetName()))
 | 
			
		||||
			err = errors.Newf("role [%s] already exists", role.GetName())
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		err = kc.CreateRole(ctx, tenant, role)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		needRollbackRole = append(needRollbackRole, role)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// restore grant
 | 
			
		||||
	for _, grant := range meta.Grants {
 | 
			
		||||
		err = kc.AlterGrant(ctx, tenant, grant, milvuspb.OperatePrivilegeType_Grant)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		needRollbackGrants = append(needRollbackGrants, grant)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// need rollback user
 | 
			
		||||
	existUser, err := kc.ListUser(ctx, tenant, nil, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	existUserMap := lo.SliceToMap(existUser, func(entity *milvuspb.UserResult) (string, struct{}) { return entity.GetUser().GetName(), struct{}{} })
 | 
			
		||||
	for _, user := range meta.Users {
 | 
			
		||||
		if _, ok := existUserMap[user.GetUser()]; ok {
 | 
			
		||||
			log.Info("failed to restore, user already exists", zap.String("user", user.GetUser()))
 | 
			
		||||
			err = errors.Newf("user [%s] already exists", user.GetUser())
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		// restore user
 | 
			
		||||
		err = kc.CreateCredential(ctx, &model.Credential{
 | 
			
		||||
			Username:          user.User,
 | 
			
		||||
			EncryptedPassword: user.Password,
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		needRollbackUser = append(needRollbackUser, user)
 | 
			
		||||
 | 
			
		||||
		// restore user role mapping
 | 
			
		||||
		entity := &milvuspb.UserEntity{
 | 
			
		||||
			Name: user.User,
 | 
			
		||||
		}
 | 
			
		||||
		for _, role := range user.Roles {
 | 
			
		||||
			err = kc.AlterUserRole(ctx, tenant, entity, role, milvuspb.OperateUserRoleType_AddUserToRole)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (kc *Catalog) Close() {
 | 
			
		||||
	// do nothing
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,7 @@ import (
 | 
			
		|||
	"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
 | 
			
		||||
	"github.com/milvus-io/milvus-proto/go-api/v2/schemapb"
 | 
			
		||||
	"github.com/milvus-io/milvus/internal/kv"
 | 
			
		||||
	etcdkv "github.com/milvus-io/milvus/internal/kv/etcd"
 | 
			
		||||
	"github.com/milvus-io/milvus/internal/kv/mocks"
 | 
			
		||||
	"github.com/milvus-io/milvus/internal/metastore"
 | 
			
		||||
	"github.com/milvus-io/milvus/internal/metastore/model"
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +31,7 @@ import (
 | 
			
		|||
	"github.com/milvus-io/milvus/pkg/log"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util/crypto"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util/etcd"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util/funcutil"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util/merr"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util/typeutil"
 | 
			
		||||
| 
						 | 
				
			
			@ -1473,7 +1475,20 @@ func TestRBAC_Credential(t *testing.T) {
 | 
			
		|||
				}
 | 
			
		||||
				return nil
 | 
			
		||||
			},
 | 
			
		||||
			nil,
 | 
			
		||||
			func(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),
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				return nil
 | 
			
		||||
			},
 | 
			
		||||
			func(key string) error {
 | 
			
		||||
				cmu.RLock()
 | 
			
		||||
				defer cmu.RUnlock()
 | 
			
		||||
| 
						 | 
				
			
			@ -1931,7 +1946,14 @@ func TestRBAC_Role(t *testing.T) {
 | 
			
		|||
					}
 | 
			
		||||
				}
 | 
			
		||||
				return nil
 | 
			
		||||
			}, nil,
 | 
			
		||||
			},
 | 
			
		||||
			func(key string) []string {
 | 
			
		||||
				if loadCredentialPrefixReturn.Load() {
 | 
			
		||||
					passwd, _ := json.Marshal(&model.Credential{EncryptedPassword: crypto.Base64Encode("passwd")})
 | 
			
		||||
					return []string{string(passwd)}
 | 
			
		||||
				}
 | 
			
		||||
				return nil
 | 
			
		||||
			},
 | 
			
		||||
			func(key string) error {
 | 
			
		||||
				if loadCredentialPrefixReturn.Load() {
 | 
			
		||||
					return nil
 | 
			
		||||
| 
						 | 
				
			
			@ -2544,6 +2566,186 @@ func TestRBAC_Grant(t *testing.T) {
 | 
			
		|||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRBAC_Backup(t *testing.T) {
 | 
			
		||||
	etcdCli, _ := etcd.GetEtcdClient(
 | 
			
		||||
		Params.EtcdCfg.UseEmbedEtcd.GetAsBool(),
 | 
			
		||||
		Params.EtcdCfg.EtcdUseSSL.GetAsBool(),
 | 
			
		||||
		Params.EtcdCfg.Endpoints.GetAsStrings(),
 | 
			
		||||
		Params.EtcdCfg.EtcdTLSCert.GetValue(),
 | 
			
		||||
		Params.EtcdCfg.EtcdTLSKey.GetValue(),
 | 
			
		||||
		Params.EtcdCfg.EtcdTLSCACert.GetValue(),
 | 
			
		||||
		Params.EtcdCfg.EtcdTLSMinVersion.GetValue())
 | 
			
		||||
	rootPath := "/test/rbac"
 | 
			
		||||
	metaKV := etcdkv.NewEtcdKV(etcdCli, rootPath)
 | 
			
		||||
	defer metaKV.RemoveWithPrefix("")
 | 
			
		||||
	defer metaKV.Close()
 | 
			
		||||
	c := &Catalog{Txn: metaKV}
 | 
			
		||||
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
	c.CreateRole(ctx, util.DefaultTenant, &milvuspb.RoleEntity{Name: "role1"})
 | 
			
		||||
	c.AlterGrant(ctx, util.DefaultTenant, &milvuspb.GrantEntity{
 | 
			
		||||
		Role:       &milvuspb.RoleEntity{Name: "role1"},
 | 
			
		||||
		Object:     &milvuspb.ObjectEntity{Name: "obj1"},
 | 
			
		||||
		ObjectName: "obj_name1",
 | 
			
		||||
		DbName:     util.DefaultDBName,
 | 
			
		||||
		Grantor: &milvuspb.GrantorEntity{
 | 
			
		||||
			User:      &milvuspb.UserEntity{Name: "user1"},
 | 
			
		||||
			Privilege: &milvuspb.PrivilegeEntity{Name: "PrivilegeLoad"},
 | 
			
		||||
		},
 | 
			
		||||
	}, milvuspb.OperatePrivilegeType_Grant)
 | 
			
		||||
	c.CreateCredential(ctx, &model.Credential{
 | 
			
		||||
		Username:          "user1",
 | 
			
		||||
		EncryptedPassword: "passwd",
 | 
			
		||||
	})
 | 
			
		||||
	c.AlterUserRole(ctx, util.DefaultTenant, &milvuspb.UserEntity{Name: "user1"}, &milvuspb.RoleEntity{Name: "role1"}, milvuspb.OperateUserRoleType_AddUserToRole)
 | 
			
		||||
 | 
			
		||||
	// test backup success
 | 
			
		||||
	backup, err := c.BackupRBAC(ctx, util.DefaultTenant)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, 1, len(backup.Grants))
 | 
			
		||||
	assert.Equal(t, "obj_name1", backup.Grants[0].ObjectName)
 | 
			
		||||
	assert.Equal(t, "role1", backup.Grants[0].Role.Name)
 | 
			
		||||
	assert.Equal(t, 1, len(backup.Users))
 | 
			
		||||
	assert.Equal(t, "user1", backup.Users[0].User)
 | 
			
		||||
	assert.Equal(t, 1, len(backup.Users[0].Roles))
 | 
			
		||||
	assert.Equal(t, 1, len(backup.Roles))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRBAC_Restore(t *testing.T) {
 | 
			
		||||
	etcdCli, _ := etcd.GetEtcdClient(
 | 
			
		||||
		Params.EtcdCfg.UseEmbedEtcd.GetAsBool(),
 | 
			
		||||
		Params.EtcdCfg.EtcdUseSSL.GetAsBool(),
 | 
			
		||||
		Params.EtcdCfg.Endpoints.GetAsStrings(),
 | 
			
		||||
		Params.EtcdCfg.EtcdTLSCert.GetValue(),
 | 
			
		||||
		Params.EtcdCfg.EtcdTLSKey.GetValue(),
 | 
			
		||||
		Params.EtcdCfg.EtcdTLSCACert.GetValue(),
 | 
			
		||||
		Params.EtcdCfg.EtcdTLSMinVersion.GetValue())
 | 
			
		||||
	rootPath := "/test/rbac"
 | 
			
		||||
	metaKV := etcdkv.NewEtcdKV(etcdCli, rootPath)
 | 
			
		||||
	defer metaKV.RemoveWithPrefix("")
 | 
			
		||||
	defer metaKV.Close()
 | 
			
		||||
	c := &Catalog{Txn: metaKV}
 | 
			
		||||
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
 | 
			
		||||
	rbacMeta := &milvuspb.RBACMeta{
 | 
			
		||||
		Users: []*milvuspb.UserInfo{
 | 
			
		||||
			{
 | 
			
		||||
				User:     "user1",
 | 
			
		||||
				Password: "passwd",
 | 
			
		||||
				Roles: []*milvuspb.RoleEntity{
 | 
			
		||||
					{
 | 
			
		||||
						Name: "role1",
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Roles: []*milvuspb.RoleEntity{
 | 
			
		||||
			{
 | 
			
		||||
				Name: "role1",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		Grants: []*milvuspb.GrantEntity{
 | 
			
		||||
			{
 | 
			
		||||
				Role:       &milvuspb.RoleEntity{Name: "role1"},
 | 
			
		||||
				Object:     &milvuspb.ObjectEntity{Name: "obj1"},
 | 
			
		||||
				ObjectName: "obj_name1",
 | 
			
		||||
				DbName:     util.DefaultDBName,
 | 
			
		||||
				Grantor: &milvuspb.GrantorEntity{
 | 
			
		||||
					User:      &milvuspb.UserEntity{Name: "user1"},
 | 
			
		||||
					Privilege: &milvuspb.PrivilegeEntity{Name: "PrivilegeLoad"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	// test restore success
 | 
			
		||||
	err := c.RestoreRBAC(ctx, util.DefaultTenant, rbacMeta)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	// check user
 | 
			
		||||
	users, err := c.ListCredentialsWithPasswd(ctx)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, users, 1)
 | 
			
		||||
	assert.Equal(t, users["user1"], "passwd")
 | 
			
		||||
	// check role
 | 
			
		||||
	roles, err := c.ListRole(ctx, util.DefaultTenant, nil, false)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, roles, 1)
 | 
			
		||||
	assert.Equal(t, "role1", roles[0].Role.Name)
 | 
			
		||||
	// check grant
 | 
			
		||||
	grants, err := c.ListGrant(ctx, util.DefaultTenant, &milvuspb.GrantEntity{
 | 
			
		||||
		Role:   roles[0].Role,
 | 
			
		||||
		DbName: util.AnyWord,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, grants, 1)
 | 
			
		||||
	assert.Equal(t, "obj_name1", grants[0].ObjectName)
 | 
			
		||||
	assert.Equal(t, "role1", grants[0].Role.Name)
 | 
			
		||||
	assert.Equal(t, "user1", grants[0].Grantor.User.Name)
 | 
			
		||||
 | 
			
		||||
	rbacMeta2 := &milvuspb.RBACMeta{
 | 
			
		||||
		Users: []*milvuspb.UserInfo{
 | 
			
		||||
			{
 | 
			
		||||
				User:     "user2",
 | 
			
		||||
				Password: "passwd",
 | 
			
		||||
				Roles: []*milvuspb.RoleEntity{
 | 
			
		||||
					{
 | 
			
		||||
						Name: "role2",
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				User:     "user1",
 | 
			
		||||
				Password: "passwd",
 | 
			
		||||
				Roles: []*milvuspb.RoleEntity{
 | 
			
		||||
					{
 | 
			
		||||
						Name: "role2",
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Roles: []*milvuspb.RoleEntity{
 | 
			
		||||
			{
 | 
			
		||||
				Name: "role2",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		Grants: []*milvuspb.GrantEntity{
 | 
			
		||||
			{
 | 
			
		||||
				Role:       &milvuspb.RoleEntity{Name: "role2"},
 | 
			
		||||
				Object:     &milvuspb.ObjectEntity{Name: "obj2"},
 | 
			
		||||
				ObjectName: "obj_name2",
 | 
			
		||||
				DbName:     util.DefaultDBName,
 | 
			
		||||
				Grantor: &milvuspb.GrantorEntity{
 | 
			
		||||
					User:      &milvuspb.UserEntity{Name: "user2"},
 | 
			
		||||
					Privilege: &milvuspb.PrivilegeEntity{Name: "PrivilegeLoad"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// test restore failed and roll back
 | 
			
		||||
	err = c.RestoreRBAC(ctx, util.DefaultTenant, rbacMeta2)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
 | 
			
		||||
	// check user
 | 
			
		||||
	users, err = c.ListCredentialsWithPasswd(ctx)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, users, 1)
 | 
			
		||||
	// check role
 | 
			
		||||
	roles, err = c.ListRole(ctx, util.DefaultTenant, nil, false)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, roles, 1)
 | 
			
		||||
	// check grant
 | 
			
		||||
	grants, err = c.ListGrant(ctx, util.DefaultTenant, &milvuspb.GrantEntity{
 | 
			
		||||
		Role:   roles[0].Role,
 | 
			
		||||
		DbName: util.AnyWord,
 | 
			
		||||
	})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, grants, 1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCatalog_AlterDatabase(t *testing.T) {
 | 
			
		||||
	kvmock := mocks.NewSnapShotKV(t)
 | 
			
		||||
	c := &Catalog{Snapshot: kvmock}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -341,6 +341,61 @@ func (_c *RootCoordCatalog_AlterUserRole_Call) RunAndReturn(run func(context.Con
 | 
			
		|||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC provides a mock function with given fields: ctx, tenant
 | 
			
		||||
func (_m *RootCoordCatalog) BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBACMeta, error) {
 | 
			
		||||
	ret := _m.Called(ctx, tenant)
 | 
			
		||||
 | 
			
		||||
	var r0 *milvuspb.RBACMeta
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, string) (*milvuspb.RBACMeta, error)); ok {
 | 
			
		||||
		return rf(ctx, tenant)
 | 
			
		||||
	}
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, string) *milvuspb.RBACMeta); ok {
 | 
			
		||||
		r0 = rf(ctx, tenant)
 | 
			
		||||
	} else {
 | 
			
		||||
		if ret.Get(0) != nil {
 | 
			
		||||
			r0 = ret.Get(0).(*milvuspb.RBACMeta)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
 | 
			
		||||
		r1 = rf(ctx, tenant)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RootCoordCatalog_BackupRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BackupRBAC'
 | 
			
		||||
type RootCoordCatalog_BackupRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - ctx context.Context
 | 
			
		||||
//   - tenant string
 | 
			
		||||
func (_e *RootCoordCatalog_Expecter) BackupRBAC(ctx interface{}, tenant interface{}) *RootCoordCatalog_BackupRBAC_Call {
 | 
			
		||||
	return &RootCoordCatalog_BackupRBAC_Call{Call: _e.mock.On("BackupRBAC", ctx, tenant)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoordCatalog_BackupRBAC_Call) Run(run func(ctx context.Context, tenant string)) *RootCoordCatalog_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		run(args[0].(context.Context), args[1].(string))
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoordCatalog_BackupRBAC_Call) Return(_a0 *milvuspb.RBACMeta, _a1 error) *RootCoordCatalog_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0, _a1)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoordCatalog_BackupRBAC_Call) RunAndReturn(run func(context.Context, string) (*milvuspb.RBACMeta, error)) *RootCoordCatalog_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close provides a mock function with given fields:
 | 
			
		||||
func (_m *RootCoordCatalog) Close() {
 | 
			
		||||
	_m.Called()
 | 
			
		||||
| 
						 | 
				
			
			@ -1327,6 +1382,60 @@ 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)
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
| 
						 | 
				
			
			@ -1662,6 +1771,50 @@ func (_c *RootCoordCatalog_ListUserRole_Call) RunAndReturn(run func(context.Cont
 | 
			
		|||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC provides a mock function with given fields: ctx, tenant, meta
 | 
			
		||||
func (_m *RootCoordCatalog) RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error {
 | 
			
		||||
	ret := _m.Called(ctx, tenant, meta)
 | 
			
		||||
 | 
			
		||||
	var r0 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, string, *milvuspb.RBACMeta) error); ok {
 | 
			
		||||
		r0 = rf(ctx, tenant, meta)
 | 
			
		||||
	} else {
 | 
			
		||||
		r0 = ret.Error(0)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RootCoordCatalog_RestoreRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestoreRBAC'
 | 
			
		||||
type RootCoordCatalog_RestoreRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - ctx context.Context
 | 
			
		||||
//   - tenant string
 | 
			
		||||
//   - meta *milvuspb.RBACMeta
 | 
			
		||||
func (_e *RootCoordCatalog_Expecter) RestoreRBAC(ctx interface{}, tenant interface{}, meta interface{}) *RootCoordCatalog_RestoreRBAC_Call {
 | 
			
		||||
	return &RootCoordCatalog_RestoreRBAC_Call{Call: _e.mock.On("RestoreRBAC", ctx, tenant, meta)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoordCatalog_RestoreRBAC_Call) Run(run func(ctx context.Context, tenant string, meta *milvuspb.RBACMeta)) *RootCoordCatalog_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		run(args[0].(context.Context), args[1].(string), args[2].(*milvuspb.RBACMeta))
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoordCatalog_RestoreRBAC_Call) Return(_a0 error) *RootCoordCatalog_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoordCatalog_RestoreRBAC_Call) RunAndReturn(run func(context.Context, string, *milvuspb.RBACMeta) error) *RootCoordCatalog_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewRootCoordCatalog creates a new instance of RootCoordCatalog. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
 | 
			
		||||
// The first argument is typically a *testing.T value.
 | 
			
		||||
func NewRootCoordCatalog(t interface {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -309,6 +309,61 @@ func (_c *MockProxy_AlterIndex_Call) RunAndReturn(run func(context.Context, *mil
 | 
			
		|||
	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)
 | 
			
		||||
 | 
			
		||||
	var r0 *milvuspb.BackupRBACMetaResponse
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error)); ok {
 | 
			
		||||
		return rf(_a0, _a1)
 | 
			
		||||
	}
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.BackupRBACMetaRequest) *milvuspb.BackupRBACMetaResponse); ok {
 | 
			
		||||
		r0 = rf(_a0, _a1)
 | 
			
		||||
	} else {
 | 
			
		||||
		if ret.Get(0) != nil {
 | 
			
		||||
			r0 = ret.Get(0).(*milvuspb.BackupRBACMetaResponse)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.BackupRBACMetaRequest) error); ok {
 | 
			
		||||
		r1 = rf(_a0, _a1)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MockProxy_BackupRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BackupRBAC'
 | 
			
		||||
type MockProxy_BackupRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - _a0 context.Context
 | 
			
		||||
//   - _a1 *milvuspb.BackupRBACMetaRequest
 | 
			
		||||
func (_e *MockProxy_Expecter) BackupRBAC(_a0 interface{}, _a1 interface{}) *MockProxy_BackupRBAC_Call {
 | 
			
		||||
	return &MockProxy_BackupRBAC_Call{Call: _e.mock.On("BackupRBAC", _a0, _a1)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockProxy_BackupRBAC_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.BackupRBACMetaRequest)) *MockProxy_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		run(args[0].(context.Context), args[1].(*milvuspb.BackupRBACMetaRequest))
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockProxy_BackupRBAC_Call) Return(_a0 *milvuspb.BackupRBACMetaResponse, _a1 error) *MockProxy_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0, _a1)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockProxy_BackupRBAC_Call) RunAndReturn(run func(context.Context, *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error)) *MockProxy_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CalcDistance provides a mock function with given fields: _a0, _a1
 | 
			
		||||
func (_m *MockProxy) CalcDistance(_a0 context.Context, _a1 *milvuspb.CalcDistanceRequest) (*milvuspb.CalcDistanceResults, error) {
 | 
			
		||||
	ret := _m.Called(_a0, _a1)
 | 
			
		||||
| 
						 | 
				
			
			@ -4940,6 +4995,61 @@ func (_c *MockProxy_ReplicateMessage_Call) RunAndReturn(run func(context.Context
 | 
			
		|||
	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)
 | 
			
		||||
 | 
			
		||||
	var r0 *commonpb.Status
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error)); ok {
 | 
			
		||||
		return rf(_a0, _a1)
 | 
			
		||||
	}
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreRBACMetaRequest) *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.RestoreRBACMetaRequest) error); ok {
 | 
			
		||||
		r1 = rf(_a0, _a1)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MockProxy_RestoreRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestoreRBAC'
 | 
			
		||||
type MockProxy_RestoreRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - _a0 context.Context
 | 
			
		||||
//   - _a1 *milvuspb.RestoreRBACMetaRequest
 | 
			
		||||
func (_e *MockProxy_Expecter) RestoreRBAC(_a0 interface{}, _a1 interface{}) *MockProxy_RestoreRBAC_Call {
 | 
			
		||||
	return &MockProxy_RestoreRBAC_Call{Call: _e.mock.On("RestoreRBAC", _a0, _a1)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockProxy_RestoreRBAC_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.RestoreRBACMetaRequest)) *MockProxy_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		run(args[0].(context.Context), args[1].(*milvuspb.RestoreRBACMetaRequest))
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockProxy_RestoreRBAC_Call) Return(_a0 *commonpb.Status, _a1 error) *MockProxy_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0, _a1)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockProxy_RestoreRBAC_Call) RunAndReturn(run func(context.Context, *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error)) *MockProxy_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Search provides a mock function with given fields: _a0, _a1
 | 
			
		||||
func (_m *MockProxy) Search(_a0 context.Context, _a1 *milvuspb.SearchRequest) (*milvuspb.SearchResults, error) {
 | 
			
		||||
	ret := _m.Called(_a0, _a1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -311,6 +311,61 @@ func (_c *RootCoord_AlterDatabase_Call) RunAndReturn(run func(context.Context, *
 | 
			
		|||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC provides a mock function with given fields: _a0, _a1
 | 
			
		||||
func (_m *RootCoord) BackupRBAC(_a0 context.Context, _a1 *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	ret := _m.Called(_a0, _a1)
 | 
			
		||||
 | 
			
		||||
	var r0 *milvuspb.BackupRBACMetaResponse
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error)); ok {
 | 
			
		||||
		return rf(_a0, _a1)
 | 
			
		||||
	}
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.BackupRBACMetaRequest) *milvuspb.BackupRBACMetaResponse); ok {
 | 
			
		||||
		r0 = rf(_a0, _a1)
 | 
			
		||||
	} else {
 | 
			
		||||
		if ret.Get(0) != nil {
 | 
			
		||||
			r0 = ret.Get(0).(*milvuspb.BackupRBACMetaResponse)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.BackupRBACMetaRequest) error); ok {
 | 
			
		||||
		r1 = rf(_a0, _a1)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RootCoord_BackupRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BackupRBAC'
 | 
			
		||||
type RootCoord_BackupRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - _a0 context.Context
 | 
			
		||||
//   - _a1 *milvuspb.BackupRBACMetaRequest
 | 
			
		||||
func (_e *RootCoord_Expecter) BackupRBAC(_a0 interface{}, _a1 interface{}) *RootCoord_BackupRBAC_Call {
 | 
			
		||||
	return &RootCoord_BackupRBAC_Call{Call: _e.mock.On("BackupRBAC", _a0, _a1)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoord_BackupRBAC_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.BackupRBACMetaRequest)) *RootCoord_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		run(args[0].(context.Context), args[1].(*milvuspb.BackupRBACMetaRequest))
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoord_BackupRBAC_Call) Return(_a0 *milvuspb.BackupRBACMetaResponse, _a1 error) *RootCoord_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0, _a1)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoord_BackupRBAC_Call) RunAndReturn(run func(context.Context, *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error)) *RootCoord_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckHealth provides a mock function with given fields: _a0, _a1
 | 
			
		||||
func (_m *RootCoord) CheckHealth(_a0 context.Context, _a1 *milvuspb.CheckHealthRequest) (*milvuspb.CheckHealthResponse, error) {
 | 
			
		||||
	ret := _m.Called(_a0, _a1)
 | 
			
		||||
| 
						 | 
				
			
			@ -2208,6 +2263,61 @@ func (_c *RootCoord_RenameCollection_Call) RunAndReturn(run func(context.Context
 | 
			
		|||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC provides a mock function with given fields: _a0, _a1
 | 
			
		||||
func (_m *RootCoord) RestoreRBAC(_a0 context.Context, _a1 *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error) {
 | 
			
		||||
	ret := _m.Called(_a0, _a1)
 | 
			
		||||
 | 
			
		||||
	var r0 *commonpb.Status
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error)); ok {
 | 
			
		||||
		return rf(_a0, _a1)
 | 
			
		||||
	}
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreRBACMetaRequest) *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.RestoreRBACMetaRequest) error); ok {
 | 
			
		||||
		r1 = rf(_a0, _a1)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RootCoord_RestoreRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestoreRBAC'
 | 
			
		||||
type RootCoord_RestoreRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - _a0 context.Context
 | 
			
		||||
//   - _a1 *milvuspb.RestoreRBACMetaRequest
 | 
			
		||||
func (_e *RootCoord_Expecter) RestoreRBAC(_a0 interface{}, _a1 interface{}) *RootCoord_RestoreRBAC_Call {
 | 
			
		||||
	return &RootCoord_RestoreRBAC_Call{Call: _e.mock.On("RestoreRBAC", _a0, _a1)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoord_RestoreRBAC_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.RestoreRBACMetaRequest)) *RootCoord_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		run(args[0].(context.Context), args[1].(*milvuspb.RestoreRBACMetaRequest))
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoord_RestoreRBAC_Call) Return(_a0 *commonpb.Status, _a1 error) *RootCoord_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0, _a1)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *RootCoord_RestoreRBAC_Call) RunAndReturn(run func(context.Context, *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error)) *RootCoord_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectGrant provides a mock function with given fields: _a0, _a1
 | 
			
		||||
func (_m *RootCoord) SelectGrant(_a0 context.Context, _a1 *milvuspb.SelectGrantRequest) (*milvuspb.SelectGrantResponse, error) {
 | 
			
		||||
	ret := _m.Called(_a0, _a1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -383,6 +383,76 @@ func (_c *MockRootCoordClient_AlterDatabase_Call) RunAndReturn(run func(context.
 | 
			
		|||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC provides a mock function with given fields: ctx, in, opts
 | 
			
		||||
func (_m *MockRootCoordClient) BackupRBAC(ctx context.Context, in *milvuspb.BackupRBACMetaRequest, opts ...grpc.CallOption) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	_va := make([]interface{}, len(opts))
 | 
			
		||||
	for _i := range opts {
 | 
			
		||||
		_va[_i] = opts[_i]
 | 
			
		||||
	}
 | 
			
		||||
	var _ca []interface{}
 | 
			
		||||
	_ca = append(_ca, ctx, in)
 | 
			
		||||
	_ca = append(_ca, _va...)
 | 
			
		||||
	ret := _m.Called(_ca...)
 | 
			
		||||
 | 
			
		||||
	var r0 *milvuspb.BackupRBACMetaResponse
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.BackupRBACMetaRequest, ...grpc.CallOption) (*milvuspb.BackupRBACMetaResponse, error)); ok {
 | 
			
		||||
		return rf(ctx, in, opts...)
 | 
			
		||||
	}
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.BackupRBACMetaRequest, ...grpc.CallOption) *milvuspb.BackupRBACMetaResponse); ok {
 | 
			
		||||
		r0 = rf(ctx, in, opts...)
 | 
			
		||||
	} else {
 | 
			
		||||
		if ret.Get(0) != nil {
 | 
			
		||||
			r0 = ret.Get(0).(*milvuspb.BackupRBACMetaResponse)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.BackupRBACMetaRequest, ...grpc.CallOption) error); ok {
 | 
			
		||||
		r1 = rf(ctx, in, opts...)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MockRootCoordClient_BackupRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BackupRBAC'
 | 
			
		||||
type MockRootCoordClient_BackupRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - ctx context.Context
 | 
			
		||||
//   - in *milvuspb.BackupRBACMetaRequest
 | 
			
		||||
//   - opts ...grpc.CallOption
 | 
			
		||||
func (_e *MockRootCoordClient_Expecter) BackupRBAC(ctx interface{}, in interface{}, opts ...interface{}) *MockRootCoordClient_BackupRBAC_Call {
 | 
			
		||||
	return &MockRootCoordClient_BackupRBAC_Call{Call: _e.mock.On("BackupRBAC",
 | 
			
		||||
		append([]interface{}{ctx, in}, opts...)...)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockRootCoordClient_BackupRBAC_Call) Run(run func(ctx context.Context, in *milvuspb.BackupRBACMetaRequest, opts ...grpc.CallOption)) *MockRootCoordClient_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		variadicArgs := make([]grpc.CallOption, len(args)-2)
 | 
			
		||||
		for i, a := range args[2:] {
 | 
			
		||||
			if a != nil {
 | 
			
		||||
				variadicArgs[i] = a.(grpc.CallOption)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		run(args[0].(context.Context), args[1].(*milvuspb.BackupRBACMetaRequest), variadicArgs...)
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockRootCoordClient_BackupRBAC_Call) Return(_a0 *milvuspb.BackupRBACMetaResponse, _a1 error) *MockRootCoordClient_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0, _a1)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockRootCoordClient_BackupRBAC_Call) RunAndReturn(run func(context.Context, *milvuspb.BackupRBACMetaRequest, ...grpc.CallOption) (*milvuspb.BackupRBACMetaResponse, error)) *MockRootCoordClient_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckHealth provides a mock function with given fields: ctx, in, opts
 | 
			
		||||
func (_m *MockRootCoordClient) CheckHealth(ctx context.Context, in *milvuspb.CheckHealthRequest, opts ...grpc.CallOption) (*milvuspb.CheckHealthResponse, error) {
 | 
			
		||||
	_va := make([]interface{}, len(opts))
 | 
			
		||||
| 
						 | 
				
			
			@ -2734,6 +2804,76 @@ func (_c *MockRootCoordClient_RenameCollection_Call) RunAndReturn(run func(conte
 | 
			
		|||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC provides a mock function with given fields: ctx, in, opts
 | 
			
		||||
func (_m *MockRootCoordClient) RestoreRBAC(ctx context.Context, in *milvuspb.RestoreRBACMetaRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
 | 
			
		||||
	_va := make([]interface{}, len(opts))
 | 
			
		||||
	for _i := range opts {
 | 
			
		||||
		_va[_i] = opts[_i]
 | 
			
		||||
	}
 | 
			
		||||
	var _ca []interface{}
 | 
			
		||||
	_ca = append(_ca, ctx, in)
 | 
			
		||||
	_ca = append(_ca, _va...)
 | 
			
		||||
	ret := _m.Called(_ca...)
 | 
			
		||||
 | 
			
		||||
	var r0 *commonpb.Status
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreRBACMetaRequest, ...grpc.CallOption) (*commonpb.Status, error)); ok {
 | 
			
		||||
		return rf(ctx, in, opts...)
 | 
			
		||||
	}
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.RestoreRBACMetaRequest, ...grpc.CallOption) *commonpb.Status); ok {
 | 
			
		||||
		r0 = rf(ctx, in, opts...)
 | 
			
		||||
	} else {
 | 
			
		||||
		if ret.Get(0) != nil {
 | 
			
		||||
			r0 = ret.Get(0).(*commonpb.Status)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.RestoreRBACMetaRequest, ...grpc.CallOption) error); ok {
 | 
			
		||||
		r1 = rf(ctx, in, opts...)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MockRootCoordClient_RestoreRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestoreRBAC'
 | 
			
		||||
type MockRootCoordClient_RestoreRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - ctx context.Context
 | 
			
		||||
//   - in *milvuspb.RestoreRBACMetaRequest
 | 
			
		||||
//   - opts ...grpc.CallOption
 | 
			
		||||
func (_e *MockRootCoordClient_Expecter) RestoreRBAC(ctx interface{}, in interface{}, opts ...interface{}) *MockRootCoordClient_RestoreRBAC_Call {
 | 
			
		||||
	return &MockRootCoordClient_RestoreRBAC_Call{Call: _e.mock.On("RestoreRBAC",
 | 
			
		||||
		append([]interface{}{ctx, in}, opts...)...)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockRootCoordClient_RestoreRBAC_Call) Run(run func(ctx context.Context, in *milvuspb.RestoreRBACMetaRequest, opts ...grpc.CallOption)) *MockRootCoordClient_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		variadicArgs := make([]grpc.CallOption, len(args)-2)
 | 
			
		||||
		for i, a := range args[2:] {
 | 
			
		||||
			if a != nil {
 | 
			
		||||
				variadicArgs[i] = a.(grpc.CallOption)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		run(args[0].(context.Context), args[1].(*milvuspb.RestoreRBACMetaRequest), variadicArgs...)
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockRootCoordClient_RestoreRBAC_Call) Return(_a0 *commonpb.Status, _a1 error) *MockRootCoordClient_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0, _a1)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *MockRootCoordClient_RestoreRBAC_Call) RunAndReturn(run func(context.Context, *milvuspb.RestoreRBACMetaRequest, ...grpc.CallOption) (*commonpb.Status, error)) *MockRootCoordClient_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectGrant provides a mock function with given fields: ctx, in, opts
 | 
			
		||||
func (_m *MockRootCoordClient) SelectGrant(ctx context.Context, in *milvuspb.SelectGrantRequest, opts ...grpc.CallOption) (*milvuspb.SelectGrantResponse, error) {
 | 
			
		||||
	_va := make([]interface{}, len(opts))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -124,6 +124,8 @@ service RootCoord {
 | 
			
		|||
    rpc OperatePrivilege(milvus.OperatePrivilegeRequest) returns (common.Status) {}
 | 
			
		||||
    rpc SelectGrant(milvus.SelectGrantRequest) returns (milvus.SelectGrantResponse) {}
 | 
			
		||||
    rpc ListPolicy(internal.ListPolicyRequest) returns (internal.ListPolicyResponse) {}
 | 
			
		||||
    rpc BackupRBAC(milvus.BackupRBACMetaRequest) returns (milvus.BackupRBACMetaResponse){}
 | 
			
		||||
    rpc RestoreRBAC(milvus.RestoreRBACMetaRequest) returns (common.Status){}
 | 
			
		||||
 | 
			
		||||
    rpc CheckHealth(milvus.CheckHealthRequest) returns (milvus.CheckHealthResponse) {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5325,6 +5325,46 @@ func (node *Proxy) SelectGrant(ctx context.Context, req *milvuspb.SelectGrantReq
 | 
			
		|||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (node *Proxy) BackupRBAC(ctx context.Context, req *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-BackupRBAC")
 | 
			
		||||
	defer sp.End()
 | 
			
		||||
 | 
			
		||||
	log := log.Ctx(ctx)
 | 
			
		||||
 | 
			
		||||
	log.Debug("BackupRBAC", zap.Any("req", req))
 | 
			
		||||
	if err := merr.CheckHealthy(node.GetStateCode()); err != nil {
 | 
			
		||||
		return &milvuspb.BackupRBACMetaResponse{Status: merr.Status(err)}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := node.rootCoord.BackupRBAC(ctx, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn("fail to backup rbac", zap.Error(err))
 | 
			
		||||
		return &milvuspb.BackupRBACMetaResponse{
 | 
			
		||||
			Status: merr.Status(err),
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (node *Proxy) RestoreRBAC(ctx context.Context, req *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error) {
 | 
			
		||||
	ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-RestoreRBAC")
 | 
			
		||||
	defer sp.End()
 | 
			
		||||
 | 
			
		||||
	log := log.Ctx(ctx)
 | 
			
		||||
 | 
			
		||||
	log.Debug("RestoreRBAC", zap.Any("req", req))
 | 
			
		||||
	if err := merr.CheckHealthy(node.GetStateCode()); err != nil {
 | 
			
		||||
		return merr.Status(err), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result, err := node.rootCoord.RestoreRBAC(ctx, req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warn("fail to restore rbac", zap.Error(err))
 | 
			
		||||
		return merr.Status(err), nil
 | 
			
		||||
	}
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (node *Proxy) RefreshPolicyInfoCache(ctx context.Context, req *proxypb.RefreshPolicyInfoCacheRequest) (*commonpb.Status, error) {
 | 
			
		||||
	ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-RefreshPolicyInfoCache")
 | 
			
		||||
	defer sp.End()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1126,6 +1126,14 @@ func (coord *RootCoordMock) AlterDatabase(ctx context.Context, in *rootcoordpb.A
 | 
			
		|||
	return &commonpb.Status{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (coord *RootCoordMock) BackupRBAC(ctx context.Context, in *milvuspb.BackupRBACMetaRequest, opts ...grpc.CallOption) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	return &milvuspb.BackupRBACMetaResponse{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (coord *RootCoordMock) RestoreRBAC(ctx context.Context, in *milvuspb.RestoreRBACMetaRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
 | 
			
		||||
	return &commonpb.Status{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DescribeCollectionFunc func(ctx context.Context, request *milvuspb.DescribeCollectionRequest, opts ...grpc.CallOption) (*milvuspb.DescribeCollectionResponse, error)
 | 
			
		||||
 | 
			
		||||
type ShowPartitionsFunc func(ctx context.Context, request *milvuspb.ShowPartitionsRequest, opts ...grpc.CallOption) (*milvuspb.ShowPartitionsResponse, error)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,6 +97,8 @@ type IMetaTable interface {
 | 
			
		|||
	DropGrant(tenant string, role *milvuspb.RoleEntity) error
 | 
			
		||||
	ListPolicy(tenant string) ([]string, error)
 | 
			
		||||
	ListUserRole(tenant string) ([]string, error)
 | 
			
		||||
	BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBACMeta, error)
 | 
			
		||||
	RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MetaTable is a persistent meta set of all databases, collections and partitions.
 | 
			
		||||
| 
						 | 
				
			
			@ -1435,3 +1437,17 @@ func (mt *MetaTable) ListUserRole(tenant string) ([]string, error) {
 | 
			
		|||
 | 
			
		||||
	return mt.catalog.ListUserRole(mt.ctx, tenant)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mt *MetaTable) BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBACMeta, error) {
 | 
			
		||||
	mt.permissionLock.RLock()
 | 
			
		||||
	defer mt.permissionLock.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return mt.catalog.BackupRBAC(mt.ctx, tenant)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mt *MetaTable) RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error {
 | 
			
		||||
	mt.permissionLock.Lock()
 | 
			
		||||
	defer mt.permissionLock.Unlock()
 | 
			
		||||
 | 
			
		||||
	return mt.catalog.RestoreRBAC(mt.ctx, tenant, meta)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2000,3 +2000,44 @@ func TestMetaTable_DropDatabase(t *testing.T) {
 | 
			
		|||
		assert.False(t, mt.aliases.exist("not_commit"))
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMetaTable_BackupRBAC(t *testing.T) {
 | 
			
		||||
	catalog := mocks.NewRootCoordCatalog(t)
 | 
			
		||||
	catalog.EXPECT().BackupRBAC(mock.Anything, mock.Anything).Return(&milvuspb.RBACMeta{}, nil)
 | 
			
		||||
	mt := &MetaTable{
 | 
			
		||||
		dbName2Meta: map[string]*model.Database{
 | 
			
		||||
			"not_commit": model.NewDatabase(1, "not_commit", pb.DatabaseState_DatabaseCreated, nil),
 | 
			
		||||
		},
 | 
			
		||||
		names:   newNameDb(),
 | 
			
		||||
		aliases: newNameDb(),
 | 
			
		||||
		catalog: catalog,
 | 
			
		||||
	}
 | 
			
		||||
	_, err := mt.BackupRBAC(context.TODO(), util.DefaultTenant)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	catalog.ExpectedCalls = nil
 | 
			
		||||
	catalog.EXPECT().BackupRBAC(mock.Anything, mock.Anything).Return(nil, errors.New("error mock BackupRBAC"))
 | 
			
		||||
	_, err = mt.BackupRBAC(context.TODO(), util.DefaultTenant)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMetaTable_RestoreRBAC(t *testing.T) {
 | 
			
		||||
	catalog := mocks.NewRootCoordCatalog(t)
 | 
			
		||||
	catalog.EXPECT().RestoreRBAC(mock.Anything, mock.Anything, mock.Anything).Return(nil)
 | 
			
		||||
	mt := &MetaTable{
 | 
			
		||||
		dbName2Meta: map[string]*model.Database{
 | 
			
		||||
			"not_commit": model.NewDatabase(1, "not_commit", pb.DatabaseState_DatabaseCreated, nil),
 | 
			
		||||
		},
 | 
			
		||||
		names:   newNameDb(),
 | 
			
		||||
		aliases: newNameDb(),
 | 
			
		||||
		catalog: catalog,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := mt.RestoreRBAC(context.TODO(), util.DefaultTenant, &milvuspb.RBACMeta{})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	catalog.ExpectedCalls = nil
 | 
			
		||||
	catalog.EXPECT().RestoreRBAC(mock.Anything, mock.Anything, mock.Anything).Return(errors.New("error mock RestoreRBAC"))
 | 
			
		||||
	err = mt.RestoreRBAC(context.TODO(), util.DefaultTenant, &milvuspb.RBACMeta{})
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -336,6 +336,61 @@ func (_c *IMetaTable_AlterDatabase_Call) RunAndReturn(run func(context.Context,
 | 
			
		|||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC provides a mock function with given fields: ctx, tenant
 | 
			
		||||
func (_m *IMetaTable) BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBACMeta, error) {
 | 
			
		||||
	ret := _m.Called(ctx, tenant)
 | 
			
		||||
 | 
			
		||||
	var r0 *milvuspb.RBACMeta
 | 
			
		||||
	var r1 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, string) (*milvuspb.RBACMeta, error)); ok {
 | 
			
		||||
		return rf(ctx, tenant)
 | 
			
		||||
	}
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, string) *milvuspb.RBACMeta); ok {
 | 
			
		||||
		r0 = rf(ctx, tenant)
 | 
			
		||||
	} else {
 | 
			
		||||
		if ret.Get(0) != nil {
 | 
			
		||||
			r0 = ret.Get(0).(*milvuspb.RBACMeta)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
 | 
			
		||||
		r1 = rf(ctx, tenant)
 | 
			
		||||
	} else {
 | 
			
		||||
		r1 = ret.Error(1)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0, r1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IMetaTable_BackupRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BackupRBAC'
 | 
			
		||||
type IMetaTable_BackupRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - ctx context.Context
 | 
			
		||||
//   - tenant string
 | 
			
		||||
func (_e *IMetaTable_Expecter) BackupRBAC(ctx interface{}, tenant interface{}) *IMetaTable_BackupRBAC_Call {
 | 
			
		||||
	return &IMetaTable_BackupRBAC_Call{Call: _e.mock.On("BackupRBAC", ctx, tenant)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *IMetaTable_BackupRBAC_Call) Run(run func(ctx context.Context, tenant string)) *IMetaTable_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		run(args[0].(context.Context), args[1].(string))
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *IMetaTable_BackupRBAC_Call) Return(_a0 *milvuspb.RBACMeta, _a1 error) *IMetaTable_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0, _a1)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *IMetaTable_BackupRBAC_Call) RunAndReturn(run func(context.Context, string) (*milvuspb.RBACMeta, error)) *IMetaTable_BackupRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChangeCollectionState provides a mock function with given fields: ctx, collectionID, state, ts
 | 
			
		||||
func (_m *IMetaTable) ChangeCollectionState(ctx context.Context, collectionID int64, state etcdpb.CollectionState, ts uint64) error {
 | 
			
		||||
	ret := _m.Called(ctx, collectionID, state, ts)
 | 
			
		||||
| 
						 | 
				
			
			@ -1986,6 +2041,50 @@ func (_c *IMetaTable_RenameCollection_Call) RunAndReturn(run func(context.Contex
 | 
			
		|||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC provides a mock function with given fields: ctx, tenant, meta
 | 
			
		||||
func (_m *IMetaTable) RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error {
 | 
			
		||||
	ret := _m.Called(ctx, tenant, meta)
 | 
			
		||||
 | 
			
		||||
	var r0 error
 | 
			
		||||
	if rf, ok := ret.Get(0).(func(context.Context, string, *milvuspb.RBACMeta) error); ok {
 | 
			
		||||
		r0 = rf(ctx, tenant, meta)
 | 
			
		||||
	} else {
 | 
			
		||||
		r0 = ret.Error(0)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IMetaTable_RestoreRBAC_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RestoreRBAC'
 | 
			
		||||
type IMetaTable_RestoreRBAC_Call struct {
 | 
			
		||||
	*mock.Call
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RestoreRBAC is a helper method to define mock.On call
 | 
			
		||||
//   - ctx context.Context
 | 
			
		||||
//   - tenant string
 | 
			
		||||
//   - meta *milvuspb.RBACMeta
 | 
			
		||||
func (_e *IMetaTable_Expecter) RestoreRBAC(ctx interface{}, tenant interface{}, meta interface{}) *IMetaTable_RestoreRBAC_Call {
 | 
			
		||||
	return &IMetaTable_RestoreRBAC_Call{Call: _e.mock.On("RestoreRBAC", ctx, tenant, meta)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *IMetaTable_RestoreRBAC_Call) Run(run func(ctx context.Context, tenant string, meta *milvuspb.RBACMeta)) *IMetaTable_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Run(func(args mock.Arguments) {
 | 
			
		||||
		run(args[0].(context.Context), args[1].(string), args[2].(*milvuspb.RBACMeta))
 | 
			
		||||
	})
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *IMetaTable_RestoreRBAC_Call) Return(_a0 error) *IMetaTable_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(_a0)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_c *IMetaTable_RestoreRBAC_Call) RunAndReturn(run func(context.Context, string, *milvuspb.RBACMeta) error) *IMetaTable_RestoreRBAC_Call {
 | 
			
		||||
	_c.Call.Return(run)
 | 
			
		||||
	return _c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SelectGrant provides a mock function with given fields: tenant, entity
 | 
			
		||||
func (_m *IMetaTable) SelectGrant(tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) {
 | 
			
		||||
	ret := _m.Called(tenant, entity)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2706,6 +2706,57 @@ func (c *Core) ListPolicy(ctx context.Context, in *internalpb.ListPolicyRequest)
 | 
			
		|||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Core) BackupRBAC(ctx context.Context, in *milvuspb.BackupRBACMetaRequest) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	method := "BackupRBAC"
 | 
			
		||||
	metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.TotalLabel).Inc()
 | 
			
		||||
	tr := timerecord.NewTimeRecorder(method)
 | 
			
		||||
	ctxLog := log.Ctx(ctx).With(zap.String("role", typeutil.RootCoordRole), zap.Any("in", in))
 | 
			
		||||
	ctxLog.Debug(method)
 | 
			
		||||
 | 
			
		||||
	if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
 | 
			
		||||
		return &milvuspb.BackupRBACMetaResponse{
 | 
			
		||||
			Status: merr.Status(err),
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rbacMeta, err := c.meta.BackupRBAC(ctx, util.DefaultTenant)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return &milvuspb.BackupRBACMetaResponse{
 | 
			
		||||
			Status: merr.Status(err),
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctxLog.Debug(method + " success")
 | 
			
		||||
	metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
 | 
			
		||||
	metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
 | 
			
		||||
 | 
			
		||||
	return &milvuspb.BackupRBACMetaResponse{
 | 
			
		||||
		Status:   merr.Success(),
 | 
			
		||||
		RBACMeta: rbacMeta,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Core) RestoreRBAC(ctx context.Context, in *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error) {
 | 
			
		||||
	method := "RestoreRBAC"
 | 
			
		||||
	metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.TotalLabel).Inc()
 | 
			
		||||
	tr := timerecord.NewTimeRecorder(method)
 | 
			
		||||
	ctxLog := log.Ctx(ctx).With(zap.String("role", typeutil.RootCoordRole), zap.Any("in", in))
 | 
			
		||||
	ctxLog.Debug(method)
 | 
			
		||||
 | 
			
		||||
	if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
 | 
			
		||||
		return merr.Status(err), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := c.meta.RestoreRBAC(ctx, util.DefaultTenant, in.RBACMeta); err != nil {
 | 
			
		||||
		return merr.Status(err), nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctxLog.Debug(method + " success")
 | 
			
		||||
	metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc()
 | 
			
		||||
	metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds()))
 | 
			
		||||
	return merr.Success(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Core) RenameCollection(ctx context.Context, req *milvuspb.RenameCollectionRequest) (*commonpb.Status, error) {
 | 
			
		||||
	if err := merr.CheckHealthy(c.GetStateCode()); err != nil {
 | 
			
		||||
		return merr.Status(err), nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1971,6 +1971,38 @@ func TestCore_InitRBAC(t *testing.T) {
 | 
			
		|||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCore_BackupRBAC(t *testing.T) {
 | 
			
		||||
	meta := mockrootcoord.NewIMetaTable(t)
 | 
			
		||||
	c := newTestCore(withHealthyCode(), withMeta(meta))
 | 
			
		||||
 | 
			
		||||
	meta.EXPECT().BackupRBAC(mock.Anything, mock.Anything).Return(&milvuspb.RBACMeta{}, nil)
 | 
			
		||||
	resp, err := c.BackupRBAC(context.Background(), &milvuspb.BackupRBACMetaRequest{})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, merr.Ok(resp.GetStatus()))
 | 
			
		||||
 | 
			
		||||
	meta.ExpectedCalls = nil
 | 
			
		||||
	meta.EXPECT().BackupRBAC(mock.Anything, mock.Anything).Return(nil, errors.New("mock error"))
 | 
			
		||||
	resp, err = c.BackupRBAC(context.Background(), &milvuspb.BackupRBACMetaRequest{})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.False(t, merr.Ok(resp.GetStatus()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCore_RestoreRBAC(t *testing.T) {
 | 
			
		||||
	meta := mockrootcoord.NewIMetaTable(t)
 | 
			
		||||
	c := newTestCore(withHealthyCode(), withMeta(meta))
 | 
			
		||||
 | 
			
		||||
	meta.EXPECT().RestoreRBAC(mock.Anything, mock.Anything, mock.Anything).Return(nil)
 | 
			
		||||
	resp, err := c.RestoreRBAC(context.Background(), &milvuspb.RestoreRBACMetaRequest{})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, merr.Ok(resp))
 | 
			
		||||
 | 
			
		||||
	meta.ExpectedCalls = nil
 | 
			
		||||
	meta.EXPECT().RestoreRBAC(mock.Anything, mock.Anything, mock.Anything).Return(errors.New("mock error"))
 | 
			
		||||
	resp, err = c.RestoreRBAC(context.Background(), &milvuspb.RestoreRBACMetaRequest{})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.False(t, merr.Ok(resp))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RootCoordSuite struct {
 | 
			
		||||
	suite.Suite
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -266,6 +266,14 @@ func (m *GrpcRootCoordClient) AlterDatabase(ctx context.Context, in *rootcoordpb
 | 
			
		|||
	return &commonpb.Status{}, m.Err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *GrpcRootCoordClient) BackupRBAC(ctx context.Context, in *milvuspb.BackupRBACMetaRequest, opts ...grpc.CallOption) (*milvuspb.BackupRBACMetaResponse, error) {
 | 
			
		||||
	return &milvuspb.BackupRBACMetaResponse{}, m.Err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *GrpcRootCoordClient) RestoreRBAC(ctx context.Context, in *milvuspb.RestoreRBACMetaRequest, opts ...grpc.CallOption) (*commonpb.Status, error) {
 | 
			
		||||
	return &commonpb.Status{}, m.Err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *GrpcRootCoordClient) Close() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,13 +6,15 @@ require (
 | 
			
		|||
	github.com/apache/pulsar-client-go v0.6.1-0.20210728062540-29414db801a7
 | 
			
		||||
	github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b
 | 
			
		||||
	github.com/blang/semver/v4 v4.0.0
 | 
			
		||||
	github.com/cenkalti/backoff/v4 v4.2.1
 | 
			
		||||
	github.com/cockroachdb/errors v1.9.1
 | 
			
		||||
	github.com/confluentinc/confluent-kafka-go v1.9.1
 | 
			
		||||
	github.com/containerd/cgroups/v3 v3.0.3
 | 
			
		||||
	github.com/expr-lang/expr v1.15.7
 | 
			
		||||
	github.com/golang/protobuf v1.5.4
 | 
			
		||||
	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
 | 
			
		||||
	github.com/klauspost/compress v1.17.7
 | 
			
		||||
	github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240717062137-3ffb1db01632
 | 
			
		||||
	github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240815113856-e2789dca8b59
 | 
			
		||||
	github.com/nats-io/nats-server/v2 v2.10.12
 | 
			
		||||
	github.com/nats-io/nats.go v1.34.1
 | 
			
		||||
	github.com/panjf2000/ants/v2 v2.7.2
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +67,6 @@ require (
 | 
			
		|||
	github.com/ardielle/ardielle-go v1.5.2 // indirect
 | 
			
		||||
	github.com/benbjohnson/clock v1.1.0 // indirect
 | 
			
		||||
	github.com/beorn7/perks v1.0.1 // indirect
 | 
			
		||||
	github.com/cenkalti/backoff/v4 v4.2.1 // indirect
 | 
			
		||||
	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 | 
			
		||||
	github.com/cilium/ebpf v0.11.0 // indirect
 | 
			
		||||
	github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f // indirect
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +93,6 @@ require (
 | 
			
		|||
	github.com/godbus/dbus/v5 v5.0.4 // indirect
 | 
			
		||||
	github.com/gogo/protobuf v1.3.2 // indirect
 | 
			
		||||
	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
 | 
			
		||||
	github.com/golang/protobuf v1.5.4 // indirect
 | 
			
		||||
	github.com/golang/snappy v0.0.4 // indirect
 | 
			
		||||
	github.com/google/btree v1.1.2 // indirect
 | 
			
		||||
	github.com/google/uuid v1.6.0 // indirect
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -494,8 +494,8 @@ github.com/milvus-io/cgosymbolizer v0.0.0-20240722103217-b7dee0e50119 h1:9VXijWu
 | 
			
		|||
github.com/milvus-io/cgosymbolizer v0.0.0-20240722103217-b7dee0e50119/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.3.4-0.20240717062137-3ffb1db01632 h1:CXig0DNtUsCLzchCFe3PR2KgOdobbz9gK2nSV7195PM=
 | 
			
		||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240717062137-3ffb1db01632/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
 | 
			
		||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240815113856-e2789dca8b59 h1:mKekr0GmCKMpIQh9OJ67TlKVKxDt08600ltARc/JUXY=
 | 
			
		||||
github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240815113856-e2789dca8b59/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
 | 
			
		||||
github.com/milvus-io/pulsar-client-go v0.6.10 h1:eqpJjU+/QX0iIhEo3nhOqMNXL+TyInAs1IAHZCrCM/A=
 | 
			
		||||
github.com/milvus-io/pulsar-client-go v0.6.10/go.mod h1:lQqCkgwDF8YFYjKA+zOheTk1tev2B+bKj5j7+nm8M1w=
 | 
			
		||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -123,6 +123,8 @@ var (
 | 
			
		|||
			MetaStore2API(commonpb.ObjectPrivilege_PrivilegeDropOwnership.String()),
 | 
			
		||||
			MetaStore2API(commonpb.ObjectPrivilege_PrivilegeSelectOwnership.String()),
 | 
			
		||||
			MetaStore2API(commonpb.ObjectPrivilege_PrivilegeManageOwnership.String()),
 | 
			
		||||
			MetaStore2API(commonpb.ObjectPrivilege_PrivilegeBackupRBAC.String()),
 | 
			
		||||
			MetaStore2API(commonpb.ObjectPrivilege_PrivilegeRestoreRBAC.String()),
 | 
			
		||||
 | 
			
		||||
			MetaStore2API(commonpb.ObjectPrivilege_PrivilegeCreateResourceGroup.String()),
 | 
			
		||||
			MetaStore2API(commonpb.ObjectPrivilege_PrivilegeUpdateResourceGroups.String()),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,166 @@
 | 
			
		|||
// 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 rbac
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/suite"
 | 
			
		||||
	"google.golang.org/grpc/metadata"
 | 
			
		||||
 | 
			
		||||
	"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
 | 
			
		||||
	"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util/crypto"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util/merr"
 | 
			
		||||
	"github.com/milvus-io/milvus/pkg/util/paramtable"
 | 
			
		||||
	"github.com/milvus-io/milvus/tests/integration"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	dim            = 128
 | 
			
		||||
	dbName         = ""
 | 
			
		||||
	collectionName = "test_load_collection"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type RBACBackupTestSuite struct {
 | 
			
		||||
	integration.MiniClusterSuite
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *RBACBackupTestSuite) SetupSuite() {
 | 
			
		||||
	paramtable.Init()
 | 
			
		||||
	paramtable.Get().Save(paramtable.Get().QueryCoordCfg.BalanceCheckInterval.Key, "1000")
 | 
			
		||||
	paramtable.Get().Save(paramtable.Get().QueryNodeCfg.GracefulStopTimeout.Key, "1")
 | 
			
		||||
	paramtable.Get().Save(paramtable.Get().CommonCfg.AuthorizationEnabled.Key, "true")
 | 
			
		||||
 | 
			
		||||
	s.Require().NoError(s.SetupEmbedEtcd())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetContext(ctx context.Context, originValue string) context.Context {
 | 
			
		||||
	authKey := strings.ToLower(util.HeaderAuthorize)
 | 
			
		||||
	authValue := crypto.Base64Encode(originValue)
 | 
			
		||||
	contextMap := map[string]string{
 | 
			
		||||
		authKey: authValue,
 | 
			
		||||
	}
 | 
			
		||||
	md := metadata.New(contextMap)
 | 
			
		||||
	return metadata.NewIncomingContext(ctx, md)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *RBACBackupTestSuite) TestBackup() {
 | 
			
		||||
	ctx := GetContext(context.Background(), "root:123456")
 | 
			
		||||
	// test empty rbac content
 | 
			
		||||
	resp, err := s.Cluster.Proxy.BackupRBAC(ctx, &milvuspb.BackupRBACMetaRequest{})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp.GetStatus()))
 | 
			
		||||
	s.Equal("", resp.GetRBACMeta().String())
 | 
			
		||||
 | 
			
		||||
	// generate some rbac content
 | 
			
		||||
	roleName := "test_role"
 | 
			
		||||
	resp1, err := s.Cluster.Proxy.CreateRole(ctx, &milvuspb.CreateRoleRequest{
 | 
			
		||||
		Entity: &milvuspb.RoleEntity{
 | 
			
		||||
			Name: roleName,
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp1))
 | 
			
		||||
	resp2, err := s.Cluster.Proxy.OperatePrivilege(ctx, &milvuspb.OperatePrivilegeRequest{
 | 
			
		||||
		Type: milvuspb.OperatePrivilegeType_Grant,
 | 
			
		||||
		Entity: &milvuspb.GrantEntity{
 | 
			
		||||
			Role:       &milvuspb.RoleEntity{Name: roleName},
 | 
			
		||||
			Object:     &milvuspb.ObjectEntity{Name: commonpb.ObjectType_Collection.String()},
 | 
			
		||||
			ObjectName: util.AnyWord,
 | 
			
		||||
			DbName:     util.AnyWord,
 | 
			
		||||
			Grantor: &milvuspb.GrantorEntity{
 | 
			
		||||
				User:      &milvuspb.UserEntity{Name: util.UserRoot},
 | 
			
		||||
				Privilege: &milvuspb.PrivilegeEntity{Name: util.AnyWord},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp2))
 | 
			
		||||
	s.Equal("", resp2.GetReason())
 | 
			
		||||
	userName := "test_user"
 | 
			
		||||
	passwd := "test_passwd"
 | 
			
		||||
	resp3, err := s.Cluster.Proxy.CreateCredential(ctx, &milvuspb.CreateCredentialRequest{
 | 
			
		||||
		Username: userName,
 | 
			
		||||
		Password: crypto.Base64Encode(passwd),
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp3))
 | 
			
		||||
	resp4, err := s.Cluster.Proxy.OperateUserRole(ctx, &milvuspb.OperateUserRoleRequest{
 | 
			
		||||
		Username: userName,
 | 
			
		||||
		RoleName: roleName,
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp4))
 | 
			
		||||
 | 
			
		||||
	// test back up rbac
 | 
			
		||||
	resp5, err := s.Cluster.Proxy.BackupRBAC(ctx, &milvuspb.BackupRBACMetaRequest{})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp5.GetStatus()))
 | 
			
		||||
 | 
			
		||||
	// test restore, expect to failed due to role/user already exist
 | 
			
		||||
	resp6, err := s.Cluster.Proxy.RestoreRBAC(ctx, &milvuspb.RestoreRBACMetaRequest{
 | 
			
		||||
		RBACMeta: resp5.GetRBACMeta(),
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.False(merr.Ok(resp6))
 | 
			
		||||
 | 
			
		||||
	// drop exist role/user, successful to restore
 | 
			
		||||
	resp7, err := s.Cluster.Proxy.OperatePrivilege(ctx, &milvuspb.OperatePrivilegeRequest{
 | 
			
		||||
		Type: milvuspb.OperatePrivilegeType_Revoke,
 | 
			
		||||
		Entity: &milvuspb.GrantEntity{
 | 
			
		||||
			Role:       &milvuspb.RoleEntity{Name: roleName},
 | 
			
		||||
			Object:     &milvuspb.ObjectEntity{Name: commonpb.ObjectType_Collection.String()},
 | 
			
		||||
			ObjectName: util.AnyWord,
 | 
			
		||||
			DbName:     util.AnyWord,
 | 
			
		||||
			Grantor: &milvuspb.GrantorEntity{
 | 
			
		||||
				User:      &milvuspb.UserEntity{Name: util.UserRoot},
 | 
			
		||||
				Privilege: &milvuspb.PrivilegeEntity{Name: util.AnyWord},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp7))
 | 
			
		||||
	resp8, err := s.Cluster.Proxy.DropRole(ctx, &milvuspb.DropRoleRequest{
 | 
			
		||||
		RoleName: roleName,
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp8))
 | 
			
		||||
	resp9, err := s.Cluster.Proxy.DeleteCredential(ctx, &milvuspb.DeleteCredentialRequest{
 | 
			
		||||
		Username: userName,
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp9))
 | 
			
		||||
 | 
			
		||||
	resp10, err := s.Cluster.Proxy.RestoreRBAC(ctx, &milvuspb.RestoreRBACMetaRequest{
 | 
			
		||||
		RBACMeta: resp5.GetRBACMeta(),
 | 
			
		||||
	})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp10))
 | 
			
		||||
 | 
			
		||||
	// check the restored rbac, should be same as the original one
 | 
			
		||||
	resp11, err := s.Cluster.Proxy.BackupRBAC(ctx, &milvuspb.BackupRBACMetaRequest{})
 | 
			
		||||
	s.NoError(err)
 | 
			
		||||
	s.True(merr.Ok(resp11.GetStatus()))
 | 
			
		||||
	s.Equal(resp11.GetRBACMeta().String(), resp5.GetRBACMeta().String())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRBACBackup(t *testing.T) {
 | 
			
		||||
	suite.Run(t, new(RBACBackupTestSuite))
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue