From 309dda93d2727e4ccb59901431f25fd038af488d Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Sun, 25 Sep 2022 16:35:01 +0800 Subject: [PATCH 01/21] docs:add error code desc --- release/conf/i18n/en.toml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/release/conf/i18n/en.toml b/release/conf/i18n/en.toml index 5236d4dcc..b0fa36774 100644 --- a/release/conf/i18n/en.toml +++ b/release/conf/i18n/en.toml @@ -156,11 +156,19 @@ 401002 = "auth token empty" #EmptyAutToken 401003 = "token already disabled" #TokenDisabled 401004 = "token not existed" #TokenNotExisted +<<<<<<< HEAD 403001 = "token verify exception" #AuthTokenVerifyException 403002 = "operation role exception" #OperationRoleException 404001 = "not found the host cmdb" #CMDBNotFindHost 409000 = "data is conflict, please try again" #DataConflict 429001 = "instance has too many requests" #InstanceTooManyRequests +======= +403001 = "server limit the ip access" #IPRateLimit +403002 = "server limit the api access" #APIRateLimit +404001 = "not found the host cmdb" #CMDBNotFindHost +409000 = "data is conflict, please try again" #DataConflict +429001 = "your instance has too many requests" #InstanceTooManyRequests +>>>>>>> c07080f0... docs:add error code desc 500000 = "execute exception" #ExecuteException 500001 = "store layer exception" #StoreLayerException 500002 = "cmdb plugin exception" #CMDBPluginException @@ -169,3 +177,8 @@ 500006 = "parse circuit breaker failed" #ParseCircuitBreakerException 500007 = "heartbeat execute exception" #HeartbeatException 500008 = "instance async regist timeout" #InstanceRegisTimeout +<<<<<<< HEAD +======= +500100 = "token verify exception" #AuthTokenVerifyException +500101 = "operation role exception" #OperationRoleException +>>>>>>> c07080f0... docs:add error code desc From 3145271d099d3c90ec74f9e1db2b4230f619e848 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 19 Oct 2022 16:00:33 +0800 Subject: [PATCH 02/21] =?UTF-8?q?fix:=E8=B0=83=E6=95=B4license-checker?= =?UTF-8?q?=E7=9A=84=E8=A7=A6=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/golangci-lint.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 394cb4df3..4fa69ac1e 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -15,10 +15,6 @@ name: golangci-lint on: - push: - branches: - - main - - release* pull_request: branches: - main From fa3b1cfc8a2519979db1eeaaf8c1c90f2abca21a Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 19 Oct 2022 17:08:41 +0800 Subject: [PATCH 03/21] =?UTF-8?q?fix:=E8=B0=83=E6=95=B4license-checker?= =?UTF-8?q?=E7=9A=84=E8=A7=A6=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/golangci-lint.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 4fa69ac1e..394cb4df3 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -15,6 +15,10 @@ name: golangci-lint on: + push: + branches: + - main + - release* pull_request: branches: - main From f700ebe41035fadbb361723ecbcafa7e5c3c5776 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Tue, 27 Jun 2023 11:58:15 +0800 Subject: [PATCH 04/21] =?UTF-8?q?hotfix:=E4=BF=AE=E5=A4=8D=E9=89=B4?= =?UTF-8?q?=E6=9D=83interceptor=E9=81=97=E6=BC=8F=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E6=9D=A5=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- release/conf/i18n/en.toml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/release/conf/i18n/en.toml b/release/conf/i18n/en.toml index b0fa36774..5236d4dcc 100644 --- a/release/conf/i18n/en.toml +++ b/release/conf/i18n/en.toml @@ -156,19 +156,11 @@ 401002 = "auth token empty" #EmptyAutToken 401003 = "token already disabled" #TokenDisabled 401004 = "token not existed" #TokenNotExisted -<<<<<<< HEAD 403001 = "token verify exception" #AuthTokenVerifyException 403002 = "operation role exception" #OperationRoleException 404001 = "not found the host cmdb" #CMDBNotFindHost 409000 = "data is conflict, please try again" #DataConflict 429001 = "instance has too many requests" #InstanceTooManyRequests -======= -403001 = "server limit the ip access" #IPRateLimit -403002 = "server limit the api access" #APIRateLimit -404001 = "not found the host cmdb" #CMDBNotFindHost -409000 = "data is conflict, please try again" #DataConflict -429001 = "your instance has too many requests" #InstanceTooManyRequests ->>>>>>> c07080f0... docs:add error code desc 500000 = "execute exception" #ExecuteException 500001 = "store layer exception" #StoreLayerException 500002 = "cmdb plugin exception" #CMDBPluginException @@ -177,8 +169,3 @@ 500006 = "parse circuit breaker failed" #ParseCircuitBreakerException 500007 = "heartbeat execute exception" #HeartbeatException 500008 = "instance async regist timeout" #InstanceRegisTimeout -<<<<<<< HEAD -======= -500100 = "token verify exception" #AuthTokenVerifyException -500101 = "operation role exception" #OperationRoleException ->>>>>>> c07080f0... docs:add error code desc From 49a157aabd89980b7d6117d7b53b097ff8691b65 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Tue, 15 Oct 2024 12:48:39 +0800 Subject: [PATCH 05/21] =?UTF-8?q?refactor:=E9=89=B4=E6=9D=83=E8=83=BD?= =?UTF-8?q?=E5=8A=9B=E4=BC=98=E5=8C=96=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auth/api.go | 4 +- auth/policy/helper.go | 44 ++++++---- auth/user/group.go | 7 +- auth/user/user.go | 2 +- cache/api/types.go | 2 + cache/mock/cache_mock.go | 20 ++++- cache/service/instance.go | 13 +++ cache/service/service.go | 2 + cache/service/service_bucket.go | 13 +-- release/conf/bolt-data.yaml | 4 +- release/conf/polaris-server.yaml | 2 +- store/auth_api.go | 2 - store/boltdb/group.go | 141 +---------------------------- store/boltdb/group_test.go | 92 ------------------- store/mysql/group.go | 146 ------------------------------- 15 files changed, 81 insertions(+), 413 deletions(-) diff --git a/auth/api.go b/auth/api.go index ebc0227f3..295dae39a 100644 --- a/auth/api.go +++ b/auth/api.go @@ -168,8 +168,8 @@ type UserHelper interface { type PolicyHelper interface { // GetPolicyRule . GetPolicyRule(id string) *authcommon.StrategyDetail - // CreatePrincipal 创建 principal 的默认 policy 资源 - CreatePrincipal(ctx context.Context, tx store.Tx, p authcommon.Principal) error + // CreatePrincipalPolicy 创建 principal 的默认 policy 资源 + CreatePrincipalPolicy(ctx context.Context, tx store.Tx, p authcommon.Principal) error // CleanPrincipal 清理 principal 所关联的 policy、role 资源 CleanPrincipal(ctx context.Context, tx store.Tx, p authcommon.Principal) error // GetRole . diff --git a/auth/policy/helper.go b/auth/policy/helper.go index 41eb1676d..0c6ce415c 100644 --- a/auth/policy/helper.go +++ b/auth/policy/helper.go @@ -45,7 +45,7 @@ func (h *DefaultPolicyHelper) GetPolicyRule(id string) *authcommon.StrategyDetai } // CreatePrincipal 创建 principal 的默认 policy 资源 -func (h *DefaultPolicyHelper) CreatePrincipal(ctx context.Context, tx store.Tx, p authcommon.Principal) error { +func (h *DefaultPolicyHelper) CreatePrincipalPolicy(ctx context.Context, tx store.Tx, p authcommon.Principal) error { if err := h.storage.AddStrategy(tx, defaultPrincipalPolicy(p)); err != nil { return err } @@ -57,25 +57,22 @@ func defaultPrincipalPolicy(p authcommon.Principal) *authcommon.StrategyDetail { ruleId := utils.NewUUID() resources := []authcommon.StrategyResource{} + calleeMethods := []string{ + // 用户操作权限 + string(authcommon.DescribeUsers), + // 鉴权策略 + string(authcommon.DescribeAuthPolicies), + string(authcommon.DescribeAuthPolicyDetail), + // 角色 + string(authcommon.DescribeAuthRoles), + } if p.PrincipalType == authcommon.PrincipalUser { resources = append(resources, authcommon.StrategyResource{ StrategyID: ruleId, ResType: int32(apisecurity.ResourceType_Users), ResID: p.PrincipalID, }) - } - - return &authcommon.StrategyDetail{ - ID: ruleId, - Name: authcommon.BuildDefaultStrategyName(authcommon.PrincipalUser, p.Name), - Action: apisecurity.AuthAction_ALLOW.String(), - Default: true, - Owner: p.Owner, - Revision: utils.NewUUID(), - Source: "Polaris", - Resources: resources, - Principals: []authcommon.Principal{p}, - CalleeMethods: []string{ + calleeMethods = []string{ // 用户操作权限 string(authcommon.DescribeUsers), string(authcommon.DescribeUserToken), @@ -88,9 +85,22 @@ func defaultPrincipalPolicy(p authcommon.Principal) *authcommon.StrategyDetail { string(authcommon.DescribeAuthPolicyDetail), // 角色 string(authcommon.DescribeAuthRoles), - }, - Valid: true, - Comment: "default principal auth policy rule", + } + } + + return &authcommon.StrategyDetail{ + ID: ruleId, + Name: authcommon.BuildDefaultStrategyName(p.PrincipalType, p.Name), + Action: apisecurity.AuthAction_ALLOW.String(), + Default: true, + Owner: p.Owner, + Revision: utils.NewUUID(), + Source: "Polaris", + Resources: resources, + Principals: []authcommon.Principal{p}, + CalleeMethods: calleeMethods, + Valid: true, + Comment: "default principal auth policy rule", } } diff --git a/auth/user/group.go b/auth/user/group.go index 18045a3dd..0fc36d639 100644 --- a/auth/user/group.go +++ b/auth/user/group.go @@ -80,7 +80,7 @@ func (svr *Server) CreateGroup(ctx context.Context, req *apisecurity.UserGroup) log.Error(err.Error(), utils.RequestID(ctx)) return api.NewAuthResponseWithMsg(commonstore.StoreCode2APICode(err), err.Error()) } - if err := svr.policySvr.PolicyHelper().CreatePrincipal(ctx, tx, authcommon.Principal{ + if err := svr.policySvr.PolicyHelper().CreatePrincipalPolicy(ctx, tx, authcommon.Principal{ PrincipalID: data.ID, PrincipalType: authcommon.PrincipalGroup, Owner: data.Owner, @@ -184,6 +184,11 @@ func (svr *Server) DeleteGroup(ctx context.Context, req *apisecurity.UserGroup) return api.NewAuthResponse(commonstore.StoreCode2APICode(err)) } + if err := tx.Commit(); err != nil { + log.Error("[Auth][User] delete user_group commit storage tx", utils.RequestID(ctx), zap.Error(err)) + return api.NewAuthResponse(apimodel.Code_ExecuteException) + } + log.Info("delete group", utils.RequestID(ctx), zap.String("name", req.Name.GetValue())) svr.RecordHistory(userGroupRecordEntry(ctx, req, group.UserGroup, model.ODelete)) diff --git a/auth/user/user.go b/auth/user/user.go index 5852dacd7..50bcb6040 100644 --- a/auth/user/user.go +++ b/auth/user/user.go @@ -120,7 +120,7 @@ func (svr *Server) createUser(ctx context.Context, req *apisecurity.User) *apise return api.NewAuthResponse(commonstore.StoreCode2APICode(err)) } - if err := svr.policySvr.PolicyHelper().CreatePrincipal(ctx, tx, authcommon.Principal{ + if err := svr.policySvr.PolicyHelper().CreatePrincipalPolicy(ctx, tx, authcommon.Principal{ PrincipalID: data.ID, PrincipalType: authcommon.PrincipalUser, Owner: data.Owner, diff --git a/cache/api/types.go b/cache/api/types.go index 506d63aac..feee9f4a2 100644 --- a/cache/api/types.go +++ b/cache/api/types.go @@ -318,6 +318,8 @@ type ( QueryInstances(filter, metaFilter map[string]string, offset, limit uint32) (uint32, []*model.Instance, error) // DiscoverServiceInstances 服务发现获取实例 DiscoverServiceInstances(serviceID string, onlyHealthy bool) []*model.Instance + // RemoveService + RemoveService(serviceID string) } ) diff --git a/cache/mock/cache_mock.go b/cache/mock/cache_mock.go index 6a8441864..29b4693ba 100644 --- a/cache/mock/cache_mock.go +++ b/cache/mock/cache_mock.go @@ -1321,6 +1321,18 @@ func (mr *MockInstanceCacheMockRecorder) QueryInstances(filter, metaFilter, offs return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryInstances", reflect.TypeOf((*MockInstanceCache)(nil).QueryInstances), filter, metaFilter, offset, limit) } +// RemoveService mocks base method. +func (m *MockInstanceCache) RemoveService(serviceID string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RemoveService", serviceID) +} + +// RemoveService indicates an expected call of RemoveService. +func (mr *MockInstanceCacheMockRecorder) RemoveService(serviceID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveService", reflect.TypeOf((*MockInstanceCache)(nil).RemoveService), serviceID) +} + // Update mocks base method. func (m *MockInstanceCache) Update() error { m.ctrl.T.Helper() @@ -2919,17 +2931,17 @@ func (mr *MockStrategyCacheMockRecorder) GetPrincipalPolicies(effect, p interfac } // Hint mocks base method. -func (m *MockStrategyCache) Hint(p auth.Principal, r *auth.ResourceEntry) security.AuthAction { +func (m *MockStrategyCache) Hint(ctx context.Context, p auth.Principal, r *auth.ResourceEntry) security.AuthAction { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Hint", p, r) + ret := m.ctrl.Call(m, "Hint", ctx, p, r) ret0, _ := ret[0].(security.AuthAction) return ret0 } // Hint indicates an expected call of Hint. -func (mr *MockStrategyCacheMockRecorder) Hint(p, r interface{}) *gomock.Call { +func (mr *MockStrategyCacheMockRecorder) Hint(ctx, p, r interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Hint", reflect.TypeOf((*MockStrategyCache)(nil).Hint), p, r) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Hint", reflect.TypeOf((*MockStrategyCache)(nil).Hint), ctx, p, r) } // Initialize mocks base method. diff --git a/cache/service/instance.go b/cache/service/instance.go index 80c60a5f0..8eced63e2 100644 --- a/cache/service/instance.go +++ b/cache/service/instance.go @@ -557,6 +557,12 @@ func (ic *instanceCache) GetServicePorts(serviceID string) []*model.ServicePort return ic.instancePorts.listPort(serviceID) } +// RemoveService . +func (ic *instanceCache) RemoveService(serviceID string) { + ic.instancePorts.removeService(serviceID) + ic.services.Delete(serviceID) +} + // iteratorInstancesProc 迭代指定的instance数据,id->instance func iteratorInstancesProc(data *utils.SyncMap[string, *model.Instance], iterProc types.InstanceIterProc) error { var err error @@ -590,6 +596,13 @@ func (b *instancePorts) reset() { b.ports = make(map[string]map[string]*model.ServicePort) } +func (b *instancePorts) removeService(serviceID string) { + b.lock.Lock() + defer b.lock.Unlock() + + delete(b.ports, serviceID) +} + func (b *instancePorts) appendPort(serviceID string, protocol string, port uint32) { if serviceID == "" || port == 0 { return diff --git a/cache/service/service.go b/cache/service/service.go index 6b3ae7e56..310b8837a 100644 --- a/cache/service/service.go +++ b/cache/service/service.go @@ -409,6 +409,8 @@ func (sc *serviceCache) removeServices(service *model.Service) { sc.alias.cleanServiceAlias(service) // delete pending count service task sc.pendingServices.Delete(service.ID) + // delete instance link service info + sc.instCache.RemoveService(service.ID) // Delete the index of servicename spaceName := service.Namespace diff --git a/cache/service/service_bucket.go b/cache/service/service_bucket.go index 5611d7d1d..6963d789e 100644 --- a/cache/service/service_bucket.go +++ b/cache/service/service_bucket.go @@ -165,8 +165,10 @@ func (s *serviceNamespaceBucket) ListAllServices() (string, []*model.Service) { ret := make([]*model.Service, 0, 32) for namespace := range s.names { - _, val := s.ListServices(namespace) - ret = append(ret, val...) + if val, ok := s.names[namespace]; ok { + _, svcs := val.listServices() + ret = append(ret, svcs...) + } } return s.revision, ret @@ -217,13 +219,12 @@ func (s *serviceNameBucket) listServices() (string, []*model.Service) { } func (s *serviceNameBucket) reloadRevision() { - s.lock.Lock() - defer s.lock.Unlock() - + s.lock.RLock() revisions := make([]string, 0, len(s.names)) for i := range s.names { revisions = append(revisions, s.names[i].Revision) } + s.lock.RUnlock() sort.Strings(revisions) @@ -235,5 +236,7 @@ func (s *serviceNameBucket) reloadRevision() { } } + s.lock.Lock() + defer s.lock.Unlock() s.revisions = hex.EncodeToString(h.Sum(nil)) } diff --git a/release/conf/bolt-data.yaml b/release/conf/bolt-data.yaml index 2c7827204..46495aed0 100644 --- a/release/conf/bolt-data.yaml +++ b/release/conf/bolt-data.yaml @@ -78,7 +78,7 @@ policies: name: 全局只读策略 action: ALLOW comment: global resources read onyly - default: false + default: true owner: 65e4789a6d5b49669adf1e9e8387549c calleemethods: ["Describe*", "List*", "Get*"] resources: @@ -127,7 +127,7 @@ policies: name: 全局读写策略 action: ALLOW comment: global resources read and write - default: false + default: true owner: 65e4789a6d5b49669adf1e9e8387549c calleemethods: ["*"] resources: diff --git a/release/conf/polaris-server.yaml b/release/conf/polaris-server.yaml index eab609cd8..b25a431f2 100644 --- a/release/conf/polaris-server.yaml +++ b/release/conf/polaris-server.yaml @@ -31,7 +31,7 @@ bootstrap: # The maximum preservation days of a single log file, default 7 rotationMaxAge: 7 # Log output level,debug/info/warn/error - outputLevel: debug + outputLevel: info # Open the log file compression compress: true # onlyContent just print log content, not print log timestamp diff --git a/store/auth_api.go b/store/auth_api.go index 0db55fec0..96f221ff6 100644 --- a/store/auth_api.go +++ b/store/auth_api.go @@ -69,8 +69,6 @@ type GroupStore interface { GetGroup(id string) (*authcommon.UserGroupDetail, error) // GetGroupByName Get user groups according to Name and Owner GetGroupByName(name, owner string) (*authcommon.UserGroup, error) - // GetGroups Get a list of user groups - GetGroups(filters map[string]string, offset uint32, limit uint32) (uint32, []*authcommon.UserGroup, error) // GetUserGroupsForCache Refresh of getting user groups for cache // 此方法用于 cache 增量更新,需要注意 mtime 应为数据库时间戳 GetGroupsForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) diff --git a/store/boltdb/group.go b/store/boltdb/group.go index 09cf886f5..8f8e89962 100644 --- a/store/boltdb/group.go +++ b/store/boltdb/group.go @@ -20,15 +20,12 @@ package boltdb import ( "errors" "fmt" - "sort" - "strings" "time" bolt "go.etcd.io/bbolt" "go.uber.org/zap" authcommon "github.com/polarismesh/polaris/common/model/auth" - "github.com/polarismesh/polaris/common/utils" "github.com/polarismesh/polaris/store" ) @@ -267,148 +264,12 @@ func (gs *groupStore) GetGroupByName(name, owner string) (*authcommon.UserGroup, return ret.UserGroup, nil } -// GetGroups get groups -func (gs *groupStore) GetGroups(filters map[string]string, offset uint32, - limit uint32) (uint32, []*authcommon.UserGroup, error) { - - // 如果本次请求参数携带了 user_id,那么就是查询这个用户所关联的所有用户组 - if _, ok := filters["user_id"]; ok { - return gs.listGroupByUser(filters, offset, limit) - } - // 正常查询用户组信息 - return gs.listSimpleGroups(filters, offset, limit) -} - -// listSimpleGroups Normal user group query -func (gs *groupStore) listSimpleGroups(filters map[string]string, offset uint32, limit uint32) (uint32, - []*authcommon.UserGroup, error) { - fields := []string{GroupFieldID, GroupFieldOwner, GroupFieldName, GroupFieldValid} - values, err := gs.handler.LoadValuesByFilter(tblGroup, fields, &groupForStore{}, - func(m map[string]interface{}) bool { - valid, ok := m[GroupFieldValid].(bool) - if ok && !valid { - return false - } - - saveId, _ := m[GroupFieldID].(string) - saveName, _ := m[GroupFieldName].(string) - saveOwner, _ := m[GroupFieldOwner].(string) - - if sId, ok := filters["id"]; ok && sId != saveId { - return false - } - if sName, ok := filters["name"]; ok { - if utils.IsPrefixWildName(sName) { - sName = sName[:len(sName)-1] - } - if !strings.Contains(saveName, sName) { - return false - } - } - - if sOwner, ok := filters["owner"]; ok && sOwner != saveOwner { - return false - } - - return true - }) - - if err != nil { - return 0, nil, err - } - - total := uint32(len(values)) - - return total, doGroupPage(values, offset, limit), nil -} - -// listGroupByUser 查询某个用户下所关联的用户组信息 -func (gs *groupStore) listGroupByUser(filters map[string]string, offset uint32, - limit uint32) (uint32, []*authcommon.UserGroup, error) { - - var ( - userID = filters["user_id"] - owner, existOwner = filters["owner"] - fields = []string{GroupFieldUserIds, GroupFieldOwner, GroupFieldValid} - ) - - values, err := gs.handler.LoadValuesByFilter(tblGroup, fields, &groupForStore{}, - func(m map[string]interface{}) bool { - valid, ok := m[GroupFieldValid].(bool) - if ok && !valid { - return false - } - saveOwner := m[GroupFieldOwner] - if existOwner && saveOwner != owner { - return false - } - - if sName, ok := filters["name"]; ok { - saveName, _ := m[GroupFieldName].(string) - if utils.IsPrefixWildName(sName) { - sName = sName[:len(sName)-1] - } - if !strings.Contains(saveName, sName) { - return false - } - } - - saveVal, ok := m[GroupFieldUserIds] - if !ok { - return false - } - - saveUserIds := saveVal.(map[string]string) - _, exist := saveUserIds[userID] - return exist - }) - - if err != nil { - return 0, nil, err - } - - total := uint32(len(values)) - - return total, doGroupPage(values, offset, limit), nil -} - -func doGroupPage(ret map[string]interface{}, offset uint32, limit uint32) []*authcommon.UserGroup { - - groups := make([]*authcommon.UserGroup, 0, len(ret)) - - beginIndex := offset - endIndex := beginIndex + limit - totalCount := uint32(len(ret)) - - if totalCount == 0 { - return groups - } - if beginIndex >= endIndex { - return groups - } - if beginIndex >= totalCount { - return groups - } - if endIndex > totalCount { - endIndex = totalCount - } - for k := range ret { - groups = append(groups, convertForGroupDetail(ret[k].(*groupForStore)).UserGroup) - } - - sort.Slice(groups, func(i, j int) bool { - return groups[i].ModifyTime.After(groups[j].ModifyTime) - }) - - return groups[beginIndex:endIndex] -} - // GetGroupsForCache 查询用户分组数据,主要用于Cache更新 func (gs *groupStore) GetGroupsForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) { ret, err := gs.handler.LoadValuesByFilter(tblGroup, []string{GroupFieldModifyTime}, &groupForStore{}, func(m map[string]interface{}) bool { mt := m[GroupFieldModifyTime].(time.Time) - isAfter := mt.After(mtime) + isAfter := !mt.Before(mtime) return isAfter }) if err != nil { diff --git a/store/boltdb/group_test.go b/store/boltdb/group_test.go index 264ba997f..8952ff0ae 100644 --- a/store/boltdb/group_test.go +++ b/store/boltdb/group_test.go @@ -189,95 +189,3 @@ func Test_groupStore_GetGroupByName(t *testing.T) { assert.Equal(t, groups[0].UserGroup, ret) }) } - -func Test_groupStore_GetGroups(t *testing.T) { - CreateTableDBHandlerAndRun(t, "test_group", func(t *testing.T, handler BoltHandler) { - gs := &groupStore{handler: handler} - - groups := createTestUserGroup(10) - - for i := range groups { - tx, err := handler.StartTx() - assert.NoError(t, err) - if err := gs.AddGroup(tx, groups[i]); err != nil { - t.Fatal(err) - } - assert.NoError(t, tx.Commit()) - } - - total, ret, err := gs.GetGroups(map[string]string{ - "name": "gr*", - }, 0, 2) - if err != nil { - t.Fatal(err) - } - - if !assert.Equal(t, 2, len(ret)) { - t.Fatal("len(ret) need equal 2") - } - - if !assert.Equal(t, len(groups), int(total)) { - t.Fatal("total != len(groups)") - } - - total, ret, err = gs.GetGroups(map[string]string{ - "name": "gr*", - }, 100, 2) - if err != nil { - t.Fatal(err) - } - - if !assert.Equal(t, 0, len(ret)) { - t.Fatal("len(ret) need zero") - } - - if !assert.Equal(t, len(groups), int(total)) { - t.Fatal("total != len(groups)") - } - - total, ret, err = gs.GetGroups(map[string]string{ - "name": "gr*", - }, 0, 100) - if err != nil { - t.Fatal(err) - } - - if !assert.Equal(t, len(groups), len(ret)) { - t.Fatal("len(ret) need zero") - } - - if !assert.Equal(t, len(groups), int(total)) { - t.Fatal("total != len(groups)") - } - - total, ret, err = gs.GetGroups(map[string]string{ - "user_id": "user_1", - }, 0, 100) - if err != nil { - t.Fatal(err) - } - - if !assert.Equal(t, len(groups), len(ret)) { - t.Fatal("len(ret) need zero") - } - - if !assert.Equal(t, len(groups), int(total)) { - t.Fatal("total != len(groups)") - } - - total, ret, err = gs.GetGroups(map[string]string{ - "owner": "polaris", - }, 0, 100) - if err != nil { - t.Fatal(err) - } - - if !assert.Equal(t, len(groups), len(ret)) { - t.Fatal("len(ret) need zero") - } - - if !assert.Equal(t, len(groups), int(total)) { - t.Fatal("total != len(groups)") - } - }) -} diff --git a/store/mysql/group.go b/store/mysql/group.go index 93df9d99a..b68be72ed 100644 --- a/store/mysql/group.go +++ b/store/mysql/group.go @@ -22,8 +22,6 @@ import ( "fmt" "time" - "go.uber.org/zap" - authcommon "github.com/polarismesh/polaris/common/model/auth" "github.com/polarismesh/polaris/common/utils" "github.com/polarismesh/polaris/store" @@ -268,150 +266,6 @@ func (u *groupStore) GetGroupByName(name, owner string) (*authcommon.UserGroup, return group, nil } -// GetGroups 根据不同的请求情况进行不同的用户组列表查询 -func (u *groupStore) GetGroups(filters map[string]string, offset uint32, limit uint32) (uint32, - []*authcommon.UserGroup, error) { - - // 如果本次请求参数携带了 user_id,那么就是查询这个用户所关联的所有用户组 - if _, ok := filters["user_id"]; ok { - return u.listGroupByUser(filters, offset, limit) - } - // 正常查询用户组信息 - return u.listSimpleGroups(filters, offset, limit) -} - -// listSimpleGroups 正常的用户组查询 -func (u *groupStore) listSimpleGroups(filters map[string]string, offset uint32, limit uint32) (uint32, - []*authcommon.UserGroup, error) { - - query := make(map[string]string) - if _, ok := filters["id"]; ok { - query["id"] = filters["id"] - } - if _, ok := filters["name"]; ok { - query["name"] = filters["name"] - } - filters = query - - countSql := "SELECT COUNT(*) FROM user_group ug WHERE ug.flag = 0 " - getSql := ` - SELECT ug.id, ug.name, ug.owner, ug.comment, ug.token, ug.token_enable - , UNIX_TIMESTAMP(ug.ctime), UNIX_TIMESTAMP(ug.mtime) - , ug.flag - FROM user_group ug - WHERE ug.flag = 0 - ` - - args := make([]interface{}, 0) - - if len(filters) != 0 { - for k, v := range filters { - getSql += " AND " - countSql += " AND " - if newK, ok := groupAttribute[k]; ok { - k = newK - } - if utils.IsPrefixWildName(v) { - getSql += (" " + k + " like ? ") - countSql += (" " + k + " like ? ") - args = append(args, "%"+v[:len(v)-1]+"%") - } else { - getSql += (" " + k + " = ? ") - countSql += (" " + k + " = ? ") - args = append(args, v) - } - } - } - - count, err := queryEntryCount(u.master, countSql, args) - if err != nil { - return 0, nil, err - } - - getSql += " ORDER BY ug.mtime LIMIT ? , ?" - args = append(args, offset, limit) - - groups, err := u.collectGroupsFromRows(u.master.Query, getSql, args) - if err != nil { - return 0, nil, err - } - - return count, groups, nil -} - -// listGroupByUser 查询某个用户下所关联的用户组信息 -func (u *groupStore) listGroupByUser(filters map[string]string, offset uint32, limit uint32) (uint32, - []*authcommon.UserGroup, error) { - countSql := "SELECT COUNT(*) FROM user_group_relation ul LEFT JOIN user_group ug ON " + - " ul.group_id = ug.id WHERE ug.flag = 0 " - getSql := "SELECT ug.id, ug.name, ug.owner, ug.comment, ug.token, ug.token_enable, UNIX_TIMESTAMP(ug.ctime), " + - " UNIX_TIMESTAMP(ug.mtime), ug.flag " + - " FROM user_group_relation ul LEFT JOIN user_group ug ON ul.group_id = ug.id WHERE ug.flag = 0 " - - args := make([]interface{}, 0) - - if len(filters) != 0 { - for k, v := range filters { - getSql += " AND " - countSql += " AND " - if newK, ok := userLinkGroupAttributeMapping[k]; ok { - k = newK - } - if utils.IsPrefixWildName(v) { - getSql += (" " + k + " like ? ") - countSql += (" " + k + " like ? ") - args = append(args, "%"+v[:len(v)-1]+"%") - } else if k == "ug.owner" { - getSql += " (ug.owner = ?) " - countSql += " (ug.owner = ?) " - args = append(args, v) - } else { - getSql += (" " + k + " = ? ") - countSql += (" " + k + " = ? ") - args = append(args, v) - } - } - } - - count, err := queryEntryCount(u.master, countSql, args) - if err != nil { - return 0, nil, err - } - - getSql += " GROUP BY ug.id ORDER BY ug.mtime LIMIT ? , ?" - args = append(args, offset, limit) - - groups, err := u.collectGroupsFromRows(u.master.Query, getSql, args) - if err != nil { - return 0, nil, err - } - - return count, groups, nil -} - -// collectGroupsFromRows 查询用户组列表 -func (u *groupStore) collectGroupsFromRows(handler QueryHandler, querySql string, - args []interface{}) ([]*authcommon.UserGroup, error) { - rows, err := u.master.Query(querySql, args...) - if err != nil { - log.Error("[Store][Group] list group", zap.String("query sql", querySql), zap.Any("args", args)) - return nil, err - } - defer rows.Close() - - groups := make([]*authcommon.UserGroup, 0) - for rows.Next() { - group, err := fetchRown2UserGroup(rows) - if err != nil { - log.Errorf("[Store][Group] list group by user fetch rows scan err: %s", err.Error()) - return nil, err - } - groups = append(groups, group) - } - - return groups, nil -} - // GetGroupsForCache . func (u *groupStore) GetGroupsForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) { tx, err := u.slave.Begin() From 8b0d10a1b83c042c6f14ebeebda75275e5ac9efa Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 23 Oct 2024 09:34:27 +0800 Subject: [PATCH 06/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=88=9D=E5=A7=8B=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/api.go | 4 +- admin/default.go | 14 +- admin/interceptor/auth/server.go | 6 +- admin/maintain.go | 23 +- admin/server.go | 5 +- apiserver/grpcserver/config/client_access.go | 9 +- apiserver/httpserver/admin_access.go | 35 +- auth/policy/helper.go | 114 ++++- auth/user/user.go | 6 +- bootstrap/server.go | 3 +- cache/auth/user.go | 4 +- cache/auth/user_test.go | 8 +- common/model/auth/context.go | 12 +- release/conf/bolt-data.yaml | 174 ------- service/client_v1.go | 3 - store/auth_api.go | 12 +- store/boltdb/group.go | 4 +- store/boltdb/user.go | 181 +------ store/boltdb/user_test.go | 125 ----- store/mock/api_mock.go | 123 ++--- store/mysql/group.go | 4 +- store/mysql/scripts/delta/v1_18_1-v1_19_0.sql | 278 ++++++++++- store/mysql/scripts/polaris_server.sql | 468 +----------------- store/mysql/user.go | 173 ++----- 24 files changed, 615 insertions(+), 1173 deletions(-) delete mode 100644 release/conf/bolt-data.yaml diff --git a/admin/api.go b/admin/api.go index 8f717c105..ce639efc1 100644 --- a/admin/api.go +++ b/admin/api.go @@ -54,7 +54,9 @@ type AdminOperateServer interface { ReleaseLeaderElection(ctx context.Context, electKey string) error // GetCMDBInfo get cmdb info GetCMDBInfo(ctx context.Context) ([]model.LocationView, error) - // InitMainUser + // HasMainUser . + HasMainUser(ctx context.Context) (*apisecurity.User, error) + // InitMainUser . InitMainUser(ctx context.Context, user apisecurity.User) error // GetServerFunctions Get server functions GetServerFunctions(ctx context.Context) []authcommon.ServerFunctionGroup diff --git a/admin/default.go b/admin/default.go index 5ebf3643b..453e34ad9 100644 --- a/admin/default.go +++ b/admin/default.go @@ -23,6 +23,7 @@ import ( "fmt" "github.com/polarismesh/polaris/admin/job" + "github.com/polarismesh/polaris/auth" "github.com/polarismesh/polaris/cache" "github.com/polarismesh/polaris/service" "github.com/polarismesh/polaris/service/healthcheck" @@ -48,13 +49,15 @@ func RegisterServerProxy(name string, factor ServerProxyFactory) error { // Initialize 初始化 func Initialize(ctx context.Context, cfg *Config, namingService service.DiscoverServer, - healthCheckServer *healthcheck.Server, cacheMgn *cache.CacheManager, storage store.Store) error { + healthCheckServer *healthcheck.Server, cacheMgn *cache.CacheManager, storage store.Store, + userSvr auth.UserServer, policySvr auth.StrategyServer) error { if finishInit { return nil } - proxySvr, actualSvr, err := InitServer(ctx, cfg, namingService, healthCheckServer, cacheMgn, storage) + proxySvr, actualSvr, err := InitServer(ctx, cfg, namingService, healthCheckServer, cacheMgn, + storage, userSvr, policySvr) if err != nil { return err } @@ -66,13 +69,16 @@ func Initialize(ctx context.Context, cfg *Config, namingService service.Discover } func InitServer(ctx context.Context, cfg *Config, namingService service.DiscoverServer, - healthCheckServer *healthcheck.Server, cacheMgn *cache.CacheManager, storage store.Store) (AdminOperateServer, *Server, error) { + healthCheckServer *healthcheck.Server, cacheMgn *cache.CacheManager, storage store.Store, + userSvr auth.UserServer, policySvr auth.StrategyServer) (AdminOperateServer, *Server, error) { actualSvr := new(Server) + actualSvr.userSvr = userSvr + actualSvr.policySvr = policySvr actualSvr.namingServer = namingService actualSvr.healthCheckServer = healthCheckServer - actualSvr.cacheMgn = cacheMgn + actualSvr.cacheMgr = cacheMgn actualSvr.storage = storage maintainJobs := job.NewMaintainJobs(namingService, cacheMgn, storage) diff --git a/admin/interceptor/auth/server.go b/admin/interceptor/auth/server.go index a5e67c578..e18ecdbee 100644 --- a/admin/interceptor/auth/server.go +++ b/admin/interceptor/auth/server.go @@ -62,12 +62,12 @@ func (svr *Server) collectMaintainAuthContext(ctx context.Context, resourceOp au ) } -func (s *Server) HasMainUser(ctx context.Context) (bool, error) { - return false, nil +func (s *Server) HasMainUser(ctx context.Context) (*apisecurity.User, error) { + return s.nextSvr.HasMainUser(ctx) } func (s *Server) InitMainUser(ctx context.Context, user apisecurity.User) error { - return nil + return s.nextSvr.InitMainUser(ctx, user) } func (svr *Server) GetServerConnections(ctx context.Context, req *admincommon.ConnReq) (*admincommon.ConnCountResp, error) { diff --git a/admin/maintain.go b/admin/maintain.go index 0b4fafa74..5800bdf54 100644 --- a/admin/maintain.go +++ b/admin/maintain.go @@ -27,6 +27,7 @@ import ( apisecurity "github.com/polarismesh/specification/source/go/api/v1/security" apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" "go.uber.org/zap" + "google.golang.org/protobuf/types/known/wrapperspb" api "github.com/polarismesh/polaris/common/api/v1" connlimit "github.com/polarismesh/polaris/common/conn/limit" @@ -39,11 +40,27 @@ import ( "github.com/polarismesh/polaris/plugin" ) -func (s *Server) HasMainUser(ctx context.Context, user apisecurity.User) (bool, error) { - return false, nil +// HasMainUser 判断是否存在主用户 +func (s *Server) HasMainUser(ctx context.Context) (*apisecurity.User, error) { + mainUser, err := s.storage.GetMainUser() + if err != nil { + log.Error("check hash main user", zap.Error(err), utils.RequestID(ctx)) + return nil, err + } + ret := mainUser.ToSpec() + ret.AuthToken = wrapperspb.String("") + return ret, nil } -func (s *Server) InitMainUser(ctx context.Context, user apisecurity.User) error { +// InitMainUser 初始化主用户 +func (s *Server) InitMainUser(_ context.Context, user apisecurity.User) error { + ctx := context.WithValue(context.Background(), authcommon.ContextKeyInitMainUser{}, true) + rsp := s.userSvr.CreateUsers(ctx, []*apisecurity.User{ + &user, + }) + if !api.IsSuccess(rsp) { + return errors.New(rsp.GetInfo().GetValue()) + } return nil } diff --git a/admin/server.go b/admin/server.go index 9ab899f00..f8d50a2c2 100644 --- a/admin/server.go +++ b/admin/server.go @@ -20,6 +20,7 @@ package admin import ( "sync" + "github.com/polarismesh/polaris/auth" "github.com/polarismesh/polaris/cache" "github.com/polarismesh/polaris/service" "github.com/polarismesh/polaris/service/healthcheck" @@ -32,8 +33,10 @@ type Server struct { mu sync.Mutex namingServer service.DiscoverServer healthCheckServer *healthcheck.Server - cacheMgn *cache.CacheManager + cacheMgr *cache.CacheManager storage store.Store + userSvr auth.UserServer + policySvr auth.StrategyServer } func GetChainOrder() []string { diff --git a/apiserver/grpcserver/config/client_access.go b/apiserver/grpcserver/config/client_access.go index 414f7eca7..9c04d4a7e 100644 --- a/apiserver/grpcserver/config/client_access.go +++ b/apiserver/grpcserver/config/client_access.go @@ -201,7 +201,14 @@ func (g *ConfigGRPCServer) Discover(svr apiconfig.PolarisConfigGRPC_DiscoverServ switch in.Type { case apiconfig.ConfigDiscoverRequest_CONFIG_FILE: action = metrics.ActionGetConfigFile - ret := g.configServer.GetConfigFileWithCache(ctx, &apiconfig.ClientConfigFileInfo{}) + version, _ := strconv.ParseUint(in.GetRevision(), 10, 64) + ret := g.configServer.GetConfigFileWithCache(ctx, &apiconfig.ClientConfigFileInfo{ + Namespace: in.GetConfigFile().GetNamespace(), + Group: in.GetConfigFile().GetGroup(), + FileName: in.GetConfigFile().GetFileName(), + Version: wrapperspb.UInt64(version), + PublicKey: in.GetConfigFile().GetPublicKey(), + }) out = api.NewConfigDiscoverResponse(apimodel.Code(ret.GetCode().GetValue())) out.ConfigFile = ret.GetConfigFile() out.Type = apiconfig.ConfigDiscoverResponse_CONFIG_FILE diff --git a/apiserver/httpserver/admin_access.go b/apiserver/httpserver/admin_access.go index 22784edac..4aa5fccb7 100644 --- a/apiserver/httpserver/admin_access.go +++ b/apiserver/httpserver/admin_access.go @@ -25,6 +25,7 @@ import ( "github.com/emicklei/go-restful/v3" apimodel "github.com/polarismesh/specification/source/go/api/v1/model" + "github.com/polarismesh/specification/source/go/api/v1/security" apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" "github.com/polarismesh/polaris/apiserver/httpserver/docs" @@ -48,7 +49,7 @@ func (h *HTTPServer) index(_ *restful.Request, rsp *restful.Response) { _, _ = rsp.Write([]byte("Polaris Server")) } -// GetMaintainAccessServer 运维接口 +// GetAdminAccessServer 运维接口 func (h *HTTPServer) GetAdminAccessServer() *restful.WebService { ws := new(restful.WebService) ws.Path("/maintain/v1").Consumes(restful.MIME_JSON).Produces(restful.MIME_JSON) @@ -68,6 +69,8 @@ func (h *HTTPServer) GetAdminAccessServer() *restful.WebService { ws.Route(docs.EnrichGetReportClientsApiDocs(ws.GET("/report/clients").To(h.GetReportClients))) ws.Route(docs.EnrichEnablePprofApiDocs(ws.POST("/pprof/enable").To(h.EnablePprof))) ws.Route(docs.EnrichGetServerFunctionsApiDocs(ws.GET("/server/functions").To(h.GetServerFunctions))) + ws.Route(ws.GET("/mainuser/exist").To(h.HasMainUser)) + ws.Route(ws.GET("/mainuser/create").To(h.InitMainUser)) return ws } @@ -309,6 +312,36 @@ func (h *HTTPServer) EnablePprof(req *restful.Request, rsp *restful.Response) { _ = rsp.WriteEntity("ok") } +func (h *HTTPServer) HasMainUser(req *restful.Request, rsp *restful.Response) { + ctx := initContext(req) + ret, err := h.maintainServer.HasMainUser(ctx) + if err != nil { + _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) + return + } + _ = rsp.WriteAsJson(ret) +} + +func (h *HTTPServer) InitMainUser(req *restful.Request, rsp *restful.Response) { + handler := &httpcommon.Handler{ + Request: req, + Response: rsp, + } + + user := &security.User{} + ctx, err := handler.Parse(user) + if err != nil { + handler.WriteHeaderAndProto(api.NewAuthResponseWithMsg(apimodel.Code_ParseException, err.Error())) + return + } + + if err := h.maintainServer.InitMainUser(ctx, *user); err != nil { + _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) + return + } + _ = rsp.WriteEntity("ok") +} + // GetServerFunctions . func (h *HTTPServer) GetServerFunctions(req *restful.Request, rsp *restful.Response) { ctx := initContext(req) diff --git a/auth/policy/helper.go b/auth/policy/helper.go index 0c6ce415c..1c77670c0 100644 --- a/auth/policy/helper.go +++ b/auth/policy/helper.go @@ -46,10 +46,118 @@ func (h *DefaultPolicyHelper) GetPolicyRule(id string) *authcommon.StrategyDetai // CreatePrincipal 创建 principal 的默认 policy 资源 func (h *DefaultPolicyHelper) CreatePrincipalPolicy(ctx context.Context, tx store.Tx, p authcommon.Principal) error { - if err := h.storage.AddStrategy(tx, defaultPrincipalPolicy(p)); err != nil { - return err + if p.PrincipalType == authcommon.PrincipalUser && authcommon.IsInitMainUser(ctx) { + // 创建的是管理员帐户策略 + if err := h.storage.AddStrategy(tx, mainUserPrincipalPolicy(p)); err != nil { + return err + } + // 创建默认策略 + policies := []*authcommon.StrategyDetail{defaultReadWritePolicy(p), defaultReadOnlyPolicy(p)} + for i := range policies { + if err := h.storage.AddStrategy(tx, policies[i]); err != nil { + return err + } + } + return nil + } + return h.storage.AddStrategy(tx, defaultPrincipalPolicy(p)) +} + +func mainUserPrincipalPolicy(p authcommon.Principal) *authcommon.StrategyDetail { + // Create the user's default weight policy + ruleId := utils.NewUUID() + + resources := []authcommon.StrategyResource{} + + for _, v := range apisecurity.ResourceType_value { + resources = append(resources, authcommon.StrategyResource{ + StrategyID: ruleId, + ResType: v, + ResID: "*", + }) + } + + calleeMethods := []string{"*"} + return &authcommon.StrategyDetail{ + ID: ruleId, + Name: authcommon.BuildDefaultStrategyName(p.PrincipalType, p.Name), + Action: apisecurity.AuthAction_ALLOW.String(), + Default: true, + Owner: p.Owner, + Revision: utils.NewUUID(), + Source: "Polaris", + Resources: resources, + Principals: []authcommon.Principal{p}, + CalleeMethods: calleeMethods, + Valid: true, + Comment: "default main user auth policy rule", + } +} + +func defaultReadWritePolicy(p authcommon.Principal) *authcommon.StrategyDetail { + // Create the user's default weight policy + ruleId := utils.NewUUID() + + resources := []authcommon.StrategyResource{} + + for _, v := range apisecurity.ResourceType_value { + resources = append(resources, authcommon.StrategyResource{ + StrategyID: ruleId, + ResType: v, + ResID: "*", + }) + } + + calleeMethods := []string{"*"} + return &authcommon.StrategyDetail{ + ID: ruleId, + Name: "全局读写策略", + Action: apisecurity.AuthAction_ALLOW.String(), + Default: true, + Owner: p.Owner, + Revision: utils.NewUUID(), + Source: "Polaris", + Resources: resources, + Principals: []authcommon.Principal{p}, + CalleeMethods: calleeMethods, + Valid: true, + Comment: "global resources read and write", + } +} + +func defaultReadOnlyPolicy(p authcommon.Principal) *authcommon.StrategyDetail { + // Create the user's default weight policy + ruleId := utils.NewUUID() + + resources := []authcommon.StrategyResource{} + + for _, v := range apisecurity.ResourceType_value { + resources = append(resources, authcommon.StrategyResource{ + StrategyID: ruleId, + ResType: v, + ResID: "*", + }) + } + + calleeMethods := []string{ + "Describe*", + "List*", + "Get*", + } + return &authcommon.StrategyDetail{ + ID: ruleId, + Name: "全局只读策略", + Action: apisecurity.AuthAction_ALLOW.String(), + Default: true, + Owner: p.Owner, + Revision: utils.NewUUID(), + Source: "Polaris", + Resources: resources, + Principals: []authcommon.Principal{p}, + CalleeMethods: calleeMethods, + Valid: true, + Comment: "global resources read only policy rule", } - return nil } func defaultPrincipalPolicy(p authcommon.Principal) *authcommon.StrategyDetail { diff --git a/auth/user/user.go b/auth/user/user.go index 50bcb6040..05d0cec70 100644 --- a/auth/user/user.go +++ b/auth/user/user.go @@ -68,7 +68,11 @@ func (svr *Server) CreateUser(ctx context.Context, req *apisecurity.User) *apise // 如果创建的目标账户类型是非子账户,则 ownerId 需要设置为 “” if convertCreateUserRole(authcommon.ParseUserRole(ctx)) != authcommon.SubAccountUserRole { - ownerID = "" + // 如果创建的不是子帐户,需要判断是否来自内部的 InitMainUser 请求 + if !authcommon.IsInitMainUser(ctx) { + log.Error("[auth][user] can't create user which role is not sub-account", utils.RequestID(ctx)) + return api.NewUserResponse(apimodel.Code_OperationRoleForbidden, req) + } } if ownerID != "" { diff --git a/bootstrap/server.go b/bootstrap/server.go index f3f190632..3bf810d9d 100644 --- a/bootstrap/server.go +++ b/bootstrap/server.go @@ -211,7 +211,8 @@ func StartComponents(ctx context.Context, cfg *boot_config.Config) error { } // 初始化运维操作模块 - if err := admin.Initialize(ctx, &cfg.Maintain, namingSvr, healthCheckServer, cacheMgn, s); err != nil { + if err := admin.Initialize(ctx, &cfg.Maintain, namingSvr, healthCheckServer, cacheMgn, s, + userMgn, strategyMgn); err != nil { return err } diff --git a/cache/auth/user.go b/cache/auth/user.go index c8f989d04..3aeff2243 100644 --- a/cache/auth/user.go +++ b/cache/auth/user.go @@ -100,13 +100,13 @@ func (uc *userCache) Update() error { func (uc *userCache) realUpdate() (map[string]time.Time, int64, error) { // Get all data before a few seconds start := time.Now() - users, err := uc.storage.GetUsersForCache(uc.LastFetchTime(), uc.IsFirstUpdate()) + users, err := uc.storage.GetMoreUsers(uc.LastFetchTime(), uc.IsFirstUpdate()) if err != nil { log.Errorf("[Cache][User] update user err: %s", err.Error()) return nil, -1, err } - groups, err := uc.storage.GetGroupsForCache(uc.LastFetchTime(), uc.IsFirstUpdate()) + groups, err := uc.storage.GetMoreGroups(uc.LastFetchTime(), uc.IsFirstUpdate()) if err != nil { log.Errorf("[Cache][Group] update group err: %s", err.Error()) return nil, -1, err diff --git a/cache/auth/user_test.go b/cache/auth/user_test.go index e87648ae4..e98a18207 100644 --- a/cache/auth/user_test.go +++ b/cache/auth/user_test.go @@ -150,8 +150,8 @@ func TestUserCache_UpdateNormal(t *testing.T) { copyGroup.UserIds = newUserIds copyGroups = append(copyGroups, ©Group) } - store.EXPECT().GetUsersForCache(gomock.Any(), gomock.Any()).Return(copyUsers, nil).Times(1) - store.EXPECT().GetGroupsForCache(gomock.Any(), gomock.Any()).Return(copyGroups, nil).Times(1) + store.EXPECT().GetMoreUsers(gomock.Any(), gomock.Any()).Return(copyUsers, nil).Times(1) + store.EXPECT().GetMoreGroups(gomock.Any(), gomock.Any()).Return(copyGroups, nil).Times(1) assert.NoError(t, uc.Update()) @@ -217,8 +217,8 @@ func TestUserCache_UpdateNormal(t *testing.T) { copyGroups = append(copyGroups, ©Group) } - store.EXPECT().GetUsersForCache(gomock.Any(), gomock.Any()).Return(copyUsers, nil).Times(1) - store.EXPECT().GetGroupsForCache(gomock.Any(), gomock.Any()).Return(copyGroups, nil).Times(1) + store.EXPECT().GetMoreUsers(gomock.Any(), gomock.Any()).Return(copyUsers, nil).Times(1) + store.EXPECT().GetMoreGroups(gomock.Any(), gomock.Any()).Return(copyGroups, nil).Times(1) assert.NoError(t, uc.Update()) diff --git a/common/model/auth/context.go b/common/model/auth/context.go index d4ccbae19..0b150234e 100644 --- a/common/model/auth/context.go +++ b/common/model/auth/context.go @@ -17,6 +17,16 @@ package auth +import "context" + type ( - ContextKeyConditions struct{} + ContextKeyConditions struct{} + ContextKeyInitMainUser struct{} ) + +// IsInitMainUser . +func IsInitMainUser(ctx context.Context) bool { + val := ctx.Value(ContextKeyInitMainUser{}) + ret, _ := val.(bool) + return ret +} diff --git a/release/conf/bolt-data.yaml b/release/conf/bolt-data.yaml deleted file mode 100644 index 46495aed0..000000000 --- a/release/conf/bolt-data.yaml +++ /dev/null @@ -1,174 +0,0 @@ -# Tencent is pleased to support the open source community by making Polaris available. -# -# Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. -# -# Licensed under the BSD 3-Clause License (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://opensource.org/licenses/BSD-3-Clause -# -# 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. - -users: - - name: polaris - token: nu/0WRA4EqSR1FagrjRj0fZwPXuGlMpX+zCuWu4uMqy8xr1vRjisSbA25aAC3mtU8MeeRsKhQiDAynUR09I= - password: $2a$10$3izWuZtE5SBdAtSZci.gs.iZ2pAn9I8hEqYrC6gwJp1dyjqQnrrum - id: 65e4789a6d5b49669adf1e9e8387549c - tokenenable: true - type: 20 - valid: true -policies: - - id: fbca9bfa04ae4ead86e1ecf5811e32a9 - name: (用户) polaris的默认策略 - action: READ_WRITE - comment: default admin - default: true - owner: 65e4789a6d5b49669adf1e9e8387549c - calleemethods: ["*"] - resources: - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 6 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 7 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 20 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 0 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 3 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 4 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 5 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 21 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 22 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 23 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 1 - resid: "*" - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - restype: 2 - resid: "*" - conditions: [] - principals: - - strategyid: fbca9bfa04ae4ead86e1ecf5811e32a9 - principalid: 65e4789a6d5b49669adf1e9e8387549c - principaltype: 1 - valid: true - revision: fbca9bfa04ae4ead86e1ecf5811e32a9 - metadata: {} - - id: bfa04ae1e32a94fbca9ead86e1ecf581 - name: 全局只读策略 - action: ALLOW - comment: global resources read onyly - default: true - owner: 65e4789a6d5b49669adf1e9e8387549c - calleemethods: ["Describe*", "List*", "Get*"] - resources: - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 6 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 7 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 20 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 0 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 3 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 4 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 5 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 21 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 22 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 23 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 1 - resid: "*" - - strategyid: bfa04ae1e32a94fbca9ead86e1ecf581 - restype: 2 - resid: "*" - conditions: [] - principals: [] - valid: true - revision: 2a04ae4ead86e1e9bfacf59fbca811e3 - metadata: {} - - id: e3d86e1ecf5812bfa04ae1a94fbca9ea - name: 全局读写策略 - action: ALLOW - comment: global resources read and write - default: true - owner: 65e4789a6d5b49669adf1e9e8387549c - calleemethods: ["*"] - resources: - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 6 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 7 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 20 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 0 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 3 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 4 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 5 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 21 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 22 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 23 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 1 - resid: "*" - - strategyid: e3d86e1ecf5812bfa04ae1a94fbca9ea - restype: 2 - resid: "*" - conditions: [] - principals: [] - valid: true - revision: 4ead86e1e9bfac2a04aef59fbca811e3 - metadata: {} diff --git a/service/client_v1.go b/service/client_v1.go index 03924acc2..9f97cf798 100644 --- a/service/client_v1.go +++ b/service/client_v1.go @@ -237,9 +237,6 @@ func (s *Server) ServiceInstancesCache(ctx context.Context, filter *apiservice.D continue } revision := s.caches.Service().GetRevisionWorker().GetServiceInstanceRevision(svc.ID) - if revision == "" { - revision = utils.NewUUID() - } revisions = append(revisions, revision) for i := range ret { diff --git a/store/auth_api.go b/store/auth_api.go index 96f221ff6..0031d3e51 100644 --- a/store/auth_api.go +++ b/store/auth_api.go @@ -36,6 +36,8 @@ type AuthStore interface { // UserStore User-related operation interface type UserStore interface { + // GetMainUser Get the main account + GetMainUser() (*authcommon.User, error) // AddUser Create a user AddUser(tx Tx, user *authcommon.User) error // UpdateUser Update user @@ -50,11 +52,9 @@ type UserStore interface { GetUserByName(name, ownerId string) (*authcommon.User, error) // GetUserByIDS Get users according to USER IDS batch GetUserByIds(ids []string) ([]*authcommon.User, error) - // GetUsers Query user list - GetUsers(filters map[string]string, offset uint32, limit uint32) (uint32, []*authcommon.User, error) - // GetUsersForCache Used to refresh user cache + // GetMoreUsers Used to refresh user cache // 此方法用于 cache 增量更新,需要注意 mtime 应为数据库时间戳 - GetUsersForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.User, error) + GetMoreUsers(mtime time.Time, firstUpdate bool) ([]*authcommon.User, error) } // GroupStore User group storage operation interface @@ -69,9 +69,9 @@ type GroupStore interface { GetGroup(id string) (*authcommon.UserGroupDetail, error) // GetGroupByName Get user groups according to Name and Owner GetGroupByName(name, owner string) (*authcommon.UserGroup, error) - // GetUserGroupsForCache Refresh of getting user groups for cache + // GetMoreGroups Refresh of getting user groups for cache // 此方法用于 cache 增量更新,需要注意 mtime 应为数据库时间戳 - GetGroupsForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) + GetMoreGroups(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) } // StrategyStore Authentication policy related storage operation interface diff --git a/store/boltdb/group.go b/store/boltdb/group.go index 8f8e89962..d36b3c69a 100644 --- a/store/boltdb/group.go +++ b/store/boltdb/group.go @@ -264,8 +264,8 @@ func (gs *groupStore) GetGroupByName(name, owner string) (*authcommon.UserGroup, return ret.UserGroup, nil } -// GetGroupsForCache 查询用户分组数据,主要用于Cache更新 -func (gs *groupStore) GetGroupsForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) { +// GetMoreGroups 查询用户分组数据,主要用于Cache更新 +func (gs *groupStore) GetMoreGroups(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) { ret, err := gs.handler.LoadValuesByFilter(tblGroup, []string{GroupFieldModifyTime}, &groupForStore{}, func(m map[string]interface{}) bool { mt := m[GroupFieldModifyTime].(time.Time) diff --git a/store/boltdb/user.go b/store/boltdb/user.go index 5e8eeb804..c744e9067 100644 --- a/store/boltdb/user.go +++ b/store/boltdb/user.go @@ -20,14 +20,12 @@ package boltdb import ( "errors" "sort" - "strings" "time" bolt "go.etcd.io/bbolt" "go.uber.org/zap" authcommon "github.com/polarismesh/polaris/common/model/auth" - "github.com/polarismesh/polaris/common/utils" "github.com/polarismesh/polaris/store" ) @@ -75,6 +73,24 @@ type userStore struct { handler BoltHandler } +// GetMainUser . +func (u *userStore) GetMainUser() (*authcommon.User, error) { + users, err := u.handler.LoadValuesAll(tblUser, &userForStore{}) + if err != nil { + log.Error("[Store][User] get main user", zap.Error(err)) + return nil, store.Error(err) + } + + for i := range users { + user := users[i].(*userForStore) + if user.Type == int(authcommon.OwnerUserRole) { + return converToUserModel(user), nil + } + } + + return nil, nil +} + // AddUser 添加用户 func (us *userStore) AddUser(tx store.Tx, user *authcommon.User) error { @@ -271,165 +287,8 @@ func (us *userStore) GetSubCount(user *authcommon.User) (uint32, error) { return uint32(len(ret)), nil } -// GetUsers 获取用户列表 -func (us *userStore) GetUsers(filters map[string]string, offset uint32, limit uint32) (uint32, []*authcommon.User, error) { - if _, ok := filters["group_id"]; ok { - return us.getGroupUsers(filters, offset, limit) - } - - return us.getUsers(filters, offset, limit) -} - -// getUsers -// "name": 1, -// "owner": 1, -// "source": 1, -func (us *userStore) getUsers(filters map[string]string, offset uint32, limit uint32) (uint32, []*authcommon.User, error) { - fields := []string{UserFieldID, UserFieldName, UserFieldOwner, UserFieldSource, UserFieldValid, UserFieldType} - ret, err := us.handler.LoadValuesByFilter(tblUser, fields, &userForStore{}, - func(m map[string]interface{}) bool { - - valid, ok := m[UserFieldValid].(bool) - if ok && !valid { - return false - } - - saveId, _ := m[UserFieldID].(string) - saveName, _ := m[UserFieldName].(string) - saveOwner, _ := m[UserFieldOwner].(string) - saveSource, _ := m[UserFieldSource].(string) - saveType, _ := m[UserFieldType].(int64) - - // 超级账户不做展示 - if authcommon.UserRoleType(saveType) == authcommon.AdminUserRole && - strings.Compare("true", filters["hide_admin"]) == 0 { - return false - } - - if name, ok := filters["name"]; ok { - if utils.IsPrefixWildName(name) { - if !strings.Contains(saveName, name[:len(name)-1]) { - return false - } - } else { - if saveName != name { - return false - } - } - } - - if owner, ok := filters["owner"]; ok { - if owner != saveOwner && saveId != owner { - return false - } - } - - if source, ok := filters["source"]; ok { - if source != saveSource { - return false - } - } - - if queryId, ok := filters["id"]; ok { - if queryId != saveId { - return false - } - } - - return true - }) - - if err != nil { - log.Error("[Store][User] get users", zap.Error(err), zap.Any("filters", filters)) - return 0, nil, err - } - if len(ret) == 0 { - return 0, nil, nil - } - - return uint32(len(ret)), doUserPage(ret, offset, limit), nil -} - -// getGroupUsers 获取某个用户组下的所有用户列表数据信息 -func (us *userStore) getGroupUsers(filters map[string]string, offset uint32, limit uint32) (uint32, - []*authcommon.User, error) { - - groupId := filters["group_id"] - delete(filters, "group_id") - - ret, err := us.handler.LoadValues(tblGroup, []string{groupId}, &groupForStore{}) - if err != nil { - log.Error("[Store][User] get user groups", zap.Error(err), zap.Any("filters", filters)) - return 0, nil, err - } - if len(ret) == 0 { - return 0, nil, nil - } - if len(ret) > 1 { - return 0, nil, ErrorMultipleGroupFound - } - group := ret[groupId].(*groupForStore) - - userIds := make([]string, 0, len(group.UserIds)) - for k := range group.UserIds { - userIds = append(userIds, k) - } - - ret, err = us.handler.LoadValues(tblUser, userIds, &userForStore{}) - if err != nil { - log.Error("[Store][User] get all users", zap.Error(err)) - return 0, nil, err - } - - predicate := func(user *userForStore) bool { - if !user.Valid { - return false - } - - if authcommon.UserRoleType(user.Type) == authcommon.AdminUserRole { - return false - } - - if name, ok := filters["name"]; ok { - if utils.IsPrefixWildName(name) { - if !strings.Contains(user.Name, name[:len(name)-1]) { - return false - } - } else { - if user.Name != name { - return false - } - } - } - - if owner, ok := filters["owner"]; ok { - if owner != user.Owner { - return false - } - } - - if source, ok := filters["source"]; ok { - if source != user.Source { - return false - } - } - - return true - } - - users := make(map[string]interface{}) - for k := range ret { - val := ret[k] - if predicate(val.(*userForStore)) { - users[k] = val.(*userForStore) - } - } - - return uint32(len(ret)), doUserPage(users, offset, limit), err -} - -// GetUsersForCache 获取所有用户信息 -func (us *userStore) GetUsersForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.User, error) { +// GetMoreUsers 获取所有用户信息 +func (us *userStore) GetMoreUsers(mtime time.Time, firstUpdate bool) ([]*authcommon.User, error) { fields := []string{UserFieldModifyTime, UserFieldValid} ret, err := us.handler.LoadValuesByFilter(tblUser, fields, &userForStore{}, func(m map[string]interface{}) bool { diff --git a/store/boltdb/user_test.go b/store/boltdb/user_test.go index 1c5441513..4e6728046 100644 --- a/store/boltdb/user_test.go +++ b/store/boltdb/user_test.go @@ -274,128 +274,3 @@ func Test_userStore_GetSubCount(t *testing.T) { }) } - -func Test_userStore_GetUsers(t *testing.T) { - CreateTableDBHandlerAndRun(t, "test_user", func(t *testing.T, handler BoltHandler) { - us := &userStore{handler: handler} - - users := createTestUsers(10) - - for i := range users { - tx, err := handler.StartTx() - assert.NoError(t, err) - if err := us.AddUser(tx, users[i]); err != nil { - t.Fatal(err) - } - assert.NoError(t, tx.Commit()) - } - - total, ret, err := us.GetUsers(map[string]string{ - "name": "ser*", - }, 0, 2) - - if err != nil { - t.Fatal(err) - } - - if !assert.Equal(t, 2, len(ret)) { - t.Fatal("len(ret) != limit(2)") - } - - if !assert.Equal(t, 10, int(total)) { - t.Fatal("total != 10") - } - - total, ret, err = us.GetUsers(map[string]string{ - "name": "pser*", - }, 0, 2) - - if err != nil { - t.Fatal(err) - } - - if !assert.Equal(t, 0, len(ret)) { - t.Fatal("len(ret) need to zero") - } - - if !assert.Equal(t, 0, int(total)) { - t.Fatal("total != 0") - } - - admins := createTestUsers(1) - admins[0].ID = "admin" - admins[0].Name = "admin" - admins[0].Type = authcommon.AdminUserRole - - tx, err := handler.StartTx() - assert.NoError(t, err) - if err := us.AddUser(tx, admins[0]); err != nil { - t.Fatal(err) - } - assert.NoError(t, tx.Commit()) - - total, ret, err = us.GetUsers(map[string]string{ - "hide_admin": "true", - }, 0, 1000) - - if !assert.Equal(t, 10, len(ret)) { - t.Fatal("len(ret) not equal 10") - } - - if !assert.Equal(t, 10, int(total)) { - t.Fatal("total != 10") - } - - total, ret, err = us.GetUsers(map[string]string{ - "hide_admin": "false", - }, 0, 1000) - - if !assert.Equal(t, 11, len(ret)) { - t.Fatal("len(ret) not equal 11") - } - - if !assert.Equal(t, 11, int(total)) { - t.Fatal("total != 11") - } - }) -} - -func Test_userStore_GetUsersByGroup(t *testing.T) { - CreateTableDBHandlerAndRun(t, "test_user", func(t *testing.T, handler BoltHandler) { - us := &userStore{handler: handler} - gs := &groupStore{handler: handler} - - groups := createTestUserGroup(1) - tx, err := handler.StartTx() - assert.NoError(t, err) - for i := range groups { - if err := gs.AddGroup(tx, groups[i]); err != nil { - t.Fatal(err) - } - } - - users := createTestUsers(10) - for i := range users { - if err := us.AddUser(tx, users[i]); err != nil { - t.Fatal(err) - } - } - assert.NoError(t, tx.Commit()) - - total, ret, err := us.GetUsers(map[string]string{ - "group_id": groups[0].ID, - }, 0, 100) - - if err != nil { - t.Fatal(err) - } - - if !assert.Equal(t, 1, len(ret)) { - t.Fatal("len(ret) need to zero") - } - - if !assert.Equal(t, 1, int(total)) { - t.Fatal("total != 0") - } - }) -} diff --git a/store/mock/api_mock.go b/store/mock/api_mock.go index 57ffee0af..18bfc97b9 100644 --- a/store/mock/api_mock.go +++ b/store/mock/api_mock.go @@ -1349,37 +1349,6 @@ func (mr *MockStoreMockRecorder) GetGroupByName(name, owner interface{}) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupByName", reflect.TypeOf((*MockStore)(nil).GetGroupByName), name, owner) } -// GetGroups mocks base method. -func (m *MockStore) GetGroups(filters map[string]string, offset, limit uint32) (uint32, []*auth.UserGroup, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetGroups", filters, offset, limit) - ret0, _ := ret[0].(uint32) - ret1, _ := ret[1].([]*auth.UserGroup) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// GetGroups indicates an expected call of GetGroups. -func (mr *MockStoreMockRecorder) GetGroups(filters, offset, limit interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroups", reflect.TypeOf((*MockStore)(nil).GetGroups), filters, offset, limit) -} - -// GetGroupsForCache mocks base method. -func (m *MockStore) GetGroupsForCache(mtime time.Time, firstUpdate bool) ([]*auth.UserGroupDetail, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetGroupsForCache", mtime, firstUpdate) - ret0, _ := ret[0].([]*auth.UserGroupDetail) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetGroupsForCache indicates an expected call of GetGroupsForCache. -func (mr *MockStoreMockRecorder) GetGroupsForCache(mtime, firstUpdate interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsForCache", reflect.TypeOf((*MockStore)(nil).GetGroupsForCache), mtime, firstUpdate) -} - // GetInstance mocks base method. func (m *MockStore) GetInstance(instanceID string) (*model.Instance, error) { m.ctrl.T.Helper() @@ -1547,6 +1516,21 @@ func (mr *MockStoreMockRecorder) GetLaneRuleMaxPriority() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLaneRuleMaxPriority", reflect.TypeOf((*MockStore)(nil).GetLaneRuleMaxPriority)) } +// GetMainUser mocks base method. +func (m *MockStore) GetMainUser() (*auth.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMainUser") + ret0, _ := ret[0].(*auth.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMainUser indicates an expected call of GetMainUser. +func (mr *MockStoreMockRecorder) GetMainUser() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMainUser", reflect.TypeOf((*MockStore)(nil).GetMainUser)) +} + // GetMoreClients mocks base method. func (m *MockStore) GetMoreClients(mtime time.Time, firstUpdate bool) (map[string]*model.Client, error) { m.ctrl.T.Helper() @@ -1592,6 +1576,21 @@ func (mr *MockStoreMockRecorder) GetMoreGrayResouces(firstUpdate, mtime interfac return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMoreGrayResouces", reflect.TypeOf((*MockStore)(nil).GetMoreGrayResouces), firstUpdate, mtime) } +// GetMoreGroups mocks base method. +func (m *MockStore) GetMoreGroups(mtime time.Time, firstUpdate bool) ([]*auth.UserGroupDetail, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMoreGroups", mtime, firstUpdate) + ret0, _ := ret[0].([]*auth.UserGroupDetail) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMoreGroups indicates an expected call of GetMoreGroups. +func (mr *MockStoreMockRecorder) GetMoreGroups(mtime, firstUpdate interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMoreGroups", reflect.TypeOf((*MockStore)(nil).GetMoreGroups), mtime, firstUpdate) +} + // GetMoreInstances mocks base method. func (m *MockStore) GetMoreInstances(tx store.Tx, mtime time.Time, firstUpdate, needMeta bool, serviceID []string) (map[string]*model.Instance, error) { m.ctrl.T.Helper() @@ -1787,6 +1786,21 @@ func (mr *MockStoreMockRecorder) GetMoreStrategies(mtime, firstUpdate interface{ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMoreStrategies", reflect.TypeOf((*MockStore)(nil).GetMoreStrategies), mtime, firstUpdate) } +// GetMoreUsers mocks base method. +func (m *MockStore) GetMoreUsers(mtime time.Time, firstUpdate bool) ([]*auth.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetMoreUsers", mtime, firstUpdate) + ret0, _ := ret[0].([]*auth.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetMoreUsers indicates an expected call of GetMoreUsers. +func (mr *MockStoreMockRecorder) GetMoreUsers(mtime, firstUpdate interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMoreUsers", reflect.TypeOf((*MockStore)(nil).GetMoreUsers), mtime, firstUpdate) +} + // GetNamespace mocks base method. func (m *MockStore) GetNamespace(name string) (*model.Namespace, error) { m.ctrl.T.Helper() @@ -2107,22 +2121,6 @@ func (mr *MockStoreMockRecorder) GetSourceServiceToken(name, namespace interface return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSourceServiceToken", reflect.TypeOf((*MockStore)(nil).GetSourceServiceToken), name, namespace) } -// GetStrategies mocks base method. -func (m *MockStore) GetStrategies(filters map[string]string, offset, limit uint32) (uint32, []*auth.StrategyDetail, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetStrategies", filters, offset, limit) - ret0, _ := ret[0].(uint32) - ret1, _ := ret[1].([]*auth.StrategyDetail) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// GetStrategies indicates an expected call of GetStrategies. -func (mr *MockStoreMockRecorder) GetStrategies(filters, offset, limit interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStrategies", reflect.TypeOf((*MockStore)(nil).GetStrategies), filters, offset, limit) -} - // GetStrategyDetail mocks base method. func (m *MockStore) GetStrategyDetail(id string) (*auth.StrategyDetail, error) { m.ctrl.T.Helper() @@ -2258,37 +2256,6 @@ func (mr *MockStoreMockRecorder) GetUserByName(name, ownerId interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByName", reflect.TypeOf((*MockStore)(nil).GetUserByName), name, ownerId) } -// GetUsers mocks base method. -func (m *MockStore) GetUsers(filters map[string]string, offset, limit uint32) (uint32, []*auth.User, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUsers", filters, offset, limit) - ret0, _ := ret[0].(uint32) - ret1, _ := ret[1].([]*auth.User) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// GetUsers indicates an expected call of GetUsers. -func (mr *MockStoreMockRecorder) GetUsers(filters, offset, limit interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsers", reflect.TypeOf((*MockStore)(nil).GetUsers), filters, offset, limit) -} - -// GetUsersForCache mocks base method. -func (m *MockStore) GetUsersForCache(mtime time.Time, firstUpdate bool) ([]*auth.User, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUsersForCache", mtime, firstUpdate) - ret0, _ := ret[0].([]*auth.User) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUsersForCache indicates an expected call of GetUsersForCache. -func (mr *MockStoreMockRecorder) GetUsersForCache(mtime, firstUpdate interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsersForCache", reflect.TypeOf((*MockStore)(nil).GetUsersForCache), mtime, firstUpdate) -} - // HasCircuitBreakerRule mocks base method. func (m *MockStore) HasCircuitBreakerRule(id string) (bool, error) { m.ctrl.T.Helper() diff --git a/store/mysql/group.go b/store/mysql/group.go index b68be72ed..1c9b0b3b9 100644 --- a/store/mysql/group.go +++ b/store/mysql/group.go @@ -266,8 +266,8 @@ func (u *groupStore) GetGroupByName(name, owner string) (*authcommon.UserGroup, return group, nil } -// GetGroupsForCache . -func (u *groupStore) GetGroupsForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) { +// GetMoreGroups . +func (u *groupStore) GetMoreGroups(mtime time.Time, firstUpdate bool) ([]*authcommon.UserGroupDetail, error) { tx, err := u.slave.Begin() if err != nil { return nil, store.Error(err) diff --git a/store/mysql/scripts/delta/v1_18_1-v1_19_0.sql b/store/mysql/scripts/delta/v1_18_1-v1_19_0.sql index 04548adc0..bfdb33c2b 100644 --- a/store/mysql/scripts/delta/v1_18_1-v1_19_0.sql +++ b/store/mysql/scripts/delta/v1_18_1-v1_19_0.sql @@ -56,4 +56,280 @@ CRAETE TABLE `auth_strategy_function` ( `strategy_id` VARCHAR(128) NOT NULL COMMENT 'strategy id', `function` VARCHAR(256) NOT NULL COMMENT 'server provider function name', PRIMARY KEY (`strategy_id`, `function`) -) ENGINE = InnoDB; \ No newline at end of file +) ENGINE = InnoDB; + +/* 默认全局读写以及全局只读策略 */ +-- Insert permission policies and association relationships for Polaris-Admin accounts +INSERT INTO + auth_principal (`strategy_id`, `principal_id`, `principal_role`) +VALUES + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + '65e4789a6d5b49669adf1e9e8387549c', + 1 + ); + +INSERT INTO + auth_strategy_function (`strategy_id`, `function`) +VALUES + ('fbca9bfa04ae4ead86e1ecf5811e32a9', '*'); + +/* 默认的全局只读策略 */ +INSERT INTO + `auth_strategy` ( + `id`, + `name`, + `action`, + `owner`, + `comment`, + `default`, + `source`, + `revision`, + `flag`, + `ctime`, + `mtime` + ) +VALUES + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + '全局只读策略', + 'ALLOW', + '65e4789a6d5b49669adf1e9e8387549c', + 'global resources read only', + 1, + 'Polaris', + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 0, + sysdate(), + sysdate() + ); + +INSERT INTO + `auth_strategy_resource` ( + `strategy_id`, + `res_type`, + `res_id`, + `ctime`, + `mtime` + ) +VALUES + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 0, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 1, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 2, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 3, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 4, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 5, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 6, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 7, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 20, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 21, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 22, + '*', + sysdate(), + sysdate() + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 23, + '*', + sysdate(), + sysdate() + ); + +INSERT INTO + auth_strategy_function (`strategy_id`, `function`) +VALUES + ('bfa04ae1e32a94fbca9ead86e1ecf581', 'Describe*'), + ('bfa04ae1e32a94fbca9ead86e1ecf581', 'List*'), + ('bfa04ae1e32a94fbca9ead86e1ecf581', 'Get*'); + +/* 默认的全局读写策略 */ +INSERT INTO + `auth_strategy` ( + `id`, + `name`, + `action`, + `owner`, + `comment`, + `default`, + `source`, + `revision`, + `flag`, + `ctime`, + `mtime` + ) +VALUES + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + '全局读写策略', + 'ALLOW', + '65e4789a6d5b49669adf1e9e8387549c', + 'global resources read and write', + 1, + 'Polaris', + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 0, + sysdate(), + sysdate() + ); + +INSERT INTO + `auth_strategy_resource` ( + `strategy_id`, + `res_type`, + `res_id`, + `ctime`, + `mtime` + ) +VALUES + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 0, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 1, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 2, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 3, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 4, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 5, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 6, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 7, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 20, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 21, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 22, + '*', + sysdate(), + sysdate() + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 23, + '*', + sysdate(), + sysdate() + ); + +INSERT INTO + auth_strategy_function (`strategy_id`, `function`) +VALUES + ('e3d86e1ecf5812bfa04ae1a94fbca9ea', '*'); \ No newline at end of file diff --git a/store/mysql/scripts/polaris_server.sql b/store/mysql/scripts/polaris_server.sql index f7a470a58..4ef3a7df7 100644 --- a/store/mysql/scripts/polaris_server.sql +++ b/store/mysql/scripts/polaris_server.sql @@ -694,20 +694,22 @@ CREATE TABLE ) ENGINE = InnoDB; /* 鉴权策略中的资源标签关联信息 */ -CREATE TABLE `auth_strategy_label` ( - `strategy_id` VARCHAR(128) NOT NULL COMMENT 'strategy id', - `key` VARCHAR(128) NOT NULL COMMENT 'tag key', - `value` TEXT NOT NULL COMMENT 'tag value', - `compare_type` VARCHAR(128) NOT NULL COMMENT 'tag kv compare func', - PRIMARY KEY (`strategy_id`, `key`) -) ENGINE = InnoDB; +CREATE TABLE + `auth_strategy_label` ( + `strategy_id` VARCHAR(128) NOT NULL COMMENT 'strategy id', + `key` VARCHAR(128) NOT NULL COMMENT 'tag key', + `value` TEXT NOT NULL COMMENT 'tag value', + `compare_type` VARCHAR(128) NOT NULL COMMENT 'tag kv compare func', + PRIMARY KEY (`strategy_id`, `key`) + ) ENGINE = InnoDB; /* 鉴权策略中的资源标签关联信息 */ -CREATE TABLE `auth_strategy_function` ( - `strategy_id` VARCHAR(128) NOT NULL COMMENT 'strategy id', - `function` VARCHAR(256) NOT NULL COMMENT 'server provider function name', - PRIMARY KEY (`strategy_id`, `function`) -) ENGINE = InnoDB; +CREATE TABLE + `auth_strategy_function` ( + `strategy_id` VARCHAR(128) NOT NULL COMMENT 'strategy id', + `function` VARCHAR(256) NOT NULL COMMENT 'server provider function name', + PRIMARY KEY (`strategy_id`, `function`) + ) ENGINE = InnoDB; -- v1.8.0, support client info storage CREATE TABLE @@ -966,445 +968,3 @@ CREATE TABLE PRIMARY KEY (`id`), UNIQUE KEY `name` (`group_name`, `name`) ) ENGINE = InnoDB; - - -/* 默认资源信息数据插入 */ - --- Create a default master account, password is Polarismesh @ 2021 -INSERT INTO - `user` ( - `id`, - `name`, - `password`, - `source`, - `token`, - `token_enable`, - `user_type`, - `comment`, - `mobile`, - `email`, - `owner` - ) -VALUES - ( - '65e4789a6d5b49669adf1e9e8387549c', - 'polaris', - '$2a$10$3izWuZtE5SBdAtSZci.gs.iZ2pAn9I8hEqYrC6gwJp1dyjqQnrrum', - 'Polaris', - 'nu/0WRA4EqSR1FagrjRj0fZwPXuGlMpX+zCuWu4uMqy8xr1vRjisSbA25aAC3mtU8MeeRsKhQiDAynUR09I=', - 1, - 20, - 'default polaris admin account', - '12345678910', - '12345678910', - '' - ); - --- Permissions policy inserted into Polaris-Admin -INSERT INTO - `auth_strategy` ( - `id`, - `name`, - `action`, - `owner`, - `comment`, - `default`, - `source`, - `revision`, - `flag`, - `ctime`, - `mtime` - ) -VALUES - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - '(用户) polaris的默认策略', - 'READ_WRITE', - '65e4789a6d5b49669adf1e9e8387549c', - 'default admin', - 1, - 'Polaris', - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 0, - sysdate(), - sysdate() - ); - --- Sport rules inserted into Polaris-Admin to access -INSERT INTO - `auth_strategy_resource` ( - `strategy_id`, - `res_type`, - `res_id`, - `ctime`, - `mtime` - ) -VALUES - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 0, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 1, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 2, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 3, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 4, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 5, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 6, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 7, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 20, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 21, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 22, - '*', - sysdate(), - sysdate() - ), - ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 23, - '*', - sysdate(), - sysdate() - ); - --- Insert permission policies and association relationships for Polaris-Admin accounts -INSERT INTO - auth_principal (`strategy_id`, `principal_id`, `principal_role`) VALUES ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - '65e4789a6d5b49669adf1e9e8387549c', - 1 - ); - -INSERT INTO - auth_strategy_function (`strategy_id`, `function`) VALUES ( - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - '*' - ); - -/* 默认的全局只读策略 */ -INSERT INTO - `auth_strategy` ( - `id`, - `name`, - `action`, - `owner`, - `comment`, - `default`, - `source`, - `revision`, - `flag`, - `ctime`, - `mtime` - ) -VALUES - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - '全局只读策略', - 'ALLOW', - '65e4789a6d5b49669adf1e9e8387549c', - 'global resources read onyly', - 1, - 'Polaris', - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 0, - sysdate(), - sysdate() - ); - -INSERT INTO - `auth_strategy_resource` ( - `strategy_id`, - `res_type`, - `res_id`, - `ctime`, - `mtime` - ) -VALUES - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 0, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 1, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 2, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 3, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 4, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 5, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 6, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 7, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 20, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 21, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 22, - '*', - sysdate(), - sysdate() - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 23, - '*', - sysdate(), - sysdate() - ); - -INSERT INTO - auth_strategy_function (`strategy_id`, `function`) VALUES ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 'Describe*' - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 'List*' - ), - ( - 'bfa04ae1e32a94fbca9ead86e1ecf581', - 'Get*' - ); - - -/* 默认的全局读写策略 */ -INSERT INTO - `auth_strategy` ( - `id`, - `name`, - `action`, - `owner`, - `comment`, - `default`, - `source`, - `revision`, - `flag`, - `ctime`, - `mtime` - ) -VALUES - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - '全局读写策略', - 'ALLOW', - '65e4789a6d5b49669adf1e9e8387549c', - 'global resources read and write', - 1, - 'Polaris', - 'fbca9bfa04ae4ead86e1ecf5811e32a9', - 0, - sysdate(), - sysdate() - ); - -INSERT INTO - `auth_strategy_resource` ( - `strategy_id`, - `res_type`, - `res_id`, - `ctime`, - `mtime` - ) -VALUES - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 0, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 1, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 2, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 3, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 4, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 5, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 6, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 7, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 20, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 21, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 22, - '*', - sysdate(), - sysdate() - ), - ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - 23, - '*', - sysdate(), - sysdate() - ); - -INSERT INTO - auth_strategy_function (`strategy_id`, `function`) VALUES ( - 'e3d86e1ecf5812bfa04ae1a94fbca9ea', - '*' - ); - diff --git a/store/mysql/user.go b/store/mysql/user.go index cdc11f611..03ab8e57a 100644 --- a/store/mysql/user.go +++ b/store/mysql/user.go @@ -25,7 +25,6 @@ import ( "go.uber.org/zap" authcommon "github.com/polarismesh/polaris/common/model/auth" - "github.com/polarismesh/polaris/common/utils" "github.com/polarismesh/polaris/store" ) @@ -51,6 +50,36 @@ type userStore struct { slave *BaseDB } +// GetMainUser . +func (u *userStore) GetMainUser() (*authcommon.User, error) { + var tokenEnable, userType int + getSql := ` + SELECT u.id, u.name, u.password, u.owner, u.comment, u.source, u.token, u.token_enable, + u.user_type, u.mobile, u.email + FROM user u + WHERE u.flag = 0 AND u.type = ? + ` + row := u.master.QueryRow(getSql, authcommon.OwnerUserRole) + + user := &authcommon.User{} + if err := row.Scan(&user.ID, &user.Name, &user.Password, &user.Owner, &user.Comment, &user.Source, + &user.Token, &tokenEnable, &userType, &user.Mobile, &user.Email); err != nil { + switch err { + case sql.ErrNoRows: + return nil, nil + default: + return nil, store.Error(err) + } + } + + user.TokenEnable = tokenEnable == 1 + user.Type = authcommon.UserRoleType(userType) + // 北极星后续不在保存用户的 mobile 以及 email 信息,这里针对原来保存的数据也不进行对外展示,强制屏蔽数据 + user.Mobile = "" + user.Email = "" + return user, nil +} + // AddUser 添加用户 func (u *userStore) AddUser(tx store.Tx, user *authcommon.User) error { if user.ID == "" || user.Name == "" || user.Token == "" || user.Password == "" { @@ -302,146 +331,8 @@ func (u *userStore) GetUserByIds(ids []string) ([]*authcommon.User, error) { return users, nil } -// GetUsers Query user list information -// Case 1. From the user's perspective, normal query conditions -// Case 2. From the perspective of the user group, query is the list of users involved under a user group. -func (u *userStore) GetUsers(filters map[string]string, offset uint32, limit uint32) (uint32, - []*authcommon.User, error) { - if _, ok := filters["group_id"]; ok { - return u.listGroupUsers(filters, offset, limit) - } - return u.listUsers(filters, offset, limit) -} - -// listUsers Query user list information -func (u *userStore) listUsers(filters map[string]string, offset uint32, limit uint32) (uint32, - []*authcommon.User, error) { - countSql := "SELECT COUNT(*) FROM user WHERE flag = 0 " - getSql := ` - SELECT id, name, password, owner, comment, source - , token, token_enable, user_type, UNIX_TIMESTAMP(ctime) - , UNIX_TIMESTAMP(mtime), flag, mobile, email - FROM user - WHERE flag = 0 - ` - - if val, ok := filters["hide_admin"]; ok && val == "true" { - delete(filters, "hide_admin") - countSql += " AND user_type != 0 " - getSql += " AND user_type != 0 " - } - - args := make([]interface{}, 0) - - if len(filters) != 0 { - for k, v := range filters { - getSql += " AND " - countSql += " AND " - if k == NameAttribute { - if utils.IsPrefixWildName(v) { - getSql += " " + k + " like ? " - countSql += " " + k + " like ? " - args = append(args, "%"+v[:len(v)-1]+"%") - } else { - getSql += " " + k + " = ? " - countSql += " " + k + " = ? " - args = append(args, v) - } - } else if k == OwnerAttribute { - getSql += " (id = ? OR owner = ?) " - countSql += " (id = ? OR owner = ?) " - args = append(args, v, v) - continue - } else { - getSql += " " + k + " = ? " - countSql += " " + k + " = ? " - args = append(args, v) - } - } - } - - count, err := queryEntryCount(u.master, countSql, args) - if err != nil { - return 0, nil, store.Error(err) - } - - getSql += " ORDER BY mtime LIMIT ? , ?" - getArgs := append(args, offset, limit) - - users, err := u.collectUsers(u.master.Query, getSql, getArgs) - if err != nil { - return 0, nil, err - } - return count, users, nil -} - -// listGroupUsers Check the user information under a user group -func (u *userStore) listGroupUsers(filters map[string]string, offset uint32, limit uint32) (uint32, - []*authcommon.User, error) { - if _, ok := filters[GroupIDAttribute]; !ok { - return 0, nil, store.NewStatusError(store.EmptyParamsErr, "group_id is missing") - } - - args := make([]interface{}, 0, len(filters)) - querySql := ` - SELECT u.id, name, password, owner, u.comment, source - , token, token_enable, user_type, UNIX_TIMESTAMP(u.ctime) - , UNIX_TIMESTAMP(u.mtime), u.flag, u.mobile, u.email - FROM user_group_relation ug - LEFT JOIN user u ON ug.user_id = u.id AND u.flag = 0 - WHERE 1=1 - ` - countSql := ` - SELECT COUNT(*) - FROM user_group_relation ug - LEFT JOIN user u ON ug.user_id = u.id AND u.flag = 0 - WHERE 1=1 - ` - - if val, ok := filters["hide_admin"]; ok && val == "true" { - delete(filters, "hide_admin") - countSql += " AND u.user_type != 0 " - querySql += " AND u.user_type != 0 " - } - - for k, v := range filters { - if newK, ok := userLinkGroupAttributeMapping[k]; ok { - k = newK - } - - if k == "ug.owner" { - k = "u.owner" - } - - if utils.IsPrefixWildName(v) { - querySql += " AND " + k + " like ?" - countSql += " AND " + k + " like ?" - args = append(args, v[:len(v)-1]+"%") - } else { - querySql += " AND " + k + " = ?" - countSql += " AND " + k + " = ?" - args = append(args, v) - } - } - - count, err := queryEntryCount(u.slave, countSql, args) - if err != nil { - return 0, nil, err - } - - querySql += " ORDER BY u.mtime LIMIT ? , ?" - args = append(args, offset, limit) - - users, err := u.collectUsers(u.master.Query, querySql, args) - if err != nil { - return 0, nil, err - } - - return count, users, nil -} - -// GetUsersForCache Get user information, mainly for cache -func (u *userStore) GetUsersForCache(mtime time.Time, firstUpdate bool) ([]*authcommon.User, error) { +// GetMoreUsers Get user information, mainly for cache +func (u *userStore) GetMoreUsers(mtime time.Time, firstUpdate bool) ([]*authcommon.User, error) { args := make([]interface{}, 0) querySql := ` SELECT u.id, u.name, u.password, u.owner, u.comment, u.source From 897c1acff57dc35be6b4865a33f4b8723275a531 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 23 Oct 2024 14:04:50 +0800 Subject: [PATCH 07/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=88=9D=E5=A7=8B=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/interceptor/paramcheck/config_file_check.go | 8 ++++++-- config/interceptor/paramcheck/server.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/config/interceptor/paramcheck/config_file_check.go b/config/interceptor/paramcheck/config_file_check.go index 72c8bac56..cf70f043b 100644 --- a/config/interceptor/paramcheck/config_file_check.go +++ b/config/interceptor/paramcheck/config_file_check.go @@ -31,7 +31,9 @@ import ( // CreateConfigFile 创建配置文件 func (s *Server) CreateConfigFile(ctx context.Context, configFile *apiconfig.ConfigFile) *apiconfig.ConfigResponse { - + if checkRsp := s.checkConfigFileParams(configFile); checkRsp != nil { + return api.NewConfigFileResponse(apimodel.Code(checkRsp.Code.GetValue()), configFile) + } return s.nextServer.CreateConfigFile(ctx, configFile) } @@ -73,7 +75,9 @@ func (s *Server) SearchConfigFile(ctx context.Context, // UpdateConfigFile 更新配置文件 func (s *Server) UpdateConfigFile( ctx context.Context, configFile *apiconfig.ConfigFile) *apiconfig.ConfigResponse { - + if checkRsp := s.checkConfigFileParams(configFile); checkRsp != nil { + return api.NewConfigFileResponse(apimodel.Code(checkRsp.Code.GetValue()), configFile) + } return s.nextServer.UpdateConfigFile(ctx, configFile) } diff --git a/config/interceptor/paramcheck/server.go b/config/interceptor/paramcheck/server.go index 05b264c7d..01dd24220 100644 --- a/config/interceptor/paramcheck/server.go +++ b/config/interceptor/paramcheck/server.go @@ -118,7 +118,7 @@ func (s *Server) checkConfigFileParams(configFile *apiconfig.ConfigFile) *apicon } if len(configFile.Tags) > 0 { for _, tag := range configFile.Tags { - if tag.Key.GetValue() == "" || tag.Value.GetValue() == "" { + if tag.Key.GetValue() == "" { return api.NewConfigFileResponse(apimodel.Code_InvalidConfigFileTags, configFile) } } From 450d53c239b3cd0668a65a786be7a40f1decd1bd Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 23 Oct 2024 14:42:39 +0800 Subject: [PATCH 08/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=88=9D=E5=A7=8B=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98?= =?UTF-8?q?=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apiserver/grpcserver/config/client_access.go | 2 +- config/api.go | 2 -- config/client.go | 6 ---- config/config_file_release.go | 36 +++++++++++++++---- config/config_file_release_test.go | 8 ++--- config/interceptor/auth/client.go | 16 --------- config/interceptor/paramcheck/client_check.go | 15 -------- 7 files changed, 35 insertions(+), 50 deletions(-) diff --git a/apiserver/grpcserver/config/client_access.go b/apiserver/grpcserver/config/client_access.go index 9c04d4a7e..9be53a89c 100644 --- a/apiserver/grpcserver/config/client_access.go +++ b/apiserver/grpcserver/config/client_access.go @@ -91,7 +91,7 @@ func (g *ConfigGRPCServer) PublishConfigFile(ctx context.Context, func (g *ConfigGRPCServer) UpsertAndPublishConfigFile(ctx context.Context, req *apiconfig.ConfigFilePublishInfo) (*apiconfig.ConfigClientResponse, error) { ctx = utils.ConvertGRPCContext(ctx) - response := g.configServer.CasUpsertAndReleaseConfigFileFromClient(ctx, req) + response := g.configServer.UpsertAndReleaseConfigFileFromClient(ctx, req) return &apiconfig.ConfigClientResponse{ Code: response.Code, Info: response.Info, diff --git a/config/api.go b/config/api.go index 432871f77..78c35a94b 100644 --- a/config/api.go +++ b/config/api.go @@ -105,8 +105,6 @@ type ConfigFileClientOperate interface { PublishConfigFileFromClient(ctx context.Context, req *apiconfig.ConfigFileRelease) *apiconfig.ConfigClientResponse // UpsertAndReleaseConfigFile 创建/更新配置文件并发布 UpsertAndReleaseConfigFileFromClient(ctx context.Context, req *apiconfig.ConfigFilePublishInfo) *apiconfig.ConfigResponse - // CasUpsertAndReleaseConfigFileFromClient 创建/更新配置文件并发布 - CasUpsertAndReleaseConfigFileFromClient(ctx context.Context, req *apiconfig.ConfigFilePublishInfo) *apiconfig.ConfigResponse // LongPullWatchFile 客户端监听配置文件 LongPullWatchFile(ctx context.Context, req *apiconfig.ClientWatchConfigFileRequest) (WatchCallback, error) // GetConfigFileNamesWithCache 获取某个配置分组下的配置文件 diff --git a/config/client.go b/config/client.go index 5636b5cb2..ed8f0207c 100644 --- a/config/client.go +++ b/config/client.go @@ -327,9 +327,3 @@ func (s *Server) PublishConfigFileFromClient(ctx context.Context, configResponse := s.PublishConfigFile(ctx, client) return api.NewConfigClientResponseFromConfigResponse(configResponse) } - -// CasUpsertAndReleaseConfigFileFromClient 创建/更新配置文件并发布 -func (s *Server) CasUpsertAndReleaseConfigFileFromClient(ctx context.Context, - req *apiconfig.ConfigFilePublishInfo) *apiconfig.ConfigResponse { - return s.CasUpsertAndReleaseConfigFile(ctx, req) -} diff --git a/config/config_file_release.go b/config/config_file_release.go index 3f361858c..f69f3f982 100644 --- a/config/config_file_release.go +++ b/config/config_file_release.go @@ -604,24 +604,48 @@ func (s *Server) UpsertAndReleaseConfigFile(ctx context.Context, tx, err := s.storage.StartTx() if err != nil { - log.Error("[Config][File] upsert config file when begin tx.", utils.RequestID(ctx), zap.Error(err)) + log.Error("[Config][File] upsert config file when begin tx.", utils.RequestID(ctx), + zap.String("namespace", req.GetNamespace().GetValue()), zap.String("group", req.GetGroup().GetValue()), + zap.String("fileName", req.GetFileName().GetValue()), zap.Error(err)) return api.NewConfigResponse(commonstore.StoreCode2APICode(err)) } defer func() { _ = tx.Rollback() }() + saveFile, err := s.storage.LockConfigFile(tx, &model.ConfigFileKey{ + Namespace: req.GetNamespace().GetValue(), + Group: req.GetGroup().GetValue(), + Name: req.GetFileName().GetValue(), + }) + if err != nil { + log.Error("[Config][File] lock config file when begin tx.", utils.RequestID(ctx), + zap.String("namespace", req.GetNamespace().GetValue()), zap.String("group", req.GetGroup().GetValue()), + zap.String("fileName", req.GetFileName().GetValue()), zap.Error(err)) + return api.NewConfigResponse(commonstore.StoreCode2APICode(err)) + } historyRecords := []func(){} - upsertResp := s.handleCreateConfigFile(ctx, tx, upsertFileReq) - if upsertResp.GetCode().GetValue() == uint32(apimodel.Code_ExistedResource) { - upsertResp = s.handleUpdateConfigFile(ctx, tx, upsertFileReq) + + var upsertResp *apiconfig.ConfigResponse + if saveFile == nil { + upsertResp = s.handleCreateConfigFile(ctx, tx, upsertFileReq) historyRecords = append(historyRecords, func() { - s.RecordHistory(ctx, configFileRecordEntry(ctx, upsertFileReq, model.OUpdate)) + s.RecordHistory(ctx, configFileRecordEntry(ctx, upsertFileReq, model.OCreate)) }) } else { + actualMd5 := CalMd5(saveFile.Content) + // 只有显示设置了 md5 字段值才会进入 CAS 发布流程 + if req.GetMd5().GetValue() != "" && req.GetMd5().GetValue() != actualMd5 { + log.Error("[Config][File] cas compare config file.", utils.RequestID(ctx), + zap.String("namespace", req.GetNamespace().GetValue()), zap.String("group", req.GetGroup().GetValue()), + zap.String("fileName", req.GetFileName().GetValue()), + zap.String("expect", req.GetMd5().GetValue()), zap.String("actual", actualMd5)) + return api.NewConfigResponse(apimodel.Code_DataConflict) + } + upsertResp = s.handleUpdateConfigFile(ctx, tx, upsertFileReq) historyRecords = append(historyRecords, func() { - s.RecordHistory(ctx, configFileRecordEntry(ctx, upsertFileReq, model.OCreate)) + s.RecordHistory(ctx, configFileRecordEntry(ctx, upsertFileReq, model.OUpdate)) }) } if upsertResp.GetCode().GetValue() != uint32(apimodel.Code_ExecuteSuccess) { diff --git a/config/config_file_release_test.go b/config/config_file_release_test.go index 34995cd79..d6dbe5353 100644 --- a/config/config_file_release_test.go +++ b/config/config_file_release_test.go @@ -744,7 +744,7 @@ func TestServer_CasUpsertAndReleaseConfigFile(t *testing.T) { t.Run("publish_cas", func(t *testing.T) { // 第一次配置发布,就算带了 MD5,也是可以发布成功 - pubResp := testSuit.ConfigServer().CasUpsertAndReleaseConfigFileFromClient(testSuit.DefaultCtx, &config_manage.ConfigFilePublishInfo{ + pubResp := testSuit.ConfigServer().UpsertAndReleaseConfigFileFromClient(testSuit.DefaultCtx, &config_manage.ConfigFilePublishInfo{ Namespace: utils.NewStringValue(mockNamespace), Group: utils.NewStringValue(mockGroup), FileName: utils.NewStringValue(mockFileName), @@ -756,7 +756,7 @@ func TestServer_CasUpsertAndReleaseConfigFile(t *testing.T) { assert.Equal(t, uint32(apimodel.Code_ExecuteSuccess), pubResp.GetCode().GetValue(), pubResp.GetInfo().GetValue()) // MD5 不一致,直接发布失败 - pubResp = testSuit.ConfigServer().CasUpsertAndReleaseConfigFileFromClient(testSuit.DefaultCtx, &config_manage.ConfigFilePublishInfo{ + pubResp = testSuit.ConfigServer().UpsertAndReleaseConfigFileFromClient(testSuit.DefaultCtx, &config_manage.ConfigFilePublishInfo{ Namespace: utils.NewStringValue(mockNamespace), Group: utils.NewStringValue(mockGroup), FileName: utils.NewStringValue(mockFileName), @@ -779,7 +779,7 @@ func TestServer_CasUpsertAndReleaseConfigFile(t *testing.T) { assert.Equal(t, config.CalMd5(mockContent), queryRsp.GetConfigFileRelease().GetMd5().GetValue()) t.Run("md5_不匹配", func(t *testing.T) { - pubResp := testSuit.ConfigServer().CasUpsertAndReleaseConfigFileFromClient(testSuit.DefaultCtx, &config_manage.ConfigFilePublishInfo{ + pubResp := testSuit.ConfigServer().UpsertAndReleaseConfigFileFromClient(testSuit.DefaultCtx, &config_manage.ConfigFilePublishInfo{ Namespace: utils.NewStringValue(mockNamespace), Group: utils.NewStringValue(mockGroup), FileName: utils.NewStringValue(mockFileName), @@ -792,7 +792,7 @@ func TestServer_CasUpsertAndReleaseConfigFile(t *testing.T) { }) t.Run("md5_匹配", func(t *testing.T) { - pubResp := testSuit.ConfigServer().CasUpsertAndReleaseConfigFileFromClient(testSuit.DefaultCtx, &config_manage.ConfigFilePublishInfo{ + pubResp := testSuit.ConfigServer().UpsertAndReleaseConfigFileFromClient(testSuit.DefaultCtx, &config_manage.ConfigFilePublishInfo{ Namespace: utils.NewStringValue(mockNamespace), Group: utils.NewStringValue(mockGroup), FileName: utils.NewStringValue(mockFileName), diff --git a/config/interceptor/auth/client.go b/config/interceptor/auth/client.go index 06a7c6d50..361fb5acb 100644 --- a/config/interceptor/auth/client.go +++ b/config/interceptor/auth/client.go @@ -184,19 +184,3 @@ func (s *Server) GetConfigGroupsWithCache(ctx context.Context, ctx = context.WithValue(ctx, utils.ContextAuthContextKey, authCtx) return s.nextServer.GetConfigGroupsWithCache(ctx, req) } - -// CasUpsertAndReleaseConfigFileFromClient 创建/更新配置文件并发布 -func (s *Server) CasUpsertAndReleaseConfigFileFromClient(ctx context.Context, - req *apiconfig.ConfigFilePublishInfo) *apiconfig.ConfigResponse { - - authCtx := s.collectConfigFilePublishAuthContext(ctx, []*apiconfig.ConfigFilePublishInfo{req}, - auth.Modify, auth.UpsertAndReleaseConfigFile) - if _, err := s.policySvr.GetAuthChecker().CheckClientPermission(authCtx); err != nil { - return api.NewConfigFileResponse(auth.ConvertToErrCode(err), nil) - } - - ctx = authCtx.GetRequestContext() - ctx = context.WithValue(ctx, utils.ContextAuthContextKey, authCtx) - - return s.nextServer.CasUpsertAndReleaseConfigFileFromClient(ctx, req) -} diff --git a/config/interceptor/paramcheck/client_check.go b/config/interceptor/paramcheck/client_check.go index 7b8ace8eb..fe8d9e99e 100644 --- a/config/interceptor/paramcheck/client_check.go +++ b/config/interceptor/paramcheck/client_check.go @@ -202,18 +202,3 @@ func (s *Server) GetConfigGroupsWithCache(ctx context.Context, return s.nextServer.GetConfigGroupsWithCache(ctx, req) } - -// CasUpsertAndReleaseConfigFileFromClient 创建/更新配置文件并发布 -func (s *Server) CasUpsertAndReleaseConfigFileFromClient(ctx context.Context, - req *apiconfig.ConfigFilePublishInfo) *apiconfig.ConfigResponse { - if err := CheckFileName(req.GetFileName()); err != nil { - return api.NewConfigResponse(apimodel.Code_InvalidConfigFileName) - } - if err := utils.CheckResourceName(req.GetNamespace()); err != nil { - return api.NewConfigResponse(apimodel.Code_InvalidNamespaceName) - } - if err := utils.CheckResourceName(req.GetGroup()); err != nil { - return api.NewConfigResponse(apimodel.Code_InvalidConfigFileGroupName) - } - return s.nextServer.CasUpsertAndReleaseConfigFileFromClient(ctx, req) -} From a800d128c7d0029fca34dc5e86f6c11537dc511f Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Thu, 24 Oct 2024 15:32:24 +0800 Subject: [PATCH 09/21] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8Ddefer=E7=94=A8?= =?UTF-8?q?=E6=B3=95=E4=B8=8D=E5=BD=93=E5=AF=BC=E8=87=B4=E5=86=85=E5=AD=98?= =?UTF-8?q?=E6=B3=84=E6=BC=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apiserver/grpcserver/config/client_access.go | 113 +++++++++--------- .../grpcserver/discover/v1/client_access.go | 94 ++++++++------- .../nacosserver/v1/config/config_file.go | 8 +- .../nacosserver/v2/config/config_file.go | 6 +- 4 files changed, 110 insertions(+), 111 deletions(-) diff --git a/apiserver/grpcserver/config/client_access.go b/apiserver/grpcserver/config/client_access.go index 9be53a89c..c989c145c 100644 --- a/apiserver/grpcserver/config/client_access.go +++ b/apiserver/grpcserver/config/client_access.go @@ -182,62 +182,67 @@ func (g *ConfigGRPCServer) Discover(svr apiconfig.PolarisConfigGRPC_DiscoverServ continue } - var out *apiconfig.ConfigDiscoverResponse - var action string - startTime := commontime.CurrentMillisecond() - defer func() { - plugin.GetStatis().ReportDiscoverCall(metrics.ClientDiscoverMetric{ - Action: action, - ClientIP: utils.ParseClientAddress(ctx), - Namespace: in.GetConfigFile().GetNamespace().GetValue(), - Resource: metrics.ResourceOfConfigFile(in.GetConfigFile().GetGroup().GetValue(), in.GetConfigFile().GetFileName().GetValue()), - Timestamp: startTime, - CostTime: commontime.CurrentMillisecond() - startTime, - Revision: out.GetRevision(), - Success: out.GetCode() > uint32(apimodel.Code_DataNoChange), - }) - }() - - switch in.Type { - case apiconfig.ConfigDiscoverRequest_CONFIG_FILE: - action = metrics.ActionGetConfigFile - version, _ := strconv.ParseUint(in.GetRevision(), 10, 64) - ret := g.configServer.GetConfigFileWithCache(ctx, &apiconfig.ClientConfigFileInfo{ - Namespace: in.GetConfigFile().GetNamespace(), - Group: in.GetConfigFile().GetGroup(), - FileName: in.GetConfigFile().GetFileName(), - Version: wrapperspb.UInt64(version), - PublicKey: in.GetConfigFile().GetPublicKey(), - }) - out = api.NewConfigDiscoverResponse(apimodel.Code(ret.GetCode().GetValue())) - out.ConfigFile = ret.GetConfigFile() - out.Type = apiconfig.ConfigDiscoverResponse_CONFIG_FILE - out.Revision = strconv.Itoa(int(out.GetConfigFile().GetVersion().GetValue())) - case apiconfig.ConfigDiscoverRequest_CONFIG_FILE_Names: - action = metrics.ActionListConfigFiles - ret := g.configServer.GetConfigFileNamesWithCache(ctx, &apiconfig.ConfigFileGroupRequest{ - Revision: wrapperspb.String(in.GetRevision()), - ConfigFileGroup: &apiconfig.ConfigFileGroup{ - Namespace: in.GetConfigFile().GetNamespace(), - Name: in.GetConfigFile().GetGroup(), - }, - }) - out = api.NewConfigDiscoverResponse(apimodel.Code(ret.GetCode().GetValue())) - out.ConfigFileNames = ret.GetConfigFileInfos() - out.Type = apiconfig.ConfigDiscoverResponse_CONFIG_FILE_Names - out.Revision = ret.GetRevision().GetValue() - case apiconfig.ConfigDiscoverRequest_CONFIG_FILE_GROUPS: - action = metrics.ActionListConfigGroups - req := in.GetConfigFile() - req.Md5 = wrapperspb.String(in.GetRevision()) - out = g.configServer.GetConfigGroupsWithCache(ctx, req) - out.Type = apiconfig.ConfigDiscoverResponse_CONFIG_FILE_GROUPS - default: - out = api.NewConfigDiscoverResponse(apimodel.Code_InvalidDiscoverResource) - } - + out := g.handleDiscoverRequest(ctx, in) if err := svr.Send(out); err != nil { return err } } } + +func (g *ConfigGRPCServer) handleDiscoverRequest(ctx context.Context, in *apiconfig.ConfigDiscoverRequest) *apiconfig.ConfigDiscoverResponse { + var out *apiconfig.ConfigDiscoverResponse + var action string + startTime := commontime.CurrentMillisecond() + defer func() { + plugin.GetStatis().ReportDiscoverCall(metrics.ClientDiscoverMetric{ + Action: action, + ClientIP: utils.ParseClientAddress(ctx), + Namespace: in.GetConfigFile().GetNamespace().GetValue(), + Resource: metrics.ResourceOfConfigFile(in.GetConfigFile().GetGroup().GetValue(), in.GetConfigFile().GetFileName().GetValue()), + Timestamp: startTime, + CostTime: commontime.CurrentMillisecond() - startTime, + Revision: out.GetRevision(), + Success: out.GetCode() > uint32(apimodel.Code_DataNoChange), + }) + }() + + switch in.Type { + case apiconfig.ConfigDiscoverRequest_CONFIG_FILE: + action = metrics.ActionGetConfigFile + version, _ := strconv.ParseUint(in.GetRevision(), 10, 64) + ret := g.configServer.GetConfigFileWithCache(ctx, &apiconfig.ClientConfigFileInfo{ + Namespace: in.GetConfigFile().GetNamespace(), + Group: in.GetConfigFile().GetGroup(), + FileName: in.GetConfigFile().GetFileName(), + Version: wrapperspb.UInt64(version), + PublicKey: in.GetConfigFile().GetPublicKey(), + }) + out = api.NewConfigDiscoverResponse(apimodel.Code(ret.GetCode().GetValue())) + out.ConfigFile = ret.GetConfigFile() + out.Type = apiconfig.ConfigDiscoverResponse_CONFIG_FILE + out.Revision = strconv.Itoa(int(out.GetConfigFile().GetVersion().GetValue())) + case apiconfig.ConfigDiscoverRequest_CONFIG_FILE_Names: + action = metrics.ActionListConfigFiles + ret := g.configServer.GetConfigFileNamesWithCache(ctx, &apiconfig.ConfigFileGroupRequest{ + Revision: wrapperspb.String(in.GetRevision()), + ConfigFileGroup: &apiconfig.ConfigFileGroup{ + Namespace: in.GetConfigFile().GetNamespace(), + Name: in.GetConfigFile().GetGroup(), + }, + }) + out = api.NewConfigDiscoverResponse(apimodel.Code(ret.GetCode().GetValue())) + out.ConfigFileNames = ret.GetConfigFileInfos() + out.Type = apiconfig.ConfigDiscoverResponse_CONFIG_FILE_Names + out.Revision = ret.GetRevision().GetValue() + case apiconfig.ConfigDiscoverRequest_CONFIG_FILE_GROUPS: + action = metrics.ActionListConfigGroups + req := in.GetConfigFile() + req.Md5 = wrapperspb.String(in.GetRevision()) + out = g.configServer.GetConfigGroupsWithCache(ctx, req) + out.Type = apiconfig.ConfigDiscoverResponse_CONFIG_FILE_GROUPS + default: + out = api.NewConfigDiscoverResponse(apimodel.Code_InvalidDiscoverResource) + } + + return out +} diff --git a/apiserver/grpcserver/discover/v1/client_access.go b/apiserver/grpcserver/discover/v1/client_access.go index d2a42d6ce..5915a2f6c 100644 --- a/apiserver/grpcserver/discover/v1/client_access.go +++ b/apiserver/grpcserver/discover/v1/client_access.go @@ -128,55 +128,59 @@ func (g *DiscoverServer) Discover(server apiservice.PolarisGRPC_DiscoverServer) continue } - var out *apiservice.DiscoverResponse - var action string - startTime := commontime.CurrentMillisecond() - defer func() { - plugin.GetStatis().ReportDiscoverCall(metrics.ClientDiscoverMetric{ - Action: action, - ClientIP: utils.ParseClientAddress(ctx), - Namespace: in.GetService().GetNamespace().GetValue(), - Resource: in.GetType().String() + ":" + in.GetService().GetName().GetValue(), - Timestamp: startTime, - CostTime: commontime.CurrentMillisecond() - startTime, - Revision: out.GetService().GetRevision().GetValue(), - Success: out.GetCode().GetValue() > uint32(apimodel.Code_DataNoChange), - }) - }() - - // 兼容。如果请求中带了token,优先使用该token - if in.GetService().GetToken().GetValue() != "" { - ctx = context.WithValue(ctx, utils.ContextAuthTokenKey, in.GetService().GetToken().GetValue()) + out := g.handleDiscoverRequest(ctx, in) + if err = server.Send(out); err != nil { + return err } + } +} - switch in.Type { - case apiservice.DiscoverRequest_INSTANCE: - action = metrics.ActionDiscoverInstance - out = g.namingServer.ServiceInstancesCache(ctx, &apiservice.DiscoverFilter{}, in.Service) - case apiservice.DiscoverRequest_ROUTING: - action = metrics.ActionDiscoverRouterRule - out = g.namingServer.GetRoutingConfigWithCache(ctx, in.Service) - case apiservice.DiscoverRequest_RATE_LIMIT: - action = metrics.ActionDiscoverRateLimit - out = g.namingServer.GetRateLimitWithCache(ctx, in.Service) - case apiservice.DiscoverRequest_CIRCUIT_BREAKER: - action = metrics.ActionDiscoverCircuitBreaker - out = g.namingServer.GetCircuitBreakerWithCache(ctx, in.Service) - case apiservice.DiscoverRequest_SERVICES: - action = metrics.ActionDiscoverServices - out = g.namingServer.GetServiceWithCache(ctx, in.Service) - case apiservice.DiscoverRequest_FAULT_DETECTOR: - action = metrics.ActionDiscoverFaultDetect - out = g.namingServer.GetFaultDetectWithCache(ctx, in.Service) - default: - out = api.NewDiscoverRoutingResponse(apimodel.Code_InvalidDiscoverResource, in.Service) - } +func (g *DiscoverServer) handleDiscoverRequest(ctx context.Context, in *apiservice.DiscoverRequest) *apiservice.DiscoverResponse { + var out *apiservice.DiscoverResponse + var action string + startTime := commontime.CurrentMillisecond() + defer func() { + plugin.GetStatis().ReportDiscoverCall(metrics.ClientDiscoverMetric{ + Action: action, + ClientIP: utils.ParseClientAddress(ctx), + Namespace: in.GetService().GetNamespace().GetValue(), + Resource: in.GetType().String() + ":" + in.GetService().GetName().GetValue(), + Timestamp: startTime, + CostTime: commontime.CurrentMillisecond() - startTime, + Revision: out.GetService().GetRevision().GetValue(), + Success: out.GetCode().GetValue() > uint32(apimodel.Code_DataNoChange), + }) + }() + + // 兼容。如果请求中带了token,优先使用该token + if in.GetService().GetToken().GetValue() != "" { + ctx = context.WithValue(ctx, utils.ContextAuthTokenKey, in.GetService().GetToken().GetValue()) + } - err = server.Send(out) - if err != nil { - return err - } + switch in.Type { + case apiservice.DiscoverRequest_INSTANCE: + action = metrics.ActionDiscoverInstance + out = g.namingServer.ServiceInstancesCache(ctx, &apiservice.DiscoverFilter{}, in.Service) + case apiservice.DiscoverRequest_ROUTING: + action = metrics.ActionDiscoverRouterRule + out = g.namingServer.GetRoutingConfigWithCache(ctx, in.Service) + case apiservice.DiscoverRequest_RATE_LIMIT: + action = metrics.ActionDiscoverRateLimit + out = g.namingServer.GetRateLimitWithCache(ctx, in.Service) + case apiservice.DiscoverRequest_CIRCUIT_BREAKER: + action = metrics.ActionDiscoverCircuitBreaker + out = g.namingServer.GetCircuitBreakerWithCache(ctx, in.Service) + case apiservice.DiscoverRequest_SERVICES: + action = metrics.ActionDiscoverServices + out = g.namingServer.GetServiceWithCache(ctx, in.Service) + case apiservice.DiscoverRequest_FAULT_DETECTOR: + action = metrics.ActionDiscoverFaultDetect + out = g.namingServer.GetFaultDetectWithCache(ctx, in.Service) + default: + out = api.NewDiscoverRoutingResponse(apimodel.Code_InvalidDiscoverResource, in.Service) } + + return out } func (g *DiscoverServer) ReportServiceContract(ctx context.Context, in *apiservice.ServiceContract) (*apiservice.Response, error) { diff --git a/apiserver/nacosserver/v1/config/config_file.go b/apiserver/nacosserver/v1/config/config_file.go index 911e987be..eeb23113a 100644 --- a/apiserver/nacosserver/v1/config/config_file.go +++ b/apiserver/nacosserver/v1/config/config_file.go @@ -42,13 +42,7 @@ import ( ) func (n *ConfigServer) handlePublishConfig(ctx context.Context, req *model.ConfigFile) (bool, error) { - var resp *config_manage.ConfigResponse - if req.CasMd5 != "" { - resp = n.configSvr.CasUpsertAndReleaseConfigFileFromClient(ctx, req.ToSpecConfigFile()) - } else { - resp = n.configSvr.UpsertAndReleaseConfigFileFromClient(ctx, req.ToSpecConfigFile()) - } - + resp := n.configSvr.UpsertAndReleaseConfigFileFromClient(ctx, req.ToSpecConfigFile()) if resp.GetCode().GetValue() == uint32(apimodel.Code_ExecuteSuccess) { return true, nil } diff --git a/apiserver/nacosserver/v2/config/config_file.go b/apiserver/nacosserver/v2/config/config_file.go index d1e54305a..76cde7741 100644 --- a/apiserver/nacosserver/v2/config/config_file.go +++ b/apiserver/nacosserver/v2/config/config_file.go @@ -62,11 +62,7 @@ func (h *ConfigServer) handlePublishConfigRequest(ctx context.Context, req nacos }) }() - if configReq.CasMd5 != "" { - resp = h.configSvr.CasUpsertAndReleaseConfigFileFromClient(ctx, configReq.ToSpec()) - } else { - resp = h.configSvr.UpsertAndReleaseConfigFileFromClient(ctx, configReq.ToSpec()) - } + resp = h.configSvr.UpsertAndReleaseConfigFileFromClient(ctx, configReq.ToSpec()) if resp.GetCode().GetValue() != uint32(apimodel.Code_ExecuteSuccess) { nacoslog.Error("[NACOS-V2][Config] publish config file fail", zap.String("tenant", configReq.Tenant), utils.ZapGroup(configReq.Group), utils.ZapFileName(configReq.DataId), From 123775b2e1c17d0235a8389f3336ba8a6df6eca6 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 6 Nov 2024 21:02:48 +0800 Subject: [PATCH 10/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/maintain.go | 3 + apiserver/httpserver/admin_access.go | 2 +- config/config_file.go | 38 ++- store/boltdb/load.go | 4 + store/mysql/scripts/init_data.sql | 469 +++++++++++++++++++++++++++ 5 files changed, 502 insertions(+), 14 deletions(-) create mode 100644 store/mysql/scripts/init_data.sql diff --git a/admin/maintain.go b/admin/maintain.go index 5800bdf54..a473e6981 100644 --- a/admin/maintain.go +++ b/admin/maintain.go @@ -47,6 +47,9 @@ func (s *Server) HasMainUser(ctx context.Context) (*apisecurity.User, error) { log.Error("check hash main user", zap.Error(err), utils.RequestID(ctx)) return nil, err } + if mainUser == nil { + return nil, nil + } ret := mainUser.ToSpec() ret.AuthToken = wrapperspb.String("") return ret, nil diff --git a/apiserver/httpserver/admin_access.go b/apiserver/httpserver/admin_access.go index 4aa5fccb7..0c0300172 100644 --- a/apiserver/httpserver/admin_access.go +++ b/apiserver/httpserver/admin_access.go @@ -70,7 +70,7 @@ func (h *HTTPServer) GetAdminAccessServer() *restful.WebService { ws.Route(docs.EnrichEnablePprofApiDocs(ws.POST("/pprof/enable").To(h.EnablePprof))) ws.Route(docs.EnrichGetServerFunctionsApiDocs(ws.GET("/server/functions").To(h.GetServerFunctions))) ws.Route(ws.GET("/mainuser/exist").To(h.HasMainUser)) - ws.Route(ws.GET("/mainuser/create").To(h.InitMainUser)) + ws.Route(ws.POST("/mainuser/create").To(h.InitMainUser)) return ws } diff --git a/config/config_file.go b/config/config_file.go index b4d4a8628..422b7c10c 100644 --- a/config/config_file.go +++ b/config/config_file.go @@ -37,6 +37,11 @@ import ( // CreateConfigFile 创建配置文件 func (s *Server) CreateConfigFile(ctx context.Context, req *apiconfig.ConfigFile) *apiconfig.ConfigResponse { + savaData := model.ToConfigFileStore(req) + if errResp := s.chains.BeforeCreateFile(ctx, savaData); errResp != nil { + return errResp + } + if rsp := s.prepareCreateConfigFile(ctx, req); rsp.Code.Value != api.ExecuteSuccess { return rsp } @@ -50,7 +55,7 @@ func (s *Server) CreateConfigFile(ctx context.Context, req *apiconfig.ConfigFile _ = tx.Rollback() }() - resp := s.handleCreateConfigFile(ctx, tx, req) + resp := s._handleCreateConfigFile(ctx, tx, savaData) if resp.GetCode().GetValue() != uint32(apimodel.Code_ExecuteSuccess) { return resp } @@ -63,30 +68,37 @@ func (s *Server) CreateConfigFile(ctx context.Context, req *apiconfig.ConfigFile return resp } +// handleCreateConfigFile . func (s *Server) handleCreateConfigFile(ctx context.Context, tx store.Tx, req *apiconfig.ConfigFile) *apiconfig.ConfigResponse { - data, err := s.storage.GetConfigFileTx(tx, req.GetNamespace().GetValue(), req.GetGroup().GetValue(), - req.GetName().GetValue()) + savaData := model.ToConfigFileStore(req) + if errResp := s.chains.BeforeCreateFile(ctx, savaData); errResp != nil { + return errResp + } + + return s._handleCreateConfigFile(ctx, tx, savaData) +} + +func (s *Server) _handleCreateConfigFile(ctx context.Context, tx store.Tx, + saveData *model.ConfigFile) *apiconfig.ConfigResponse { + + data, err := s.storage.GetConfigFileTx(tx, saveData.Namespace, saveData.Group, + saveData.Name) if err != nil { log.Error("[Config][File] create config file when get save data.", utils.RequestID(ctx), - utils.ZapNamespace(req.GetNamespace().GetValue()), utils.ZapGroup(req.GetGroup().GetValue()), - utils.ZapFileName(req.GetName().GetValue()), zap.Error(err)) + utils.ZapNamespace(saveData.Namespace), utils.ZapGroup(saveData.Group), + utils.ZapFileName(saveData.Name), zap.Error(err)) return api.NewConfigResponse(commonstore.StoreCode2APICode(err)) } if data != nil { return api.NewConfigResponse(apimodel.Code_ExistedResource) } - - savaData := model.ToConfigFileStore(req) - if errResp := s.chains.BeforeCreateFile(ctx, savaData); errResp != nil { - return errResp - } // 创建配置文件 - if err := s.storage.CreateConfigFileTx(tx, savaData); err != nil { + if err := s.storage.CreateConfigFileTx(tx, saveData); err != nil { log.Error("[Config][File] create config file error.", utils.RequestID(ctx), - utils.ZapNamespace(req.GetNamespace().GetValue()), utils.ZapGroup(req.GetGroup().GetValue()), - utils.ZapFileName(req.GetName().GetValue()), zap.Error(err)) + utils.ZapNamespace(saveData.Namespace), utils.ZapGroup(saveData.Group), + utils.ZapFileName(saveData.Name), zap.Error(err)) return api.NewConfigResponse(commonstore.StoreCode2APICode(err)) } return api.NewConfigResponse(apimodel.Code_ExecuteSuccess) diff --git a/store/boltdb/load.go b/store/boltdb/load.go index 0779c01d0..f697ebff7 100644 --- a/store/boltdb/load.go +++ b/store/boltdb/load.go @@ -44,6 +44,10 @@ func (m *boltStore) loadByFile(loadFile string) error { } cf, err := os.Open(loadFile) if err != nil { + // 如果文件不存在,则需要用户首次调用接口进行管理员帐户的初始化操作 + if errors.Is(err, os.ErrNotExist) { + return nil + } return err } defer cf.Close() diff --git a/store/mysql/scripts/init_data.sql b/store/mysql/scripts/init_data.sql new file mode 100644 index 000000000..dae2581de --- /dev/null +++ b/store/mysql/scripts/init_data.sql @@ -0,0 +1,469 @@ +/* + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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. + */ +SET + SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; + +SET + time_zone = "+00:00"; + +USE `polaris_server`; + +-- Create a default master account, password is Polarismesh @ 2021 +INSERT INTO + `user` ( + `id`, + `name`, + `password`, + `source`, + `token`, + `token_enable`, + `user_type`, + `comment`, + `mobile`, + `email`, + `owner` + ) +VALUES + ( + '65e4789a6d5b49669adf1e9e8387549c', + 'polaris', + '$2a$10$3izWuZtE5SBdAtSZci.gs.iZ2pAn9I8hEqYrC6gwJp1dyjqQnrrum', + 'Polaris', + 'nu/0WRA4EqSR1FagrjRj0fZwPXuGlMpX+zCuWu4uMqy8xr1vRjisSbA25aAC3mtU8MeeRsKhQiDAynUR09I=', + 1, + 20, + 'default polaris admin account', + '12345678910', + '12345678910', + '' + ); + +-- Permissions policy inserted into Polaris-Admin +INSERT INTO + `auth_strategy` ( + `id`, + `name`, + `action`, + `owner`, + `comment`, + `default`, + `source`, + `revision`, + `flag`, + `ctime`, + `mtime` + ) +VALUES + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + '(用户) polaris的默认策略', + 'READ_WRITE', + '65e4789a6d5b49669adf1e9e8387549c', + 'default admin', + 1, + 'Polaris', + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 0, + sysdate (), + sysdate () + ); + +-- Sport rules inserted into Polaris-Admin to access +INSERT INTO + `auth_strategy_resource` ( + `strategy_id`, + `res_type`, + `res_id`, + `ctime`, + `mtime` + ) +VALUES + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 0, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 1, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 2, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 3, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 4, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 5, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 6, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 7, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 20, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 21, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 22, + '*', + sysdate (), + sysdate () + ), + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 23, + '*', + sysdate (), + sysdate () + ); + +-- Insert permission policies and association relationships for Polaris-Admin accounts +INSERT INTO + auth_principal (`strategy_id`, `principal_id`, `principal_role`) +VALUES + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + '65e4789a6d5b49669adf1e9e8387549c', + 1 + ); + +INSERT INTO + auth_strategy_function (`strategy_id`, `function`) +VALUES + ('fbca9bfa04ae4ead86e1ecf5811e32a9', '*'); + +/* 默认全局读写以及全局只读策略 */ +-- Insert permission policies and association relationships for Polaris-Admin accounts +INSERT INTO + auth_principal (`strategy_id`, `principal_id`, `principal_role`) +VALUES + ( + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + '65e4789a6d5b49669adf1e9e8387549c', + 1 + ); + +INSERT INTO + auth_strategy_function (`strategy_id`, `function`) +VALUES + ('fbca9bfa04ae4ead86e1ecf5811e32a9', '*'); + +/* 默认的全局只读策略 */ +INSERT INTO + `auth_strategy` ( + `id`, + `name`, + `action`, + `owner`, + `comment`, + `default`, + `source`, + `revision`, + `flag`, + `ctime`, + `mtime` + ) +VALUES + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + '全局只读策略', + 'ALLOW', + '65e4789a6d5b49669adf1e9e8387549c', + 'global resources read only', + 1, + 'Polaris', + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 0, + sysdate (), + sysdate () + ); + +INSERT INTO + `auth_strategy_resource` ( + `strategy_id`, + `res_type`, + `res_id`, + `ctime`, + `mtime` + ) +VALUES + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 0, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 1, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 2, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 3, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 4, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 5, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 6, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 7, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 20, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 21, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 22, + '*', + sysdate (), + sysdate () + ), + ( + 'bfa04ae1e32a94fbca9ead86e1ecf581', + 23, + '*', + sysdate (), + sysdate () + ); + +INSERT INTO + auth_strategy_function (`strategy_id`, `function`) +VALUES + ('bfa04ae1e32a94fbca9ead86e1ecf581', 'Describe*'), + ('bfa04ae1e32a94fbca9ead86e1ecf581', 'List*'), + ('bfa04ae1e32a94fbca9ead86e1ecf581', 'Get*'); + +/* 默认的全局读写策略 */ +INSERT INTO + `auth_strategy` ( + `id`, + `name`, + `action`, + `owner`, + `comment`, + `default`, + `source`, + `revision`, + `flag`, + `ctime`, + `mtime` + ) +VALUES + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + '全局读写策略', + 'ALLOW', + '65e4789a6d5b49669adf1e9e8387549c', + 'global resources read and write', + 1, + 'Polaris', + 'fbca9bfa04ae4ead86e1ecf5811e32a9', + 0, + sysdate (), + sysdate () + ); + +INSERT INTO + `auth_strategy_resource` ( + `strategy_id`, + `res_type`, + `res_id`, + `ctime`, + `mtime` + ) +VALUES + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 0, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 1, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 2, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 3, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 4, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 5, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 6, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 7, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 20, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 21, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 22, + '*', + sysdate (), + sysdate () + ), + ( + 'e3d86e1ecf5812bfa04ae1a94fbca9ea', + 23, + '*', + sysdate (), + sysdate () + ); + +INSERT INTO + auth_strategy_function (`strategy_id`, `function`) +VALUES + ('e3d86e1ecf5812bfa04ae1a94fbca9ea', '*'); \ No newline at end of file From d8f48fe4595fab5f5259022e2facf0a9afa49960 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Mon, 18 Nov 2024 16:01:09 +0800 Subject: [PATCH 11/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/api.go | 4 +-- admin/interceptor/auth/server.go | 4 +-- admin/job/clean_deleted_resource.go | 53 +++++++++++++++++++++++++++- admin/maintain.go | 20 +++++------ apiserver/httpserver/admin_access.go | 18 ++++------ auth/policy/auth_checker.go | 4 +++ auth/policy/helper.go | 14 +++++--- auth/policy/strategy.go | 5 +++ auth/user/user.go | 24 ++++++------- common/model/auth/const.go | 4 +++ config/config_file.go | 1 + release/conf/polaris-server.yaml | 13 ++----- store/boltdb/default.go | 1 + store/boltdb/strategy.go | 13 ++++--- store/boltdb/user.go | 3 +- store/mysql/strategy.go | 19 ++++++++-- 16 files changed, 138 insertions(+), 62 deletions(-) diff --git a/admin/api.go b/admin/api.go index ce639efc1..5d418f6e4 100644 --- a/admin/api.go +++ b/admin/api.go @@ -55,9 +55,9 @@ type AdminOperateServer interface { // GetCMDBInfo get cmdb info GetCMDBInfo(ctx context.Context) ([]model.LocationView, error) // HasMainUser . - HasMainUser(ctx context.Context) (*apisecurity.User, error) + HasMainUser(ctx context.Context) *apiservice.Response // InitMainUser . - InitMainUser(ctx context.Context, user apisecurity.User) error + InitMainUser(ctx context.Context, user *apisecurity.User) *apiservice.Response // GetServerFunctions Get server functions GetServerFunctions(ctx context.Context) []authcommon.ServerFunctionGroup } diff --git a/admin/interceptor/auth/server.go b/admin/interceptor/auth/server.go index e18ecdbee..b56d82eb3 100644 --- a/admin/interceptor/auth/server.go +++ b/admin/interceptor/auth/server.go @@ -62,11 +62,11 @@ func (svr *Server) collectMaintainAuthContext(ctx context.Context, resourceOp au ) } -func (s *Server) HasMainUser(ctx context.Context) (*apisecurity.User, error) { +func (s *Server) HasMainUser(ctx context.Context) *apiservice.Response { return s.nextSvr.HasMainUser(ctx) } -func (s *Server) InitMainUser(ctx context.Context, user apisecurity.User) error { +func (s *Server) InitMainUser(ctx context.Context, user *apisecurity.User) *apiservice.Response { return s.nextSvr.InitMainUser(ctx, user) } diff --git a/admin/job/clean_deleted_resource.go b/admin/job/clean_deleted_resource.go index 8d315c2cc..1339f97c1 100644 --- a/admin/job/clean_deleted_resource.go +++ b/admin/job/clean_deleted_resource.go @@ -48,6 +48,47 @@ var cleanFuncMapping = map[string]func(timeout time.Duration, job *cleanDeletedR "config_file_release": cleanDeletedConfigFiles, } +var defaultCleanDeletedResourceConfig = CleandeletedResourceConf{ + Resources: []CleanDeletedResource{ + { + Resource: "instance", + Enable: true, + }, + { + Resource: "service", + Enable: true, + }, + { + Resource: "clients", + Enable: true, + }, + { + Resource: "circuitbreaker_rule", + Enable: true, + }, + { + Resource: "ratelimit_rule", + Enable: true, + }, + { + Resource: "router_rule", + Enable: true, + }, + { + Resource: "faultdetect_rule", + Enable: true, + }, + { + Resource: "lane_rule", + Enable: true, + }, + { + Resource: "config_file_release", + Enable: true, + }, + }, +} + type CleanDeletedResource struct { // Resource 记录需要清理的资源类型 Resource string `mapstructure:"resource"` @@ -59,7 +100,7 @@ type CleanDeletedResource struct { type CleandeletedResourceConf struct { // ResourceTimeout 记录资源的额外超时时间,用户可自定义 - Resources []CleanDeletedResource `json:"resourceTimeout"` + Resources []CleanDeletedResource `json:"resources" mapstructure:"resources"` // Timeout 记录清理资源的超时时间,默认20分钟 Timeout time.Duration `mapstructure:"timeout"` } @@ -90,6 +131,16 @@ func (job *cleanDeletedResourceJob) init(raw map[string]interface{}) error { cfg.Timeout = 2 * time.Minute } job.cfg = cfg + + if len(cfg.Resources) == 0 { + job.cfg.Resources = defaultCleanDeletedResourceConfig.Resources + for i := range job.cfg.Resources { + if job.cfg.Resources[i].Timeout == nil { + job.cfg.Resources[i].Timeout = &job.cfg.Timeout + } + } + } + return nil } diff --git a/admin/maintain.go b/admin/maintain.go index a473e6981..e2d1d5012 100644 --- a/admin/maintain.go +++ b/admin/maintain.go @@ -41,30 +41,30 @@ import ( ) // HasMainUser 判断是否存在主用户 -func (s *Server) HasMainUser(ctx context.Context) (*apisecurity.User, error) { +func (s *Server) HasMainUser(ctx context.Context) *apiservice.Response { mainUser, err := s.storage.GetMainUser() if err != nil { log.Error("check hash main user", zap.Error(err), utils.RequestID(ctx)) - return nil, err + return api.NewResponse(apimodel.Code_ExecuteException) } if mainUser == nil { - return nil, nil + return api.NewResponse(apimodel.Code_NotFoundResource) } ret := mainUser.ToSpec() ret.AuthToken = wrapperspb.String("") - return ret, nil + return api.NewUserResponse(apimodel.Code_ExecuteSuccess, ret) } // InitMainUser 初始化主用户 -func (s *Server) InitMainUser(_ context.Context, user apisecurity.User) error { +func (s *Server) InitMainUser(_ context.Context, user *apisecurity.User) *apiservice.Response { + if user.GetSource().GetValue() == "" { + user.Source = utils.NewStringValue("Polaris") + } ctx := context.WithValue(context.Background(), authcommon.ContextKeyInitMainUser{}, true) rsp := s.userSvr.CreateUsers(ctx, []*apisecurity.User{ - &user, + user, }) - if !api.IsSuccess(rsp) { - return errors.New(rsp.GetInfo().GetValue()) - } - return nil + return rsp.Responses[0] } func (s *Server) GetServerConnections(_ context.Context, req *admin.ConnReq) (*admin.ConnCountResp, error) { diff --git a/apiserver/httpserver/admin_access.go b/apiserver/httpserver/admin_access.go index 0c0300172..1ed336441 100644 --- a/apiserver/httpserver/admin_access.go +++ b/apiserver/httpserver/admin_access.go @@ -24,6 +24,7 @@ import ( "strconv" "github.com/emicklei/go-restful/v3" + "github.com/golang/protobuf/jsonpb" apimodel "github.com/polarismesh/specification/source/go/api/v1/model" "github.com/polarismesh/specification/source/go/api/v1/security" apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" @@ -314,12 +315,9 @@ func (h *HTTPServer) EnablePprof(req *restful.Request, rsp *restful.Response) { func (h *HTTPServer) HasMainUser(req *restful.Request, rsp *restful.Response) { ctx := initContext(req) - ret, err := h.maintainServer.HasMainUser(ctx) - if err != nil { - _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) - return - } - _ = rsp.WriteAsJson(ret) + ret := h.maintainServer.HasMainUser(ctx) + marshaler := jsonpb.Marshaler{Indent: " ", EmitDefaults: true} + _ = marshaler.Marshal(rsp, ret) } func (h *HTTPServer) InitMainUser(req *restful.Request, rsp *restful.Response) { @@ -335,11 +333,9 @@ func (h *HTTPServer) InitMainUser(req *restful.Request, rsp *restful.Response) { return } - if err := h.maintainServer.InitMainUser(ctx, *user); err != nil { - _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) - return - } - _ = rsp.WriteEntity("ok") + ret := h.maintainServer.InitMainUser(ctx, user) + marshaler := jsonpb.Marshaler{Indent: " ", EmitDefaults: true} + _ = marshaler.Marshal(rsp, ret) } // GetServerFunctions . diff --git a/auth/policy/auth_checker.go b/auth/policy/auth_checker.go index c8efc8d32..f8d516382 100644 --- a/auth/policy/auth_checker.go +++ b/auth/policy/auth_checker.go @@ -140,6 +140,10 @@ func (d *DefaultAuthChecker) CheckConsolePermission(preCtx *authcommon.AcquireCo if d.IsOpenConsoleAuth() && !d.conf.ConsoleStrict { preCtx.SetAllowAnonymous(true) } + // 如果是初始化主用户的请求,直接放行 + if authcommon.IsInitMainUser(preCtx.GetRequestContext()) { + return true, nil + } return d.CheckPermission(preCtx) } diff --git a/auth/policy/helper.go b/auth/policy/helper.go index 1c77670c0..8c85d9aed 100644 --- a/auth/policy/helper.go +++ b/auth/policy/helper.go @@ -83,7 +83,7 @@ func mainUserPrincipalPolicy(p authcommon.Principal) *authcommon.StrategyDetail Name: authcommon.BuildDefaultStrategyName(p.PrincipalType, p.Name), Action: apisecurity.AuthAction_ALLOW.String(), Default: true, - Owner: p.Owner, + Owner: p.PrincipalID, Revision: utils.NewUUID(), Source: "Polaris", Resources: resources, @@ -114,14 +114,16 @@ func defaultReadWritePolicy(p authcommon.Principal) *authcommon.StrategyDetail { Name: "全局读写策略", Action: apisecurity.AuthAction_ALLOW.String(), Default: true, - Owner: p.Owner, + Owner: p.PrincipalID, Revision: utils.NewUUID(), Source: "Polaris", Resources: resources, - Principals: []authcommon.Principal{p}, CalleeMethods: calleeMethods, Valid: true, Comment: "global resources read and write", + Metadata: map[string]string{ + authcommon.MetadKeySystemDefaultPolicy: "true", + }, } } @@ -149,14 +151,16 @@ func defaultReadOnlyPolicy(p authcommon.Principal) *authcommon.StrategyDetail { Name: "全局只读策略", Action: apisecurity.AuthAction_ALLOW.String(), Default: true, - Owner: p.Owner, + Owner: p.PrincipalID, Revision: utils.NewUUID(), Source: "Polaris", Resources: resources, - Principals: []authcommon.Principal{p}, CalleeMethods: calleeMethods, Valid: true, Comment: "global resources read only policy rule", + Metadata: map[string]string{ + authcommon.MetadKeySystemDefaultPolicy: "true", + }, } } diff --git a/auth/policy/strategy.go b/auth/policy/strategy.go index 022d39d2c..a134eeec4 100644 --- a/auth/policy/strategy.go +++ b/auth/policy/strategy.go @@ -194,6 +194,11 @@ func (svr *Server) GetStrategies(ctx context.Context, filters map[string]string) // 透传兼容模式信息数据 ctx = context.WithValue(ctx, model.ContextKeyCompatible{}, svr.options.Compatible) + // 这里需要框定大体的数据查询范围 + if authcommon.ParseUserRole(ctx) != authcommon.AdminUserRole { + filters["owner"] = utils.ParseOwnerID(ctx) + } + total, strategies, err := svr.cacheMgr.AuthStrategy().Query(ctx, cachetypes.PolicySearchArgs{ Filters: filters, Offset: offset, diff --git a/auth/user/user.go b/auth/user/user.go index 05d0cec70..fdc73953f 100644 --- a/auth/user/user.go +++ b/auth/user/user.go @@ -62,19 +62,10 @@ func (svr *Server) CreateUser(ctx context.Context, req *apisecurity.User) *apise ownerID := utils.ParseOwnerID(ctx) req.Owner = utils.NewStringValue(ownerID) - if checkErrResp := checkCreateUser(req); checkErrResp != nil { + if checkErrResp := checkCreateUser(ctx, req); checkErrResp != nil { return checkErrResp } - // 如果创建的目标账户类型是非子账户,则 ownerId 需要设置为 “” - if convertCreateUserRole(authcommon.ParseUserRole(ctx)) != authcommon.SubAccountUserRole { - // 如果创建的不是子帐户,需要判断是否来自内部的 InitMainUser 请求 - if !authcommon.IsInitMainUser(ctx) { - log.Error("[auth][user] can't create user which role is not sub-account", utils.RequestID(ctx)) - return api.NewUserResponse(apimodel.Code_OperationRoleForbidden, req) - } - } - if ownerID != "" { owner, err := svr.storage.GetUser(ownerID) if err != nil { @@ -579,7 +570,7 @@ func userRecordEntry(ctx context.Context, req *apisecurity.User, md *authcommon. } // checkCreateUser 检查创建用户的请求 -func checkCreateUser(req *apisecurity.User) *apiservice.Response { +func checkCreateUser(ctx context.Context, req *apisecurity.User) *apiservice.Response { if req == nil { return api.NewUserResponse(apimodel.Code_EmptyRequest, req) } @@ -592,8 +583,15 @@ func checkCreateUser(req *apisecurity.User) *apiservice.Response { return api.NewUserResponse(apimodel.Code_InvalidUserPassword, req) } - if err := CheckOwner(req.Owner); err != nil { - return api.NewUserResponse(apimodel.Code_InvalidUserOwners, req) + if !authcommon.IsInitMainUser(ctx) { + if err := CheckOwner(req.Owner); err != nil { + return api.NewUserResponse(apimodel.Code_InvalidUserOwners, req) + } + // 如果创建的目标账户类型是非子账户,则 ownerId 需要设置为 “” + if convertCreateUserRole(authcommon.ParseUserRole(ctx)) != authcommon.SubAccountUserRole { + log.Error("[auth][user] can't create user which role is not sub-account", utils.RequestID(ctx)) + return api.NewUserResponse(apimodel.Code_OperationRoleForbidden, req) + } } return nil } diff --git a/common/model/auth/const.go b/common/model/auth/const.go index d58a621fb..f44e00b77 100644 --- a/common/model/auth/const.go +++ b/common/model/auth/const.go @@ -21,6 +21,10 @@ import ( apisecurity "github.com/polarismesh/specification/source/go/api/v1/security" ) +const ( + MetadKeySystemDefaultPolicy = "internal-polaris-system-policy" +) + type ServerFunctionName string // SDK 接口 diff --git a/config/config_file.go b/config/config_file.go index 422b7c10c..e17196e56 100644 --- a/config/config_file.go +++ b/config/config_file.go @@ -80,6 +80,7 @@ func (s *Server) handleCreateConfigFile(ctx context.Context, tx store.Tx, return s._handleCreateConfigFile(ctx, tx, savaData) } +// _handleCreateConfigFile 不推荐直接调用,需统一通过 (*Server) handleCreateConfigFile 调用 func (s *Server) _handleCreateConfigFile(ctx context.Context, tx store.Tx, saveData *model.ConfigFile) *apiconfig.ConfigResponse { diff --git a/release/conf/polaris-server.yaml b/release/conf/polaris-server.yaml index b25a431f2..82b16d912 100644 --- a/release/conf/polaris-server.yaml +++ b/release/conf/polaris-server.yaml @@ -433,18 +433,11 @@ maintain: option: # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". serviceDeleteTimeout: 30m - # Clean soft deleted instances - - name: CleanDeletedInstances + # Clean soft deleted resources + - name: CleanDeletedResources enable: true option: - # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - # instanceCleanTimeout: 10m - # Clean soft deleted clients - - name: CleanDeletedClients - enable: true - option: - # Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". - # clientCleanTimeout: 10m + timeout: 1h # Storage configuration store: # # Standalone file storage plugin diff --git a/store/boltdb/default.go b/store/boltdb/default.go index 17f143e59..d60b63269 100644 --- a/store/boltdb/default.go +++ b/store/boltdb/default.go @@ -56,6 +56,7 @@ const ( CommonFieldNamespace = "Namespace" CommonFieldDescription = "Description" CommonFieldEnable = "Enable" + CommonFieldMetadata = "Metadata" ) type boltStore struct { diff --git a/store/boltdb/strategy.go b/store/boltdb/strategy.go index a47f19807..d794059de 100644 --- a/store/boltdb/strategy.go +++ b/store/boltdb/strategy.go @@ -361,7 +361,7 @@ func (ss *strategyStore) GetDefaultStrategyDetailByPrincipal(principalId string, fields := []string{StrategyFieldValid, StrategyFieldDefault, StrategyFieldUsersPrincipal} if principalType == authcommon.PrincipalGroup { - fields = []string{StrategyFieldValid, StrategyFieldDefault, StrategyFieldGroupsPrincipal} + fields = []string{StrategyFieldValid, StrategyFieldDefault, StrategyFieldGroupsPrincipal, CommonFieldMetadata} } values, err := ss.handler.LoadValuesByFilter(tblStrategy, fields, &strategyData{}, @@ -383,10 +383,15 @@ func (ss *strategyStore) GetDefaultStrategyDetailByPrincipal(principalId string, } else { principals, _ = m[StrategyFieldGroupsPrincipal].(map[string]string) } + if _, exist := principals[principalId]; !exist { + return false + } - _, exist := principals[principalId] - - return exist + metadata, _ := m[CommonFieldMetadata].(map[string]string) + if val, exist := metadata[authcommon.MetadKeySystemDefaultPolicy]; exist && val == "true" { + return false + } + return true }) if err != nil { diff --git a/store/boltdb/user.go b/store/boltdb/user.go index c744e9067..3734cff0d 100644 --- a/store/boltdb/user.go +++ b/store/boltdb/user.go @@ -96,8 +96,7 @@ func (us *userStore) AddUser(tx store.Tx, user *authcommon.User) error { initUser(user) - if user.ID == "" || user.Name == "" || user.Source == "" || - user.Owner == "" || user.Token == "" { + if user.ID == "" || user.Name == "" || user.Source == "" || user.Token == "" { return store.NewStatusError(store.EmptyParamsErr, "add user missing some params") } diff --git a/store/mysql/strategy.go b/store/mysql/strategy.go index c55d69624..85fbf3d8b 100644 --- a/store/mysql/strategy.go +++ b/store/mysql/strategy.go @@ -477,8 +477,23 @@ func (s *strategyStore) GetDefaultStrategyDetailByPrincipal(principalId string, ) ` - row := s.master.QueryRow(querySql, principalId, int(principalType)) - return s.getStrategyDetail(row) + rows, err := s.master.Query(querySql, principalId, int(principalType)) + if err != nil { + return nil, store.Error(err) + } + defer rows.Close() + + for rows.Next() { + detail, err := fetchRown2StrategyDetail(rows) + if err != nil { + return nil, store.Error(err) + } + if detail.Metadata[authcommon.MetadKeySystemDefaultPolicy] == "true" { + continue + } + return detail, nil + } + return nil, nil } // getStrategyDetail From e8e9fb745bae7e8b4f7011f363643c86be4c2f28 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Thu, 21 Nov 2024 11:34:59 +0800 Subject: [PATCH 12/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/job/clean_deleted_resource.go | 26 ++++- store/admin_api.go | 2 + store/boltdb/admin.go | 109 ++++++++++++++++---- store/mock/api_mock.go | 15 +++ store/mysql/admin.go | 150 +++++++++++++++++++++++++++- 5 files changed, 278 insertions(+), 24 deletions(-) diff --git a/admin/job/clean_deleted_resource.go b/admin/job/clean_deleted_resource.go index 1339f97c1..f936391f2 100644 --- a/admin/job/clean_deleted_resource.go +++ b/admin/job/clean_deleted_resource.go @@ -27,9 +27,10 @@ import ( ) var cleanFuncMapping = map[string]func(timeout time.Duration, job *cleanDeletedResourceJob){ - "instance": cleanDeletedInstances, - "service": cleanDeletedServices, - "clients": cleanDeletedClients, + "instance": cleanDeletedInstances, + "service": cleanDeletedServices, + "clients": cleanDeletedClients, + "service_contract": cleanDeletedServiceContracts, "circuitbreaker_rule": func(timeout time.Duration, job *cleanDeletedResourceJob) { cleanDeletedRules("circuitbreaker_rule", timeout, job) }, @@ -58,6 +59,10 @@ var defaultCleanDeletedResourceConfig = CleandeletedResourceConf{ Resource: "service", Enable: true, }, + { + Resource: "service_contract", + Enable: true, + }, { Resource: "clients", Enable: true, @@ -233,6 +238,21 @@ func cleanDeletedInstances(timeout time.Duration, job *cleanDeletedResourceJob) } } +func cleanDeletedServiceContracts(timeout time.Duration, job *cleanDeletedResourceJob) { + batchSize := uint32(100) + for { + count, err := job.storage.BatchCleanDeletedClients(timeout, batchSize) + if err != nil { + log.Errorf("[Maintain][Job][CleanDeletedClients] batch clean deleted client, err: %v", err) + break + } + log.Infof("[Maintain][Job][CleanDeletedClients] clean deleted client count %d", count) + if count < batchSize { + break + } + } +} + func cleanDeletedRules(rule string, timeout time.Duration, job *cleanDeletedResourceJob) { batchSize := uint32(100) for { diff --git a/store/admin_api.go b/store/admin_api.go index 4114019d0..870e76977 100644 --- a/store/admin_api.go +++ b/store/admin_api.go @@ -43,6 +43,8 @@ type AdminStore interface { GetUnHealthyInstances(timeout time.Duration, limit uint32) ([]string, error) // BatchCleanDeletedClients batch clean soft deleted clients BatchCleanDeletedClients(timeout time.Duration, batchSize uint32) (uint32, error) + // BatchCleanDeletedServiceContracts batch clean soft deleted service_contract + BatchCleanDeletedServiceContracts(timeout time.Duration, batchSize uint32) (uint32, error) // BatchCleanDeletedServices batch clean soft deleted clients BatchCleanDeletedServices(timeout time.Duration, batchSize uint32) (uint32, error) // BatchCleanDeletedRules batch clean soft deleted clients diff --git a/store/boltdb/admin.go b/store/boltdb/admin.go index 4d536c97a..44ac77e3f 100644 --- a/store/boltdb/admin.go +++ b/store/boltdb/admin.go @@ -157,37 +157,22 @@ func (m *adminStore) getUnHealthyInstancesBefore(mtime time.Time, limit uint32) fields := []string{insFieldProto, insFieldValid} instances, err := m.handler.LoadValuesByFilter(tblNameInstance, fields, &model.Instance{}, func(m map[string]interface{}) bool { - - valid, ok := m[insFieldValid] - if ok && !valid.(bool) { + if valid, ok := m[insFieldValid]; ok && !valid.(bool) { return false } - insProto, ok := m[insFieldProto] if !ok { return false } - ins := insProto.(*apiservice.Instance) - insMtime, err := time.Parse("2006-01-02 15:04:05", ins.GetMtime().GetValue()) if err != nil { log.Errorf("[Store][boltdb] parse instance mtime error, %v", err) return false } - - if insMtime.Before(mtime) { - return false - } - - if !ins.GetEnableHealthCheck().GetValue() { - return false - } - - if ins.GetHealthy().GetValue() { + if insMtime.Before(mtime) || !ins.GetEnableHealthCheck().GetValue() || ins.GetHealthy().GetValue() { return false } - return true }) @@ -255,7 +240,49 @@ func (m *adminStore) BatchCleanDeletedClients(timeout time.Duration, batchSize u // BatchCleanDeletedServices batch clean soft deleted clients func (m *adminStore) BatchCleanDeletedServices(timeout time.Duration, batchSize uint32) (uint32, error) { - return 0, nil + mtime := time.Now().Add(-timeout) + fields := []string{svcFieldValid, SvcFieldModifyTime} + values, err := m.handler.LoadValuesByFilter(tblNameService, fields, &model.Service{}, + func(m map[string]interface{}) bool { + valid, ok := m[svcFieldValid] + if !ok { + return false + } + if valid.(bool) { + return false + } + + modifyTime, ok := m[SvcFieldModifyTime] + if !ok { + return false + } + if modifyTime.(time.Time).After(mtime) { + return false + } + + return true + }) + if err != nil { + return 0, err + } + if len(values) == 0 { + return 0, nil + } + + var count uint32 = 0 + keys := make([]string, 0, batchSize) + for k := range values { + keys = append(keys, k) + count++ + if count >= batchSize { + break + } + } + err = m.handler.DeleteValues(tblNameService, keys) + if err != nil { + return count, err + } + return count, nil } // BatchCleanDeletedRules batch clean soft deleted clients @@ -267,3 +294,49 @@ func (m *adminStore) BatchCleanDeletedRules(rule string, timeout time.Duration, func (m *adminStore) BatchCleanDeletedConfigFiles(timeout time.Duration, batchSize uint32) (uint32, error) { return 0, nil } + +func (m *adminStore) BatchCleanDeletedServiceContracts(timeout time.Duration, batchSize uint32) (uint32, error) { + mtime := time.Now().Add(-timeout) + fields := []string{ContractFieldValid, ContractFieldModifyTime} + values, err := m.handler.LoadValuesByFilter(tblServiceContract, fields, &serviceContractStore{}, + func(m map[string]interface{}) bool { + valid, ok := m[ContractFieldValid] + if !ok { + return false + } + if valid.(bool) { + return false + } + + modifyTime, ok := m[ContractFieldModifyTime] + if !ok { + return false + } + if modifyTime.(time.Time).After(mtime) { + return false + } + + return true + }) + if err != nil { + return 0, err + } + if len(values) == 0 { + return 0, nil + } + + var count uint32 = 0 + keys := make([]string, 0, batchSize) + for k := range values { + keys = append(keys, k) + count++ + if count >= batchSize { + break + } + } + err = m.handler.DeleteValues(tblServiceContract, keys) + if err != nil { + return count, err + } + return count, nil +} diff --git a/store/mock/api_mock.go b/store/mock/api_mock.go index 18bfc97b9..5ea342a35 100644 --- a/store/mock/api_mock.go +++ b/store/mock/api_mock.go @@ -295,6 +295,21 @@ func (mr *MockStoreMockRecorder) BatchCleanDeletedRules(rule, timeout, batchSize return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchCleanDeletedRules", reflect.TypeOf((*MockStore)(nil).BatchCleanDeletedRules), rule, timeout, batchSize) } +// BatchCleanDeletedServiceContracts mocks base method. +func (m *MockStore) BatchCleanDeletedServiceContracts(timeout time.Duration, batchSize uint32) (uint32, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BatchCleanDeletedServiceContracts", timeout, batchSize) + ret0, _ := ret[0].(uint32) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BatchCleanDeletedServiceContracts indicates an expected call of BatchCleanDeletedServiceContracts. +func (mr *MockStoreMockRecorder) BatchCleanDeletedServiceContracts(timeout, batchSize interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchCleanDeletedServiceContracts", reflect.TypeOf((*MockStore)(nil).BatchCleanDeletedServiceContracts), timeout, batchSize) +} + // BatchCleanDeletedServices mocks base method. func (m *MockStore) BatchCleanDeletedServices(timeout time.Duration, batchSize uint32) (uint32, error) { m.ctrl.T.Helper() diff --git a/store/mysql/admin.go b/store/mysql/admin.go index 658c9d9cf..1423881a6 100644 --- a/store/mysql/admin.go +++ b/store/mysql/admin.go @@ -561,15 +561,159 @@ func (m *adminStore) BatchCleanDeletedClients(timeout time.Duration, batchSize u // BatchCleanDeletedServices batch clean soft deleted clients func (m *adminStore) BatchCleanDeletedServices(timeout time.Duration, batchSize uint32) (uint32, error) { - return 0, nil + log.Infof("[Store][database] batch clean soft deleted services(%d)", batchSize) + var rowsAffected int64 + err := m.master.processWithTransaction("batchCleanDeletedServices", func(tx *BaseTx) error { + // 查询出需要清理的实例 ID 信息 + loadWaitDel := "SELECT id FROM service WHERE flag = 1 AND " + + "mtime <= FROM_UNIXTIME(UNIX_TIMESTAMP(SYSDATE()) - ?) LIMIT ?" + rows, err := tx.Query(loadWaitDel, int32(timeout.Seconds()), batchSize) + if err != nil { + log.Errorf("[Store][database] batch clean soft deleted services(%d), err: %s", batchSize, err.Error()) + return store.Error(err) + } + waitDelIds := make([]interface{}, 0, batchSize) + defer func() { + _ = rows.Close() + }() + + placeholders := make([]string, 0, batchSize) + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + log.Errorf("[Store][database] scan deleted services id, err: %s", err.Error()) + return store.Error(err) + } + waitDelIds = append(waitDelIds, id) + placeholders = append(placeholders, "?") + } + + if len(waitDelIds) == 0 { + return nil + } + inSql := strings.Join(placeholders, ",") + + cleanMetaStr := fmt.Sprintf("delete from service_metadata where id in (%s)", inSql) + if _, err := tx.Exec(cleanMetaStr, waitDelIds...); err != nil { + log.Errorf("[Store][database] batch clean soft deleted services(%d), err: %s", batchSize, err.Error()) + return store.Error(err) + } + + cleanInsStr := fmt.Sprintf("delete from service where flag = 1 and id in (%s)", inSql) + result, err := tx.Exec(cleanInsStr, waitDelIds...) + if err != nil { + log.Errorf("[Store][database] batch clean soft deleted services(%d), err: %s", batchSize, err.Error()) + return store.Error(err) + } + + tRows, err := result.RowsAffected() + if err != nil { + log.Warnf("[Store][database] batch clean soft deleted services(%d), get RowsAffected err: %s", + batchSize, err.Error()) + return store.Error(err) + } + + if err = tx.Commit(); err != nil { + log.Errorf("[Store][database] batch clean soft deleted services(%d) commit tx err: %s", + batchSize, err.Error()) + return err + } + + rowsAffected = tRows + return nil + }) + return uint32(rowsAffected), err } // BatchCleanDeletedRules batch clean soft deleted clients func (m *adminStore) BatchCleanDeletedRules(rule string, timeout time.Duration, batchSize uint32) (uint32, error) { - return 0, nil + log.Infof("[Store][database] batch clean soft deleted %s(%d)", rule, batchSize) + var rows int64 + err := m.master.processWithTransaction("batchCleanDeleted"+rule, func(tx *BaseTx) error { + mainStr := "delete from " + rule + " where flag = 1 limit ?" + result, err := tx.Exec(mainStr, int32(timeout.Seconds()), batchSize) + if err != nil { + log.Errorf("[Store][database] batch clean soft deleted %s(%d), err: %s", rule, batchSize, err.Error()) + return store.Error(err) + } + + tRows, err := result.RowsAffected() + if err != nil { + log.Warnf("[Store][database] batch clean soft deleted %s(%d), get RowsAffected err: %s", + rule, batchSize, err.Error()) + return store.Error(err) + } + + if err := tx.Commit(); err != nil { + log.Errorf("[Store][database] batch clean soft deleted %s(%d) commit tx err: %s", + rule, batchSize, err.Error()) + return err + } + + rows = tRows + return nil + }) + return uint32(rows), err } // BatchCleanDeletedConfigFiles batch clean soft deleted clients func (m *adminStore) BatchCleanDeletedConfigFiles(timeout time.Duration, batchSize uint32) (uint32, error) { - return 0, nil + log.Infof("[Store][database] batch clean soft deleted config_files(%d)", batchSize) + var rows int64 + err := m.master.processWithTransaction("batchCleanDeletedConfigFiles", func(tx *BaseTx) error { + mainStr := "delete from config_file where flag = 1 limit ?" + result, err := tx.Exec(mainStr, int32(timeout.Seconds()), batchSize) + if err != nil { + log.Errorf("[Store][database] batch clean soft deleted config_files(%d), err: %s", batchSize, err.Error()) + return store.Error(err) + } + + tRows, err := result.RowsAffected() + if err != nil { + log.Warnf("[Store][database] batch clean soft deleted config_files(%d), get RowsAffected err: %s", + batchSize, err.Error()) + return store.Error(err) + } + + if err := tx.Commit(); err != nil { + log.Errorf("[Store][database] batch clean soft deleted config_files(%d) commit tx err: %s", + batchSize, err.Error()) + return err + } + + rows = tRows + return nil + }) + return uint32(rows), err +} + +// BatchCleanDeletedServiceContracts batch clean soft deleted service_contract +func (m *adminStore) BatchCleanDeletedServiceContracts(timeout time.Duration, batchSize uint32) (uint32, error) { + log.Infof("[Store][database] batch clean soft deleted service_contract(%d)", batchSize) + var rows int64 + err := m.master.processWithTransaction("batchCleanDeletedServiceContracts", func(tx *BaseTx) error { + mainStr := "delete from service_contract sc join service_contract_detail sd ON sc.id = sd.contract_id where sc.flag = 1 limit ?" + result, err := tx.Exec(mainStr, int32(timeout.Seconds()), batchSize) + if err != nil { + log.Errorf("[Store][database] batch clean soft deleted service_contract(%d), err: %s", batchSize, err.Error()) + return store.Error(err) + } + + tRows, err := result.RowsAffected() + if err != nil { + log.Warnf("[Store][database] batch clean soft deleted service_contract(%d), get RowsAffected err: %s", + batchSize, err.Error()) + return store.Error(err) + } + + if err := tx.Commit(); err != nil { + log.Errorf("[Store][database] batch clean soft deleted service_contract(%d) commit tx err: %s", + batchSize, err.Error()) + return err + } + + rows = tRows + return nil + }) + return uint32(rows), err } From 8980b089ec1cc8d190efb672b5239d4725b2645f Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 27 Nov 2024 09:51:48 +0800 Subject: [PATCH 13/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/model/config_file.go | 40 +++++++++++++++++++++++++++++++++ common/model/http.go | 6 +++++ config/client.go | 45 +++++++++---------------------------- config/test_export.go | 32 ++++++++++++++++++++++++-- service/client_info.go | 21 +++++++++++++++++ 5 files changed, 107 insertions(+), 37 deletions(-) diff --git a/common/model/config_file.go b/common/model/config_file.go index af9ce1347..32ae2577c 100644 --- a/common/model/config_file.go +++ b/common/model/config_file.go @@ -550,3 +550,43 @@ func ToConfigFileTemplateStore(template *config_manage.ConfigFileTemplate) *Conf ModifyBy: template.ModifyBy.GetValue(), } } + +type Subscriber struct { + // 客户端 ID 信息 + ID string `json:"id"` + // 客户端 Host 信息 + Host string `json:"host"` + // 客户端版本 + Version string `json:"version"` + // 客户端类型 + ClientType string `json:"client_type"` +} + +// ConfigSubscribers 以文件视角的监听数据 +type ConfigSubscribers struct { + // key + key ConfigFileKey + // VersionClients 版本对应的客户端 + VersionClients []*struct { + Versoin uint64 `json:"versoin"` + Subscribers []Subscriber `json:"subscribers"` + } `json:"clients"` +} + +// FileReleaseSubscribeInfo 文件订阅信息 +type FileReleaseSubscribeInfo struct { + Id uint64 `json:"id"` + Name string `json:"name"` + Namespace string `json:"namespace"` + Group string `json:"group"` + FileName string `json:"file_name"` + ReleaseType ReleaseType `json:"release_type"` + Version uint64 `json:"version"` +} + +// ClientSubscriber 以客户端视角的监听数据 +type ClientSubscriber struct { + Subscriber Subscriber `json:"subscriber"` + // Files + Files []FileReleaseSubscribeInfo `json:"files"` +} diff --git a/common/model/http.go b/common/model/http.go index 836beae8a..f81171fe6 100644 --- a/common/model/http.go +++ b/common/model/http.go @@ -29,3 +29,9 @@ type DebugHandler struct { Path string Handler http.HandlerFunc } + +type CommonResponse struct { + Code uint32 `json:"code"` + Info string `json:"info"` + Data interface{} `json:"data"` +} diff --git a/config/client.go b/config/client.go index ed8f0207c..4d1f3f3c3 100644 --- a/config/client.go +++ b/config/client.go @@ -206,41 +206,6 @@ func (s *Server) GetConfigGroupsWithCache(ctx context.Context, req *apiconfig.Cl return out } -func CompareByVersion(clientInfo *apiconfig.ClientConfigFileInfo, file *model.ConfigFileRelease) bool { - return clientInfo.GetVersion().GetValue() < file.Version -} - -// only for unit test -func (s *Server) checkClientConfigFile(ctx context.Context, files []*apiconfig.ClientConfigFileInfo, - compartor CompareFunction) (*apiconfig.ConfigClientResponse, bool) { - if len(files) == 0 { - return api.NewConfigClientResponse(apimodel.Code_InvalidWatchConfigFileFormat, nil), false - } - for _, configFile := range files { - namespace := configFile.GetNamespace().GetValue() - group := configFile.GetGroup().GetValue() - fileName := configFile.GetFileName().GetValue() - - if namespace == "" || group == "" || fileName == "" { - return api.NewConfigClientResponseWithInfo(apimodel.Code_BadRequest, - "namespace & group & fileName can not be empty"), false - } - // 从缓存中获取最新的配置文件信息 - release := s.fileCache.GetActiveRelease(namespace, group, fileName) - if release != nil && compartor(configFile, release) { - ret := &apiconfig.ClientConfigFileInfo{ - Namespace: utils.NewStringValue(namespace), - Group: utils.NewStringValue(group), - FileName: utils.NewStringValue(fileName), - Version: utils.NewUInt64Value(release.Version), - Md5: utils.NewStringValue(release.Md5), - } - return api.NewConfigClientResponse(apimodel.Code_ExecuteSuccess, ret), false - } - } - return api.NewConfigClientResponse(apimodel.Code_DataNoChange, nil), true -} - func toClientInfo(client *apiconfig.ClientConfigFileInfo, release *model.ConfigFileRelease) (*apiconfig.ClientConfigFileInfo, error) { @@ -327,3 +292,13 @@ func (s *Server) PublishConfigFileFromClient(ctx context.Context, configResponse := s.PublishConfigFile(ctx, client) return api.NewConfigClientResponseFromConfigResponse(configResponse) } + +// GetConfigSubscribers 根据配置视角获取订阅者列表 +func (s *Server) GetConfigSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse { + return nil +} + +// GetConfigSubscribers 根据客户端视角获取订阅的配置文件列表 +func (s *Server) GetClientSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse { + return nil +} diff --git a/config/test_export.go b/config/test_export.go index 6c3366714..518926371 100644 --- a/config/test_export.go +++ b/config/test_export.go @@ -22,11 +22,14 @@ import ( "fmt" apiconfig "github.com/polarismesh/specification/source/go/api/v1/config_manage" + apimodel "github.com/polarismesh/specification/source/go/api/v1/model" "go.uber.org/zap" "github.com/polarismesh/polaris/auth" "github.com/polarismesh/polaris/cache" + api "github.com/polarismesh/polaris/common/api/v1" "github.com/polarismesh/polaris/common/model" + "github.com/polarismesh/polaris/common/utils" "github.com/polarismesh/polaris/namespace" "github.com/polarismesh/polaris/plugin" "github.com/polarismesh/polaris/store" @@ -67,11 +70,36 @@ func TestInitialize(ctx context.Context, config Config, s store.Store, cacheMgn func (s *Server) TestCheckClientConfigFile(ctx context.Context, files []*apiconfig.ClientConfigFileInfo, compartor CompareFunction) (*apiconfig.ConfigClientResponse, bool) { - return s.checkClientConfigFile(ctx, files, compartor) + if len(files) == 0 { + return api.NewConfigClientResponse(apimodel.Code_InvalidWatchConfigFileFormat, nil), false + } + for _, configFile := range files { + namespace := configFile.GetNamespace().GetValue() + group := configFile.GetGroup().GetValue() + fileName := configFile.GetFileName().GetValue() + + if namespace == "" || group == "" || fileName == "" { + return api.NewConfigClientResponseWithInfo(apimodel.Code_BadRequest, + "namespace & group & fileName can not be empty"), false + } + // 从缓存中获取最新的配置文件信息 + release := s.fileCache.GetActiveRelease(namespace, group, fileName) + if release != nil && compartor(configFile, release) { + ret := &apiconfig.ClientConfigFileInfo{ + Namespace: utils.NewStringValue(namespace), + Group: utils.NewStringValue(group), + FileName: utils.NewStringValue(fileName), + Version: utils.NewUInt64Value(release.Version), + Md5: utils.NewStringValue(release.Md5), + } + return api.NewConfigClientResponse(apimodel.Code_ExecuteSuccess, ret), false + } + } + return api.NewConfigClientResponse(apimodel.Code_DataNoChange, nil), true } func TestCompareByVersion(clientInfo *apiconfig.ClientConfigFileInfo, file *model.ConfigFileRelease) bool { - return CompareByVersion(clientInfo, file) + return clientInfo.GetVersion().GetValue() < file.Version } // TestDecryptConfigFile 解密配置文件 diff --git a/service/client_info.go b/service/client_info.go index 105b79e57..189cbef8d 100644 --- a/service/client_info.go +++ b/service/client_info.go @@ -19,6 +19,7 @@ package service import ( "context" + "sort" apimodel "github.com/polarismesh/specification/source/go/api/v1/model" apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" @@ -177,6 +178,26 @@ func ClientEquals(client1 *apiservice.Client, client2 *apiservice.Client) bool { if len(client1.Stat) != len(client2.Stat) { return false } + + sortStat := func(stat []*apiservice.StatInfo) { + sort.Slice(stat, func(i, j int) bool { + if client1.Stat[i].GetTarget().GetValue() != client1.Stat[j].GetTarget().GetValue() { + return client1.Stat[i].GetTarget().GetValue() < client1.Stat[j].GetTarget().GetValue() + } + if client1.Stat[i].GetPort().GetValue() != client1.Stat[j].GetPort().GetValue() { + return client1.Stat[i].GetPort().GetValue() < client1.Stat[j].GetPort().GetValue() + } + if client1.Stat[i].GetPath().GetValue() != client1.Stat[j].GetPath().GetValue() { + return client1.Stat[i].GetPath().GetValue() < client1.Stat[j].GetPath().GetValue() + } + return client1.Stat[i].GetProtocol().GetValue() < client1.Stat[j].GetProtocol().GetValue() + }) + } + + // 针对 client1 和 client2 的 stat 进行排序 + sortStat(client1.Stat) + sortStat(client2.Stat) + for i := 0; i < len(client1.Stat); i++ { if client1.Stat[i].GetTarget().GetValue() != client2.Stat[i].GetTarget().GetValue() { return false From 0b00ebb1984fde6f15cbf6e91f994b1d7e6743ad Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 27 Nov 2024 11:47:45 +0800 Subject: [PATCH 14/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apiserver/nacosserver/v1/config/watch.go | 20 ++++ apiserver/nacosserver/v2/config/watch.go | 8 ++ cache/api/types.go | 2 +- common/model/client.go | 2 + common/model/config_file.go | 13 +-- common/model/http.go | 13 ++- config/api.go | 4 + config/client.go | 99 ++++++++++++++++++- config/interceptor/auth/config_file.go | 11 +++ .../paramcheck/config_file_check.go | 30 ++++++ config/watcher.go | 22 +++++ 11 files changed, 213 insertions(+), 11 deletions(-) diff --git a/apiserver/nacosserver/v1/config/watch.go b/apiserver/nacosserver/v1/config/watch.go index 42365ca85..b7fee566b 100644 --- a/apiserver/nacosserver/v1/config/watch.go +++ b/apiserver/nacosserver/v1/config/watch.go @@ -29,6 +29,7 @@ import ( ) type LongPollWatchContext struct { + lock sync.RWMutex clientId string labels map[string]string once sync.Once @@ -76,6 +77,9 @@ func (c *LongPollWatchContext) ClientID() string { // ShouldNotify . func (c *LongPollWatchContext) ShouldNotify(event *model.SimpleConfigFileRelease) bool { + c.lock.RLock() + defer c.lock.RUnlock() + key := event.FileKey() watchFile, ok := c.watchConfigFiles[key] if !ok { @@ -90,6 +94,9 @@ func (c *LongPollWatchContext) ShouldNotify(event *model.SimpleConfigFileRelease } func (c *LongPollWatchContext) ListWatchFiles() []*config_manage.ClientConfigFileInfo { + c.lock.RLock() + defer c.lock.RUnlock() + ret := make([]*config_manage.ClientConfigFileInfo, 0, len(c.watchConfigFiles)) for _, v := range c.watchConfigFiles { ret = append(ret, v) @@ -97,14 +104,27 @@ func (c *LongPollWatchContext) ListWatchFiles() []*config_manage.ClientConfigFil return ret } +func (c *LongPollWatchContext) CurWatchVersion(k string) uint64 { + c.lock.RLock() + defer c.lock.RUnlock() + + return c.watchConfigFiles[k].GetVersion().GetValue() +} + // AppendInterest . func (c *LongPollWatchContext) AppendInterest(item *config_manage.ClientConfigFileInfo) { + c.lock.Lock() + defer c.lock.Unlock() + key := model.BuildKeyForClientConfigFileInfo(item) c.watchConfigFiles[key] = item } // RemoveInterest . func (c *LongPollWatchContext) RemoveInterest(item *config_manage.ClientConfigFileInfo) { + c.lock.Lock() + defer c.lock.Unlock() + key := model.BuildKeyForClientConfigFileInfo(item) delete(c.watchConfigFiles, key) } diff --git a/apiserver/nacosserver/v2/config/watch.go b/apiserver/nacosserver/v2/config/watch.go index 185a1de73..187ea0582 100644 --- a/apiserver/nacosserver/v2/config/watch.go +++ b/apiserver/nacosserver/v2/config/watch.go @@ -123,6 +123,14 @@ func (c *StreamWatchContext) ListWatchFiles() []*apiconfig.ClientConfigFileInfo return c.watchConfigFiles.Values() } +func (c *StreamWatchContext) CurWatchVersion(k string) uint64 { + val, ok := c.watchConfigFiles.Load(k) + if !ok { + return 0 + } + return val.GetVersion().GetValue() +} + // AppendInterest . func (c *StreamWatchContext) AppendInterest(item *apiconfig.ClientConfigFileInfo) { key := model.BuildKeyForClientConfigFileInfo(item) diff --git a/cache/api/types.go b/cache/api/types.go index feee9f4a2..2f184cf7a 100644 --- a/cache/api/types.go +++ b/cache/api/types.go @@ -318,7 +318,7 @@ type ( QueryInstances(filter, metaFilter map[string]string, offset, limit uint32) (uint32, []*model.Instance, error) // DiscoverServiceInstances 服务发现获取实例 DiscoverServiceInstances(serviceID string, onlyHealthy bool) []*model.Instance - // RemoveService + // RemoveService RemoveService(serviceID string) } ) diff --git a/common/model/client.go b/common/model/client.go index dc0d6fd30..3d85fd2f3 100644 --- a/common/model/client.go +++ b/common/model/client.go @@ -141,4 +141,6 @@ const ( ClientLabel_Version = "CLIENT_VERSION" // ClientLabel_Language 客户端语言 ClientLabel_Language = "CLIENT_LANGUAGE" + // ClientLabel_Host 客户端主机名 + ClientLabel_Host = "CLIENT_HOST" ) diff --git a/common/model/config_file.go b/common/model/config_file.go index 32ae2577c..0db62a0a2 100644 --- a/common/model/config_file.go +++ b/common/model/config_file.go @@ -565,17 +565,18 @@ type Subscriber struct { // ConfigSubscribers 以文件视角的监听数据 type ConfigSubscribers struct { // key - key ConfigFileKey + Key ConfigFileKey // VersionClients 版本对应的客户端 - VersionClients []*struct { - Versoin uint64 `json:"versoin"` - Subscribers []Subscriber `json:"subscribers"` - } `json:"clients"` + VersionClients []*VersionClient `json:"clients"` +} + +type VersionClient struct { + Versoin uint64 `json:"versoin"` + Subscribers []*Subscriber `json:"subscribers"` } // FileReleaseSubscribeInfo 文件订阅信息 type FileReleaseSubscribeInfo struct { - Id uint64 `json:"id"` Name string `json:"name"` Namespace string `json:"namespace"` Group string `json:"group"` diff --git a/common/model/http.go b/common/model/http.go index f81171fe6..1df99633b 100644 --- a/common/model/http.go +++ b/common/model/http.go @@ -17,7 +17,11 @@ package model -import "net/http" +import ( + "net/http" + + api "github.com/polarismesh/polaris/common/api/v1" +) type DebugHandlerGroup struct { Name string @@ -35,3 +39,10 @@ type CommonResponse struct { Info string `json:"info"` Data interface{} `json:"data"` } + +func NewCommonResponse(code uint32) *CommonResponse { + return &CommonResponse{ + Code: code, + Info: api.Code2Info(code), + } +} diff --git a/config/api.go b/config/api.go index 78c35a94b..2594a2eb9 100644 --- a/config/api.go +++ b/config/api.go @@ -69,6 +69,10 @@ type ConfigFileOperate interface { configFiles []*apiconfig.ConfigFile, conflictHandling string) *apiconfig.ConfigImportResponse // GetAllConfigEncryptAlgorithms 获取配置加密算法 GetAllConfigEncryptAlgorithms(ctx context.Context) *apiconfig.ConfigEncryptAlgorithmResponse + // GetClientSubscribers 获取客户端订阅者 + GetClientSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse + // GetConfigSubscribers 获取配置订阅者 + GetConfigSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse } // ConfigFileReleaseOperate 配置文件发布接口 diff --git a/config/client.go b/config/client.go index 4d1f3f3c3..99e45d08e 100644 --- a/config/client.go +++ b/config/client.go @@ -295,10 +295,103 @@ func (s *Server) PublishConfigFileFromClient(ctx context.Context, // GetConfigSubscribers 根据配置视角获取订阅者列表 func (s *Server) GetConfigSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse { - return nil + namespace := filter["namespace"] + group := filter["group"] + fileName := filter["file_name"] + + key := utils.GenFileId(namespace, group, fileName) + clientIds, _ := s.watchCenter.watchers.Load(key) + if clientIds == nil { + return model.NewCommonResponse(uint32(apimodel.Code_NotFoundResource)) + } + + versionClients := map[uint64][]*model.Subscriber{} + clientIds.Range(func(val string) { + watchCtx, ok := s.watchCenter.clients.Load(val) + if !ok { + return + } + curVer := watchCtx.CurWatchVersion(key) + if _, ok := versionClients[curVer]; !ok { + versionClients[curVer] = []*model.Subscriber{} + } + + watchCtx.ClientLabels() + + versionClients[curVer] = append(versionClients[curVer], &model.Subscriber{ + ID: watchCtx.ClientID(), + Host: watchCtx.ClientLabels()[model.ClientLabel_Host], + Version: watchCtx.ClientLabels()[model.ClientLabel_Version], + ClientType: watchCtx.ClientLabels()[model.ClientLabel_Language], + }) + }) + + rsp := model.NewCommonResponse(uint32(apimodel.Code_ExecuteSuccess)) + rsp.Data = &model.ConfigSubscribers{ + Key: model.ConfigFileKey{ + Namespace: namespace, + Group: group, + Name: fileName, + }, + VersionClients: func() []*model.VersionClient { + ret := make([]*model.VersionClient, 0, len(versionClients)) + for ver, clients := range versionClients { + ret = append(ret, &model.VersionClient{ + Versoin: ver, + Subscribers: clients, + }) + } + return ret + }(), + } + return rsp } -// GetConfigSubscribers 根据客户端视角获取订阅的配置文件列表 +// GetClientSubscribers 根据客户端视角获取订阅的配置文件列表 func (s *Server) GetClientSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse { - return nil + clientId := filter["client_id"] + watchCtx, ok := s.watchCenter.clients.Load(clientId) + if !ok { + return model.NewCommonResponse(uint32(apimodel.Code_NotFoundResource)) + } + + watchFiles := watchCtx.ListWatchFiles() + data := &model.ClientSubscriber{ + Subscriber: model.Subscriber{ + ID: watchCtx.ClientID(), + Host: watchCtx.ClientLabels()[model.ClientLabel_Host], + Version: watchCtx.ClientLabels()[model.ClientLabel_Version], + ClientType: watchCtx.ClientLabels()[model.ClientLabel_Language], + }, + Files: []model.FileReleaseSubscribeInfo{}, + } + + for _, file := range watchFiles { + key := model.BuildKeyForClientConfigFileInfo(file) + curVer := watchCtx.CurWatchVersion(key) + + ns := file.GetNamespace().GetValue() + group := file.GetGroup().GetValue() + filename := file.GetFileName().GetValue() + + data.Files = append(data.Files, model.FileReleaseSubscribeInfo{ + Name: file.GetName().GetValue(), + Namespace: ns, + Group: group, + FileName: filename, + ReleaseType: func() model.ReleaseType { + if gray := s.fileCache.GetActiveGrayRelease(ns, group, filename); gray != nil { + if gray.Version == curVer { + return model.ReleaseTypeGray + } + } + return model.ReleaseTypeFull + }(), + Version: curVer, + }) + } + + rsp := model.NewCommonResponse(uint32(apimodel.Code_ExecuteSuccess)) + rsp.Data = data + return rsp } diff --git a/config/interceptor/auth/config_file.go b/config/interceptor/auth/config_file.go index f515b8f55..e9e4245bd 100644 --- a/config/interceptor/auth/config_file.go +++ b/config/interceptor/auth/config_file.go @@ -23,6 +23,7 @@ import ( apiconfig "github.com/polarismesh/specification/source/go/api/v1/config_manage" api "github.com/polarismesh/polaris/common/api/v1" + "github.com/polarismesh/polaris/common/model" "github.com/polarismesh/polaris/common/model/auth" "github.com/polarismesh/polaris/common/utils" ) @@ -152,3 +153,13 @@ func (s *Server) GetAllConfigEncryptAlgorithms( ctx context.Context) *apiconfig.ConfigEncryptAlgorithmResponse { return s.nextServer.GetAllConfigEncryptAlgorithms(ctx) } + +// GetClientSubscribers 获取客户端订阅者 +func (s *Server) GetClientSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse { + return s.nextServer.GetClientSubscribers(ctx, filter) +} + +// GetConfigSubscribers 获取配置订阅者 +func (s *Server) GetConfigSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse { + return s.nextServer.GetConfigSubscribers(ctx, filter) +} diff --git a/config/interceptor/paramcheck/config_file_check.go b/config/interceptor/paramcheck/config_file_check.go index cf70f043b..0888a38d5 100644 --- a/config/interceptor/paramcheck/config_file_check.go +++ b/config/interceptor/paramcheck/config_file_check.go @@ -23,8 +23,10 @@ import ( apiconfig "github.com/polarismesh/specification/source/go/api/v1/config_manage" apimodel "github.com/polarismesh/specification/source/go/api/v1/model" + "google.golang.org/protobuf/types/known/wrapperspb" api "github.com/polarismesh/polaris/common/api/v1" + "github.com/polarismesh/polaris/common/model" "github.com/polarismesh/polaris/common/utils" ) @@ -115,3 +117,31 @@ func (s *Server) GetAllConfigEncryptAlgorithms( ctx context.Context) *apiconfig.ConfigEncryptAlgorithmResponse { return s.nextServer.GetAllConfigEncryptAlgorithms(ctx) } + +// GetClientSubscribers 获取客户端订阅者 +func (s *Server) GetClientSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse { + clientId := filter["client_id"] + if clientId == "" { + return model.NewCommonResponse(uint32(apimodel.Code_BadRequest)) + } + return s.nextServer.GetClientSubscribers(ctx, filter) +} + +// GetConfigSubscribers 获取配置订阅者 +func (s *Server) GetConfigSubscribers(ctx context.Context, filter map[string]string) *model.CommonResponse { + namespace := filter["namespace"] + group := filter["group"] + fileName := filter["file_name"] + + if err := CheckFileName(wrapperspb.String(fileName)); err != nil { + return model.NewCommonResponse(uint32(apimodel.Code_InvalidConfigFileName)) + } + if err := utils.CheckResourceName(wrapperspb.String(group)); err != nil { + return model.NewCommonResponse(uint32(apimodel.Code_InvalidConfigFileGroupName)) + } + if err := utils.CheckResourceName(wrapperspb.String(namespace)); err != nil { + return model.NewCommonResponse(uint32(apimodel.Code_InvalidNamespaceName)) + } + + return s.nextServer.GetConfigSubscribers(ctx, filter) +} diff --git a/config/watcher.go b/config/watcher.go index 3d8323d5f..e49bc65c2 100644 --- a/config/watcher.go +++ b/config/watcher.go @@ -71,12 +71,15 @@ type ( ShouldExpire(now time.Time) bool // ListWatchFiles 列举出当前订阅的所有配置文件 ListWatchFiles() []*apiconfig.ClientConfigFileInfo + // CurWatchVersion 获取当前订阅的配置文件的版本 + CurWatchVersion(k string) uint64 // IsOnce 是不是只能被通知一次 IsOnce() bool } ) type LongPollWatchContext struct { + lock sync.RWMutex clientId string labels map[string]string once sync.Once @@ -120,6 +123,9 @@ func (c *LongPollWatchContext) ClientID() string { } func (c *LongPollWatchContext) ShouldNotify(event *model.SimpleConfigFileRelease) bool { + c.lock.RLock() + defer c.lock.RUnlock() + if event.ReleaseType == model.ReleaseTypeGray && !c.betaMatcher(c.ClientLabels(), event) { return false } @@ -133,6 +139,9 @@ func (c *LongPollWatchContext) ShouldNotify(event *model.SimpleConfigFileRelease } func (c *LongPollWatchContext) ListWatchFiles() []*apiconfig.ClientConfigFileInfo { + c.lock.RLock() + defer c.lock.RUnlock() + ret := make([]*apiconfig.ClientConfigFileInfo, 0, len(c.watchConfigFiles)) for _, v := range c.watchConfigFiles { ret = append(ret, v) @@ -140,14 +149,27 @@ func (c *LongPollWatchContext) ListWatchFiles() []*apiconfig.ClientConfigFileInf return ret } +func (c *LongPollWatchContext) CurWatchVersion(k string) uint64 { + c.lock.RLock() + defer c.lock.RUnlock() + + return c.watchConfigFiles[k].GetVersion().GetValue() +} + // AppendInterest . func (c *LongPollWatchContext) AppendInterest(item *apiconfig.ClientConfigFileInfo) { + c.lock.Lock() + defer c.lock.Unlock() + key := model.BuildKeyForClientConfigFileInfo(item) c.watchConfigFiles[key] = item } // RemoveInterest . func (c *LongPollWatchContext) RemoveInterest(item *apiconfig.ClientConfigFileInfo) { + c.lock.Lock() + defer c.lock.Unlock() + key := model.BuildKeyForClientConfigFileInfo(item) delete(c.watchConfigFiles, key) } From db26d9d1b85508fd245dd9ff178cd97dce954fe2 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 27 Nov 2024 14:18:43 +0800 Subject: [PATCH 15/21] =?UTF-8?q?feat:=E6=94=AF=E6=8C=81=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E7=AE=A1=E7=90=86=E5=91=98=E5=B8=90=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f2590eca3..b571f4cc7 100644 --- a/go.mod +++ b/go.mod @@ -78,7 +78,7 @@ require ( require ( github.com/DATA-DOG/go-sqlmock v1.5.0 - github.com/polarismesh/specification v1.5.3-alpha.2 + github.com/polarismesh/specification v1.5.4 ) require ( diff --git a/go.sum b/go.sum index ef02521f5..46c47454b 100644 --- a/go.sum +++ b/go.sum @@ -300,8 +300,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polarismesh/go-restful-openapi/v2 v2.0.0-20220928152401-083908d10219 h1:XnFyNUWnciM6zgXaz6tm+Egs35rhoD0KGMmKh4gCdi0= github.com/polarismesh/go-restful-openapi/v2 v2.0.0-20220928152401-083908d10219/go.mod h1:4WhwBysTom9Eoy0hQ4W69I0FmO+T0EpjEW9/5sgHoUk= -github.com/polarismesh/specification v1.5.3-alpha.2 h1:QSgpGmx5VfPcDPAq7qnTOkMVFNpmBMgLSDhtyMlS6/g= -github.com/polarismesh/specification v1.5.3-alpha.2/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= +github.com/polarismesh/specification v1.5.4 h1:a0aAO/E12wbASFCC5nCeXtDDYay6vtmn6jpYjxTAsbY= +github.com/polarismesh/specification v1.5.4/go.mod h1:rDvMMtl5qebPmqiBLNa5Ps0XtwkP31ZLirbH4kXA0YU= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= From 722ebbf5dfd054b2791f89cb76fafdd98392ec8a Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Fri, 29 Nov 2024 10:50:37 +0800 Subject: [PATCH 16/21] =?UTF-8?q?fix:=E6=9C=8D=E5=8A=A1=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81=E6=80=A7?= =?UTF-8?q?&=E4=BF=AE=E5=A4=8D=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81?= =?UTF-8?q?=E6=80=A7=E4=BC=98=E5=85=88=E7=BA=A7=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cache/api/types.go | 4 +++- cache/service/service.go | 39 +++++++++++++++++++++++++++++------ cache/service/service_test.go | 8 +++---- service/client_v1.go | 29 ++++++++++++++++++++------ service/client_v1_test.go | 26 +++++++++++++++++++++++ 5 files changed, 89 insertions(+), 17 deletions(-) create mode 100644 service/client_v1_test.go diff --git a/cache/api/types.go b/cache/api/types.go index 2f184cf7a..03ea3b43a 100644 --- a/cache/api/types.go +++ b/cache/api/types.go @@ -267,7 +267,9 @@ type ( // GetRevisionWorker . GetRevisionWorker() ServiceRevisionWorker // GetVisibleServicesInOtherNamespace get same service in other namespace and it's visible - GetVisibleServicesInOtherNamespace(name string, namespace string) []*model.Service + // 如果 name == *,表示返回所有对 namespace 可见的服务 + // 如果 name 是具体服务,表示返回对 name + namespace 设置了可见的服务 + GetVisibleServicesInOtherNamespace(ctx context.Context, name string, namespace string) []*model.Service } // ServiceRevisionWorker diff --git a/cache/service/service.go b/cache/service/service.go index 310b8837a..ef27a54fe 100644 --- a/cache/service/service.go +++ b/cache/service/service.go @@ -637,7 +637,7 @@ func (sc *serviceCache) updateCl5SidAndNames(service *model.Service) { } // GetVisibleServicesInOtherNamespace 查询是否存在别的命名空间下存在名称相同且可见的服务 -func (sc *serviceCache) GetVisibleServicesInOtherNamespace(svcName, namespace string) []*model.Service { +func (sc *serviceCache) GetVisibleServicesInOtherNamespace(ctx context.Context, svcName, namespace string) []*model.Service { ret := make(map[string]*model.Service) // 根据服务级别的可见性进行查询, 先查询精确匹配 sc.exportServices.ReadRange(func(exportToNs string, services *utils.SyncMap[string, *model.Service]) { @@ -645,7 +645,7 @@ func (sc *serviceCache) GetVisibleServicesInOtherNamespace(svcName, namespace st return } services.ReadRange(func(_ string, svc *model.Service) { - if svc.Name == svcName && svc.Namespace != namespace { + if (svc.Name == svcName || utils.IsMatchAll(svcName)) && svc.Namespace != namespace { ret[svc.ID] = svc } }) @@ -658,11 +658,38 @@ func (sc *serviceCache) GetVisibleServicesInOtherNamespace(svcName, namespace st if !exactMatch && !allMatch { return } - svc := sc.GetServiceByName(svcName, exportNs) - if svc == nil { - return + if utils.IsMatchAll(svcName) { + // 如果是全匹配,那就看下这个命名空间下的所有服务 + _, svcs := sc.ListServices(ctx, exportNs) + for i := range svcs { + if len(svcs[i].ExportTo) != 0 { + // 需要在额外判断下 svc 自己可见性设置 + _, exactMatch := svcs[i].ExportTo[namespace] + _, allMatch := svcs[i].ExportTo[types.AllMatched] + if !exactMatch && !allMatch { + continue + } + } + + ret[svcs[i].ID] = svcs[i] + } + } else { + svc := sc.GetServiceByName(svcName, exportNs) + if svc == nil { + return + } + // 可能 svc 有自己的可见性设置,此处优先级高于 namespace 的可见性设置 + if len(svc.ExportTo) != 0 { + // 需要在额外判断下 svc 自己可见性设置 + _, exactMatch := svc.ExportTo[namespace] + _, allMatch := svc.ExportTo[namespace] + if !exactMatch && !allMatch { + return + } + } + + ret[svc.ID] = svc } - ret[svc.ID] = svc }) visibleServices := make([]*model.Service, 0, len(ret)) diff --git a/cache/service/service_test.go b/cache/service/service_test.go index b9015e3ec..9e70d045b 100644 --- a/cache/service/service_test.go +++ b/cache/service/service_test.go @@ -650,7 +650,7 @@ func Test_serviceCache_GetVisibleServicesInOtherNamespace(t *testing.T) { }) _, _, _ = svcCache.setServices(serviceList) - visibles := svcCache.GetVisibleServicesInOtherNamespace("service-1", "ns-2") + visibles := svcCache.GetVisibleServicesInOtherNamespace(context.Background(), "service-1", "ns-2") assert.Equal(t, 1, len(visibles)) assert.Equal(t, "ns-1", visibles[0].Namespace) }) @@ -707,15 +707,15 @@ func Test_serviceCache_GetVisibleServicesInOtherNamespace(t *testing.T) { }, }) - visibles := svcCache.GetVisibleServicesInOtherNamespace("service-1", "ns-2") + visibles := svcCache.GetVisibleServicesInOtherNamespace(context.Background(), "service-1", "ns-2") assert.Equal(t, 1, len(visibles)) assert.Equal(t, "ns-1", visibles[0].Namespace) - visibles = svcCache.GetVisibleServicesInOtherNamespace("service-1", "ns-3") + visibles = svcCache.GetVisibleServicesInOtherNamespace(context.Background(), "service-1", "ns-3") assert.Equal(t, 1, len(visibles)) assert.Equal(t, "ns-1", visibles[0].Namespace) - visibles = svcCache.GetVisibleServicesInOtherNamespace("service-1", "ns-4") + visibles = svcCache.GetVisibleServicesInOtherNamespace(context.Background(), "service-1", "ns-4") assert.Equal(t, 0, len(visibles)) }) diff --git a/service/client_v1.go b/service/client_v1.go index 9f97cf798..66abf3107 100644 --- a/service/client_v1.go +++ b/service/client_v1.go @@ -176,7 +176,23 @@ func (s *Server) GetServiceWithCache(ctx context.Context, req *apiservice.Servic if req.GetNamespace().GetValue() != "" { revision, svcs = s.Cache().Service().ListServices(ctx, req.GetNamespace().GetValue()) + // 需要加上服务可见性处理 + visibleSvcs := s.caches.Service().GetVisibleServicesInOtherNamespace(ctx, utils.MatchAll, req.GetNamespace().GetValue()) + revisions := make([]string, 0, len(visibleSvcs)+1) + revisions = append(revisions, revision) + for i := range visibleSvcs { + revisions = append(revisions, visibleSvcs[i].Revision) + } + if rever, err := cachetypes.CompositeComputeRevision(revisions); err != nil { + // 如果计算失败,直接返回一个新的revision + revision = utils.NewUUID() + } else { + revision = rever + } + svcs = append(svcs, visibleSvcs...) + // 需要重新计算 revison } else { + // 这里拉的是全部服务实例列表,如果客户端可以发起这个请求,应该是不需要 revision, svcs = s.Cache().Service().ListAllServices(ctx) } if revision == "" { @@ -212,14 +228,14 @@ func (s *Server) ServiceInstancesCache(ctx context.Context, filter *apiservice.D req *apiservice.Service) *apiservice.DiscoverResponse { resp := createCommonDiscoverResponse(req, apiservice.DiscoverResponse_INSTANCE) - serviceName := req.GetName().GetValue() - namespaceName := req.GetNamespace().GetValue() + svcName := req.GetName().GetValue() + nsName := req.GetNamespace().GetValue() // 数据源都来自Cache,这里拿到的service,已经是源服务 - aliasFor, visibleServices := s.findVisibleServices(serviceName, namespaceName, req) + aliasFor, visibleServices := s.findVisibleServices(ctx, svcName, nsName, req) if len(visibleServices) == 0 { log.Infof("[Server][Service][Instance] not found name(%s) namespace(%s) service", - serviceName, namespaceName) + svcName, nsName) return api.NewDiscoverInstanceResponse(apimodel.Code_NotFoundResource, req) } @@ -273,14 +289,15 @@ func (s *Server) ServiceInstancesCache(ctx context.Context, filter *apiservice.D return resp } -func (s *Server) findVisibleServices(serviceName, namespaceName string, req *apiservice.Service) (*model.Service, []*model.Service) { +func (s *Server) findVisibleServices(ctx context.Context, serviceName, namespaceName string, + req *apiservice.Service) (*model.Service, []*model.Service) { visibleServices := make([]*model.Service, 0, 4) // 数据源都来自Cache,这里拿到的service,已经是源服务 aliasFor := s.getServiceCache(serviceName, namespaceName) if aliasFor != nil { visibleServices = append(visibleServices, aliasFor) } - ret := s.caches.Service().GetVisibleServicesInOtherNamespace(serviceName, namespaceName) + ret := s.caches.Service().GetVisibleServicesInOtherNamespace(ctx, serviceName, namespaceName) if len(ret) > 0 { visibleServices = append(visibleServices, ret...) } diff --git a/service/client_v1_test.go b/service/client_v1_test.go new file mode 100644 index 000000000..07f388f96 --- /dev/null +++ b/service/client_v1_test.go @@ -0,0 +1,26 @@ +/** + * Tencent is pleased to support the open source community by making Polaris available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * 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 service + +import ( + "testing" +) + +func TestServer_GetServiceWithCache(t *testing.T) { + // TODO +} From 48e85105e7d47533babafb8c4df4d629121b6d7f Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Fri, 29 Nov 2024 11:37:33 +0800 Subject: [PATCH 17/21] =?UTF-8?q?fix:=E6=9C=8D=E5=8A=A1=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81=E6=80=A7?= =?UTF-8?q?&=E4=BF=AE=E5=A4=8D=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81?= =?UTF-8?q?=E6=80=A7=E4=BC=98=E5=85=88=E7=BA=A7=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/client_v1.go | 5 +++-- store/mysql/service.go | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/service/client_v1.go b/service/client_v1.go index 66abf3107..268596058 100644 --- a/service/client_v1.go +++ b/service/client_v1.go @@ -184,8 +184,9 @@ func (s *Server) GetServiceWithCache(ctx context.Context, req *apiservice.Servic revisions = append(revisions, visibleSvcs[i].Revision) } if rever, err := cachetypes.CompositeComputeRevision(revisions); err != nil { - // 如果计算失败,直接返回一个新的revision - revision = utils.NewUUID() + log.Errorf("[Server][Discover] list services compute multi revision", + zap.String("namespace", req.GetNamespace().GetValue()), zap.Error(err)) + return api.NewDiscoverInstanceResponse(apimodel.Code_ExecuteException, req) } else { revision = rever } diff --git a/store/mysql/service.go b/store/mysql/service.go index e7e7bde00..cc30163a9 100644 --- a/store/mysql/service.go +++ b/store/mysql/service.go @@ -1050,7 +1050,6 @@ func callFetchServiceRows(rows *sql.Rows, callback func(entry *model.Service) (b } defer rows.Close() - var ctime, mtime int64 var flag int progress := 0 for rows.Next() { @@ -1063,7 +1062,7 @@ func callFetchServiceRows(rows *sql.Rows, callback func(entry *model.Service) (b var exportTo string err := rows.Scan( &item.ID, &item.Name, &item.Namespace, &item.Business, &item.Comment, - &item.Token, &item.Revision, &item.Owner, &flag, &ctime, &mtime, &item.Ports, + &item.Token, &item.Revision, &item.Owner, &flag, &item.Ctime, &item.Mtime, &item.Ports, &item.Department, &item.CmdbMod1, &item.CmdbMod2, &item.CmdbMod3, &item.Reference, &item.ReferFilter, &item.PlatformID, &exportTo) @@ -1072,8 +1071,8 @@ func callFetchServiceRows(rows *sql.Rows, callback func(entry *model.Service) (b return err } - item.CreateTime = time.Unix(ctime, 0) - item.ModifyTime = time.Unix(mtime, 0) + item.CreateTime = time.Unix(item.Ctime, 0) + item.ModifyTime = time.Unix(item.Mtime, 0) item.ExportTo = map[string]struct{}{} _ = json.Unmarshal([]byte(exportTo), &item.ExportTo) item.Valid = true From 46387bf9fa6a286b9a7e365ba34d5a4303f9728d Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Fri, 29 Nov 2024 11:38:20 +0800 Subject: [PATCH 18/21] =?UTF-8?q?fix:=E6=9C=8D=E5=8A=A1=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81=E6=80=A7?= =?UTF-8?q?&=E4=BF=AE=E5=A4=8D=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81?= =?UTF-8?q?=E6=80=A7=E4=BC=98=E5=85=88=E7=BA=A7=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/client_v1.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/client_v1.go b/service/client_v1.go index 268596058..7fff9f32f 100644 --- a/service/client_v1.go +++ b/service/client_v1.go @@ -184,7 +184,7 @@ func (s *Server) GetServiceWithCache(ctx context.Context, req *apiservice.Servic revisions = append(revisions, visibleSvcs[i].Revision) } if rever, err := cachetypes.CompositeComputeRevision(revisions); err != nil { - log.Errorf("[Server][Discover] list services compute multi revision", + log.Error("[Server][Discover] list services compute multi revision", zap.String("namespace", req.GetNamespace().GetValue()), zap.Error(err)) return api.NewDiscoverInstanceResponse(apimodel.Code_ExecuteException, req) } else { From a09ba8418639e3f126ca04cb2b712900a615014e Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Fri, 29 Nov 2024 11:48:17 +0800 Subject: [PATCH 19/21] =?UTF-8?q?fix:=E6=9C=8D=E5=8A=A1=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81=E6=80=A7?= =?UTF-8?q?&=E4=BF=AE=E5=A4=8D=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81?= =?UTF-8?q?=E6=80=A7=E4=BC=98=E5=85=88=E7=BA=A7=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/client_v1.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/client_v1.go b/service/client_v1.go index 7fff9f32f..e7c3f7037 100644 --- a/service/client_v1.go +++ b/service/client_v1.go @@ -183,6 +183,8 @@ func (s *Server) GetServiceWithCache(ctx context.Context, req *apiservice.Servic for i := range visibleSvcs { revisions = append(revisions, visibleSvcs[i].Revision) } + svcs = append(svcs, visibleSvcs...) + // 需要重新计算 revison if rever, err := cachetypes.CompositeComputeRevision(revisions); err != nil { log.Error("[Server][Discover] list services compute multi revision", zap.String("namespace", req.GetNamespace().GetValue()), zap.Error(err)) @@ -190,8 +192,6 @@ func (s *Server) GetServiceWithCache(ctx context.Context, req *apiservice.Servic } else { revision = rever } - svcs = append(svcs, visibleSvcs...) - // 需要重新计算 revison } else { // 这里拉的是全部服务实例列表,如果客户端可以发起这个请求,应该是不需要 revision, svcs = s.Cache().Service().ListAllServices(ctx) From 1a2334b3fc6a5a790f3de6c8dbb93d9946a98a08 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Wed, 4 Dec 2024 17:06:26 +0800 Subject: [PATCH 20/21] =?UTF-8?q?fix:=E6=9C=8D=E5=8A=A1=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81=E6=80=A7?= =?UTF-8?q?&=E4=BF=AE=E5=A4=8D=E6=9C=8D=E5=8A=A1=E5=8F=AF=E8=A7=81?= =?UTF-8?q?=E6=80=A7=E4=BC=98=E5=85=88=E7=BA=A7=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../grpcserver/discover/v1/client_access.go | 3 ++ service/api.go | 2 ++ service/client_v1.go | 30 +++++++++++++++++++ service/interceptor/auth/client_v1.go | 13 ++++++++ service/interceptor/paramcheck/client.go | 9 ++++++ 5 files changed, 57 insertions(+) diff --git a/apiserver/grpcserver/discover/v1/client_access.go b/apiserver/grpcserver/discover/v1/client_access.go index 5915a2f6c..e040e8e75 100644 --- a/apiserver/grpcserver/discover/v1/client_access.go +++ b/apiserver/grpcserver/discover/v1/client_access.go @@ -164,6 +164,9 @@ func (g *DiscoverServer) handleDiscoverRequest(ctx context.Context, in *apiservi case apiservice.DiscoverRequest_ROUTING: action = metrics.ActionDiscoverRouterRule out = g.namingServer.GetRoutingConfigWithCache(ctx, in.Service) + case apiservice.DiscoverRequest_CUSTOM_ROUTE_RULE: + action = metrics.ActionDiscoverRouterRule + out = g.namingServer.GetRoutingConfigWithCache(ctx, in.Service) case apiservice.DiscoverRequest_RATE_LIMIT: action = metrics.ActionDiscoverRateLimit out = g.namingServer.GetRateLimitWithCache(ctx, in.Service) diff --git a/service/api.go b/service/api.go index 676f806cb..e0f63f88b 100644 --- a/service/api.go +++ b/service/api.go @@ -222,6 +222,8 @@ type ClientServer interface { ReportServiceContract(ctx context.Context, req *apiservice.ServiceContract) *apiservice.Response // GetLaneRuleWithCache fetch lane rules by client GetLaneRuleWithCache(ctx context.Context, req *apiservice.Service) *apiservice.DiscoverResponse + // GetRouterRuleWithCache fetch lane rules by client + GetRouterRuleWithCache(ctx context.Context, req *apiservice.Service) *apiservice.DiscoverResponse } // L5OperateServer L5 related operations diff --git a/service/client_v1.go b/service/client_v1.go index e7c3f7037..065d4821c 100644 --- a/service/client_v1.go +++ b/service/client_v1.go @@ -499,6 +499,36 @@ func (s *Server) GetLaneRuleWithCache(ctx context.Context, req *apiservice.Servi return resp } +// GetRouterRuleWithCache fetch lane rules by client +func (s *Server) GetRouterRuleWithCache(ctx context.Context, req *apiservice.Service) *apiservice.DiscoverResponse { + resp := createCommonDiscoverResponse(req, apiservice.DiscoverResponse_CUSTOM_ROUTE_RULE) + aliasFor := s.findServiceAlias(req) + + out, err := s.caches.RoutingConfig().GetRouterConfigV2(aliasFor.ID, aliasFor.Name, aliasFor.Namespace) + if err != nil { + log.Error("[Server][Service][Routing] discover routing", utils.RequestID(ctx), zap.Error(err)) + return api.NewDiscoverRoutingResponse(apimodel.Code_ExecuteException, req) + } + if out == nil { + return resp + } + + // 获取路由数据,并对比revision + if out.GetRevision().GetValue() == req.GetRevision().GetValue() { + return api.NewDiscoverRoutingResponse(apimodel.Code_DataNoChange, req) + } + + // 数据不一致,发生了改变 + // 数据格式转换,service只需要返回二元组与routing的revision + resp.Service.Revision = out.GetRevision() + resp.CustomRouteRules = out.Rules + resp.AliasFor = &apiservice.Service{ + Name: utils.NewStringValue(aliasFor.Name), + Namespace: utils.NewStringValue(aliasFor.Namespace), + } + return resp +} + func (s *Server) findServiceAlias(req *apiservice.Service) *model.Service { // 获取源服务 aliasFor := s.getServiceCache(req.GetName().GetValue(), req.GetNamespace().GetValue()) diff --git a/service/interceptor/auth/client_v1.go b/service/interceptor/auth/client_v1.go index 4dd6a0fb3..2c24cae95 100644 --- a/service/interceptor/auth/client_v1.go +++ b/service/interceptor/auth/client_v1.go @@ -236,3 +236,16 @@ func (svr *Server) GetLaneRuleWithCache(ctx context.Context, req *apiservice.Ser return svr.nextSvr.GetLaneRuleWithCache(ctx, req) } + +// GetRouterRuleWithCache . +func (svr *Server) GetRouterRuleWithCache(ctx context.Context, req *apiservice.Service) *apiservice.DiscoverResponse { + authCtx := svr.collectServiceAuthContext( + ctx, []*apiservice.Service{req}, authcommon.Read, authcommon.DiscoverRouterRule) + if _, err := svr.policySvr.GetAuthChecker().CheckClientPermission(authCtx); err != nil { + return api.NewDiscoverResponse(authcommon.ConvertToErrCode(err)) + } + ctx = authCtx.GetRequestContext() + ctx = context.WithValue(ctx, utils.ContextAuthContextKey, authCtx) + + return svr.nextSvr.GetRouterRuleWithCache(ctx, req) +} diff --git a/service/interceptor/paramcheck/client.go b/service/interceptor/paramcheck/client.go index 83c5d7246..f56fa5a9f 100644 --- a/service/interceptor/paramcheck/client.go +++ b/service/interceptor/paramcheck/client.go @@ -162,6 +162,15 @@ func (s *Server) GetLaneRuleWithCache(ctx context.Context, req *apiservice.Servi return s.nextSvr.GetLaneRuleWithCache(ctx, req) } +// GetRouterRuleWithCache . +func (s *Server) GetRouterRuleWithCache(ctx context.Context, req *apiservice.Service) *apiservice.DiscoverResponse { + resp := service.CreateCommonDiscoverResponse(req, apiservice.DiscoverResponse_CUSTOM_ROUTE_RULE) + if !s.commonCheckDiscoverRequest(req, resp) { + return resp + } + return s.nextSvr.GetRouterRuleWithCache(ctx, req) +} + // UpdateInstance update one instance by client func (s *Server) UpdateInstance(ctx context.Context, req *apiservice.Instance) *apiservice.Response { // 参数检查 From c346bafae8e6ff186b47f191304f22f3918f47e1 Mon Sep 17 00:00:00 2001 From: chuntaojun Date: Tue, 4 Mar 2025 10:13:32 +0800 Subject: [PATCH 21/21] =?UTF-8?q?fix:=E7=A7=BB=E9=99=A4=20serviceCount=20?= =?UTF-8?q?=E7=9A=84=E8=AE=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cache/service/service.go | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/cache/service/service.go b/cache/service/service.go index ef27a54fe..62e54fcaa 100644 --- a/cache/service/service.go +++ b/cache/service/service.go @@ -63,9 +63,7 @@ type serviceCache struct { // namespace -> model.NamespaceServiceCount namespaceServiceCnt *utils.SyncMap[string, *model.NamespaceServiceCount] - lastMtimeLogged int64 - - serviceCount int64 + lastMtimeLogged int64 lastCheckAllTime int64 revisionWorker *ServiceRevisionWorker @@ -166,12 +164,12 @@ func (sc *serviceCache) checkAll() { log.Errorf("[Cache][Service] get service count from storage err: %s", err.Error()) return } - if sc.serviceCount == int64(count) { + if int64(sc.ids.Len()) == int64(count) { return } log.Infof( "[Cache][Service] service count not match, expect %d, actual %d, fallback to load all", - count, sc.serviceCount) + count, sc.ids.Len()) sc.ResetLastMtime(sc.Name()) } @@ -441,7 +439,7 @@ func (sc *serviceCache) setServices(services map[string]*model.Service) (map[str // 这里要记录 ns 的变动情况,避免由于 svc delete 之后,命名空间的服务计数无法更新 changeNs := make(map[string]struct{}) - svcCount := sc.serviceCount + svcCount := sc.ids.Len() aliases := make([]*model.Service, 0, 32) @@ -459,7 +457,7 @@ func (sc *serviceCache) setServices(services map[string]*model.Service) (map[str if service.IsAlias() { aliases = append(aliases, service) } - oldVal, exist := sc.ids.Load(service.ID) + oldVal, _ := sc.ids.Load(service.ID) if oldVal != nil { service.OldExportTo = oldVal.ExportTo } @@ -471,14 +469,10 @@ func (sc *serviceCache) setServices(services map[string]*model.Service) (map[str sc.removeServices(service) sc.notifyRevisionWorker(service.ID, false) del++ - svcCount-- continue } update++ - if !exist { - svcCount++ - } sc.ids.Store(service.ID, service) sc.serviceList.addService(service) @@ -496,10 +490,8 @@ func (sc *serviceCache) setServices(services map[string]*model.Service) (map[str /******兼容cl5******/ } - if sc.serviceCount != svcCount { - log.Infof("[Cache][Service] service count update from %d to %d", - sc.serviceCount, svcCount) - sc.serviceCount = svcCount + if sc.ids.Len() != svcCount { + log.Infof("[Cache][Service] service count update from %d to %d", svcCount, sc.ids.Len()) } sc.postProcessServiceAlias(aliases)