From b0375b874aaa05ffd8c82682d43cccfd21b17602 Mon Sep 17 00:00:00 2001 From: shaoting-huang Date: Wed, 23 Oct 2024 21:35:57 +0800 Subject: [PATCH] fix proxy impl conflict Signed-off-by: shaoting-huang --- go.mod | 2 + .../distributed/proxy/httpserver/constant.go | 33 ++-- .../proxy/httpserver/handler_v2.go | 81 +++++++++ .../proxy/httpserver/request_v2.go | 7 + internal/distributed/proxy/service.go | 20 +++ internal/distributed/rootcoord/service.go | 20 +++ internal/metastore/catalog.go | 5 + internal/metastore/kv/rootcoord/kv_catalog.go | 81 +++++++++ .../kv/rootcoord/rootcoord_constant.go | 7 + internal/proto/root_coord.proto | 5 + internal/proxy/impl.go | 163 ++++++++++++++++++ internal/proxy/util.go | 8 + internal/rootcoord/meta_table.go | 116 ++++++++++++- internal/rootcoord/root_coord.go | 141 ++++++++++++++- pkg/go.mod | 2 + pkg/metrics/rootcoord_metrics.go | 9 + scripts/generate_proto.sh | 2 +- 17 files changed, 680 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index 33079cb112c20..f94077c5e28b2 100644 --- a/go.mod +++ b/go.mod @@ -274,3 +274,5 @@ replace ( ) exclude github.com/apache/pulsar-client-go/oauth2 v0.0.0-20211108044248-fe3b7c4e445b + +replace github.com/milvus-io/milvus-proto/go-api/v2 => /home/shaoting/workspace/milvus-proto/go-api diff --git a/internal/distributed/proxy/httpserver/constant.go b/internal/distributed/proxy/httpserver/constant.go index b064c69e6ac39..747485b9b4ed7 100644 --- a/internal/distributed/proxy/httpserver/constant.go +++ b/internal/distributed/proxy/httpserver/constant.go @@ -9,14 +9,15 @@ import ( // v2 const ( // --- category --- - CollectionCategory = "/collections/" - EntityCategory = "/entities/" - PartitionCategory = "/partitions/" - UserCategory = "/users/" - RoleCategory = "/roles/" - IndexCategory = "/indexes/" - AliasCategory = "/aliases/" - ImportJobCategory = "/jobs/import/" + CollectionCategory = "/collections/" + EntityCategory = "/entities/" + PartitionCategory = "/partitions/" + UserCategory = "/users/" + RoleCategory = "/roles/" + IndexCategory = "/indexes/" + AliasCategory = "/aliases/" + ImportJobCategory = "/jobs/import/" + PrivilegeGroupCategory = "/privilege_groups/" ListAction = "list" HasAction = "has" @@ -37,13 +38,15 @@ const ( AdvancedSearchAction = "advanced_search" HybridSearchAction = "hybrid_search" - UpdatePasswordAction = "update_password" - GrantRoleAction = "grant_role" - RevokeRoleAction = "revoke_role" - GrantPrivilegeAction = "grant_privilege" - RevokePrivilegeAction = "revoke_privilege" - AlterAction = "alter" - GetProgressAction = "get_progress" // deprecated, keep it for compatibility, use `/v2/vectordb/jobs/import/describe` instead + UpdatePasswordAction = "update_password" + GrantRoleAction = "grant_role" + RevokeRoleAction = "revoke_role" + GrantPrivilegeAction = "grant_privilege" + RevokePrivilegeAction = "revoke_privilege" + AlterAction = "alter" + GetProgressAction = "get_progress" // deprecated, keep it for compatibility, use `/v2/vectordb/jobs/import/describe` instead + AddPrivilegesToGroupAction = "add_privileges_to_group" + DropPrivilegesFromGroupAction = "drop_privileges_from_group" ) const ( diff --git a/internal/distributed/proxy/httpserver/handler_v2.go b/internal/distributed/proxy/httpserver/handler_v2.go index c57ee26c10c26..051e368bb5e63 100644 --- a/internal/distributed/proxy/httpserver/handler_v2.go +++ b/internal/distributed/proxy/httpserver/handler_v2.go @@ -123,6 +123,13 @@ func (h *HandlersV2) RegisterRoutesToV2(router gin.IRouter) { router.POST(RoleCategory+GrantPrivilegeAction, timeoutMiddleware(wrapperPost(func() any { return &GrantReq{} }, wrapperTraceLog(h.addPrivilegeToRole)))) router.POST(RoleCategory+RevokePrivilegeAction, timeoutMiddleware(wrapperPost(func() any { return &GrantReq{} }, wrapperTraceLog(h.removePrivilegeFromRole)))) + // privilege group + router.POST(PrivilegeGroupCategory+CreateAction, timeoutMiddleware(wrapperPost(func() any { return &GrantReq{} }, wrapperTraceLog(h.createPrivilegeGroup)))) + router.POST(PrivilegeGroupCategory+DropAction, timeoutMiddleware(wrapperPost(func() any { return &GrantReq{} }, wrapperTraceLog(h.dropPrivilegeGroup)))) + router.POST(PrivilegeGroupCategory+ListAction, timeoutMiddleware(wrapperPost(func() any { return &GrantReq{} }, wrapperTraceLog(h.listPrivilegeGroups)))) + router.POST(PrivilegeGroupCategory+AddPrivilegesToGroupAction, timeoutMiddleware(wrapperPost(func() any { return &GrantReq{} }, wrapperTraceLog(h.addPrivilegesToGroup)))) + router.POST(PrivilegeGroupCategory+DropPrivilegesFromGroupAction, timeoutMiddleware(wrapperPost(func() any { return &GrantReq{} }, wrapperTraceLog(h.dropPrivilegesFromGroup)))) + router.POST(IndexCategory+ListAction, timeoutMiddleware(wrapperPost(func() any { return &CollectionNameReq{} }, wrapperTraceLog(h.wrapperCheckDatabase(h.listIndexes))))) router.POST(IndexCategory+DescribeAction, timeoutMiddleware(wrapperPost(func() any { return &IndexReq{} }, wrapperTraceLog(h.wrapperCheckDatabase(h.describeIndex))))) @@ -1760,6 +1767,80 @@ func (h *HandlersV2) removePrivilegeFromRole(ctx context.Context, c *gin.Context return h.operatePrivilegeToRole(ctx, c, anyReq.(*GrantReq), milvuspb.OperatePrivilegeType_Revoke, dbName) } +func (h *HandlersV2) createPrivilegeGroup(ctx context.Context, c *gin.Context, anyReq any, dbName string) (interface{}, error) { + httpReq := anyReq.(*PrivilegeGroupReq) + req := &milvuspb.CreatePrivilegeGroupRequest{ + GroupName: &milvuspb.PrivilegeGroupEntity{Name: httpReq.PrivilegeGroupName}, + Privileges: httpReq.Privileges, + } + resp, err := wrapperProxy(ctx, c, req, h.checkAuth, false, "/milvus.proto.milvus.MilvusService/CreatePrivilegeGroup", func(reqCtx context.Context, req any) (interface{}, error) { + return h.proxy.CreatePrivilegeGroup(reqCtx, req.(*milvuspb.CreatePrivilegeGroupRequest)) + }) + if err == nil { + HTTPReturn(c, http.StatusOK, wrapperReturnDefault()) + } + return resp, err +} + +func (h *HandlersV2) dropPrivilegeGroup(ctx context.Context, c *gin.Context, anyReq any, dbName string) (interface{}, error) { + httpReq := anyReq.(*PrivilegeGroupReq) + req := &milvuspb.DropPrivilegeGroupRequest{ + GroupName: &milvuspb.PrivilegeGroupEntity{Name: httpReq.PrivilegeGroupName}, + } + resp, err := wrapperProxy(ctx, c, req, h.checkAuth, false, "/milvus.proto.milvus.MilvusService/DropPrivilegeGroup", func(reqCtx context.Context, req any) (interface{}, error) { + return h.proxy.DropPrivilegeGroup(reqCtx, req.(*milvuspb.DropPrivilegeGroupRequest)) + }) + if err == nil { + HTTPReturn(c, http.StatusOK, wrapperReturnDefault()) + } + return resp, err +} + +func (h *HandlersV2) listPrivilegeGroups(ctx context.Context, c *gin.Context, anyReq any, dbName string) (interface{}, error) { + req := &milvuspb.ListPrivilegeGroupsRequest{} + resp, err := wrapperProxy(ctx, c, req, h.checkAuth, false, "/milvus.proto.milvus.MilvusService/ListPrivilegeGroups", func(reqCtx context.Context, req any) (interface{}, error) { + return h.proxy.ListPrivilegeGroups(reqCtx, req.(*milvuspb.ListPrivilegeGroupsRequest)) + }) + if err == nil { + groupNames := []string{} + for _, group := range resp.(*milvuspb.ListPrivilegeGroupsResponse).Groups { + groupNames = append(groupNames, group.Name) + } + HTTPReturn(c, http.StatusOK, wrapperReturnList(groupNames)) + } + return resp, err +} + +func (h *HandlersV2) addPrivilegesToGroup(ctx context.Context, c *gin.Context, anyReq any, dbName string) (interface{}, error) { + httpReq := anyReq.(*PrivilegeGroupReq) + req := &milvuspb.AddPrivilegesToGroupRequest{ + GroupName: &milvuspb.PrivilegeGroupEntity{Name: httpReq.PrivilegeGroupName}, + Privileges: httpReq.Privileges, + } + resp, err := wrapperProxy(ctx, c, req, h.checkAuth, false, "/milvus.proto.milvus.MilvusService/AddPrivilegesToGroup", func(reqCtx context.Context, req any) (interface{}, error) { + return h.proxy.AddPrivilegesToGroup(reqCtx, req.(*milvuspb.AddPrivilegesToGroupRequest)) + }) + if err == nil { + HTTPReturn(c, http.StatusOK, wrapperReturnDefault()) + } + return resp, err +} + +func (h *HandlersV2) dropPrivilegesFromGroup(ctx context.Context, c *gin.Context, anyReq any, dbName string) (interface{}, error) { + httpReq := anyReq.(*PrivilegeGroupReq) + req := &milvuspb.DropPrivilegesFromGroupRequest{ + GroupName: &milvuspb.PrivilegeGroupEntity{Name: httpReq.PrivilegeGroupName}, + Privileges: httpReq.Privileges, + } + resp, err := wrapperProxy(ctx, c, req, h.checkAuth, false, "/milvus.proto.milvus.MilvusService/DropPrivilegesFromGroups", func(reqCtx context.Context, req any) (interface{}, error) { + return h.proxy.DropPrivilegesFromGroup(reqCtx, req.(*milvuspb.DropPrivilegesFromGroupRequest)) + }) + if err == nil { + HTTPReturn(c, http.StatusOK, wrapperReturnDefault()) + } + return resp, err +} + func (h *HandlersV2) listIndexes(ctx context.Context, c *gin.Context, anyReq any, dbName string) (interface{}, error) { collectionGetter, _ := anyReq.(requestutil.CollectionNameGetter) indexNames := []string{} diff --git a/internal/distributed/proxy/httpserver/request_v2.go b/internal/distributed/proxy/httpserver/request_v2.go index 31bf6f0d585b6..5cfaa50171947 100644 --- a/internal/distributed/proxy/httpserver/request_v2.go +++ b/internal/distributed/proxy/httpserver/request_v2.go @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" "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/merr" ) @@ -273,6 +274,12 @@ func (req *RoleReq) GetRoleName() string { return req.RoleName } +type PrivilegeGroupReq struct { + PrivilegeGroupName string `json:"privilegeGroupName" binding:"required"` + Privileges []*milvuspb.PrivilegeEntity `json:"privileges"` + DbName string `json:"dbName"` +} + type GrantReq struct { RoleName string `json:"roleName" binding:"required"` ObjectType string `json:"objectType" binding:"required"` diff --git a/internal/distributed/proxy/service.go b/internal/distributed/proxy/service.go index c497ae82a3309..590b3d551478d 100644 --- a/internal/distributed/proxy/service.go +++ b/internal/distributed/proxy/service.go @@ -993,6 +993,26 @@ func (s *Server) RestoreRBAC(ctx context.Context, req *milvuspb.RestoreRBACMetaR return s.proxy.RestoreRBAC(ctx, req) } +func (s *Server) CreatePrivilegeGroup(ctx context.Context, req *milvuspb.CreatePrivilegeGroupRequest) (*commonpb.Status, error) { + return s.proxy.CreatePrivilegeGroup(ctx, req) +} + +func (s *Server) DropPrivilegeGroup(ctx context.Context, req *milvuspb.DropPrivilegeGroupRequest) (*commonpb.Status, error) { + return s.proxy.DropPrivilegeGroup(ctx, req) +} + +func (s *Server) ListPrivilegeGroups(ctx context.Context, req *milvuspb.ListPrivilegeGroupsRequest) (*milvuspb.ListPrivilegeGroupsResponse, error) { + return s.proxy.ListPrivilegeGroups(ctx, req) +} + +func (s *Server) addPrivilegesToGroup(ctx context.Context, req *milvuspb.AddPrivilegesToGroupRequest) (*commonpb.Status, error) { + return s.proxy.AddPrivilegesToGroup(ctx, req) +} + +func (s *Server) dropPrivilegesFromGroup(ctx context.Context, req *milvuspb.DropPrivilegesFromGroupRequest) (*commonpb.Status, error) { + return s.proxy.DropPrivilegesFromGroup(ctx, req) +} + func (s *Server) RefreshPolicyInfoCache(ctx context.Context, req *proxypb.RefreshPolicyInfoCacheRequest) (*commonpb.Status, error) { return s.proxy.RefreshPolicyInfoCache(ctx, req) } diff --git a/internal/distributed/rootcoord/service.go b/internal/distributed/rootcoord/service.go index d49c3ae4a89f6..164540d645d7a 100644 --- a/internal/distributed/rootcoord/service.go +++ b/internal/distributed/rootcoord/service.go @@ -550,3 +550,23 @@ func (s *Server) BackupRBAC(ctx context.Context, request *milvuspb.BackupRBACMet func (s *Server) RestoreRBAC(ctx context.Context, request *milvuspb.RestoreRBACMetaRequest) (*commonpb.Status, error) { return s.rootCoord.RestoreRBAC(ctx, request) } + +func (s *Server) CreatePrivilegeGroup(ctx context.Context, request *milvuspb.CreatePrivilegeGroupRequest) (*commonpb.Status, error) { + return s.rootCoord.CreatePrivilegeGroup(ctx, request) +} + +func (s *Server) DropPrivilegeGroup(ctx context.Context, request *milvuspb.DropPrivilegeGroupRequest) (*commonpb.Status, error) { + return s.rootCoord.DropPrivilegeGroup(ctx, request) +} + +func (s *Server) ListPrivilegeGroups(ctx context.Context, request *milvuspb.ListPrivilegeGroupsRequest) (*milvuspb.ListPrivilegeGroupsResponse, error) { + return s.rootCoord.ListPrivilegeGroups(ctx, request) +} + +func (s *Server) addPrivilegesToGroup(ctx context.Context, request *milvuspb.AddPrivilegesToGroupRequest) (*commonpb.Status, error) { + return s.rootCoord.AddPrivilegesToGroup(ctx, request) +} + +func (s *Server) dropPrivilegesFromGroup(ctx context.Context, request *milvuspb.DropPrivilegesFromGroupRequest) (*commonpb.Status, error) { + return s.rootCoord.DropPrivilegesFromGroup(ctx, request) +} diff --git a/internal/metastore/catalog.go b/internal/metastore/catalog.go index a3121eb9fefb0..623842d2fd6a1 100644 --- a/internal/metastore/catalog.go +++ b/internal/metastore/catalog.go @@ -86,6 +86,11 @@ type RootCoordCatalog interface { BackupRBAC(ctx context.Context, tenant string) (*milvuspb.RBACMeta, error) RestoreRBAC(ctx context.Context, tenant string, meta *milvuspb.RBACMeta) error + GetPrivilegeGroup(ctx context.Context, groupName string) ([]*milvuspb.PrivilegeEntity, error) + DropPrivilegeGroup(ctx context.Context, groupName string) error + AlterPrivilegeGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity) error + ListPrivilegeGroups(ctx context.Context) ([]*milvuspb.PrivilegeGroupEntity, error) + Close() } diff --git a/internal/metastore/kv/rootcoord/kv_catalog.go b/internal/metastore/kv/rootcoord/kv_catalog.go index 7af3c30485081..a0c39cc5a452e 100644 --- a/internal/metastore/kv/rootcoord/kv_catalog.go +++ b/internal/metastore/kv/rootcoord/kv_catalog.go @@ -1439,6 +1439,87 @@ func (kc *Catalog) RestoreRBAC(ctx context.Context, tenant string, meta *milvusp return err } +func (kc *Catalog) GetPrivilegeGroup(ctx context.Context, groupName string) ([]*milvuspb.PrivilegeEntity, error) { + k := BuildPrivilegeGroupkey(groupName) + data, err := kc.Txn.Load(k) + if err != nil { + if errors.Is(err, merr.ErrIoKeyNotFound) { + return nil, fmt.Errorf("privilege group [%s] does not exist", groupName) + } + log.Error("failed to load privilege group", zap.String("group", groupName), zap.Error(err)) + return nil, err + } + var privilegeNames []string + err = json.Unmarshal([]byte(data), &privilegeNames) + if err != nil { + log.Error("failed to unmarshal privilege group data", zap.String("group", groupName), zap.Error(err)) + return nil, err + } + + var privileges []*milvuspb.PrivilegeEntity + for _, name := range privilegeNames { + privileges = append(privileges, &milvuspb.PrivilegeEntity{Name: name}) + } + return privileges, nil +} + +func (kc *Catalog) DropPrivilegeGroup(ctx context.Context, groupName string) error { + k := BuildPrivilegeGroupkey(groupName) + err := kc.Txn.Remove(k) + if err != nil { + log.Warn("fail to drop privilege group", zap.String("key", k), zap.Error(err)) + return err + } + return nil +} + +func (kc *Catalog) AlterPrivilegeGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity) error { + var privilegeNames []string + for _, privilege := range privileges { + privilegeNames = append(privilegeNames, privilege.Name) + } + + privilegeData, err := json.Marshal(privilegeNames) + if err != nil { + log.Error("failed to marshal privileges", zap.String("group", groupName), zap.Error(err)) + return err + } + k := BuildPrivilegeGroupkey(groupName) + hasKey, err := kc.Txn.Has(k) + if hasKey { + err = kc.Txn.Remove(k) + } + err = kc.Txn.Save(k, string(privilegeData)) + if err != nil { + log.Warn("fail to put privilege group", zap.String("key", k), zap.Error(err)) + return err + } + return nil +} + +func (kc *Catalog) ListPrivilegeGroups(ctx context.Context) ([]*milvuspb.PrivilegeGroupEntity, error) { + var privilegeGroups []*milvuspb.PrivilegeGroupEntity + + keys, _, err := kc.Txn.LoadWithPrefix(PrivilegeGroupPrefix) + if err != nil { + log.Error("failed to list privilege groups", zap.String("prefix", PrivilegeGroupPrefix), zap.Error(err)) + return nil, err + } + + for _, key := range keys { + groupName := typeutil.AfterN(key, PrivilegeGroupPrefix+"/", "/") + if len(groupName) != 1 { + log.Warn("invalid privilege group key", zap.String("string", key), zap.String("sub_string", PrivilegeGroupPrefix)) + continue + } + + privilegeGroups = append(privilegeGroups, &milvuspb.PrivilegeGroupEntity{ + Name: groupName[0], + }) + } + return privilegeGroups, nil +} + func (kc *Catalog) Close() { // do nothing } diff --git a/internal/metastore/kv/rootcoord/rootcoord_constant.go b/internal/metastore/kv/rootcoord/rootcoord_constant.go index c48e6f619529d..7ea71f4fe4006 100644 --- a/internal/metastore/kv/rootcoord/rootcoord_constant.go +++ b/internal/metastore/kv/rootcoord/rootcoord_constant.go @@ -50,6 +50,9 @@ const ( // GranteeIDPrefix prefix for mapping among privilege and grantor GranteeIDPrefix = ComponentPrefix + CommonCredentialPrefix + "/grantee-id" + + // PrivilegeGroupPrefix prefix for privilege group + PrivilegeGroupPrefix = ComponentPrefix + "/privilege-group" ) func BuildDatabasePrefixWithDBID(dbID int64) string { @@ -70,3 +73,7 @@ func getDatabasePrefix(dbID int64) string { } return CollectionMetaPrefix } + +func BuildPrivilegeGroupkey(groupName string) string { + return fmt.Sprintf("%s/%s", PrivilegeGroupPrefix, groupName) +} diff --git a/internal/proto/root_coord.proto b/internal/proto/root_coord.proto index fbdb1d0a5e7dc..dec854e6c54ab 100644 --- a/internal/proto/root_coord.proto +++ b/internal/proto/root_coord.proto @@ -126,6 +126,11 @@ service RootCoord { rpc ListPolicy(internal.ListPolicyRequest) returns (internal.ListPolicyResponse) {} rpc BackupRBAC(milvus.BackupRBACMetaRequest) returns (milvus.BackupRBACMetaResponse){} rpc RestoreRBAC(milvus.RestoreRBACMetaRequest) returns (common.Status){} + rpc CreatePrivilegeGroup(milvus.CreatePrivilegeGroupRequest) returns (common.Status) {} + rpc DropPrivilegeGroup(milvus.DropPrivilegeGroupRequest) returns (common.Status) {} + rpc ListPrivilegeGroups(milvus.ListPrivilegeGroupsRequest) returns (milvus.ListPrivilegeGroupsResponse) {} + rpc AddPrivilegesToGroup(milvus.AddPrivilegesToGroupRequest) returns (common.Status) {} + rpc DropPrivilegesFromGroup(milvus.DropPrivilegesFromGroupRequest) returns (common.Status) {} rpc CheckHealth(milvus.CheckHealthRequest) returns (milvus.CheckHealthResponse) {} diff --git a/internal/proxy/impl.go b/internal/proxy/impl.go index ed7ab17641a81..a0cc63232c5b2 100644 --- a/internal/proxy/impl.go +++ b/internal/proxy/impl.go @@ -6488,3 +6488,166 @@ func (node *Proxy) RegisterRestRouter(router gin.IRouter) { router.GET(http.QcoordChannelsPath, getQueryComponentMetrics(node, metricsinfo.QueryChannelDist)) router.GET(http.QcoordTasksPath, getQueryComponentMetrics(node, metricsinfo.QueryTasks)) } + +func (node *Proxy) CreatePrivilegeGroup(ctx context.Context, req *milvuspb.CreatePrivilegeGroupRequest) (*commonpb.Status, error) { + ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-CreatePrivilegeGroup") + defer sp.End() + + log := log.Ctx(ctx) + + log.Info("CreatePrivilegeGroup", zap.Any("req", req)) + if err := merr.CheckHealthy(node.GetStateCode()); err != nil { + return merr.Status(err), nil + } + if err := ValidatePrivilegeGroupName(req.GroupName.Name); err != nil { + return merr.Status(err), nil + } + for _, priv := range req.GetPrivileges() { + if err := ValidatePrivilegeGroup(priv.Name); err != nil { + return merr.Status(err), nil + } + } + if req.Base == nil { + req.Base = &commonpb.MsgBase{} + } + req.Base.MsgType = commonpb.MsgType_CreatePrivilegeGroup + + result, err := node.rootCoord.CreatePrivilegeGroup(ctx, req) + if err != nil { + log.Warn("fail to create privilege group", zap.Error(err)) + return merr.Status(err), nil + } + if merr.Ok(result) { + SendReplicateMessagePack(ctx, node.replicateMsgStream, req) + } + return result, nil +} + +func (node *Proxy) DropPrivilegeGroup(ctx context.Context, req *milvuspb.DropPrivilegeGroupRequest) (*commonpb.Status, error) { + ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-DropPrivilegeGroup") + defer sp.End() + + log := log.Ctx(ctx) + + log.Info("DropPrivilegeGroup", zap.Any("req", req)) + if err := merr.CheckHealthy(node.GetStateCode()); err != nil { + return merr.Status(err), nil + } + if err := ValidatePrivilegeGroupName(req.GroupName.Name); err != nil { + return merr.Status(err), nil + } + if req.Base == nil { + req.Base = &commonpb.MsgBase{} + } + req.Base.MsgType = commonpb.MsgType_DropPrivilegeGroup + + result, err := node.rootCoord.DropPrivilegeGroup(ctx, req) + if err != nil { + log.Warn("fail to drop privilege group", zap.Error(err)) + return merr.Status(err), nil + } + if merr.Ok(result) { + SendReplicateMessagePack(ctx, node.replicateMsgStream, req) + } + return result, nil +} + +func (node *Proxy) ListPrivilegeGroups(ctx context.Context, req *milvuspb.ListPrivilegeGroupsRequest) (*milvuspb.ListPrivilegeGroupsResponse, error) { + ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-ListPrivilegeGroups") + defer sp.End() + + log := log.Ctx(ctx).With( + zap.String("role", typeutil.ProxyRole)) + + log.Debug("ListPrivilegeGroups") + if err := merr.CheckHealthy(node.GetStateCode()); err != nil { + return &milvuspb.ListPrivilegeGroupsResponse{Status: merr.Status(err)}, nil + } + if req.Base == nil { + req.Base = &commonpb.MsgBase{} + } + req.Base.MsgType = commonpb.MsgType_ListCredUsernames + rootCoordReq := &milvuspb.ListPrivilegeGroupsRequest{ + Base: commonpbutil.NewMsgBase( + commonpbutil.WithMsgType(commonpb.MsgType_ListCredUsernames), + ), + } + resp, err := node.rootCoord.ListPrivilegeGroups(ctx, rootCoordReq) + if err != nil { + return &milvuspb.ListPrivilegeGroupsResponse{ + Status: merr.Status(err), + }, nil + } + return &milvuspb.ListPrivilegeGroupsResponse{ + Status: merr.Success(), + Groups: resp.Groups, + }, nil +} + +func (node *Proxy) AddPrivilegesToGroup(ctx context.Context, req *milvuspb.AddPrivilegesToGroupRequest) (*commonpb.Status, error) { + ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-AddPrivilegesToGroup") + defer sp.End() + + log := log.Ctx(ctx) + + log.Info("AddPrivilegesToGroup", zap.Any("req", req)) + if err := merr.CheckHealthy(node.GetStateCode()); err != nil { + return merr.Status(err), nil + } + if err := ValidatePrivilegeGroupName(req.GroupName.Name); err != nil { + return merr.Status(err), nil + } + for _, priv := range req.GetPrivileges() { + if err := ValidatePrivilegeGroup(priv.Name); err != nil { + return merr.Status(err), nil + } + } + if req.Base == nil { + req.Base = &commonpb.MsgBase{} + } + req.Base.MsgType = commonpb.MsgType_AddPrivilegesToGroup + + result, err := node.rootCoord.AddPrivilegesToGroup(ctx, req) + if err != nil { + log.Warn("fail to add privileges to privilege group", zap.Error(err)) + return merr.Status(err), nil + } + if merr.Ok(result) { + SendReplicateMessagePack(ctx, node.replicateMsgStream, req) + } + return result, nil +} + +func (node *Proxy) DropPrivilegesFromGroup(ctx context.Context, req *milvuspb.DropPrivilegesFromGroupRequest) (*commonpb.Status, error) { + ctx, sp := otel.Tracer(typeutil.ProxyRole).Start(ctx, "Proxy-DropPrivilegesFromGroup") + defer sp.End() + + log := log.Ctx(ctx) + + log.Info("DropPrivilegesFromGroup", zap.Any("req", req)) + if err := merr.CheckHealthy(node.GetStateCode()); err != nil { + return merr.Status(err), nil + } + if err := ValidatePrivilegeGroupName(req.GroupName.Name); err != nil { + return merr.Status(err), nil + } + for _, priv := range req.GetPrivileges() { + if err := ValidatePrivilegeGroup(priv.Name); err != nil { + return merr.Status(err), nil + } + } + if req.Base == nil { + req.Base = &commonpb.MsgBase{} + } + req.Base.MsgType = commonpb.MsgType_AddPrivilegesToGroup + + result, err := node.rootCoord.DropPrivilegesFromGroup(ctx, req) + if err != nil { + log.Warn("fail to drop privileges from privilege group", zap.Error(err)) + return merr.Status(err), nil + } + if merr.Ok(result) { + SendReplicateMessagePack(ctx, node.replicateMsgStream, req) + } + return result, nil +} diff --git a/internal/proxy/util.go b/internal/proxy/util.go index 1d2ccb6f049db..cffab50571add 100644 --- a/internal/proxy/util.go +++ b/internal/proxy/util.go @@ -1070,6 +1070,14 @@ func ValidatePrivilege(entity string) error { return validateName(entity, "Privilege") } +func ValidatePrivilegeGroupName(entity string) error { + return validateName(entity, "PrivilegeGroupName") +} + +func ValidatePrivilegeGroup(entity string) error { + return validateName(entity, "PrivilegeGroup") +} + func GetCurUserFromContext(ctx context.Context) (string, error) { return contextutil.GetCurUserFromContext(ctx) } diff --git a/internal/rootcoord/meta_table.go b/internal/rootcoord/meta_table.go index 54ba01c55492d..15d060aa91df7 100644 --- a/internal/rootcoord/meta_table.go +++ b/internal/rootcoord/meta_table.go @@ -92,13 +92,18 @@ type IMetaTable interface { OperateUserRole(tenant string, userEntity *milvuspb.UserEntity, roleEntity *milvuspb.RoleEntity, operateType milvuspb.OperateUserRoleType) error SelectRole(tenant string, entity *milvuspb.RoleEntity, includeUserInfo bool) ([]*milvuspb.RoleResult, error) SelectUser(tenant string, entity *milvuspb.UserEntity, includeRoleInfo bool) ([]*milvuspb.UserResult, error) - OperatePrivilege(tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error + OperatePrivilege(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error SelectGrant(tenant string, entity *milvuspb.GrantEntity) ([]*milvuspb.GrantEntity, error) 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 + CreatePrivilegeGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity) error + DropPrivilegeGroup(ctx context.Context, groupName string) error + ListPrivilegeGroups(ctx context.Context) ([]*milvuspb.PrivilegeGroupEntity, error) + AddPrivilegesToGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity) error + DropPrivilegesFromGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity) error } // MetaTable is a persistent meta set of all databases, collections and partitions. @@ -1365,7 +1370,7 @@ func (mt *MetaTable) SelectUser(tenant string, entity *milvuspb.UserEntity, incl } // OperatePrivilege grant or revoke privilege by setting the operateType param -func (mt *MetaTable) OperatePrivilege(tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error { +func (mt *MetaTable) OperatePrivilege(ctx context.Context, tenant string, entity *milvuspb.GrantEntity, operateType milvuspb.OperatePrivilegeType) error { if funcutil.IsEmptyString(entity.ObjectName) { return fmt.Errorf("the object name in the grant entity is empty") } @@ -1381,6 +1386,10 @@ func (mt *MetaTable) OperatePrivilege(tenant string, entity *milvuspb.GrantEntit if entity.Grantor.Privilege == nil || funcutil.IsEmptyString(entity.Grantor.Privilege.Name) { return fmt.Errorf("the privilege name in the grant entity is empty") } + conflict, err := mt.CheckWithPrivilegeGroupNames(ctx, entity.Grantor.Privilege.Name) + if err != nil || conflict { + return fmt.Errorf("the privilege name in the grant entity is conflict with any of the privilege group names") + } if entity.Grantor.User == nil || funcutil.IsEmptyString(entity.Grantor.User.Name) { return fmt.Errorf("the grantor name in the grant entity is empty") } @@ -1397,6 +1406,23 @@ func (mt *MetaTable) OperatePrivilege(tenant string, entity *milvuspb.GrantEntit return mt.catalog.AlterGrant(mt.ctx, tenant, entity, operateType) } +// IsPrivilegeInAnyGroup checks if the given privilege name is conflict with any of the privilege group names. +func (mt *MetaTable) CheckWithPrivilegeGroupNames(ctx context.Context, privilegeName string) (bool, error) { + privilegeGroups, err := mt.catalog.ListPrivilegeGroups(ctx) + if err != nil { + log.Warn("fail to list privilege groups", zap.Error(err)) + return false, err + } + + privilegeGroupNames := make(map[string]struct{}) + for _, group := range privilegeGroups { + privilegeGroupNames[group.Name] = struct{}{} + } + + _, exists := privilegeGroupNames[privilegeName] + return exists, nil +} + // SelectGrant select grant // The principal entity MUST be not empty in the grant entity // The resource entity and the resource name are optional, and the two params should be not empty together when you select some grants about the resource kind. @@ -1456,3 +1482,89 @@ func (mt *MetaTable) RestoreRBAC(ctx context.Context, tenant string, meta *milvu return mt.catalog.RestoreRBAC(mt.ctx, tenant, meta) } + +func (mt *MetaTable) CreatePrivilegeGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity) error { + if funcutil.IsEmptyString(groupName) { + return fmt.Errorf("the privilege group name is empty") + } + mt.permissionLock.Lock() + defer mt.permissionLock.Unlock() + + results, err := mt.catalog.ListPrivilegeGroups(mt.ctx) + if err != nil { + log.Warn("fail to list privilege groups", zap.Error(err)) + return err + } + for _, result := range results { + if result.GetName() == groupName { + log.Info("privilege group already exists", zap.String("privilege_group", groupName)) + return common.NewIgnorableError(errors.Newf("privilege group [%s] already exists", groupName)) + } + } + + return mt.catalog.AlterPrivilegeGroup(mt.ctx, groupName, privileges) +} + +func (mt *MetaTable) DropPrivilegeGroup(ctx context.Context, groupName string) error { + mt.permissionLock.Lock() + defer mt.permissionLock.Unlock() + + return mt.catalog.DropPrivilegeGroup(mt.ctx, groupName) +} + +func (mt *MetaTable) ListPrivilegeGroups(ctx context.Context) ([]*milvuspb.PrivilegeGroupEntity, error) { + mt.permissionLock.Lock() + defer mt.permissionLock.Unlock() + + return mt.catalog.ListPrivilegeGroups(mt.ctx) +} + +func (mt *MetaTable) AddPrivilegesToGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity) error { + mt.permissionLock.Lock() + defer mt.permissionLock.Unlock() + + toMergePrivileges, err := mt.catalog.GetPrivilegeGroup(mt.ctx, groupName) + if err != nil { + log.Warn("fail to get privilege group", zap.String("privilege_group", groupName), zap.Error(err)) + return err + } + privilegeSet := make(map[string]struct{}) + for _, p := range toMergePrivileges { + privilegeSet[p.Name] = struct{}{} + } + for _, p := range privileges { + privilegeSet[p.Name] = struct{}{} + } + var mergedPrivileges []*milvuspb.PrivilegeEntity + for privilegeName := range privilegeSet { + mergedPrivileges = append(mergedPrivileges, &milvuspb.PrivilegeEntity{Name: privilegeName}) + } + + return mt.catalog.AlterPrivilegeGroup(mt.ctx, groupName, mergedPrivileges) +} + +func (mt *MetaTable) DropPrivilegesFromGroup(ctx context.Context, groupName string, privileges []*milvuspb.PrivilegeEntity) error { + mt.permissionLock.Lock() + defer mt.permissionLock.Unlock() + + toUpdatePrivileges, err := mt.catalog.GetPrivilegeGroup(mt.ctx, groupName) + if err != nil { + log.Warn("fail to get privilege group", zap.String("privilege_group", groupName), zap.Error(err)) + return err + } + + privilegesToRemove := make(map[string]struct{}) + for _, p := range privileges { + privilegesToRemove[p.Name] = struct{}{} + } + + var updatedPrivileges []*milvuspb.PrivilegeEntity + for _, p := range toUpdatePrivileges { + // If the privilege is not in the removal set, keep it + if _, exists := privilegesToRemove[p.Name]; !exists { + updatedPrivileges = append(updatedPrivileges, p) + } + } + + return mt.catalog.AlterPrivilegeGroup(mt.ctx, groupName, updatedPrivileges) +} diff --git a/internal/rootcoord/root_coord.go b/internal/rootcoord/root_coord.go index 81998fadcb98a..80b2624687ba0 100644 --- a/internal/rootcoord/root_coord.go +++ b/internal/rootcoord/root_coord.go @@ -571,7 +571,7 @@ func (c *Core) initPublicRolePrivilege() error { var err error for _, globalPrivilege := range globalPrivileges { - err = c.meta.OperatePrivilege(util.DefaultTenant, &milvuspb.GrantEntity{ + err = c.meta.OperatePrivilege(c.ctx, util.DefaultTenant, &milvuspb.GrantEntity{ Role: &milvuspb.RoleEntity{Name: util.RolePublic}, Object: &milvuspb.ObjectEntity{Name: commonpb.ObjectType_Global.String()}, ObjectName: util.AnyWord, @@ -586,7 +586,7 @@ func (c *Core) initPublicRolePrivilege() error { } } for _, collectionPrivilege := range collectionPrivileges { - err = c.meta.OperatePrivilege(util.DefaultTenant, &milvuspb.GrantEntity{ + err = c.meta.OperatePrivilege(c.ctx, util.DefaultTenant, &milvuspb.GrantEntity{ Role: &milvuspb.RoleEntity{Name: util.RolePublic}, Object: &milvuspb.ObjectEntity{Name: commonpb.ObjectType_Collection.String()}, ObjectName: util.AnyWord, @@ -616,7 +616,7 @@ func (c *Core) initBuiltinRoles() error { if !util.IsAnyWord(privilege[util.RoleConfigPrivilege]) { privilegeName = util.PrivilegeNameForMetastore(privilege[util.RoleConfigPrivilege]) } - err := c.meta.OperatePrivilege(util.DefaultTenant, &milvuspb.GrantEntity{ + err := c.meta.OperatePrivilege(c.ctx, util.DefaultTenant, &milvuspb.GrantEntity{ Role: &milvuspb.RoleEntity{Name: role}, Object: &milvuspb.ObjectEntity{Name: privilege[util.RoleConfigObjectType]}, ObjectName: privilege[util.RoleConfigObjectName], @@ -2581,7 +2581,7 @@ func (c *Core) OperatePrivilege(ctx context.Context, in *milvuspb.OperatePrivile redoTask := newBaseRedoTask(c.stepExecutor) redoTask.AddSyncStep(NewSimpleStep("operate privilege meta data", func(ctx context.Context) ([]nestedStep, error) { - err := c.meta.OperatePrivilege(util.DefaultTenant, in.Entity, in.Type) + err := c.meta.OperatePrivilege(c.ctx, util.DefaultTenant, in.Entity, in.Type) if err != nil && !common.IsIgnorableError(err) { log.Warn("fail to operate the privilege", zap.Any("in", in), zap.Error(err)) return nil, err @@ -2922,3 +2922,136 @@ func (c *Core) CheckHealth(ctx context.Context, in *milvuspb.CheckHealthRequest) return &milvuspb.CheckHealthResponse{Status: merr.Success(), IsHealthy: true, Reasons: []string{}}, nil } + +func (c *Core) CreatePrivilegeGroup(ctx context.Context, in *milvuspb.CreatePrivilegeGroupRequest) (*commonpb.Status, error) { + method := "CreatePrivilegeGroup" + 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 + " begin") + + if err := merr.CheckHealthy(c.GetStateCode()); err != nil { + return merr.Status(err), nil + } + + err := c.meta.CreatePrivilegeGroup(ctx, in.GroupName.Name, in.Privileges) + if err != nil { + errMsg := "fail to create privilege group" + ctxLog.Warn(errMsg, zap.Error(err)) + return merr.StatusWithErrorCode(err, commonpb.ErrorCode_CreatePrivilegeGroupFailure), nil + } + + ctxLog.Debug(method + " success") + metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc() + metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds())) + metrics.RootCoordNumOfPrivilegeGroups.Inc() + + return merr.Success(), nil +} + +func (c *Core) DropPrivilegeGroup(ctx context.Context, in *milvuspb.DropPrivilegeGroupRequest) (*commonpb.Status, error) { + method := "DropPrivilegeGroup" + 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 + " begin") + + if err := merr.CheckHealthy(c.GetStateCode()); err != nil { + return merr.Status(err), nil + } + + err := c.meta.DropPrivilegeGroup(ctx, in.GroupName.Name) + if err != nil { + errMsg := "fail to drop privilege group" + ctxLog.Warn(errMsg, zap.Error(err)) + return merr.StatusWithErrorCode(err, commonpb.ErrorCode_CreatePrivilegeGroupFailure), nil + } + + ctxLog.Debug(method + " success") + metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc() + metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds())) + metrics.RootCoordNumOfPrivilegeGroups.Desc() + + return merr.Success(), nil +} + +func (c *Core) ListPrivilegeGroup(ctx context.Context, in *milvuspb.ListPrivilegeGroupsRequest) (*milvuspb.ListPrivilegeGroupsResponse, error) { + method := "ListPrivilegeGroup" + 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 + " begin") + + if err := merr.CheckHealthy(c.GetStateCode()); err != nil { + return &milvuspb.ListPrivilegeGroupsResponse{ + Status: merr.Status(err), + }, nil + } + + groups, err := c.meta.ListPrivilegeGroups(ctx) + if err != nil { + errMsg := "fail to list privilege group" + ctxLog.Warn(errMsg, zap.Error(err)) + return &milvuspb.ListPrivilegeGroupsResponse{ + Status: merr.StatusWithErrorCode(err, commonpb.ErrorCode_ListPrivilegeGroupsFailure), + }, nil + } + + ctxLog.Debug(method + " success") + metrics.RootCoordDDLReqCounter.WithLabelValues(method, metrics.SuccessLabel).Inc() + metrics.RootCoordDDLReqLatency.WithLabelValues(method).Observe(float64(tr.ElapseSpan().Milliseconds())) + + return &milvuspb.ListPrivilegeGroupsResponse{ + Status: merr.Success(), + Groups: groups, + }, nil +} + +func (c *Core) AddPrivilegesToGroup(ctx context.Context, in *milvuspb.AddPrivilegesToGroupRequest) (*commonpb.Status, error) { + method := "AddPrivilegesToGroup" + 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 + " begin") + + if err := merr.CheckHealthy(c.GetStateCode()); err != nil { + return merr.Status(err), nil + } + + err := c.meta.AddPrivilegesToGroup(ctx, in.GroupName.Name, in.Privileges) + if err != nil { + errMsg := "fail to add privileges to group" + ctxLog.Warn(errMsg, zap.Error(err)) + return merr.StatusWithErrorCode(err, commonpb.ErrorCode_AddPrivilegesToGroupFailure), 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) DropPrivilegesFromGroup(ctx context.Context, in *milvuspb.DropPrivilegesFromGroupRequest) (*commonpb.Status, error) { + method := "DropPrivilegesFromGroup" + 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 + " begin") + if err := merr.CheckHealthy(c.GetStateCode()); err != nil { + return merr.Status(err), nil + } + + err := c.meta.DropPrivilegesFromGroup(ctx, in.GroupName.Name, in.Privileges) + if err != nil { + errMsg := "fail to drop privileges from group" + ctxLog.Warn(errMsg, zap.Error(err)) + return merr.StatusWithErrorCode(err, commonpb.ErrorCode_DropPrivilegesFromGroupFailure), 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 +} diff --git a/pkg/go.mod b/pkg/go.mod index de8f2ab91014c..b688562fbcdaf 100644 --- a/pkg/go.mod +++ b/pkg/go.mod @@ -197,3 +197,5 @@ replace ( ) exclude github.com/apache/pulsar-client-go/oauth2 v0.0.0-20211108044248-fe3b7c4e445b + +replace github.com/milvus-io/milvus-proto/go-api/v2 => /home/shaoting/workspace/milvus-proto/go-api diff --git a/pkg/metrics/rootcoord_metrics.go b/pkg/metrics/rootcoord_metrics.go index 86ad947aaf3f5..9ec5118da19b7 100644 --- a/pkg/metrics/rootcoord_metrics.go +++ b/pkg/metrics/rootcoord_metrics.go @@ -146,6 +146,15 @@ var ( Help: "The number of roles", }) + // RootCoordNumOfPrivilegeGroups counts the number of credentials. + RootCoordNumOfPrivilegeGroups = prometheus.NewGauge( + prometheus.GaugeOpts{ + Namespace: milvusNamespace, + Subsystem: typeutil.RootCoordRole, + Name: "num_of_privilege_groups", + Help: "The number of privilege groups", + }) + // RootCoordTtDelay records the max time tick delay of flow graphs in DataNodes and QueryNodes. RootCoordTtDelay = prometheus.NewGaugeVec( prometheus.GaugeOpts{ diff --git a/scripts/generate_proto.sh b/scripts/generate_proto.sh index 1b087e8360a10..5eb6214c32e24 100755 --- a/scripts/generate_proto.sh +++ b/scripts/generate_proto.sh @@ -25,7 +25,7 @@ done ROOT_DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )" PROTO_DIR=$ROOT_DIR/internal/proto/ -API_PROTO_DIR=$ROOT_DIR/cmake_build/thirdparty/milvus-proto/proto +API_PROTO_DIR=/home/shaoting/workspace/milvus-proto/proto CPP_SRC_DIR=$ROOT_DIR/internal/core PROTOC_BIN=$ROOT_DIR/cmake_build/bin/protoc