Repository: milvus-io/milvus-sdk-go
Pull request #845 (2024-11-13 03:09:20)

enhance: RBAC Custom Privilege Group API
issue: https://github.com/milvus-io/milvus/issues/37031

sre-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/845#" title="Author self-approved">shaoting-huang</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **yah01** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @yah01` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=milvus-io%2Fmilvus-sdk-go).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/milvus-io/milvus-sdk-go/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["yah01"]} -->
sre-ci-robot: Welcome @shaoting-huang! It looks like this is your first PR to milvus-io/milvus-sdk-go 🎉
weiliu1031: /lgtm
weiliu1031: /cc @congqixia 
sre-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/845#pullrequestreview-2432322324" title="Approved">congqixia</a>*, *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/845#" title="Author self-approved">shaoting-huang</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=milvus-io%2Fmilvus-sdk-go).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/milvus-io/milvus-sdk-go/blob/master/OWNERS)~~ [congqixia]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
sre-ci-robot: New changes are detected. LGTM label has been removed.
congqixia: /kind enhancement
sre-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/845#pullrequestreview-2434864689" title="LGTM">congqixia</a>*, *<a href="https://github.com/milvus-io/milvus-sdk-go/pull/845#" title="Author self-approved">shaoting-huang</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=milvus-io%2Fmilvus-sdk-go).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/milvus-io/milvus-sdk-go/blob/master/OWNERS)~~ [congqixia]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/client/client.go b/client/client.go
index 9330a0c..14de87d 100644
--- a/client/client.go
+++ b/client/client.go
@@ -86,6 +86,17 @@ type Client interface {
 	BackupRBAC(ctx context.Context) (*entity.RBACMeta, error)
 	RestoreRBAC(ctx context.Context, meta *entity.RBACMeta) error
 
+	// CreatePrivilegeGroup creates a privilege group
+	CreatePrivilegeGroup(ctx context.Context, groupName string) error
+	// DropPrivilegeGroup drops the specified privilege group
+	DropPrivilegeGroup(ctx context.Context, groupName string) error
+	// ListPrivilegeGroups lists all privilege groups
+	ListPrivilegeGroups(ctx context.Context) ([]*entity.PrivilegeGroup, error)
+	// AddPrivilegeToGroup adds privileges to a privilege group
+	AddPrivilegesToGroup(ctx context.Context, groupName string, privileges []string) error
+	// RemovePrivilegesFromGroup removes privileges from a privilege group
+	RemovePrivilegesFromGroup(ctx context.Context, groupName string, privileges []string) error
+
 	// -- authentication --
 
 	// CreateCredential create new user and password
diff --git a/client/rbac.go b/client/rbac.go
index 091bbff..1495434 100644
--- a/client/rbac.go
+++ b/client/rbac.go
@@ -521,3 +521,127 @@ func (c *GrpcClient) RestoreRBAC(ctx context.Context, meta *entity.RBACMeta) err
 
 	return handleRespStatus(resp)
 }
+
+func (c *GrpcClient) CreatePrivilegeGroup(ctx context.Context, groupName string) error {
+	if c.Service == nil {
+		return ErrClientNotReady
+	}
+
+	req := &milvuspb.CreatePrivilegeGroupRequest{
+		GroupName: groupName,
+	}
+
+	resp, err := c.Service.CreatePrivilegeGroup(ctx, req)
+	if err != nil {
+		return err
+	}
+
+	return handleRespStatus(resp)
+}
+
+func (c *GrpcClient) DropPrivilegeGroup(ctx context.Context, groupName string) error {
+	if c.Service == nil {
+		return ErrClientNotReady
+	}
+
+	req := &milvuspb.DropPrivilegeGroupRequest{
+		GroupName: groupName,
+	}
+
+	resp, err := c.Service.DropPrivilegeGroup(ctx, req)
+	if err != nil {
+		return err
+	}
+
+	return handleRespStatus(resp)
+}
+
+func (c *GrpcClient) ListPrivilegeGroups(ctx context.Context) ([]*entity.PrivilegeGroup, error) {
+	PrivilegeGroupList := make([]*entity.PrivilegeGroup, 0)
+	if c.Service == nil {
+		return PrivilegeGroupList, ErrClientNotReady
+	}
+
+	req := &milvuspb.ListPrivilegeGroupsRequest{}
+
+	resp, err := c.Service.ListPrivilegeGroups(ctx, req)
+	if err != nil {
+		return PrivilegeGroupList, err
+	}
+
+	if err = handleRespStatus(resp.GetStatus()); err != nil {
+		return PrivilegeGroupList, err
+	}
+
+	results := resp.GetPrivilegeGroups()
+
+	if len(results) == 0 {
+		return PrivilegeGroupList, nil
+	}
+
+	for _, pg := range results {
+		privs := make([]string, 0, len(pg.Privileges))
+		for _, p := range pg.Privileges {
+			privs = append(privs, p.GetName())
+		}
+		PrivilegeGroup := &entity.PrivilegeGroup{
+			GroupName:  pg.GroupName,
+			Privileges: privs,
+		}
+		PrivilegeGroupList = append(PrivilegeGroupList, PrivilegeGroup)
+	}
+
+	return PrivilegeGroupList, nil
+}
+
+func (c *GrpcClient) AddPrivilegesToGroup(ctx context.Context, groupName string, privileges []string) error {
+	if c.Service == nil {
+		return ErrClientNotReady
+	}
+
+	privs := make([]*milvuspb.PrivilegeEntity, 0, len(privileges))
+	for _, p := range privileges {
+		privs = append(privs, &milvuspb.PrivilegeEntity{
+			Name: p,
+		})
+	}
+
+	req := &milvuspb.OperatePrivilegeGroupRequest{
+		GroupName:  groupName,
+		Privileges: privs,
+		Type:       milvuspb.OperatePrivilegeGroupType_AddPrivilegesToGroup,
+	}
+
+	resp, err := c.Service.OperatePrivilegeGroup(ctx, req)
+	if err != nil {
+		return err
+	}
+
+	return handleRespStatus(resp)
+}
+
+func (c *GrpcClient) RemovePrivilegesFromGroup(ctx context.Context, groupName string, privileges []string) error {
+	if c.Service == nil {
+		return ErrClientNotReady
+	}
+
+	privs := make([]*milvuspb.PrivilegeEntity, 0, len(privileges))
+	for _, p := range privileges {
+		privs = append(privs, &milvuspb.PrivilegeEntity{
+			Name: p,
+		})
+	}
+
+	req := &milvuspb.OperatePrivilegeGroupRequest{
+		GroupName:  groupName,
+		Privileges: privs,
+		Type:       milvuspb.OperatePrivilegeGroupType_RemovePrivilegesFromGroup,
+	}
+
+	resp, err := c.Service.OperatePrivilegeGroup(ctx, req)
+	if err != nil {
+		return err
+	}
+
+	return handleRespStatus(resp)
+}
diff --git a/entity/rbac.go b/entity/rbac.go
index 22f473e..c16d637 100644
--- a/entity/rbac.go
+++ b/entity/rbac.go
@@ -72,3 +72,8 @@ type RBACMeta struct {
 	Roles      []*Role
 	RoleGrants []*RoleGrants
 }
+
+type PrivilegeGroup struct {
+	GroupName  string
+	Privileges []string
+}
diff --git a/go.mod b/go.mod
index 1536779..08b1f53 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/go-faker/faker/v4 v4.1.0
 	github.com/golang/protobuf v1.5.2
 	github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
-	github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240909041258-8f8ca67816cd
+	github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20241108105827-266fb751b620
 	github.com/stretchr/testify v1.8.1
 	github.com/tidwall/gjson v1.14.4
 	github.com/x448/float16 v0.8.4
@@ -27,12 +27,13 @@ require (
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/rogpeppe/go-internal v1.8.1 // indirect
+	github.com/samber/lo v1.47.0 // indirect
 	github.com/stretchr/objx v0.5.0 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
 	golang.org/x/net v0.17.0 // indirect
 	golang.org/x/sys v0.13.0 // indirect
-	golang.org/x/text v0.13.0 // indirect
+	golang.org/x/text v0.16.0 // indirect
 	google.golang.org/genproto v0.0.0-20220503193339-ba3ae3f07e29 // indirect
 	google.golang.org/protobuf v1.33.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/go.sum b/go.sum
index 260f795..019bdd9 100644
--- a/go.sum
+++ b/go.sum
@@ -157,12 +157,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/v2 v2.3.4-0.20240407081710-6c95f3065923 h1:95AQHE3LbCrbegdFZ+lfVNuPYnRgQDVEXHJQkk+3jj8=
-github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240407081710-6c95f3065923/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
-github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240909041258-8f8ca67816cd h1:x0b0+foTe23sKcVFseR1DE8+BB08EH6ViiRHaz8PEik=
-github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20240909041258-8f8ca67816cd/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
-github.com/milvus-io/milvus-proto/go-api/v2 v2.4.10-0.20240819025435-512e3b98866a h1:0B/8Fo66D8Aa23Il0yrQvg1KKz92tE/BJ5BvkUxxAAk=
-github.com/milvus-io/milvus-proto/go-api/v2 v2.4.10-0.20240819025435-512e3b98866a/go.mod h1:1OIl0v5PQeNxIJhCvY+K55CBUOYDZevw9g9380u1Wek=
+github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20241108105827-266fb751b620 h1:0IWUDtDloift7cQHalhdjuVkL/3qSeiXFqR7MofZBkg=
+github.com/milvus-io/milvus-proto/go-api/v2 v2.3.4-0.20241108105827-266fb751b620/go.mod h1:/6UT4zZl6awVeXLeE7UGDWZvXj3IWkRsh3mqsn0DiAs=
 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=
@@ -194,6 +190,8 @@ github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XF
 github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc=
+github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU=
 github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -293,7 +291,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
@@ -336,9 +333,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -360,6 +355,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/mocks/MilvusServiceServer.go b/mocks/MilvusServiceServer.go
index 2ae5737..6179aa1 100644
--- a/mocks/MilvusServiceServer.go
+++ b/mocks/MilvusServiceServer.go
@@ -192,6 +192,61 @@ func (_c *MilvusServiceServer_AlterCollection_Call) RunAndReturn(run func(contex
 	return _c
 }
 
+// AlterCollectionField provides a mock function with given fields: _a0, _a1
+func (_m *MilvusServiceServer) AlterCollectionField(_a0 context.Context, _a1 *milvuspb.AlterCollectionFieldRequest) (*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.AlterCollectionFieldRequest) (*commonpb.Status, error)); ok {
+		return rf(_a0, _a1)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.AlterCollectionFieldRequest) *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.AlterCollectionFieldRequest) error); ok {
+		r1 = rf(_a0, _a1)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// MilvusServiceServer_AlterCollectionField_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AlterCollectionField'
+type MilvusServiceServer_AlterCollectionField_Call struct {
+	*mock.Call
+}
+
+// AlterCollectionField is a helper method to define mock.On call
+//   - _a0 context.Context
+//   - _a1 *milvuspb.AlterCollectionFieldRequest
+func (_e *MilvusServiceServer_Expecter) AlterCollectionField(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_AlterCollectionField_Call {
+	return &MilvusServiceServer_AlterCollectionField_Call{Call: _e.mock.On("AlterCollectionField", _a0, _a1)}
+}
+
+func (_c *MilvusServiceServer_AlterCollectionField_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.AlterCollectionFieldRequest)) *MilvusServiceServer_AlterCollectionField_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*milvuspb.AlterCollectionFieldRequest))
+	})
+	return _c
+}
+
+func (_c *MilvusServiceServer_AlterCollectionField_Call) Return(_a0 *commonpb.Status, _a1 error) *MilvusServiceServer_AlterCollectionField_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *MilvusServiceServer_AlterCollectionField_Call) RunAndReturn(run func(context.Context, *milvuspb.AlterCollectionFieldRequest) (*commonpb.Status, error)) *MilvusServiceServer_AlterCollectionField_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // AlterDatabase provides a mock function with given fields: _a0, _a1
 func (_m *MilvusServiceServer) AlterDatabase(_a0 context.Context, _a1 *milvuspb.AlterDatabaseRequest) (*commonpb.Status, error) {
 	ret := _m.Called(_a0, _a1)
@@ -852,6 +907,61 @@ func (_c *MilvusServiceServer_CreatePartition_Call) RunAndReturn(run func(contex
 	return _c
 }
 
+// CreatePrivilegeGroup provides a mock function with given fields: _a0, _a1
+func (_m *MilvusServiceServer) CreatePrivilegeGroup(_a0 context.Context, _a1 *milvuspb.CreatePrivilegeGroupRequest) (*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.CreatePrivilegeGroupRequest) (*commonpb.Status, error)); ok {
+		return rf(_a0, _a1)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.CreatePrivilegeGroupRequest) *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.CreatePrivilegeGroupRequest) error); ok {
+		r1 = rf(_a0, _a1)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// MilvusServiceServer_CreatePrivilegeGroup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreatePrivilegeGroup'
+type MilvusServiceServer_CreatePrivilegeGroup_Call struct {
+	*mock.Call
+}
+
+// CreatePrivilegeGroup is a helper method to define mock.On call
+//   - _a0 context.Context
+//   - _a1 *milvuspb.CreatePrivilegeGroupRequest
+func (_e *MilvusServiceServer_Expecter) CreatePrivilegeGroup(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_CreatePrivilegeGroup_Call {
+	return &MilvusServiceServer_CreatePrivilegeGroup_Call{Call: _e.mock.On("CreatePrivilegeGroup", _a0, _a1)}
+}
+
+func (_c *MilvusServiceServer_CreatePrivilegeGroup_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.CreatePrivilegeGroupRequest)) *MilvusServiceServer_CreatePrivilegeGroup_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*milvuspb.CreatePrivilegeGroupRequest))
+	})
+	return _c
+}
+
+func (_c *MilvusServiceServer_CreatePrivilegeGroup_Call) Return(_a0 *commonpb.Status, _a1 error) *MilvusServiceServer_CreatePrivilegeGroup_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *MilvusServiceServer_CreatePrivilegeGroup_Call) RunAndReturn(run func(context.Context, *milvuspb.CreatePrivilegeGroupRequest) (*commonpb.Status, error)) *MilvusServiceServer_CreatePrivilegeGroup_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // CreateResourceGroup provides a mock function with given fields: _a0, _a1
 func (_m *MilvusServiceServer) CreateResourceGroup(_a0 context.Context, _a1 *milvuspb.CreateResourceGroupRequest) (*commonpb.Status, error) {
 	ret := _m.Called(_a0, _a1)
@@ -1677,6 +1787,61 @@ func (_c *MilvusServiceServer_DropPartition_Call) RunAndReturn(run func(context.
 	return _c
 }
 
+// DropPrivilegeGroup provides a mock function with given fields: _a0, _a1
+func (_m *MilvusServiceServer) DropPrivilegeGroup(_a0 context.Context, _a1 *milvuspb.DropPrivilegeGroupRequest) (*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.DropPrivilegeGroupRequest) (*commonpb.Status, error)); ok {
+		return rf(_a0, _a1)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.DropPrivilegeGroupRequest) *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.DropPrivilegeGroupRequest) error); ok {
+		r1 = rf(_a0, _a1)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// MilvusServiceServer_DropPrivilegeGroup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DropPrivilegeGroup'
+type MilvusServiceServer_DropPrivilegeGroup_Call struct {
+	*mock.Call
+}
+
+// DropPrivilegeGroup is a helper method to define mock.On call
+//   - _a0 context.Context
+//   - _a1 *milvuspb.DropPrivilegeGroupRequest
+func (_e *MilvusServiceServer_Expecter) DropPrivilegeGroup(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_DropPrivilegeGroup_Call {
+	return &MilvusServiceServer_DropPrivilegeGroup_Call{Call: _e.mock.On("DropPrivilegeGroup", _a0, _a1)}
+}
+
+func (_c *MilvusServiceServer_DropPrivilegeGroup_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.DropPrivilegeGroupRequest)) *MilvusServiceServer_DropPrivilegeGroup_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*milvuspb.DropPrivilegeGroupRequest))
+	})
+	return _c
+}
+
+func (_c *MilvusServiceServer_DropPrivilegeGroup_Call) Return(_a0 *commonpb.Status, _a1 error) *MilvusServiceServer_DropPrivilegeGroup_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *MilvusServiceServer_DropPrivilegeGroup_Call) RunAndReturn(run func(context.Context, *milvuspb.DropPrivilegeGroupRequest) (*commonpb.Status, error)) *MilvusServiceServer_DropPrivilegeGroup_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // DropResourceGroup provides a mock function with given fields: _a0, _a1
 func (_m *MilvusServiceServer) DropResourceGroup(_a0 context.Context, _a1 *milvuspb.DropResourceGroupRequest) (*commonpb.Status, error) {
 	ret := _m.Called(_a0, _a1)
@@ -3492,6 +3657,61 @@ func (_c *MilvusServiceServer_ListIndexedSegment_Call) RunAndReturn(run func(con
 	return _c
 }
 
+// ListPrivilegeGroups provides a mock function with given fields: _a0, _a1
+func (_m *MilvusServiceServer) ListPrivilegeGroups(_a0 context.Context, _a1 *milvuspb.ListPrivilegeGroupsRequest) (*milvuspb.ListPrivilegeGroupsResponse, error) {
+	ret := _m.Called(_a0, _a1)
+
+	var r0 *milvuspb.ListPrivilegeGroupsResponse
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.ListPrivilegeGroupsRequest) (*milvuspb.ListPrivilegeGroupsResponse, error)); ok {
+		return rf(_a0, _a1)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.ListPrivilegeGroupsRequest) *milvuspb.ListPrivilegeGroupsResponse); ok {
+		r0 = rf(_a0, _a1)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*milvuspb.ListPrivilegeGroupsResponse)
+		}
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, *milvuspb.ListPrivilegeGroupsRequest) error); ok {
+		r1 = rf(_a0, _a1)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// MilvusServiceServer_ListPrivilegeGroups_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListPrivilegeGroups'
+type MilvusServiceServer_ListPrivilegeGroups_Call struct {
+	*mock.Call
+}
+
+// ListPrivilegeGroups is a helper method to define mock.On call
+//   - _a0 context.Context
+//   - _a1 *milvuspb.ListPrivilegeGroupsRequest
+func (_e *MilvusServiceServer_Expecter) ListPrivilegeGroups(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_ListPrivilegeGroups_Call {
+	return &MilvusServiceServer_ListPrivilegeGroups_Call{Call: _e.mock.On("ListPrivilegeGroups", _a0, _a1)}
+}
+
+func (_c *MilvusServiceServer_ListPrivilegeGroups_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.ListPrivilegeGroupsRequest)) *MilvusServiceServer_ListPrivilegeGroups_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*milvuspb.ListPrivilegeGroupsRequest))
+	})
+	return _c
+}
+
+func (_c *MilvusServiceServer_ListPrivilegeGroups_Call) Return(_a0 *milvuspb.ListPrivilegeGroupsResponse, _a1 error) *MilvusServiceServer_ListPrivilegeGroups_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *MilvusServiceServer_ListPrivilegeGroups_Call) RunAndReturn(run func(context.Context, *milvuspb.ListPrivilegeGroupsRequest) (*milvuspb.ListPrivilegeGroupsResponse, error)) *MilvusServiceServer_ListPrivilegeGroups_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // ListResourceGroups provides a mock function with given fields: _a0, _a1
 func (_m *MilvusServiceServer) ListResourceGroups(_a0 context.Context, _a1 *milvuspb.ListResourceGroupsRequest) (*milvuspb.ListResourceGroupsResponse, error) {
 	ret := _m.Called(_a0, _a1)
@@ -3822,6 +4042,61 @@ func (_c *MilvusServiceServer_OperatePrivilege_Call) RunAndReturn(run func(conte
 	return _c
 }
 
+// OperatePrivilegeGroup provides a mock function with given fields: _a0, _a1
+func (_m *MilvusServiceServer) OperatePrivilegeGroup(_a0 context.Context, _a1 *milvuspb.OperatePrivilegeGroupRequest) (*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.OperatePrivilegeGroupRequest) (*commonpb.Status, error)); ok {
+		return rf(_a0, _a1)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, *milvuspb.OperatePrivilegeGroupRequest) *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.OperatePrivilegeGroupRequest) error); ok {
+		r1 = rf(_a0, _a1)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// MilvusServiceServer_OperatePrivilegeGroup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OperatePrivilegeGroup'
+type MilvusServiceServer_OperatePrivilegeGroup_Call struct {
+	*mock.Call
+}
+
+// OperatePrivilegeGroup is a helper method to define mock.On call
+//   - _a0 context.Context
+//   - _a1 *milvuspb.OperatePrivilegeGroupRequest
+func (_e *MilvusServiceServer_Expecter) OperatePrivilegeGroup(_a0 interface{}, _a1 interface{}) *MilvusServiceServer_OperatePrivilegeGroup_Call {
+	return &MilvusServiceServer_OperatePrivilegeGroup_Call{Call: _e.mock.On("OperatePrivilegeGroup", _a0, _a1)}
+}
+
+func (_c *MilvusServiceServer_OperatePrivilegeGroup_Call) Run(run func(_a0 context.Context, _a1 *milvuspb.OperatePrivilegeGroupRequest)) *MilvusServiceServer_OperatePrivilegeGroup_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(*milvuspb.OperatePrivilegeGroupRequest))
+	})
+	return _c
+}
+
+func (_c *MilvusServiceServer_OperatePrivilegeGroup_Call) Return(_a0 *commonpb.Status, _a1 error) *MilvusServiceServer_OperatePrivilegeGroup_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *MilvusServiceServer_OperatePrivilegeGroup_Call) RunAndReturn(run func(context.Context, *milvuspb.OperatePrivilegeGroupRequest) (*commonpb.Status, error)) *MilvusServiceServer_OperatePrivilegeGroup_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // OperateUserRole provides a mock function with given fields: _a0, _a1
 func (_m *MilvusServiceServer) OperateUserRole(_a0 context.Context, _a1 *milvuspb.OperateUserRoleRequest) (*commonpb.Status, error) {
 	ret := _m.Called(_a0, _a1)


Test patch:
diff --git a/client/client_mock_test.go b/client/client_mock_test.go
index 91215fc..6472b46 100644
--- a/client/client_mock_test.go
+++ b/client/client_mock_test.go
@@ -256,6 +256,7 @@ const (
 	MAlterCollection         ServiceMethod = 109
 	MGetLoadingProgress      ServiceMethod = 110
 	MGetLoadState            ServiceMethod = 111
+	MAlterCollectionField    ServiceMethod = 112
 
 	MCreatePartition   ServiceMethod = 201
 	MDropPartition     ServiceMethod = 202
@@ -312,6 +313,11 @@ const (
 	MReplicateMessage ServiceMethod = 1100
 	MBackupRBAC       ServiceMethod = 1101
 	MRestoreRBAC      ServiceMethod = 1102
+
+	MCreatePrivilegeGroup  ServiceMethod = 1200
+	MDropPrivilegeGroup    ServiceMethod = 1201
+	MListPrivilegeGroups   ServiceMethod = 1202
+	MOperatePrivilegeGroup ServiceMethod = 1203
 )
 
 // injection function definition
@@ -1079,3 +1085,49 @@ func (m *MockServer) RestoreRBAC(ctx context.Context, req *milvuspb.RestoreRBACM
 	}
 	return SuccessStatus()
 }
+
+func (m *MockServer) AlterCollectionField(ctx context.Context, req *milvuspb.AlterCollectionFieldRequest) (*commonpb.Status, error) {
+	f := m.GetInjection(MAlterCollectionField)
+	if f != nil {
+		r, err := f(ctx, req)
+		return r.(*commonpb.Status), err
+	}
+	return SuccessStatus()
+}
+
+func (m *MockServer) CreatePrivilegeGroup(ctx context.Context, req *milvuspb.CreatePrivilegeGroupRequest) (*commonpb.Status, error) {
+	f := m.GetInjection(MCreatePrivilegeGroup)
+	if f != nil {
+		r, err := f(ctx, req)
+		return r.(*commonpb.Status), err
+	}
+	return SuccessStatus()
+}
+
+func (m *MockServer) DropPrivilegeGroup(ctx context.Context, req *milvuspb.DropPrivilegeGroupRequest) (*commonpb.Status, error) {
+	f := m.GetInjection(MDropPrivilegeGroup)
+	if f != nil {
+		r, err := f(ctx, req)
+		return r.(*commonpb.Status), err
+	}
+	return SuccessStatus()
+}
+
+func (m *MockServer) ListPrivilegeGroups(ctx context.Context, req *milvuspb.ListPrivilegeGroupsRequest) (*milvuspb.ListPrivilegeGroupsResponse, error) {
+	f := m.GetInjection(MListPrivilegeGroups)
+	if f != nil {
+		r, err := f(ctx, req)
+		return r.(*milvuspb.ListPrivilegeGroupsResponse), err
+	}
+	s, err := SuccessStatus()
+	return &milvuspb.ListPrivilegeGroupsResponse{Status: s}, err
+}
+
+func (m *MockServer) OperatePrivilegeGroup(ctx context.Context, req *milvuspb.OperatePrivilegeGroupRequest) (*commonpb.Status, error) {
+	f := m.GetInjection(MOperatePrivilegeGroup)
+	if f != nil {
+		r, err := f(ctx, req)
+		return r.(*commonpb.Status), err
+	}
+	return SuccessStatus()
+}