Skip to content

Commit

Permalink
feat(config): support gray
Browse files Browse the repository at this point in the history
  • Loading branch information
skywli committed Nov 7, 2023
1 parent 65b3bbc commit c3cfe19
Show file tree
Hide file tree
Showing 26 changed files with 663 additions and 65 deletions.
4 changes: 0 additions & 4 deletions apiserver/httpserver/config/console_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,16 +291,12 @@ func (h *HTTPServer) PublishConfigFile(req *restful.Request, rsp *restful.Respon

configFile := &apiconfig.ConfigFileRelease{}
ctx, err := handler.Parse(configFile)
requestId := ctx.Value(utils.StringContext("request-id"))

if err != nil {
configLog.Error("[Config][HttpServer] parse config file release from request error.",
zap.String("requestId", requestId.(string)),
zap.String("error", err.Error()))
handler.WriteHeaderAndProto(api.NewConfigFileReleaseResponseWithMessage(apimodel.Code_ParseException, err.Error()))
return
}

handler.WriteHeaderAndProto(h.configServer.PublishConfigFile(ctx, configFile))
}

Expand Down
14 changes: 13 additions & 1 deletion cache/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
apisecurity "github.com/polarismesh/specification/source/go/api/v1/security"
apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage"
apitraffic "github.com/polarismesh/specification/source/go/api/v1/traffic_manage"
apimodel "github.com/polarismesh/specification/source/go/api/v1/model"

"github.com/polarismesh/polaris/common/metrics"
"github.com/polarismesh/polaris/common/model"
Expand Down Expand Up @@ -64,6 +65,8 @@ const (
StrategyRuleName = "strategyRule"
// ServiceContractName service contract config name
ServiceContractName = "serviceContract"
// GrayName gray config name
GrayName = "gray"
)

type CacheIndex int
Expand All @@ -85,6 +88,7 @@ const (
CacheFaultDetector
CacheConfigGroup
CacheServiceContract
CacheGray

CacheLast
)
Expand Down Expand Up @@ -440,7 +444,7 @@ type (
Cache
// GetActiveRelease
GetGroupActiveReleases(namespace, group string) ([]*model.ConfigFileRelease, string)
GetActiveRelease(namespace, group, fileName string, typ model.ConfigeFileType) *model.ConfigFileRelease
GetActiveRelease(namespace, group, fileName string, typ model.ReleaseType) *model.ConfigFileRelease
// GetRelease
GetRelease(key model.ConfigFileReleaseKey) *model.ConfigFileRelease
// QueryReleases
Expand Down Expand Up @@ -646,3 +650,11 @@ func (bc *BaseCache) Clear() {
func (bc *BaseCache) Close() error {
return nil
}

type (
// GrayCache 灰度 Cache 接口
GrayCache interface {
Cache
GetGrayRule(name string) *apimodel.MatchTerm
}
)
5 changes: 5 additions & 0 deletions cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ func (nc *CacheManager) ConfigGroup() types.ConfigGroupCache {
return nc.caches[types.CacheConfigGroup].(types.ConfigGroupCache)
}

// Gray get Gray cache information
func (nc *CacheManager) Gray() types.GrayCache {
return nc.caches[types.CacheGray].(types.GrayCache)
}

// GetCacher get types.Cache impl
func (nc *CacheManager) GetCacher(cacheIndex types.CacheIndex) types.Cache {
return nc.caches[cacheIndex]
Expand Down
4 changes: 2 additions & 2 deletions cache/config/config_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ func (fc *fileCache) GetGroupActiveReleases(namespace, group string) ([]*model.C
}

// GetActiveRelease
func (fc *fileCache) GetActiveRelease(namespace, group, fileName string, typ model.ConfigeFileType) *model.ConfigFileRelease {
func (fc *fileCache) GetActiveRelease(namespace, group, fileName string, typ model.ReleaseType) *model.ConfigFileRelease {
nsBucket, ok := fc.activeReleases.Load(namespace)
if !ok {
return nil
Expand Down Expand Up @@ -455,7 +455,7 @@ func (fc *fileCache) QueryReleases(args *types.ConfigReleaseArgs) (uint32, []*mo
if args.ReleaseName != "" && utils.IsWildNotMatch(item.Name, args.ReleaseName) {
return
}
if !args.IncludeGray && item.Typ == model.ConfigeFileTypeGray {
if !args.IncludeGray && item.Typ == model.ReleaseTypeGray {
return
}
if args.OnlyActive && !item.Active {
Expand Down
3 changes: 3 additions & 0 deletions cache/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
cacheconfig "github.com/polarismesh/polaris/cache/config"
cachens "github.com/polarismesh/polaris/cache/namespace"
cachesvc "github.com/polarismesh/polaris/cache/service"
cachegray "github.com/polarismesh/polaris/cache/gray"
"github.com/polarismesh/polaris/store"
)

Expand All @@ -46,6 +47,7 @@ func init() {
RegisterCache(types.StrategyRuleName, types.CacheAuthStrategy)
RegisterCache(types.ClientName, types.CacheClient)
RegisterCache(types.ServiceContractName, types.CacheServiceContract)
RegisterCache(types.GrayName, types.CacheGray)
}

var (
Expand Down Expand Up @@ -106,6 +108,7 @@ func newCacheManager(ctx context.Context, cacheOpt *Config, storage store.Store)
mgr.RegisterCacher(types.CacheAuthStrategy, cacheauth.NewStrategyCache(storage, mgr))
// 北极星SDK Client
mgr.RegisterCacher(types.CacheClient, cacheclient.NewClientCache(storage, mgr))
mgr.RegisterCacher(types.CacheGray, cachegray.NewGrayCache(storage, mgr))

if len(mgr.caches) != int(types.CacheLast) {
return nil, errors.New("some Cache implement not loaded into CacheManager")
Expand Down
129 changes: 129 additions & 0 deletions cache/gray/gray.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/**
* 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 gray

import (
"bytes"
"time"

"go.uber.org/zap"
"golang.org/x/sync/singleflight"

"github.com/golang/protobuf/jsonpb"
types "github.com/polarismesh/polaris/cache/api"
"github.com/polarismesh/polaris/common/log"
"github.com/polarismesh/polaris/common/model"
"github.com/polarismesh/polaris/common/utils"
"github.com/polarismesh/polaris/store"
apimodel "github.com/polarismesh/specification/source/go/api/v1/model"
)

var (
_ types.GrayCache = (*grayCache)(nil)
)

type grayCache struct {
*types.BaseCache
storage store.Store
grayResources *utils.SyncMap[string, *apimodel.MatchTerm]
updater *singleflight.Group
}

// NewGrayCache create gray cache obj
func NewGrayCache(storage store.Store, cacheMgr types.CacheManager) types.GrayCache {
return &grayCache{
BaseCache: types.NewBaseCache(storage, cacheMgr),
storage: storage,
}
}

// Initialize init gray cache
func (gc *grayCache) Initialize(opt map[string]interface{}) error {
gc.grayResources = utils.NewSyncMap[string, *apimodel.MatchTerm]()
gc.updater = &singleflight.Group{}
return nil
}

// Update update cache
func (gc *grayCache) Update() error {
// 多个线程竞争,只有一个线程进行更新
_, err, _ := gc.updater.Do(gc.Name(), func() (interface{}, error) {
return nil, gc.DoCacheUpdate(gc.Name(), gc.realUpdate)
})
return err
}

func (gc *grayCache) realUpdate() (map[string]time.Time, int64, error) {
grayResources, err := gc.storage.GetMoreGrayResouces(gc.IsFirstUpdate(), gc.LastFetchTime())

if err != nil {
log.Error("[Cache][Gray] get storage more", zap.Error(err))
return nil, -1, err
}
if len(grayResources) == 0 {
return nil, 0, nil
}
lastMtimes := gc.setGrayResources(grayResources)
log.Info("[Cache][Gray] get more gray resource",
zap.Int("total", len(grayResources)))
return lastMtimes, int64(len(grayResources)), nil
}

func (gc *grayCache) setGrayResources(grayResources []*model.GrayResource) map[string]time.Time {
lastMtime := gc.LastMtime(gc.Name()).Unix()
for _, grayResource := range grayResources {
modifyUnix := grayResource.ModifyTime.Unix()
if modifyUnix > lastMtime {
lastMtime = modifyUnix
}
grayRule := &apimodel.MatchTerm{}
reader := bytes.NewReader([]byte(grayResource.MatchRule))
err := jsonpb.Unmarshal(reader, grayRule)
if err != nil {
log.Error("[Cache][Gray] setGrayResources unmarshal gray rule fail.",
zap.String("name", grayResource.Name), zap.Error(err))
continue
}
gc.grayResources.Store(grayResource.Name, grayRule)
}

return map[string]time.Time{
gc.Name(): time.Unix(lastMtime, 0),
}
}

// Clear clear cache
func (gc *grayCache) Clear() error {
gc.BaseCache.Clear()
gc.grayResources = utils.NewSyncMap[string, *apimodel.MatchTerm]()
return nil
}

// Name return gray name
func (gc *grayCache) Name() string {
return types.GrayName
}

// GetGrayRule get gray rule
func (gc *grayCache) GetGrayRule(name string) *apimodel.MatchTerm {
val, ok := gc.grayResources.Load(name)
if !ok {
return nil
}
return val
}
18 changes: 10 additions & 8 deletions common/model/config_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ import (
"github.com/polarismesh/polaris/common/utils"
)

type ConfigeFileType uint32
type ReleaseType uint32

const (
// ConfigeFileTypeFull 全量类型
ConfigeFileTypeFull ConfigeFileType = iota
// ConfigeFileTypeGray 灰度类型
ConfigeFileTypeGray
_ ReleaseType = iota
// ReleaseTypeFull 全量类型
ReleaseTypeFull
// ReleaseTypeGray 灰度类型
ReleaseTypeGray
)

/** ----------- DataObject ------------- */
Expand Down Expand Up @@ -133,7 +134,7 @@ type ConfigFileReleaseKey struct {
Namespace string
Group string
FileName string
Typ ConfigeFileType
Typ ReleaseType
}

func (c ConfigFileReleaseKey) ToFileKey() *ConfigFileKey {
Expand All @@ -149,11 +150,11 @@ func (c ConfigFileReleaseKey) OwnerKey() string {
}

func (c ConfigFileReleaseKey) ActiveKey() string {
return fmt.Sprintf("%v@%v@%v@%v", c.Namespace, c.Group, c.FileName, c.Typ)
return fmt.Sprintf("%v@%v@%v@%v", c.Namespace, c.Group, c.FileName, c.Typ)
}

func (c ConfigFileReleaseKey) ReleaseKey() string {
return fmt.Sprintf("%v@%v@%v@%v@%v", c.Namespace, c.Group, c.FileName, c.Typ,c.Name)
return fmt.Sprintf("%v@%v@%v@%v", c.Namespace, c.Group, c.FileName, c.Name)
}

// SimpleConfigFileRelease 配置文件发布数据持久化对象
Expand Down Expand Up @@ -336,6 +337,7 @@ func ToConfiogFileReleaseApi(release *ConfigFileRelease) *config_manage.ConfigFi
ReleaseDescription: utils.NewStringValue(release.ReleaseDescription),
Tags: FromTagMap(release.Metadata),
Active: utils.NewBoolValue(release.Active),
Type: utils.NewUInt32Value(uint32(release.Typ)),
}
}

Expand Down
47 changes: 47 additions & 0 deletions common/model/gray.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* 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 model

import (
"fmt"
"time"
)

type GrayModule string

const (
GrayModuleConfig GrayModule = "config"
GrayModuleRatelimit GrayModule = "ratelimit"
GrayModuleCircuitbreaker GrayModule = "circuitbreaker"
GrayModuleRoute GrayModule = "route"
)

// GrayRule 灰度资源
type GrayResource struct {
Name string
MatchRule string
CreateTime time.Time
ModifyTime time.Time
CreateBy string
ModifyBy string
}

// GetGrayConfigRealseKey 获取灰度资源key
func GetGrayConfigRealseKey(release *SimpleConfigFileRelease) string {
return fmt.Sprintf("%v@%v@%v@%v", GrayModuleConfig, release.Namespace, release.Group, release.FileName)
}
50 changes: 50 additions & 0 deletions common/utils/match.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* 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 utils

import (
"strings"

apimodel "github.com/polarismesh/specification/source/go/api/v1/model"
)

// Match 查找tags 中寻找匹配term 的tag
func Match(term *apimodel.MatchTerm, tags []*apimodel.Tag) bool {
for _, tag := range tags {
if term.GetKey().GetValue() == tag.GetKey().GetValue() {
val := term.GetValue()
express := val.GetValue().GetValue()
tagValue := tag.GetValue().GetValue()
switch val.GetType() {
case apimodel.MatchString_EXACT:
if tagValue == express {
return true
}
case apimodel.MatchString_IN:
fields := strings.Split(express, ",")
for _, field := range fields {
if tagValue == field {
return true
}
}
}
return false
}
}
return false
}
Loading

0 comments on commit c3cfe19

Please sign in to comment.