diff --git a/.golangci.yml b/.golangci.yml index 935440599..a75e5f01d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -108,6 +108,6 @@ linters-settings: - name: range - name: receiver-naming - name: time-naming - # - name: unexported-return + - name: unexported-return - name: var-declaration # - name: var-naming diff --git a/client/client.go b/client/client.go index ce2752484..8fd91cc11 100644 --- a/client/client.go +++ b/client/client.go @@ -30,18 +30,17 @@ import ( "github.com/TencentBlueKing/bscp-go/internal/util" "github.com/TencentBlueKing/bscp-go/internal/watch" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" "github.com/TencentBlueKing/bscp-go/types" ) // Client bscp client method type Client interface { // PullFiles pull files from remote - PullFiles(app string, opts ...option.AppOption) (*types.Release, error) + PullFiles(app string, opts ...types.AppOption) (*types.Release, error) // Pull Key Value from remote - Get(app string, key string, opts ...option.AppOption) (string, error) + Get(app string, key string, opts ...types.AppOption) (string, error) // AddWatcher add a watcher to client - AddWatcher(callback option.Callback, app string, opts ...option.AppOption) error + AddWatcher(callback types.Callback, app string, opts ...types.AppOption) error // StartWatch start watch StartWatch() error // StopWatch stop watch @@ -53,22 +52,22 @@ type Client interface { // Client is the bscp client type client struct { pairs map[string]string - opts option.ClientOptions + opts options fingerPrint sfs.FingerPrint watcher *watch.Watcher upstream upstream.Upstream } // New return a bscp client instance -func New(opts ...option.ClientOption) (Client, error) { - clientOpt := &option.ClientOptions{} +func New(opts ...Option) (Client, error) { + clientOpt := &options{} fp, err := sfs.GetFingerPrint() if err != nil { return nil, fmt.Errorf("get instance fingerprint failed, err: %s", err.Error()) } logger.Info("instance fingerprint", slog.String("fingerprint", fp.Encode())) - clientOpt.Fingerprint = fp.Encode() - clientOpt.UID = clientOpt.Fingerprint + clientOpt.fingerprint = fp.Encode() + clientOpt.uid = clientOpt.fingerprint for _, opt := range opts { if e := opt(clientOpt); e != nil { return nil, e @@ -80,8 +79,8 @@ func New(opts ...option.ClientOption) (Client, error) { pairs[constant.SideUserKey] = "TODO-USER" // add finger printer mh := sfs.SidecarMetaHeader{ - BizID: clientOpt.BizID, - Fingerprint: clientOpt.Fingerprint, + BizID: clientOpt.bizID, + Fingerprint: clientOpt.fingerprint, } mhBytes, err := json.Marshal(mh) if err != nil { @@ -90,9 +89,9 @@ func New(opts ...option.ClientOption) (Client, error) { pairs[constant.SidecarMetaKey] = string(mhBytes) // prepare upstream u, err := upstream.New( - upstream.WithFeedAddrs(clientOpt.FeedAddrs), - upstream.WithDialTimeoutMS(clientOpt.DialTimeoutMS), - upstream.WithBizID(clientOpt.BizID)) + upstream.WithFeedAddrs(clientOpt.feedAddrs), + upstream.WithDialTimeoutMS(clientOpt.dialTimeoutMS), + upstream.WithBizID(clientOpt.bizID)) if err != nil { return nil, fmt.Errorf("init upstream client failed, err: %s", err.Error()) } @@ -107,7 +106,7 @@ func New(opts ...option.ClientOption) (Client, error) { msg := &pbfs.HandshakeMessage{ ApiVersion: sfs.CurrentAPIVersion, Spec: &pbfs.SidecarSpec{ - BizId: clientOpt.BizID, + BizId: clientOpt.bizID, Version: c.upstream.Version(), }, } @@ -120,16 +119,16 @@ func New(opts ...option.ClientOption) (Client, error) { if err != nil { return nil, fmt.Errorf("decode handshake payload failed, err: %s, rid: %s", err.Error(), vas.Rid) } - err = downloader.Init(vas, clientOpt.BizID, clientOpt.Token, u, pl.RuntimeOption.RepositoryTLS) + err = downloader.Init(vas, clientOpt.bizID, clientOpt.token, u, pl.RuntimeOption.RepositoryTLS) if err != nil { return nil, fmt.Errorf("init downloader failed, err: %s", err.Error()) } - if clientOpt.UseFileCache { - cache.Init(true, clientOpt.FileCacheDir) + if clientOpt.useFileCache { + cache.Init(true, clientOpt.fileCacheDir) } - watcher, err := watch.New(u, option.WatchOptions{ - BizID: clientOpt.BizID, - Labels: clientOpt.Labels, + watcher, err := watch.New(u, watch.Options{ + BizID: clientOpt.bizID, + Labels: clientOpt.labels, Fingerprint: fp.Encode(), }) if err != nil { @@ -140,7 +139,7 @@ func New(opts ...option.ClientOption) (Client, error) { } // AddWatcher add a watcher to client -func (c *client) AddWatcher(callback option.Callback, app string, opts ...option.AppOption) error { +func (c *client) AddWatcher(callback types.Callback, app string, opts ...types.AppOption) error { _ = c.watcher.Subscribe(callback, app, opts...) return nil } @@ -157,34 +156,34 @@ func (c *client) StopWatch() { // ResetLabels reset bscp client labels, if key conflict, app value will overwrite client value func (c *client) ResetLabels(labels map[string]string) { - c.opts.Labels = labels + c.opts.labels = labels for _, subscriber := range c.watcher.Subscribers() { subscriber.ResetLabels(labels) } - c.watcher.NotifyReconnect(types.ReconnectSignal{Reason: "reset labels"}) + c.watcher.NotifyReconnect(watch.ReconnectSignal{Reason: "reset labels"}) } // PullFiles pull files from remote -func (c *client) PullFiles(app string, opts ...option.AppOption) (*types.Release, error) { - option := &option.AppOptions{} +func (c *client) PullFiles(app string, opts ...types.AppOption) (*types.Release, error) { + option := &types.AppOptions{} for _, opt := range opts { opt(option) } vas, _ := c.buildVas() req := &pbfs.PullAppFileMetaReq{ ApiVersion: sfs.CurrentAPIVersion, - BizId: c.opts.BizID, + BizId: c.opts.bizID, AppMeta: &pbfs.AppMeta{ App: app, - Labels: c.opts.Labels, - Uid: c.opts.UID, + Labels: c.opts.labels, + Uid: c.opts.uid, }, - Token: c.opts.Token, + Token: c.opts.token, Key: option.Key, } // merge labels, if key conflict, app value will overwrite client value - req.AppMeta.Labels = util.MergeLabels(c.opts.Labels, option.Labels) + req.AppMeta.Labels = util.MergeLabels(c.opts.labels, option.Labels) // reset uid if option.UID != "" { req.AppMeta.Uid = option.UID @@ -220,24 +219,24 @@ func (c *client) PullFiles(app string, opts ...option.AppOption) (*types.Release } // Get 读取 Key 的值 -func (c *client) Get(app string, key string, opts ...option.AppOption) (string, error) { - option := &option.AppOptions{} +func (c *client) Get(app string, key string, opts ...types.AppOption) (string, error) { + option := &types.AppOptions{} for _, opt := range opts { opt(option) } vas, _ := c.buildVas() req := &pbfs.GetKvValueReq{ ApiVersion: sfs.CurrentAPIVersion, - BizId: c.opts.BizID, + BizId: c.opts.bizID, AppMeta: &pbfs.AppMeta{ App: app, - Labels: c.opts.Labels, - Uid: c.opts.UID, + Labels: c.opts.labels, + Uid: c.opts.uid, }, - Token: c.opts.Token, + Token: c.opts.token, Key: key, } - req.AppMeta.Labels = util.MergeLabels(c.opts.Labels, option.Labels) + req.AppMeta.Labels = util.MergeLabels(c.opts.labels, option.Labels) // reset uid if option.UID != "" { req.AppMeta.Uid = option.UID diff --git a/client/options.go b/client/options.go new file mode 100644 index 000000000..8bfa8ae9a --- /dev/null +++ b/client/options.go @@ -0,0 +1,88 @@ +/* + * Tencent is pleased to support the open source community by making Blueking Container Service available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * http://opensource.org/licenses/MIT + * 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 client + +// options options for bscp sdk client +type options struct { + // FeedAddr BSCP feed_server address + feedAddrs []string + // BizID BSCP business id + bizID uint32 + // Labels instance labels + labels map[string]string + // Fingerprint sdk fingerprint + fingerprint string + // UID sdk uid + uid string + // UseFileCache use file cache + useFileCache bool + // FileCacheDir file cache directory + fileCacheDir string + // DialTimeoutMS dial upstream timeout in millisecond + dialTimeoutMS int64 + // Token sdk token + token string +} + +// Option setter for bscp sdk options +type Option func(*options) error + +// WithFeedAddrs set feed_server addresses +func WithFeedAddrs(addrs []string) Option { + // TODO: validate Address + return func(o *options) error { + o.feedAddrs = addrs + return nil + } +} + +// WithFeedAddr set feed_server addresse +func WithFeedAddr(addr string) Option { + // TODO: validate Address + return func(o *options) error { + o.feedAddrs = []string{addr} + return nil + } +} + +// WithBizID set bscp business id +func WithBizID(id uint32) Option { + return func(o *options) error { + o.bizID = id + return nil + } +} + +// WithLabels set instance labels +func WithLabels(labels map[string]string) Option { + return func(o *options) error { + o.labels = labels + return nil + } +} + +// WithUID set sdk uid +func WithUID(uid string) Option { + return func(o *options) error { + o.uid = uid + return nil + } +} + +// WithToken set sdk token +func WithToken(token string) Option { + return func(o *options) error { + o.token = token + return nil + } +} diff --git a/cmd/bscp/pull.go b/cmd/bscp/pull.go index 7b4c954f8..0158932ea 100644 --- a/cmd/bscp/pull.go +++ b/cmd/bscp/pull.go @@ -29,7 +29,7 @@ import ( "github.com/TencentBlueKing/bscp-go/cmd/bscp/internal/util" pkgutil "github.com/TencentBlueKing/bscp-go/internal/util" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" + "github.com/TencentBlueKing/bscp-go/types" ) var ( @@ -58,21 +58,21 @@ func Pull(cmd *cobra.Command, args []string) { conf.Labels = pkgutil.MergeLabels(conf.Labels, labels) } bscp, err := client.New( - option.FeedAddrs(conf.FeedAddrs), - option.BizID(conf.Biz), - option.Token(conf.Token), - option.Labels(conf.Labels), - option.UID(conf.UID), + client.WithFeedAddrs(conf.FeedAddrs), + client.WithBizID(conf.Biz), + client.WithToken(conf.Token), + client.WithLabels(conf.Labels), + client.WithUID(conf.UID), ) if err != nil { logger.Error("init client", logger.ErrAttr(err)) os.Exit(1) } for _, app := range conf.Apps { - opts := []option.AppOption{} - opts = append(opts, option.WithKey("**")) - opts = append(opts, option.WithLabels(app.Labels)) - opts = append(opts, option.WithUID(app.UID)) + opts := []types.AppOption{} + opts = append(opts, types.WithAppKey("**")) + opts = append(opts, types.WithAppLabels(app.Labels)) + opts = append(opts, types.WithAppUID(app.UID)) if conf.TempDir != "" { tempDir = conf.TempDir } @@ -83,7 +83,7 @@ func Pull(cmd *cobra.Command, args []string) { } } -func pullAppFiles(bscp client.Client, tempDir string, biz uint32, app string, opts []option.AppOption) error { +func pullAppFiles(bscp client.Client, tempDir string, biz uint32, app string, opts []types.AppOption) error { // 1. prepare app workspace dir appDir := path.Join(tempDir, strconv.Itoa(int(biz)), app) if e := os.MkdirAll(appDir, os.ModePerm); e != nil { diff --git a/cmd/bscp/watch.go b/cmd/bscp/watch.go index a77f070e9..474ae899f 100644 --- a/cmd/bscp/watch.go +++ b/cmd/bscp/watch.go @@ -37,7 +37,6 @@ import ( "github.com/TencentBlueKing/bscp-go/internal/metrics" pkgutil "github.com/TencentBlueKing/bscp-go/internal/util" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" "github.com/TencentBlueKing/bscp-go/types" ) @@ -75,11 +74,11 @@ func Watch(cmd *cobra.Command, args []string) { } bscp, err := client.New( - option.FeedAddrs(conf.FeedAddrs), - option.BizID(conf.Biz), - option.Token(conf.Token), - option.Labels(confLabels), - option.UID(conf.UID), + client.WithFeedAddrs(conf.FeedAddrs), + client.WithBizID(conf.Biz), + client.WithToken(conf.Token), + client.WithLabels(confLabels), + client.WithUID(conf.UID), ) if err != nil { logger.Error("init client", logger.ErrAttr(err)) @@ -236,10 +235,10 @@ func (w *WatchHandler) watchCallback(release *types.Release) error { return nil } -func (w *WatchHandler) getSubscribeOptions() []option.AppOption { - options := []option.AppOption{} - options = append(options, option.WithLabels(w.Labels)) - options = append(options, option.WithUID(w.UID)) +func (w *WatchHandler) getSubscribeOptions() []types.AppOption { + options := []types.AppOption{} + options = append(options, types.WithAppLabels(w.Labels)) + options = append(options, types.WithAppUID(w.UID)) return options } diff --git a/examples/README.md b/examples/README.md index aa7cb2001..0709a1f40 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,6 +2,7 @@ bscp sdk examples ============ ## 示例代码 +* [config](./config) - bscp 命令行配置文件示例 * [kv-ctl](./kv-ctl) - 拉取 kv 型配置命令行示例 * [pull-file](./pull-file) - 拉取 file 型配置 * [watch-file](./watch-file) - 拉取 file 型配置并监听配置变更 @@ -13,7 +14,7 @@ bscp sdk examples 添加环境变量 ```bash # FEED 地址 -export BSCP_FEED_ADDRS="bscp-feed.example.com:9510" +export BSCP_FEED_ADDR="bscp-feed.example.com:9510" # 服务密钥 Token, 记得需要关联配置文件 export BSCP_TOKEN="xxx" # 当前业务 diff --git a/examples/config/config.yml b/examples/config/config.yml new file mode 100644 index 000000000..570eced6c --- /dev/null +++ b/examples/config/config.yml @@ -0,0 +1,25 @@ +# 订阅地址,必填 +feed_addrs: + - "{feed_addr_host}:9510" +# 业务ID,必填 +biz: 1 +# 服务秘钥,必填 +token: "****************" +# 实例标签,选填 +labels: + - "region": "nanjing" + - "env": "prod" +# bscp 临时工作目录,选填 +temp_dir: "/data/bscp" +# 拉取或监听的服务 +apps: + # 服务名称,必填 + - name: bscp-demo + # 服务标签(将覆盖实例中相同key的标签),选填 + labels: + - "env": "prod" + - "app": "demo" + - name: demo-2 + labels: + - "env": "prod" + - "app": "demo-2" diff --git a/examples/go.mod b/examples/go.mod index 6ecb21cfa..75c0f808a 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,4 +1,4 @@ -module github.com/TencentBlueKing/bscp-go/examples/pull-file +module github.com/TencentBlueKing/bscp-go/examples go 1.20 @@ -68,7 +68,6 @@ require ( google.golang.org/grpc v1.57.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.100.1 // indirect ) diff --git a/examples/go.sum b/examples/go.sum index de0d89851..b3fd7a201 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -584,7 +584,6 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/kv-ctl/main.go b/examples/kv-ctl/main.go index ad2634ccd..d3c265c5e 100644 --- a/examples/kv-ctl/main.go +++ b/examples/kv-ctl/main.go @@ -27,7 +27,6 @@ import ( "github.com/TencentBlueKing/bscp-go/client" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" "github.com/TencentBlueKing/bscp-go/types" ) @@ -90,10 +89,10 @@ func execute() { } bscp, err := client.New( - option.FeedAddrs(strings.Split(os.Getenv("BSCP_FEED_ADDRS"), ",")), - option.BizID(uint32(biz)), - option.Token(os.Getenv("BSCP_TOKEN")), - option.Labels(labels), + client.WithFeedAddr(os.Getenv("BSCP_FEED_ADDR")), + client.WithBizID(uint32(biz)), + client.WithToken(os.Getenv("BSCP_TOKEN")), + client.WithLabels(labels), ) if err != nil { logger.Error("init client", logger.ErrAttr(err)) @@ -101,7 +100,7 @@ func execute() { } appName := os.Getenv("BSCP_APP") - opts := []option.AppOption{} + opts := []types.AppOption{} keySlice := strings.Split(keys, ",") if watchMode { if err = watchAppKV(bscp, appName, keySlice, opts); err != nil { @@ -154,7 +153,7 @@ func (w *watcher) callback(release *types.Release) error { } // watchAppKV watch 服务版本 -func watchAppKV(bscp client.Client, app string, keys []string, opts []option.AppOption) error { +func watchAppKV(bscp client.Client, app string, keys []string, opts []types.AppOption) error { keyMap := map[string]struct{}{} for _, v := range keys { keyMap[v] = struct{}{} diff --git a/examples/pull-file/main.go b/examples/pull-file/main.go index 3cc41a43e..519d91374 100644 --- a/examples/pull-file/main.go +++ b/examples/pull-file/main.go @@ -16,13 +16,12 @@ package main import ( "os" "strconv" - "strings" "golang.org/x/exp/slog" "github.com/TencentBlueKing/bscp-go/client" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" + "github.com/TencentBlueKing/bscp-go/types" ) func main() { @@ -33,30 +32,30 @@ func main() { bizStr := os.Getenv("BSCP_BIZ") biz, err := strconv.ParseInt(bizStr, 10, 64) if err != nil { - logger.Error("parse BSCP_BIZ", logger.ErrAttr(err)) + slog.Error("parse BSCP_BIZ", logger.ErrAttr(err)) os.Exit(1) } bscp, err := client.New( - option.FeedAddrs(strings.Split(os.Getenv("BSCP_FEED_ADDRS"), ",")), - option.BizID(uint32(biz)), - option.Token(os.Getenv("BSCP_TOKEN")), + client.WithFeedAddr(os.Getenv("BSCP_FEED_ADDRS")), + client.WithBizID(uint32(biz)), + client.WithToken(os.Getenv("BSCP_TOKEN")), ) if err != nil { - logger.Error("init client", logger.ErrAttr(err)) + slog.Error("init client", logger.ErrAttr(err)) os.Exit(1) } appName := os.Getenv("BSCP_APP") - opts := []option.AppOption{} + opts := []types.AppOption{} if err = pullAppFiles(bscp, appName, opts); err != nil { - logger.Error("pull", logger.ErrAttr(err)) + slog.Error("pull", logger.ErrAttr(err)) os.Exit(1) } } // pullAppFiles 拉取服务文件 -func pullAppFiles(bscp client.Client, app string, opts []option.AppOption) error { +func pullAppFiles(bscp client.Client, app string, opts []types.AppOption) error { release, err := bscp.PullFiles(app, opts...) if err != nil { return err diff --git a/examples/pull-kv/main.go b/examples/pull-kv/main.go index dee8cb660..223facabf 100644 --- a/examples/pull-kv/main.go +++ b/examples/pull-kv/main.go @@ -17,13 +17,12 @@ import ( "encoding/json" "os" "strconv" - "strings" "golang.org/x/exp/slog" "github.com/TencentBlueKing/bscp-go/client" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" + "github.com/TencentBlueKing/bscp-go/types" ) func main() { @@ -45,10 +44,10 @@ func main() { } bscp, err := client.New( - option.FeedAddrs(strings.Split(os.Getenv("BSCP_FEED_ADDRS"), ",")), - option.BizID(uint32(biz)), - option.Token(os.Getenv("BSCP_TOKEN")), - option.Labels(labels), + client.WithFeedAddr(os.Getenv("BSCP_FEED_ADDRS")), + client.WithBizID(uint32(biz)), + client.WithToken(os.Getenv("BSCP_TOKEN")), + client.WithLabels(labels), ) if err != nil { logger.Error("init client", logger.ErrAttr(err)) @@ -56,7 +55,7 @@ func main() { } appName := os.Getenv("BSCP_APP") - opts := []option.AppOption{} + opts := []types.AppOption{} key := "key1" if err = pullAppKvs(bscp, appName, key, opts); err != nil { logger.Error("pull", logger.ErrAttr(err)) @@ -65,7 +64,7 @@ func main() { } // pullAppKvs 拉取 key 的值 -func pullAppKvs(bscp client.Client, app string, key string, opts []option.AppOption) error { +func pullAppKvs(bscp client.Client, app string, key string, opts []types.AppOption) error { value, err := bscp.Get(app, key, opts...) if err != nil { return err diff --git a/examples/watch-file/main.go b/examples/watch-file/main.go index e25362999..6719f4238 100644 --- a/examples/watch-file/main.go +++ b/examples/watch-file/main.go @@ -18,14 +18,12 @@ import ( "os" "os/signal" "strconv" - "strings" "syscall" "golang.org/x/exp/slog" "github.com/TencentBlueKing/bscp-go/client" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" "github.com/TencentBlueKing/bscp-go/types" ) @@ -42,9 +40,9 @@ func main() { } bscp, err := client.New( - option.FeedAddrs(strings.Split(os.Getenv("BSCP_FEED_ADDRS"), ",")), - option.BizID(uint32(biz)), - option.Token(os.Getenv("BSCP_TOKEN")), + client.WithFeedAddr(os.Getenv("BSCP_FEED_ADDR")), + client.WithBizID(uint32(biz)), + client.WithToken(os.Getenv("BSCP_TOKEN")), ) if err != nil { logger.Error("init client", logger.ErrAttr(err)) @@ -52,7 +50,7 @@ func main() { } appName := os.Getenv("BSCP_APP") - opts := []option.AppOption{} + opts := []types.AppOption{} if err = watchAppRelease(bscp, appName, opts); err != nil { logger.Error("watch", logger.ErrAttr(err)) os.Exit(1) @@ -68,7 +66,7 @@ func callback(release *types.Release) error { } // watchAppRelease watch 服务版本 -func watchAppRelease(bscp client.Client, app string, opts []option.AppOption) error { +func watchAppRelease(bscp client.Client, app string, opts []types.AppOption) error { err := bscp.AddWatcher(callback, app, opts...) if err != nil { return err diff --git a/examples/watch-kv/main.go b/examples/watch-kv/main.go index cc2e1d59c..c643d03c7 100644 --- a/examples/watch-kv/main.go +++ b/examples/watch-kv/main.go @@ -19,14 +19,12 @@ import ( "os" "os/signal" "strconv" - "strings" "syscall" "golang.org/x/exp/slog" "github.com/TencentBlueKing/bscp-go/client" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" "github.com/TencentBlueKing/bscp-go/types" ) @@ -49,10 +47,10 @@ func main() { } bscp, err := client.New( - option.FeedAddrs(strings.Split(os.Getenv("BSCP_FEED_ADDRS"), ",")), - option.BizID(uint32(biz)), - option.Token(os.Getenv("BSCP_TOKEN")), - option.Labels(labels), + client.WithFeedAddr(os.Getenv("BSCP_FEED_ADDR")), + client.WithBizID(uint32(biz)), + client.WithToken(os.Getenv("BSCP_TOKEN")), + client.WithLabels(labels), ) if err != nil { logger.Error("init bscp client", logger.ErrAttr(err)) @@ -60,7 +58,7 @@ func main() { } appName := os.Getenv("BSCP_APP") - opts := []option.AppOption{} + opts := []types.AppOption{} if err = watchAppKV(bscp, appName, opts); err != nil { logger.Error("watch kv", logger.ErrAttr(err)) os.Exit(1) @@ -89,7 +87,7 @@ func (w *watcher) callback(release *types.Release) error { } // watchAppKV watch 服务版本 -func watchAppKV(bscp client.Client, app string, opts []option.AppOption) error { +func watchAppKV(bscp client.Client, app string, opts []types.AppOption) error { w := watcher{ bscp: bscp, app: app, diff --git a/internal/watch/heartbeat.go b/internal/watch/heartbeat.go index a864c292b..b9096bec1 100644 --- a/internal/watch/heartbeat.go +++ b/internal/watch/heartbeat.go @@ -22,7 +22,6 @@ import ( "golang.org/x/exp/slog" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/types" ) const ( @@ -78,7 +77,7 @@ func (w *Watcher) loopHeartbeat() error { logger.Warn("stream heartbeat failed, notify reconnect upstream", logger.ErrAttr(err), slog.String("rid", w.vas.Rid)) - w.NotifyReconnect(types.ReconnectSignal{Reason: "stream heartbeat failed"}) + w.NotifyReconnect(ReconnectSignal{Reason: "stream heartbeat failed"}) return } logger.Debug("stream heartbeat successfully", slog.String("rid", w.vas.Rid)) diff --git a/internal/watch/reconnect.go b/internal/watch/reconnect.go index d80e745b7..2cfd51669 100644 --- a/internal/watch/reconnect.go +++ b/internal/watch/reconnect.go @@ -20,11 +20,10 @@ import ( "golang.org/x/exp/slog" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/types" ) // NotifyReconnect notify the watcher to reconnect the upstream server. -func (w *Watcher) NotifyReconnect(signal types.ReconnectSignal) { +func (w *Watcher) NotifyReconnect(signal ReconnectSignal) { select { case w.reconnectChan <- signal: default: diff --git a/internal/watch/watch.go b/internal/watch/watch.go index 28338662b..c8e53453f 100644 --- a/internal/watch/watch.go +++ b/internal/watch/watch.go @@ -35,18 +35,42 @@ import ( "github.com/TencentBlueKing/bscp-go/internal/upstream" "github.com/TencentBlueKing/bscp-go/internal/util" "github.com/TencentBlueKing/bscp-go/logger" - "github.com/TencentBlueKing/bscp-go/option" "github.com/TencentBlueKing/bscp-go/types" ) +// Options options for watch bscp config items +type Options struct { + // FeedAddrs bscp feed server addresses + FeedAddrs []string + // DialTimeoutMS dial timeout milliseconds + DialTimeoutMS int64 + // Fingerprint watch fingerprint + Fingerprint string + // Labels watch labels + Labels map[string]string + // BizID watch biz id + BizID uint32 +} + +// ReconnectSignal defines the signal information to tell the +// watcher to reconnect the remote upstream server. +type ReconnectSignal struct { + Reason string +} + +// String format the reconnect signal to a string. +func (rs ReconnectSignal) String() string { + return rs.Reason +} + // Watcher is the main watch stream for instance type Watcher struct { subscribers []*Subscriber vas *kit.Vas cancel context.CancelFunc - opts option.WatchOptions + opts Options metaHeaderValue string - reconnectChan chan types.ReconnectSignal + reconnectChan chan ReconnectSignal Conn *grpc.ClientConn upstream upstream.Upstream } @@ -65,12 +89,12 @@ func (w *Watcher) buildVas() (*kit.Vas, context.CancelFunc) { } // New return a Watcher -func New(u upstream.Upstream, opts option.WatchOptions) (*Watcher, error) { +func New(u upstream.Upstream, opts Options) (*Watcher, error) { w := &Watcher{ opts: opts, upstream: u, // 重启按原子顺序, 添加一个buff, 对labelfile watch的场景,保留一个重启次数 - reconnectChan: make(chan types.ReconnectSignal, 1), + reconnectChan: make(chan ReconnectSignal, 1), } mh := sfs.SidecarMetaHeader{ @@ -179,13 +203,13 @@ func (w *Watcher) loopReceiveWatchedEvent(wStream pbfs.Upstream_WatchClient) { if err != nil { if errors.Is(err, io.EOF) { logger.Error("watch stream has been closed by remote upstream stream server, need to re-connect again") - w.NotifyReconnect(types.ReconnectSignal{Reason: "connection is closed " + + w.NotifyReconnect(ReconnectSignal{Reason: "connection is closed " + "by remote upstream server"}) return } logger.Error("watch stream is corrupted", logger.ErrAttr(err), slog.String("rid", w.vas.Rid)) - w.NotifyReconnect(types.ReconnectSignal{Reason: "watch stream corrupted"}) + w.NotifyReconnect(ReconnectSignal{Reason: "watch stream corrupted"}) return } @@ -206,7 +230,7 @@ func (w *Watcher) loopReceiveWatchedEvent(wStream pbfs.Upstream_WatchClient) { switch sfs.FeedMessageType(event.Type) { case sfs.Bounce: logger.Info("received upstream bounce request, need to reconnect upstream server", slog.String("rid", event.Rid)) - w.NotifyReconnect(types.ReconnectSignal{Reason: "received bounce request"}) + w.NotifyReconnect(ReconnectSignal{Reason: "received bounce request"}) return case sfs.PublishRelease: @@ -284,8 +308,8 @@ func (w *Watcher) OnReleaseChange(event *sfs.ReleaseChangeEvent) { } // Subscribe subscribe the instance release change event -func (w *Watcher) Subscribe(callback option.Callback, app string, opts ...option.AppOption) *Subscriber { - options := &option.AppOptions{} +func (w *Watcher) Subscribe(callback types.Callback, app string, opts ...types.AppOption) *Subscriber { + options := &types.AppOptions{} for _, opt := range opts { opt(options) } @@ -312,10 +336,10 @@ func (w *Watcher) Subscribers() []*Subscriber { // Subscriber is the subscriber of the instance type Subscriber struct { - Opts *option.AppOptions + Opts *types.AppOptions App string // Callback is the callback function when the watched items are changed - Callback option.Callback + Callback types.Callback // CurrentReleaseID is the current release id of the subscriber CurrentReleaseID uint32 // Labels is the labels of the subscriber diff --git a/option/client.go b/option/client.go deleted file mode 100644 index a18ec1118..000000000 --- a/option/client.go +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Blueking Container Service available. - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * Licensed under the MIT License (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * http://opensource.org/licenses/MIT - * 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 option - -// ClientOptions options for bscp sdk client -type ClientOptions struct { - // FeedAddr BSCP feed_server address - FeedAddrs []string - // BizID BSCP business id - BizID uint32 - // Labels instance labels - Labels map[string]string - // Version SDK version - Version string - // Fingerprint sdk fingerprint - Fingerprint string - // UID sdk uid - UID string - // UseFileCache use file cache - UseFileCache bool - // FileCacheDir file cache directory - FileCacheDir string - // DialTimeoutMS dial upstream timeout in millisecond - DialTimeoutMS int64 - // Token sdk token - Token string -} - -// ClientOption setter for bscp sdk options -type ClientOption func(*ClientOptions) error - -// FeedAddrs set feed_server addresses -func FeedAddrs(addrs []string) ClientOption { - // TODO: validate Address - return func(o *ClientOptions) error { - o.FeedAddrs = addrs - return nil - } -} - -// BizID set bscp business id -func BizID(id uint32) ClientOption { - return func(o *ClientOptions) error { - o.BizID = id - return nil - } -} - -// Labels set instance labels -func Labels(labels map[string]string) ClientOption { - return func(o *ClientOptions) error { - o.Labels = labels - return nil - } -} - -// UID set sdk uid -func UID(uid string) ClientOption { - return func(o *ClientOptions) error { - o.UID = uid - return nil - } -} - -// UseFileCache cache file to local file system -func UseFileCache(useFileCache bool) ClientOption { - return func(o *ClientOptions) error { - o.UseFileCache = useFileCache - return nil - } -} - -// FileCacheDir file local cache directory -func FileCacheDir(dir string) ClientOption { - return func(o *ClientOptions) error { - o.FileCacheDir = dir - return nil - } -} - -// WithDialTimeoutMS set dial timeout in millisecond -func WithDialTimeoutMS(timeout int64) ClientOption { - return func(o *ClientOptions) error { - o.DialTimeoutMS = timeout - return nil - } -} - -// Token set sdk token -func Token(token string) ClientOption { - return func(o *ClientOptions) error { - o.Token = token - return nil - } -} diff --git a/option/watch.go b/option/watch.go deleted file mode 100644 index 3d41d4005..000000000 --- a/option/watch.go +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Blueking Container Service available. - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * Licensed under the MIT License (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * http://opensource.org/licenses/MIT - * 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 option - -import ( - "github.com/TencentBlueKing/bscp-go/types" -) - -// WatchOptions options for watch bscp config items -type WatchOptions struct { - // FeedAddrs bscp feed server addresses - FeedAddrs []string - // DialTimeoutMS dial timeout milliseconds - DialTimeoutMS int64 - // Fingerprint watch fingerprint - Fingerprint string - // Labels watch labels - Labels map[string]string - // BizID watch biz id - BizID uint32 -} - -// Callback watch callback -type Callback func(release *types.Release) error diff --git a/readme.md b/readme.md index 6f78e7e70..c16c46a34 100644 --- a/readme.md +++ b/readme.md @@ -26,6 +26,21 @@ bscp-go 是蓝鲸基础配置平台(BK-BSCP)提供的用于快速接入KV SDK, - [容器化接入](./docs/usage.md) - [SDK代码示例](./examples/README.md) +## 安装 bscp 命令行 +方式1,有 golang 环境,可以直接安装 +``` +go install github.com/TencentBlueKing/bscp-go/cmd/bscp@latest +bscp version +``` + +方式2, 安装已编译的二进制,支持 linux/mac/windows, 以 linux 为例 +``` +wget https://github.com/TencentBlueKing/bscp-go/releases/download/v1.0.5/bscp-v1.0.5-linux-amd64.tar.gz +tar -xf bscp-v1.0.5-linux-amd64.tar.gz +cp bscp /usr/local/bin/ +bscp version +``` + ## Support - [蓝鲸论坛](https://bk.tencent.com/s-mart/community) diff --git a/readme_en.md b/readme_en.md index 28be95931..eccf40675 100644 --- a/readme_en.md +++ b/readme_en.md @@ -25,6 +25,21 @@ bscp-go is an official command-line tool provided by BlueKing Basic Configuratio - [Containerized Access](./docs/usage.md) - [SDK Examples](./examples/README.md) +## Install bscp cmd +Method 1, with golang environment, you can install it directly +``` +go install github.com/TencentBlueKing/bscp-go/cmd/bscp@latest +bscp version +``` + +Method 2, install the compiled binary, support linux/mac/windows, take linux as an example +``` +wget https://github.com/TencentBlueKing/bscp-go/releases/download/v1.0.5/bscp-v1.0.5-linux-amd64.tar.gz +tar -xf bscp-v1.0.5-linux-amd64.tar.gz +cp bscp /usr/local/bin/ +bscp version +``` + ## Support - [bk forum](https://bk.tencent.com/s-mart/community) diff --git a/option/app.go b/types/options.go similarity index 80% rename from option/app.go rename to types/options.go index 5ebdd2f54..eb486e7e2 100644 --- a/option/app.go +++ b/types/options.go @@ -10,8 +10,7 @@ * limitations under the License. */ -// Package option defines the common options. -package option +package types // AppOptions options for app pull and watch type AppOptions struct { @@ -26,22 +25,22 @@ type AppOptions struct { // AppOption setter for app options type AppOption func(*AppOptions) -// WithKey set watch config item key -func WithKey(key string) AppOption { +// WithAppKey set watch config item key +func WithAppKey(key string) AppOption { return func(o *AppOptions) { o.Key = key } } -// WithLabels set watch labels -func WithLabels(labels map[string]string) AppOption { +// WithAppLabels set watch labels +func WithAppLabels(labels map[string]string) AppOption { return func(o *AppOptions) { o.Labels = labels } } -// WithUID set watch uid -func WithUID(uid string) AppOption { +// WithAppUID set watch uid +func WithAppUID(uid string) AppOption { return func(o *AppOptions) { o.UID = uid } diff --git a/types/types.go b/types/types.go index 69e9b3d00..8b2e06a98 100644 --- a/types/types.go +++ b/types/types.go @@ -27,17 +27,6 @@ import ( "github.com/TencentBlueKing/bscp-go/logger" ) -// ReconnectSignal defines the signal information to tell the -// watcher to reconnect the remote upstream server. -type ReconnectSignal struct { - Reason string -} - -// String format the reconnect signal to a string. -func (rs ReconnectSignal) String() string { - return rs.Reason -} - // Release bscp 服务版本 type Release struct { ReleaseID uint32 `json:"release_id"` @@ -94,3 +83,6 @@ func (c *ConfigItemFile) SaveToFile(src string) error { return nil } + +// Callback watch callback +type Callback func(release *Release) error