From c66a80c4372596faaa70e0d2a44e3e9aea5b5e63 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 16:59:57 +0800 Subject: [PATCH 01/25] feat: zookeeper init code --- .github/workflows/tests.yml | 5 + linceses/LICENSE-gozookeeper | 25 ++++ linceses/LICENSE-testify | 21 ++++ zookeeper/Makefile | 5 + zookeeper/README.md | 109 +++++++++++++++++ zookeeper/discovery_test.go | 128 ++++++++++++++++++++ zookeeper/entity/entity.go | 20 +++ zookeeper/example/auth/client/main.go | 46 +++++++ zookeeper/example/auth/server/main.go | 48 ++++++++ zookeeper/example/basic/client/main.go | 46 +++++++ zookeeper/example/basic/server/main.go | 48 ++++++++ zookeeper/go.mod | 12 ++ zookeeper/go.sum | 81 +++++++++++++ zookeeper/registry.go | 161 +++++++++++++++++++++++++ zookeeper/reslover.go | 128 ++++++++++++++++++++ zookeeper/utils/const.go | 20 +++ zookeeper/utils/net.go | 38 ++++++ 17 files changed, 941 insertions(+) create mode 100644 linceses/LICENSE-gozookeeper create mode 100644 linceses/LICENSE-testify create mode 100644 zookeeper/Makefile create mode 100644 zookeeper/README.md create mode 100644 zookeeper/discovery_test.go create mode 100644 zookeeper/entity/entity.go create mode 100644 zookeeper/example/auth/client/main.go create mode 100644 zookeeper/example/auth/server/main.go create mode 100644 zookeeper/example/basic/client/main.go create mode 100644 zookeeper/example/basic/server/main.go create mode 100644 zookeeper/go.mod create mode 100644 zookeeper/go.sum create mode 100644 zookeeper/registry.go create mode 100644 zookeeper/reslover.go create mode 100644 zookeeper/utils/const.go create mode 100644 zookeeper/utils/net.go diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 12b6438..75b1f88 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,6 +5,11 @@ on: [ push, pull_request ] jobs: ut: runs-on: ubuntu-latest + services: + zookeeper: + image: 'zookeeper:3.7.0' + ports: + - '2181:2181' steps: - uses: actions/checkout@v3 diff --git a/linceses/LICENSE-gozookeeper b/linceses/LICENSE-gozookeeper new file mode 100644 index 0000000..4decd5f --- /dev/null +++ b/linceses/LICENSE-gozookeeper @@ -0,0 +1,25 @@ +Copyright (c) 2013, Samuel Stauffer +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +* Neither the name of the author nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/linceses/LICENSE-testify b/linceses/LICENSE-testify new file mode 100644 index 0000000..0be77a0 --- /dev/null +++ b/linceses/LICENSE-testify @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/zookeeper/Makefile b/zookeeper/Makefile new file mode 100644 index 0000000..c49c4eb --- /dev/null +++ b/zookeeper/Makefile @@ -0,0 +1,5 @@ +ZOOKEEPRER_VERSION ?= 3.7.0 + +prepare: + docker pull zookeeper:$(ZOOKEEPRER_VERSION) + docker run --name zookeeper -p 2181:2181 -d zookeeper:$(ZOOKEEPRER_VERSION) diff --git a/zookeeper/README.md b/zookeeper/README.md new file mode 100644 index 0000000..8a4d797 --- /dev/null +++ b/zookeeper/README.md @@ -0,0 +1,109 @@ +# zookeeper (*This is a community driven project*) + +Zookeeper as service discovery for Hertz. + +## how to use? + +### server + +**[example/basic/server/main.go](example/basic/server/main.go)** + +```go +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + addr := "127.0.0.1:8888" + r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} + +``` + +### Client + +**[example/basic/client/main.go](example/basic/client/main.go)** + +```go +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err :=zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) +// ... +} +``` +## How to run example? + +### run docker + +- make prepare + +```bash +make prepare +``` + +### run server + +```go +go run ./example/basic/server/main.go +``` + +### run client + +```go +go run ./example/basic/client/main.go +``` +```go +2022/08/21 23:31:59.391243 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.391493 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.391603 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.391714 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.391816 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.391913 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.392039 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.392144 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.392249 main.go:44: [Info] code=200,body={"ping":"pong2"} +2022/08/21 23:31:59.392379 main.go:44: [Info] code=200,body={"ping":"pong2"} +``` \ No newline at end of file diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go new file mode 100644 index 0000000..c5ae3fe --- /dev/null +++ b/zookeeper/discovery_test.go @@ -0,0 +1,128 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 zookeeper + +import ( + "context" + "net" + "testing" + "time" + + "github.com/cloudwego/hertz/pkg/app/client/discovery" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/stretchr/testify/assert" + + "github.com/hertz-contrib/registry/zookeeper/utils" +) + +func TestZookeeperDiscovery(t *testing.T) { + // register + r, err := NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + assert.Nil(t, err) + tags := map[string]string{"group": "blue", "idc": "hd1"} + addr, _ := net.ResolveTCPAddr("tcp", ":9999") + info := ®istry.Info{ServiceName: "product", Weight: 100, Tags: tags, Addr: addr} + err = r.Register(info) + assert.Nil(t, err) + + // resolve + res, err := NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + assert.Nil(t, err) + target := res.Target(context.Background(), &discovery.TargetInfo{Host: "product", Tags: nil}) + result, err := res.Resolve(context.Background(), target) + assert.Nil(t, err) + + // compare data + if len(result.Instances) == 0 { + t.Errorf("instance num mismatch, expect: %d, in fact: %d", 1, 0) + } else if len(result.Instances) == 1 { + instance := result.Instances[0] + host, port, err := net.SplitHostPort(instance.Address().String()) + assert.Nil(t, err) + local, _ := utils.GetLocalIPv4Address() + if host != local { + t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) + } + if port != "9999" { + t.Errorf("instance port is mismatch, expect: %s, in fact: %s", "9999", port) + } + if info.Weight != instance.Weight() { + t.Errorf("instance weight is mismatch, expect: %d, in fact: %d", info.Weight, instance.Weight()) + } + for k, v := range info.Tags { + if v1, exist := instance.Tag(k); !exist || v != v1 { + t.Errorf("instance tags is mismatch, expect k:v %s:%s, in fact k:v %s:%s", k, v, k, v1) + } + } + } + + // deregister + err = r.Deregister(info) + assert.Nil(t, err) + + // resolve again + result, err = res.Resolve(context.Background(), target) + assert.EqualError(t, err, "no instance remains for product") +} + +func TestZookeeperResolverWithAuth(t *testing.T) { + // register + r, err := NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "horizon", "horizon") + assert.Nil(t, err) + tags := map[string]string{"group": "blue", "idc": "hd1"} + addr, _ := net.ResolveTCPAddr("tcp", ":9999") + info := ®istry.Info{ServiceName: "product", Weight: 100, Tags: tags, Addr: addr} + err = r.Register(info) + assert.Nil(t, err) + + // resolve + res, err := NewZookeeperResolverWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "horizon", "horizon") + assert.Nil(t, err) + target := res.Target(context.Background(), &discovery.TargetInfo{Host: "product", Tags: nil}) + result, err := res.Resolve(context.Background(), target) + assert.Nil(t, err) + + // compare data + if len(result.Instances) == 0 { + t.Errorf("instance num mismatch, expect: %d, in fact: %d", 1, 0) + } else if len(result.Instances) == 1 { + instance := result.Instances[0] + host, port, err := net.SplitHostPort(instance.Address().String()) + assert.Nil(t, err) + local, _ := utils.GetLocalIPv4Address() + if host != local { + t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) + } + if port != "9999" { + t.Errorf("instance port is mismatch, expect: %s, in fact: %s", "9999", port) + } + if info.Weight != instance.Weight() { + t.Errorf("instance weight is mismatch, expect: %d, in fact: %d", info.Weight, instance.Weight()) + } + for k, v := range info.Tags { + if v1, exist := instance.Tag(k); !exist || v != v1 { + t.Errorf("instance tags is mismatch, expect k:v %s:%s, in fact k:v %s:%s", k, v, k, v1) + } + } + } + + // deregister + err = r.Deregister(info) + assert.Nil(t, err) + + // resolve again + result, err = res.Resolve(context.Background(), target) + assert.EqualError(t, err, "no instance remains for product") +} diff --git a/zookeeper/entity/entity.go b/zookeeper/entity/entity.go new file mode 100644 index 0000000..aa14008 --- /dev/null +++ b/zookeeper/entity/entity.go @@ -0,0 +1,20 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 entity + +type RegistryEntity struct { + Weight int + Tags map[string]string +} diff --git a/zookeeper/example/auth/client/main.go b/zookeeper/example/auth/client/main.go new file mode 100644 index 0000000..d1cb857 --- /dev/null +++ b/zookeeper/example/auth/client/main.go @@ -0,0 +1,46 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 main + +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := zookeeper.NewZookeeperResolverWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "hertzuser", "hertzpass") + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s", status, string(body)) + } +} diff --git a/zookeeper/example/auth/server/main.go b/zookeeper/example/auth/server/main.go new file mode 100644 index 0000000..54dc684 --- /dev/null +++ b/zookeeper/example/auth/server/main.go @@ -0,0 +1,48 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 main + +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + addr := "127.0.0.1:8888" + r, err := zookeeper.NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 20*time.Second, "hertzuser", "hertzpass") + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} diff --git a/zookeeper/example/basic/client/main.go b/zookeeper/example/basic/client/main.go new file mode 100644 index 0000000..125a354 --- /dev/null +++ b/zookeeper/example/basic/client/main.go @@ -0,0 +1,46 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 main + +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s", status, string(body)) + } +} diff --git a/zookeeper/example/basic/server/main.go b/zookeeper/example/basic/server/main.go new file mode 100644 index 0000000..69b9572 --- /dev/null +++ b/zookeeper/example/basic/server/main.go @@ -0,0 +1,48 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 main + +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + addr := "127.0.0.1:8888" + r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} diff --git a/zookeeper/go.mod b/zookeeper/go.mod new file mode 100644 index 0000000..3383cf7 --- /dev/null +++ b/zookeeper/go.mod @@ -0,0 +1,12 @@ +module github.com/hertz-contrib/registry/zookeeper + +go 1.16 + +require ( + github.com/cloudwego/hertz v0.2.2-0.20220809100505-e428c8fd938b + github.com/go-zookeeper/zk v1.0.3 + github.com/golang/protobuf v1.5.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect +) diff --git a/zookeeper/go.sum b/zookeeper/go.sum new file mode 100644 index 0000000..0a5e1b8 --- /dev/null +++ b/zookeeper/go.sum @@ -0,0 +1,81 @@ +github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= +github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= +github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 h1:PtwsQyQJGxf8iaPptPNaduEIu9BnrNms+pcRdHAxZaM= +github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= +github.com/bytedance/sonic v1.3.0 h1:T2rlvNytw6bTmczlAXvGqmuMzIqGJBOsJKYwRPWR7Y8= +github.com/bytedance/sonic v1.3.0/go.mod h1:V973WhNhGmvHxW6nQmsHEfHaoU9F3zTF+93rH03hcUQ= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 h1:1sDoSuDPWzhkdzNVxCxtIaKiAe96ESVPv8coGwc1gZ4= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/cloudwego/hertz v0.2.2-0.20220809100505-e428c8fd938b h1:fjXgpWRtRMxhyVxChAdCQP/7YYPJw5gSFjcuuMUEeLo= +github.com/cloudwego/hertz v0.2.2-0.20220809100505-e428c8fd938b/go.mod h1:GWWYlAVkq1gDu6vJd/XNciWsP6q0d4TrEKk5fpJYF04= +github.com/cloudwego/netpoll v0.2.4 h1:Kbo2HA1cXEgoy/bu1jSNrjcqZj2diENcJqLy6vKiROU= +github.com/cloudwego/netpoll v0.2.4/go.mod h1:1T2WVuQ+MQw6h6DpE45MohSvDTKdy2DlzCx2KsnPI4E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= +github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/goccy/go-json v0.9.4 h1:L8MLKG2mvVXiQu07qB6hmfqeSYQdOnqPot2GhsIwIaI= +github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= +github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk= +github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= +github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhYIrO6sdV/FPe0xQM6fNHkVQW2IAymfM0= +github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= +github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= +github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe h1:W8vbETX/n8S6EmY0Pu4Ix7VvpsJUESTwl0oCK8MJOgk= +golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/zookeeper/registry.go b/zookeeper/registry.go new file mode 100644 index 0000000..e8c2ec9 --- /dev/null +++ b/zookeeper/registry.go @@ -0,0 +1,161 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 zookeeper + +import ( + "encoding/json" + "errors" + "fmt" + "net" + "strings" + "time" + + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/go-zookeeper/zk" + + "github.com/hertz-contrib/registry/zookeeper/entity" + "github.com/hertz-contrib/registry/zookeeper/utils" +) + +type zookeeperRegistry struct { + conn *zk.Conn + authOpen bool + user, password string +} + +func (z *zookeeperRegistry) Register(info *registry.Info) error { + if err := z.validRegistryInfo(info); err != nil { + return fmt.Errorf("valid parse registry info error: %w", err) + } + path, err := buildPath(info) + if err != nil { + return err + } + content, err := json.Marshal(&entity.RegistryEntity{Weight: info.Weight, Tags: info.Tags}) + if err != nil { + return err + } + return z.createNode(path, content, true) +} + +func (z *zookeeperRegistry) Deregister(info *registry.Info) error { + if err := z.validRegistryInfo(info); err != nil { + return fmt.Errorf("valid parse registry info error: %w", err) + } + + path, err := buildPath(info) + if err != nil { + return err + } + return z.deleteNode(path) +} + +func NewZookeeperRegistry(servers []string, sessionTimeout time.Duration) (registry.Registry, error) { + conn, _, err := zk.Connect(servers, sessionTimeout) + if err != nil { + return nil, err + } + return &zookeeperRegistry{conn: conn}, nil +} + +func NewZookeeperRegistryWithAuth(servers []string, sessionTimeout time.Duration, user, password string) (registry.Registry, error) { + if user == "" || password == "" { + return nil, fmt.Errorf("user or password can't be empty") + } + conn, _, err := zk.Connect(servers, sessionTimeout) + if err != nil { + return nil, err + } + auth := []byte(fmt.Sprintf("%s:%s", user, password)) + err = conn.AddAuth(utils.Scheme, auth) + if err != nil { + return nil, err + } + return &zookeeperRegistry{conn: conn, authOpen: true, user: user, password: password}, nil +} + +func (z *zookeeperRegistry) validRegistryInfo(info *registry.Info) error { + if info == nil { + return errors.New("registry.Info can not be empty") + } + if info.ServiceName == "" { + return errors.New("registry.Info ServiceName can not be empty") + } + if info.Addr == nil { + return errors.New("registry.Info Addr can not be empty") + } + return nil +} + +// buildPath path format as follows: {serviceName}/{ip}:{port} +func buildPath(info *registry.Info) (string, error) { + var path string + if !strings.HasPrefix(info.ServiceName, utils.Separator) { + path = utils.Separator + info.ServiceName + } + + if host, port, err := net.SplitHostPort(info.Addr.String()); err == nil { + if port == "" { + return "", fmt.Errorf("registry info addr missing port") + } + if host == "" { + ipv4, err := utils.GetLocalIPv4Address() + if err != nil { + return "", fmt.Errorf("get local ipv4 error, cause %w", err) + } + path = path + utils.Separator + ipv4 + ":" + port + } else { + path = path + utils.Separator + host + ":" + port + } + } else { + return "", fmt.Errorf("parse registry info addr error") + } + return path, nil +} + +func (z *zookeeperRegistry) createNode(path string, content []byte, ephemeral bool) error { + i := strings.LastIndex(path, utils.Separator) + if i > 0 { + err := z.createNode(path[0:i], nil, false) + if err != nil && !errors.Is(err, zk.ErrNodeExists) { + return err + } + } + var flag int32 + if ephemeral { + flag = zk.FlagEphemeral + } + if z.authOpen { + _, err := z.conn.Create(path, content, flag, zk.DigestACL(zk.PermAll, z.user, z.password)) + if err != nil { + return fmt.Errorf("create node [%s] with auth error, cause %w", path, err) + } + return nil + } else { + _, err := z.conn.Create(path, content, flag, zk.WorldACL(zk.PermAll)) + if err != nil { + return fmt.Errorf("create node [%s] error, cause %w", path, err) + } + return nil + } +} + +func (z *zookeeperRegistry) deleteNode(path string) error { + err := z.conn.Delete(path, -1) + if err != nil && err != zk.ErrNoNode { + return fmt.Errorf("delete node [%s] error, cause %w", path, err) + } + return nil +} diff --git a/zookeeper/reslover.go b/zookeeper/reslover.go new file mode 100644 index 0000000..1c25cea --- /dev/null +++ b/zookeeper/reslover.go @@ -0,0 +1,128 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 zookeeper + +import ( + "context" + "encoding/json" + "fmt" + "net" + "strings" + "time" + + "github.com/cloudwego/hertz/pkg/app/client/discovery" + "github.com/go-zookeeper/zk" + + "github.com/hertz-contrib/registry/zookeeper/entity" + "github.com/hertz-contrib/registry/zookeeper/utils" +) + +type zookeeperResolver struct { + conn *zk.Conn +} + +// NewZookeeperResolver create a zookeeper based resolver +func NewZookeeperResolver(servers []string, sessionTimeout time.Duration) (discovery.Resolver, error) { + conn, _, err := zk.Connect(servers, sessionTimeout) + if err != nil { + return nil, err + } + return &zookeeperResolver{conn: conn}, nil +} + +// NewZookeeperResolver create a zookeeper based resolver with auth +func NewZookeeperResolverWithAuth(servers []string, sessionTimeout time.Duration, user, password string) (discovery.Resolver, error) { + conn, _, err := zk.Connect(servers, sessionTimeout) + if err != nil { + return nil, err + } + auth := []byte(fmt.Sprintf("%s:%s", user, password)) + err = conn.AddAuth(utils.Scheme, auth) + if err != nil { + return nil, err + } + return &zookeeperResolver{conn: conn}, nil +} + +func (z *zookeeperResolver) Target(ctx context.Context, target *discovery.TargetInfo) string { + return target.Host +} + +func (z *zookeeperResolver) Resolve(ctx context.Context, desc string) (discovery.Result, error) { + path := desc + if !strings.HasPrefix(path, utils.Separator) { + path = utils.Separator + path + } + eps, err := z.getEndPoints(path) + if err != nil { + return discovery.Result{}, err + } + if len(eps) == 0 { + return discovery.Result{}, fmt.Errorf("no instance remains for %v", desc) + } + instances, err := z.getInstances(eps, path) + if err != nil { + return discovery.Result{}, err + } + res := discovery.Result{ + CacheKey: desc, + Instances: instances, + } + return res, nil +} + +func (z *zookeeperResolver) getEndPoints(path string) ([]string, error) { + child, _, err := z.conn.Children(path) + return child, err +} + +func (z *zookeeperResolver) getInstances(eps []string, path string) ([]discovery.Instance, error) { + instances := make([]discovery.Instance, 0, len(eps)) + for _, ep := range eps { + if host, port, err := net.SplitHostPort(ep); err == nil { + if port == "" { + return []discovery.Instance{}, fmt.Errorf("missing port when parse node [%s]", ep) + } + if host == "" { + return []discovery.Instance{}, fmt.Errorf("missing host when parse node [%s]", ep) + } + ins, err := z.detailEndPoints(path, ep) + if err != nil { + return []discovery.Instance{}, fmt.Errorf("detail endpoint [%s] info error, cause %w", ep, err) + } + instances = append(instances, ins) + } else { + return []discovery.Instance{}, fmt.Errorf("parse node [%s] error, details info [%w]", ep, err) + } + } + return instances, nil +} + +func (z *zookeeperResolver) detailEndPoints(path, ep string) (discovery.Instance, error) { + data, _, err := z.conn.Get(path + utils.Separator + ep) + if err != nil { + return nil, err + } + en := new(entity.RegistryEntity) + err = json.Unmarshal(data, en) + if err != nil { + return nil, fmt.Errorf("unmarshal data [%s] error, cause %w", data, err) + } + return discovery.NewInstance("tcp", ep, en.Weight, en.Tags), nil +} + +func (z *zookeeperResolver) Name() string { + return "zookeeper" +} diff --git a/zookeeper/utils/const.go b/zookeeper/utils/const.go new file mode 100644 index 0000000..6a37426 --- /dev/null +++ b/zookeeper/utils/const.go @@ -0,0 +1,20 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 + +const ( + Separator = "/" + Scheme = "digest" // For auth +) diff --git a/zookeeper/utils/net.go b/zookeeper/utils/net.go new file mode 100644 index 0000000..b687d8e --- /dev/null +++ b/zookeeper/utils/net.go @@ -0,0 +1,38 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 ( + "fmt" + "net" +) + +func GetLocalIPv4Address() (string, error) { + addr, err := net.InterfaceAddrs() + if err != nil { + return "", err + } + + for _, addr := range addr { + ipNet, isIpNet := addr.(*net.IPNet) + if isIpNet && !ipNet.IP.IsLoopback() { + ipv4 := ipNet.IP.To4() + if ipv4 != nil { + return ipv4.String(), nil + } + } + } + return "", fmt.Errorf("not found ipv4 address") +} From 1239e9730fce64a95f5b9d8ddc6fdf234b9d5e56 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 17:08:18 +0800 Subject: [PATCH 02/25] chore: simplify dupliate code && no eps return nil --- zookeeper/registry.go | 19 +++++++++---------- zookeeper/reslover.go | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/zookeeper/registry.go b/zookeeper/registry.go index e8c2ec9..56503d9 100644 --- a/zookeeper/registry.go +++ b/zookeeper/registry.go @@ -137,19 +137,18 @@ func (z *zookeeperRegistry) createNode(path string, content []byte, ephemeral bo if ephemeral { flag = zk.FlagEphemeral } + var acl []zk.ACL if z.authOpen { - _, err := z.conn.Create(path, content, flag, zk.DigestACL(zk.PermAll, z.user, z.password)) - if err != nil { - return fmt.Errorf("create node [%s] with auth error, cause %w", path, err) - } - return nil + acl = zk.DigestACL(zk.PermAll, z.user, z.password) } else { - _, err := z.conn.Create(path, content, flag, zk.WorldACL(zk.PermAll)) - if err != nil { - return fmt.Errorf("create node [%s] error, cause %w", path, err) - } - return nil + acl = zk.WorldACL(zk.PermAll) + } + _, err := z.conn.Create(path, content, flag, acl) + if err != nil { + return fmt.Errorf("create node [%s] error, cause %w", path, err) } + return nil + } func (z *zookeeperRegistry) deleteNode(path string) error { diff --git a/zookeeper/reslover.go b/zookeeper/reslover.go index 1c25cea..01cfbc2 100644 --- a/zookeeper/reslover.go +++ b/zookeeper/reslover.go @@ -70,7 +70,7 @@ func (z *zookeeperResolver) Resolve(ctx context.Context, desc string) (discovery return discovery.Result{}, err } if len(eps) == 0 { - return discovery.Result{}, fmt.Errorf("no instance remains for %v", desc) + return discovery.Result{}, nil } instances, err := z.getInstances(eps, path) if err != nil { From ade98b53999ee4efa9c41ed43df53583b6fd5081 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 18:49:28 +0800 Subject: [PATCH 03/25] style: import style --- zookeeper/README.md | 2 -- zookeeper/discovery_test.go | 1 - zookeeper/example/auth/client/main.go | 1 - zookeeper/example/auth/server/main.go | 1 - zookeeper/example/basic/client/main.go | 1 - zookeeper/example/basic/server/main.go | 1 - zookeeper/registry.go | 1 - zookeeper/reslover.go | 1 - 8 files changed, 9 deletions(-) diff --git a/zookeeper/README.md b/zookeeper/README.md index 8a4d797..9ee4cff 100644 --- a/zookeeper/README.md +++ b/zookeeper/README.md @@ -18,7 +18,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/server/registry" "github.com/cloudwego/hertz/pkg/common/utils" "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/zookeeper" ) @@ -57,7 +56,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" "github.com/cloudwego/hertz/pkg/common/config" "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/zookeeper" ) diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go index c5ae3fe..008d2f8 100644 --- a/zookeeper/discovery_test.go +++ b/zookeeper/discovery_test.go @@ -23,7 +23,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/client/discovery" "github.com/cloudwego/hertz/pkg/app/server/registry" "github.com/stretchr/testify/assert" - "github.com/hertz-contrib/registry/zookeeper/utils" ) diff --git a/zookeeper/example/auth/client/main.go b/zookeeper/example/auth/client/main.go index d1cb857..39bc04d 100644 --- a/zookeeper/example/auth/client/main.go +++ b/zookeeper/example/auth/client/main.go @@ -22,7 +22,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" "github.com/cloudwego/hertz/pkg/common/config" "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/zookeeper" ) diff --git a/zookeeper/example/auth/server/main.go b/zookeeper/example/auth/server/main.go index 54dc684..fff5614 100644 --- a/zookeeper/example/auth/server/main.go +++ b/zookeeper/example/auth/server/main.go @@ -23,7 +23,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/server/registry" "github.com/cloudwego/hertz/pkg/common/utils" "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/zookeeper" ) diff --git a/zookeeper/example/basic/client/main.go b/zookeeper/example/basic/client/main.go index 125a354..0d84d78 100644 --- a/zookeeper/example/basic/client/main.go +++ b/zookeeper/example/basic/client/main.go @@ -22,7 +22,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" "github.com/cloudwego/hertz/pkg/common/config" "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/zookeeper" ) diff --git a/zookeeper/example/basic/server/main.go b/zookeeper/example/basic/server/main.go index 69b9572..a957ceb 100644 --- a/zookeeper/example/basic/server/main.go +++ b/zookeeper/example/basic/server/main.go @@ -23,7 +23,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/server/registry" "github.com/cloudwego/hertz/pkg/common/utils" "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/zookeeper" ) diff --git a/zookeeper/registry.go b/zookeeper/registry.go index 56503d9..240adf7 100644 --- a/zookeeper/registry.go +++ b/zookeeper/registry.go @@ -24,7 +24,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/server/registry" "github.com/go-zookeeper/zk" - "github.com/hertz-contrib/registry/zookeeper/entity" "github.com/hertz-contrib/registry/zookeeper/utils" ) diff --git a/zookeeper/reslover.go b/zookeeper/reslover.go index 01cfbc2..e6580ac 100644 --- a/zookeeper/reslover.go +++ b/zookeeper/reslover.go @@ -24,7 +24,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/client/discovery" "github.com/go-zookeeper/zk" - "github.com/hertz-contrib/registry/zookeeper/entity" "github.com/hertz-contrib/registry/zookeeper/utils" ) From b603b82af22af959327e95c834591bd958eef6d4 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 20:40:00 +0800 Subject: [PATCH 04/25] chore: remove utils/entity folder && use Localp --- zookeeper/discovery_test.go | 6 +++--- zookeeper/entity/entity.go | 20 ------------------- zookeeper/registry.go | 31 +++++++++++++++++++----------- zookeeper/reslover.go | 12 +++++------- zookeeper/utils/const.go | 20 ------------------- zookeeper/utils/net.go | 38 ------------------------------------- 6 files changed, 28 insertions(+), 99 deletions(-) delete mode 100644 zookeeper/entity/entity.go delete mode 100644 zookeeper/utils/const.go delete mode 100644 zookeeper/utils/net.go diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go index 008d2f8..ef5d577 100644 --- a/zookeeper/discovery_test.go +++ b/zookeeper/discovery_test.go @@ -22,8 +22,8 @@ import ( "github.com/cloudwego/hertz/pkg/app/client/discovery" "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" "github.com/stretchr/testify/assert" - "github.com/hertz-contrib/registry/zookeeper/utils" ) func TestZookeeperDiscovery(t *testing.T) { @@ -50,7 +50,7 @@ func TestZookeeperDiscovery(t *testing.T) { instance := result.Instances[0] host, port, err := net.SplitHostPort(instance.Address().String()) assert.Nil(t, err) - local, _ := utils.GetLocalIPv4Address() + local := utils.LocalIP() if host != local { t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) } @@ -100,7 +100,7 @@ func TestZookeeperResolverWithAuth(t *testing.T) { instance := result.Instances[0] host, port, err := net.SplitHostPort(instance.Address().String()) assert.Nil(t, err) - local, _ := utils.GetLocalIPv4Address() + local := utils.LocalIP() if host != local { t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) } diff --git a/zookeeper/entity/entity.go b/zookeeper/entity/entity.go deleted file mode 100644 index aa14008..0000000 --- a/zookeeper/entity/entity.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2021 CloudWeGo Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 entity - -type RegistryEntity struct { - Weight int - Tags map[string]string -} diff --git a/zookeeper/registry.go b/zookeeper/registry.go index 240adf7..1a07fe3 100644 --- a/zookeeper/registry.go +++ b/zookeeper/registry.go @@ -23,11 +23,20 @@ import ( "time" "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" "github.com/go-zookeeper/zk" - "github.com/hertz-contrib/registry/zookeeper/entity" - "github.com/hertz-contrib/registry/zookeeper/utils" ) +const ( + Separator = "/" + Scheme = "digest" // For auth +) + +type RegistryEntity struct { + Weight int + Tags map[string]string +} + type zookeeperRegistry struct { conn *zk.Conn authOpen bool @@ -42,7 +51,7 @@ func (z *zookeeperRegistry) Register(info *registry.Info) error { if err != nil { return err } - content, err := json.Marshal(&entity.RegistryEntity{Weight: info.Weight, Tags: info.Tags}) + content, err := json.Marshal(&RegistryEntity{Weight: info.Weight, Tags: info.Tags}) if err != nil { return err } @@ -78,7 +87,7 @@ func NewZookeeperRegistryWithAuth(servers []string, sessionTimeout time.Duration return nil, err } auth := []byte(fmt.Sprintf("%s:%s", user, password)) - err = conn.AddAuth(utils.Scheme, auth) + err = conn.AddAuth(Scheme, auth) if err != nil { return nil, err } @@ -101,22 +110,22 @@ func (z *zookeeperRegistry) validRegistryInfo(info *registry.Info) error { // buildPath path format as follows: {serviceName}/{ip}:{port} func buildPath(info *registry.Info) (string, error) { var path string - if !strings.HasPrefix(info.ServiceName, utils.Separator) { - path = utils.Separator + info.ServiceName + if !strings.HasPrefix(info.ServiceName, Separator) { + path = Separator + info.ServiceName } if host, port, err := net.SplitHostPort(info.Addr.String()); err == nil { if port == "" { return "", fmt.Errorf("registry info addr missing port") } - if host == "" { - ipv4, err := utils.GetLocalIPv4Address() + if host == "::" { + ipv4 := utils.LocalIP() if err != nil { return "", fmt.Errorf("get local ipv4 error, cause %w", err) } - path = path + utils.Separator + ipv4 + ":" + port + path = path + Separator + ipv4 + ":" + port } else { - path = path + utils.Separator + host + ":" + port + path = path + Separator + host + ":" + port } } else { return "", fmt.Errorf("parse registry info addr error") @@ -125,7 +134,7 @@ func buildPath(info *registry.Info) (string, error) { } func (z *zookeeperRegistry) createNode(path string, content []byte, ephemeral bool) error { - i := strings.LastIndex(path, utils.Separator) + i := strings.LastIndex(path, Separator) if i > 0 { err := z.createNode(path[0:i], nil, false) if err != nil && !errors.Is(err, zk.ErrNodeExists) { diff --git a/zookeeper/reslover.go b/zookeeper/reslover.go index e6580ac..b1373c0 100644 --- a/zookeeper/reslover.go +++ b/zookeeper/reslover.go @@ -24,8 +24,6 @@ import ( "github.com/cloudwego/hertz/pkg/app/client/discovery" "github.com/go-zookeeper/zk" - "github.com/hertz-contrib/registry/zookeeper/entity" - "github.com/hertz-contrib/registry/zookeeper/utils" ) type zookeeperResolver struct { @@ -48,7 +46,7 @@ func NewZookeeperResolverWithAuth(servers []string, sessionTimeout time.Duration return nil, err } auth := []byte(fmt.Sprintf("%s:%s", user, password)) - err = conn.AddAuth(utils.Scheme, auth) + err = conn.AddAuth(Scheme, auth) if err != nil { return nil, err } @@ -61,8 +59,8 @@ func (z *zookeeperResolver) Target(ctx context.Context, target *discovery.Target func (z *zookeeperResolver) Resolve(ctx context.Context, desc string) (discovery.Result, error) { path := desc - if !strings.HasPrefix(path, utils.Separator) { - path = utils.Separator + path + if !strings.HasPrefix(path, Separator) { + path = Separator + path } eps, err := z.getEndPoints(path) if err != nil { @@ -110,11 +108,11 @@ func (z *zookeeperResolver) getInstances(eps []string, path string) ([]discovery } func (z *zookeeperResolver) detailEndPoints(path, ep string) (discovery.Instance, error) { - data, _, err := z.conn.Get(path + utils.Separator + ep) + data, _, err := z.conn.Get(path + Separator + ep) if err != nil { return nil, err } - en := new(entity.RegistryEntity) + en := new(RegistryEntity) err = json.Unmarshal(data, en) if err != nil { return nil, fmt.Errorf("unmarshal data [%s] error, cause %w", data, err) diff --git a/zookeeper/utils/const.go b/zookeeper/utils/const.go deleted file mode 100644 index 6a37426..0000000 --- a/zookeeper/utils/const.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2021 CloudWeGo Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 - -const ( - Separator = "/" - Scheme = "digest" // For auth -) diff --git a/zookeeper/utils/net.go b/zookeeper/utils/net.go deleted file mode 100644 index b687d8e..0000000 --- a/zookeeper/utils/net.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2021 CloudWeGo Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 ( - "fmt" - "net" -) - -func GetLocalIPv4Address() (string, error) { - addr, err := net.InterfaceAddrs() - if err != nil { - return "", err - } - - for _, addr := range addr { - ipNet, isIpNet := addr.(*net.IPNet) - if isIpNet && !ipNet.IP.IsLoopback() { - ipv4 := ipNet.IP.To4() - if ipv4 != nil { - return ipv4.String(), nil - } - } - } - return "", fmt.Errorf("not found ipv4 address") -} From 6bb181e271c15d8a6f64a2ad3e5a8186b0464033 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 20:41:27 +0800 Subject: [PATCH 05/25] fix: typo --- zookeeper/registry.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zookeeper/registry.go b/zookeeper/registry.go index 1a07fe3..b9837bc 100644 --- a/zookeeper/registry.go +++ b/zookeeper/registry.go @@ -118,7 +118,7 @@ func buildPath(info *registry.Info) (string, error) { if port == "" { return "", fmt.Errorf("registry info addr missing port") } - if host == "::" { + if host == "" { ipv4 := utils.LocalIP() if err != nil { return "", fmt.Errorf("get local ipv4 error, cause %w", err) From 9419e392ce3198ce749f50bc7bf6dc12be54211f Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 20:43:02 +0800 Subject: [PATCH 06/25] chore: change basic -> standard --- zookeeper/README.md | 8 ++++---- zookeeper/example/{basic => standard}/client/main.go | 0 zookeeper/example/{basic => standard}/server/main.go | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename zookeeper/example/{basic => standard}/client/main.go (100%) rename zookeeper/example/{basic => standard}/server/main.go (100%) diff --git a/zookeeper/README.md b/zookeeper/README.md index 9ee4cff..a1a7a03 100644 --- a/zookeeper/README.md +++ b/zookeeper/README.md @@ -6,7 +6,7 @@ Zookeeper as service discovery for Hertz. ### server -**[example/basic/server/main.go](example/basic/server/main.go)** +**[example/standard/server/main.go](example/standard/server/main.go)** ```go import ( @@ -45,7 +45,7 @@ func main() { ### Client -**[example/basic/client/main.go](example/basic/client/main.go)** +**[example/standard/client/main.go](example/standard/client/main.go)** ```go import ( @@ -85,13 +85,13 @@ make prepare ### run server ```go -go run ./example/basic/server/main.go +go run ./example/standard/server/main.go ``` ### run client ```go -go run ./example/basic/client/main.go +go run ./example/standard/client/main.go ``` ```go 2022/08/21 23:31:59.391243 main.go:44: [Info] code=200,body={"ping":"pong2"} diff --git a/zookeeper/example/basic/client/main.go b/zookeeper/example/standard/client/main.go similarity index 100% rename from zookeeper/example/basic/client/main.go rename to zookeeper/example/standard/client/main.go diff --git a/zookeeper/example/basic/server/main.go b/zookeeper/example/standard/server/main.go similarity index 100% rename from zookeeper/example/basic/server/main.go rename to zookeeper/example/standard/server/main.go From c077fe44acf75544ee0cd7182a86eb414cbf0a05 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 23:24:49 +0800 Subject: [PATCH 07/25] refactor: use local utils to get ipv4Address --- zookeeper/discovery_test.go | 8 ++++---- zookeeper/example/standard/server/main.go | 0 zookeeper/registry.go | 5 ++--- zookeeper/utils/net.go | 24 +++++++++++++++++++++++ 4 files changed, 30 insertions(+), 7 deletions(-) mode change 100644 => 100755 zookeeper/example/standard/server/main.go create mode 100644 zookeeper/utils/net.go diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go index ef5d577..a26f769 100644 --- a/zookeeper/discovery_test.go +++ b/zookeeper/discovery_test.go @@ -22,8 +22,8 @@ import ( "github.com/cloudwego/hertz/pkg/app/client/discovery" "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" "github.com/stretchr/testify/assert" + "github.com/hertz-contrib/registry/zookeeper/utils" ) func TestZookeeperDiscovery(t *testing.T) { @@ -50,7 +50,7 @@ func TestZookeeperDiscovery(t *testing.T) { instance := result.Instances[0] host, port, err := net.SplitHostPort(instance.Address().String()) assert.Nil(t, err) - local := utils.LocalIP() + local, _ := utils.GetLocalIPv4Address() if host != local { t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) } @@ -73,7 +73,7 @@ func TestZookeeperDiscovery(t *testing.T) { // resolve again result, err = res.Resolve(context.Background(), target) - assert.EqualError(t, err, "no instance remains for product") + assert.Nil(t, err) } func TestZookeeperResolverWithAuth(t *testing.T) { @@ -100,7 +100,7 @@ func TestZookeeperResolverWithAuth(t *testing.T) { instance := result.Instances[0] host, port, err := net.SplitHostPort(instance.Address().String()) assert.Nil(t, err) - local := utils.LocalIP() + local, _ := utils.GetLocalIPv4Address() if host != local { t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) } diff --git a/zookeeper/example/standard/server/main.go b/zookeeper/example/standard/server/main.go old mode 100644 new mode 100755 diff --git a/zookeeper/registry.go b/zookeeper/registry.go index b9837bc..e2f8267 100644 --- a/zookeeper/registry.go +++ b/zookeeper/registry.go @@ -23,8 +23,8 @@ import ( "time" "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" "github.com/go-zookeeper/zk" + "github.com/hertz-contrib/registry/zookeeper/utils" ) const ( @@ -119,7 +119,7 @@ func buildPath(info *registry.Info) (string, error) { return "", fmt.Errorf("registry info addr missing port") } if host == "" { - ipv4 := utils.LocalIP() + ipv4, err := utils.GetLocalIPv4Address() if err != nil { return "", fmt.Errorf("get local ipv4 error, cause %w", err) } @@ -156,7 +156,6 @@ func (z *zookeeperRegistry) createNode(path string, content []byte, ephemeral bo return fmt.Errorf("create node [%s] error, cause %w", path, err) } return nil - } func (z *zookeeperRegistry) deleteNode(path string) error { diff --git a/zookeeper/utils/net.go b/zookeeper/utils/net.go new file mode 100644 index 0000000..1c715e3 --- /dev/null +++ b/zookeeper/utils/net.go @@ -0,0 +1,24 @@ +package utils + +import ( + "fmt" + "net" +) + +func GetLocalIPv4Address() (string, error) { + addr, err := net.InterfaceAddrs() + if err != nil { + return "", err + } + + for _, addr := range addr { + ipNet, isIpNet := addr.(*net.IPNet) + if isIpNet && !ipNet.IP.IsLoopback() { + ipv4 := ipNet.IP.To4() + if ipv4 != nil { + return ipv4.String(), nil + } + } + } + return "", fmt.Errorf("not found ipv4 address") +} From a72bb8aafa06def33d5d64d3f3de4fa4dfb60080 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 23:30:46 +0800 Subject: [PATCH 08/25] fix: add cacheKey --- zookeeper/reslover.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zookeeper/reslover.go b/zookeeper/reslover.go index b1373c0..f92b8de 100644 --- a/zookeeper/reslover.go +++ b/zookeeper/reslover.go @@ -67,7 +67,7 @@ func (z *zookeeperResolver) Resolve(ctx context.Context, desc string) (discovery return discovery.Result{}, err } if len(eps) == 0 { - return discovery.Result{}, nil + return discovery.Result{CacheKey: desc}, nil } instances, err := z.getInstances(eps, path) if err != nil { From 0dd2e6a3785c1b74b6168152e2943f614bdf5183 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 23:37:27 +0800 Subject: [PATCH 09/25] test: unit test assert nil --- zookeeper/discovery_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go index a26f769..de8abb7 100644 --- a/zookeeper/discovery_test.go +++ b/zookeeper/discovery_test.go @@ -23,6 +23,7 @@ import ( "github.com/cloudwego/hertz/pkg/app/client/discovery" "github.com/cloudwego/hertz/pkg/app/server/registry" "github.com/stretchr/testify/assert" + "github.com/hertz-contrib/registry/zookeeper/utils" ) @@ -123,5 +124,5 @@ func TestZookeeperResolverWithAuth(t *testing.T) { // resolve again result, err = res.Resolve(context.Background(), target) - assert.EqualError(t, err, "no instance remains for product") + assert.Nil(t, err) } From c13e3fab7868cdcfed120904c59f4e8e444c966e Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 23:39:47 +0800 Subject: [PATCH 10/25] style: add license header --- zookeeper/utils/net.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/zookeeper/utils/net.go b/zookeeper/utils/net.go index 1c715e3..b687d8e 100644 --- a/zookeeper/utils/net.go +++ b/zookeeper/utils/net.go @@ -1,3 +1,17 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 ( From 9c78dcfea0c257e6befe129bf66957912d6a0931 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Tue, 23 Aug 2022 23:51:17 +0800 Subject: [PATCH 11/25] fix: handle host :: case --- zookeeper/reslover.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zookeeper/reslover.go b/zookeeper/reslover.go index f92b8de..6432091 100644 --- a/zookeeper/reslover.go +++ b/zookeeper/reslover.go @@ -92,7 +92,7 @@ func (z *zookeeperResolver) getInstances(eps []string, path string) ([]discovery if port == "" { return []discovery.Instance{}, fmt.Errorf("missing port when parse node [%s]", ep) } - if host == "" { + if host == "" || host == "::" { return []discovery.Instance{}, fmt.Errorf("missing host when parse node [%s]", ep) } ins, err := z.detailEndPoints(path, ep) From bf4faa4535021fd582dc18fea1ff7b35c497a13f Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 00:02:21 +0800 Subject: [PATCH 12/25] doc: add compatibility part --- zookeeper/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/zookeeper/README.md b/zookeeper/README.md index a1a7a03..78e58bf 100644 --- a/zookeeper/README.md +++ b/zookeeper/README.md @@ -104,4 +104,9 @@ go run ./example/standard/client/main.go 2022/08/21 23:31:59.392144 main.go:44: [Info] code=200,body={"ping":"pong2"} 2022/08/21 23:31:59.392249 main.go:44: [Info] code=200,body={"ping":"pong2"} 2022/08/21 23:31:59.392379 main.go:44: [Info] code=200,body={"ping":"pong2"} -``` \ No newline at end of file +``` + +## Compatibility +Compatible with server (3.4.0 - 3.7.0), If you want to use older server version, please modify the version in `Makefile` to test. + +[zookeeper server version list]( https://zookeeper.apache.org/documentation.html) \ No newline at end of file From d5d359678866e1a6dc2509d31f0c268be085ceb0 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 00:33:05 +0800 Subject: [PATCH 13/25] refactor: use Localp instead of local utils --- zookeeper/discovery_test.go | 7 +++---- zookeeper/registry.go | 9 +++------ zookeeper/utils/net.go | 38 ------------------------------------- 3 files changed, 6 insertions(+), 48 deletions(-) delete mode 100644 zookeeper/utils/net.go diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go index de8abb7..2c051f1 100644 --- a/zookeeper/discovery_test.go +++ b/zookeeper/discovery_test.go @@ -22,9 +22,8 @@ import ( "github.com/cloudwego/hertz/pkg/app/client/discovery" "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" "github.com/stretchr/testify/assert" - - "github.com/hertz-contrib/registry/zookeeper/utils" ) func TestZookeeperDiscovery(t *testing.T) { @@ -51,7 +50,7 @@ func TestZookeeperDiscovery(t *testing.T) { instance := result.Instances[0] host, port, err := net.SplitHostPort(instance.Address().String()) assert.Nil(t, err) - local, _ := utils.GetLocalIPv4Address() + local := utils.LocalIP() if host != local { t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) } @@ -101,7 +100,7 @@ func TestZookeeperResolverWithAuth(t *testing.T) { instance := result.Instances[0] host, port, err := net.SplitHostPort(instance.Address().String()) assert.Nil(t, err) - local, _ := utils.GetLocalIPv4Address() + local := utils.LocalIP() if host != local { t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) } diff --git a/zookeeper/registry.go b/zookeeper/registry.go index e2f8267..3f378fc 100644 --- a/zookeeper/registry.go +++ b/zookeeper/registry.go @@ -23,8 +23,8 @@ import ( "time" "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" "github.com/go-zookeeper/zk" - "github.com/hertz-contrib/registry/zookeeper/utils" ) const ( @@ -119,11 +119,8 @@ func buildPath(info *registry.Info) (string, error) { return "", fmt.Errorf("registry info addr missing port") } if host == "" { - ipv4, err := utils.GetLocalIPv4Address() - if err != nil { - return "", fmt.Errorf("get local ipv4 error, cause %w", err) - } - path = path + Separator + ipv4 + ":" + port + host = utils.LocalIP() // LocalIP example fe80::1 + path = path + Separator + "[" + host + "]" + ":" + port } else { path = path + Separator + host + ":" + port } diff --git a/zookeeper/utils/net.go b/zookeeper/utils/net.go deleted file mode 100644 index b687d8e..0000000 --- a/zookeeper/utils/net.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2021 CloudWeGo Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 ( - "fmt" - "net" -) - -func GetLocalIPv4Address() (string, error) { - addr, err := net.InterfaceAddrs() - if err != nil { - return "", err - } - - for _, addr := range addr { - ipNet, isIpNet := addr.(*net.IPNet) - if isIpNet && !ipNet.IP.IsLoopback() { - ipv4 := ipNet.IP.To4() - if ipv4 != nil { - return ipv4.String(), nil - } - } - } - return "", fmt.Errorf("not found ipv4 address") -} From 6b6fa9130ca937be7baa3f0a335ebf594d34e118 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 00:56:27 +0800 Subject: [PATCH 14/25] test: add assert for reslove --- zookeeper/discovery_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go index 2c051f1..434a293 100644 --- a/zookeeper/discovery_test.go +++ b/zookeeper/discovery_test.go @@ -74,6 +74,9 @@ func TestZookeeperDiscovery(t *testing.T) { // resolve again result, err = res.Resolve(context.Background(), target) assert.Nil(t, err) + assert.Empty(t, result.Instances) + assert.Equal(t, "product", result.CacheKey) + } func TestZookeeperResolverWithAuth(t *testing.T) { @@ -124,4 +127,7 @@ func TestZookeeperResolverWithAuth(t *testing.T) { // resolve again result, err = res.Resolve(context.Background(), target) assert.Nil(t, err) + assert.Empty(t, result.Instances) + assert.Equal(t, "product", result.CacheKey) + } From d7d9b5ae1fc822055f88834a2349bd92c842dd60 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 01:28:00 +0800 Subject: [PATCH 15/25] test: add test with hertz --- zookeeper/zookeeper_test.go | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 zookeeper/zookeeper_test.go diff --git a/zookeeper/zookeeper_test.go b/zookeeper/zookeeper_test.go new file mode 100644 index 0000000..4241b8e --- /dev/null +++ b/zookeeper/zookeeper_test.go @@ -0,0 +1,68 @@ +package zookeeper + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/stretchr/testify/assert" +) + +func TestZookeeperRegistryAndDeregister(t *testing.T) { + address := "127.0.0.1:8888" + r, _ := NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + srvName := "hertz.test.demo" + h := server.Default( + server.WithHostPorts(address), + server.WithRegistry(r, ®istry.Info{ + ServiceName: srvName, + Addr: utils.NewNetAddr("tcp", address), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + go h.Spin() + + time.Sleep(1 * time.Second) + + // register + newClient, _ := client.NewClient() + resolver, _ := NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + newClient.Use(sd.Discovery(resolver)) + + addr := fmt.Sprintf("http://" + srvName + "/ping") + status, body, err := newClient.Get(context.Background(), nil, addr, config.WithSD(true)) + assert.Nil(t, err) + assert.Equal(t, 200, status) + assert.Equal(t, "{\"ping\":\"pong2\"}", string(body)) + + // compare data + opt := h.GetOptions() + assert.Equal(t, opt.RegistryInfo.Weight, 10) + assert.Equal(t, opt.RegistryInfo.Addr.String(), "127.0.0.1:8888") + assert.Equal(t, opt.RegistryInfo.ServiceName, "hertz.test.demo") + assert.Nil(t, opt.RegistryInfo.Tags) + + // deregister + if err := opt.Registry.Deregister(opt.RegistryInfo); err != nil { + t.Errorf("HERTZ: Deregister error=%v", err) + } + + time.Sleep(5 * time.Second) + + status1, body1, err1 := newClient.Get(context.Background(), nil, addr, config.WithSD(true)) + assert.NotNil(t, err1) + assert.Equal(t, 0, status1) + assert.Equal(t, "", string(body1)) +} From 446af242b98437c08e88bd4f787aa3589cddab53 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 01:30:14 +0800 Subject: [PATCH 16/25] style: add license header && gofumpt --- zookeeper/discovery_test.go | 2 -- zookeeper/zookeeper_test.go | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go index 434a293..dc17f95 100644 --- a/zookeeper/discovery_test.go +++ b/zookeeper/discovery_test.go @@ -76,7 +76,6 @@ func TestZookeeperDiscovery(t *testing.T) { assert.Nil(t, err) assert.Empty(t, result.Instances) assert.Equal(t, "product", result.CacheKey) - } func TestZookeeperResolverWithAuth(t *testing.T) { @@ -129,5 +128,4 @@ func TestZookeeperResolverWithAuth(t *testing.T) { assert.Nil(t, err) assert.Empty(t, result.Instances) assert.Equal(t, "product", result.CacheKey) - } diff --git a/zookeeper/zookeeper_test.go b/zookeeper/zookeeper_test.go index 4241b8e..14c3034 100644 --- a/zookeeper/zookeeper_test.go +++ b/zookeeper/zookeeper_test.go @@ -1,3 +1,17 @@ +// Copyright 2021 CloudWeGo Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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 zookeeper import ( From 7c154dec50ece8c1fc5ceac0e5fdc8c302f59a12 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 01:32:56 +0800 Subject: [PATCH 17/25] style: add newline to end of file --- linceses/LICENSE-gozookeeper | 2 +- linceses/LICENSE-testify | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linceses/LICENSE-gozookeeper b/linceses/LICENSE-gozookeeper index 4decd5f..bc00498 100644 --- a/linceses/LICENSE-gozookeeper +++ b/linceses/LICENSE-gozookeeper @@ -22,4 +22,4 @@ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/linceses/LICENSE-testify b/linceses/LICENSE-testify index 0be77a0..4b0421c 100644 --- a/linceses/LICENSE-testify +++ b/linceses/LICENSE-testify @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. From 0b1fe3956d300717979a9543d6bbd6727e223855 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 01:40:55 +0800 Subject: [PATCH 18/25] doc: optimize README.md format --- zookeeper/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zookeeper/README.md b/zookeeper/README.md index 78e58bf..043bd9e 100644 --- a/zookeeper/README.md +++ b/zookeeper/README.md @@ -76,9 +76,7 @@ func main() { ### run docker -- make prepare - -```bash +```shell make prepare ``` @@ -93,6 +91,7 @@ go run ./example/standard/server/main.go ```go go run ./example/standard/client/main.go ``` + ```go 2022/08/21 23:31:59.391243 main.go:44: [Info] code=200,body={"ping":"pong2"} 2022/08/21 23:31:59.391493 main.go:44: [Info] code=200,body={"ping":"pong2"} From f604a4a0114c05db7153d903cb33ccadb0f3009f Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 11:01:18 +0800 Subject: [PATCH 19/25] fix: handle host :: case && optimize getInstances code --- zookeeper/registry.go | 4 ++-- zookeeper/reslover.go | 19 ++++--------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/zookeeper/registry.go b/zookeeper/registry.go index 3f378fc..6c24b0d 100644 --- a/zookeeper/registry.go +++ b/zookeeper/registry.go @@ -118,8 +118,8 @@ func buildPath(info *registry.Info) (string, error) { if port == "" { return "", fmt.Errorf("registry info addr missing port") } - if host == "" { - host = utils.LocalIP() // LocalIP example fe80::1 + if host == "" || host == "::" { + host = utils.LocalIP() path = path + Separator + "[" + host + "]" + ":" + port } else { path = path + Separator + host + ":" + port diff --git a/zookeeper/reslover.go b/zookeeper/reslover.go index 6432091..63fdfd1 100644 --- a/zookeeper/reslover.go +++ b/zookeeper/reslover.go @@ -18,7 +18,6 @@ import ( "context" "encoding/json" "fmt" - "net" "strings" "time" @@ -88,21 +87,11 @@ func (z *zookeeperResolver) getEndPoints(path string) ([]string, error) { func (z *zookeeperResolver) getInstances(eps []string, path string) ([]discovery.Instance, error) { instances := make([]discovery.Instance, 0, len(eps)) for _, ep := range eps { - if host, port, err := net.SplitHostPort(ep); err == nil { - if port == "" { - return []discovery.Instance{}, fmt.Errorf("missing port when parse node [%s]", ep) - } - if host == "" || host == "::" { - return []discovery.Instance{}, fmt.Errorf("missing host when parse node [%s]", ep) - } - ins, err := z.detailEndPoints(path, ep) - if err != nil { - return []discovery.Instance{}, fmt.Errorf("detail endpoint [%s] info error, cause %w", ep, err) - } - instances = append(instances, ins) - } else { - return []discovery.Instance{}, fmt.Errorf("parse node [%s] error, details info [%w]", ep, err) + ins, err := z.detailEndPoints(path, ep) + if err != nil { + return []discovery.Instance{}, fmt.Errorf("detail endpoint [%s] info error, cause %w", ep, err) } + instances = append(instances, ins) } return instances, nil } From c4afa3460d340748b5789cfa13217f1984352de9 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 14:07:45 +0800 Subject: [PATCH 20/25] fix: resolver & licences typo --- {linceses => licences}/LICENSE-gozookeeper | 0 {linceses => licences}/LICENSE-testify | 0 zookeeper/{reslover.go => resolver.go} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {linceses => licences}/LICENSE-gozookeeper (100%) rename {linceses => licences}/LICENSE-testify (100%) rename zookeeper/{reslover.go => resolver.go} (100%) diff --git a/linceses/LICENSE-gozookeeper b/licences/LICENSE-gozookeeper similarity index 100% rename from linceses/LICENSE-gozookeeper rename to licences/LICENSE-gozookeeper diff --git a/linceses/LICENSE-testify b/licences/LICENSE-testify similarity index 100% rename from linceses/LICENSE-testify rename to licences/LICENSE-testify diff --git a/zookeeper/reslover.go b/zookeeper/resolver.go similarity index 100% rename from zookeeper/reslover.go rename to zookeeper/resolver.go From 92ef25ec1d21ac7d976605c3f3633d8b704ca68e Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 15:03:47 +0800 Subject: [PATCH 21/25] test: merge test file && remove judge len(ep) --- zookeeper/discovery_test.go | 131 ------------------------------------ zookeeper/resolver.go | 4 +- zookeeper/zookeeper_test.go | 112 ++++++++++++++++++++++++++++-- 3 files changed, 108 insertions(+), 139 deletions(-) delete mode 100644 zookeeper/discovery_test.go diff --git a/zookeeper/discovery_test.go b/zookeeper/discovery_test.go deleted file mode 100644 index dc17f95..0000000 --- a/zookeeper/discovery_test.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2021 CloudWeGo Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// 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 zookeeper - -import ( - "context" - "net" - "testing" - "time" - - "github.com/cloudwego/hertz/pkg/app/client/discovery" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/stretchr/testify/assert" -) - -func TestZookeeperDiscovery(t *testing.T) { - // register - r, err := NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) - assert.Nil(t, err) - tags := map[string]string{"group": "blue", "idc": "hd1"} - addr, _ := net.ResolveTCPAddr("tcp", ":9999") - info := ®istry.Info{ServiceName: "product", Weight: 100, Tags: tags, Addr: addr} - err = r.Register(info) - assert.Nil(t, err) - - // resolve - res, err := NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) - assert.Nil(t, err) - target := res.Target(context.Background(), &discovery.TargetInfo{Host: "product", Tags: nil}) - result, err := res.Resolve(context.Background(), target) - assert.Nil(t, err) - - // compare data - if len(result.Instances) == 0 { - t.Errorf("instance num mismatch, expect: %d, in fact: %d", 1, 0) - } else if len(result.Instances) == 1 { - instance := result.Instances[0] - host, port, err := net.SplitHostPort(instance.Address().String()) - assert.Nil(t, err) - local := utils.LocalIP() - if host != local { - t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) - } - if port != "9999" { - t.Errorf("instance port is mismatch, expect: %s, in fact: %s", "9999", port) - } - if info.Weight != instance.Weight() { - t.Errorf("instance weight is mismatch, expect: %d, in fact: %d", info.Weight, instance.Weight()) - } - for k, v := range info.Tags { - if v1, exist := instance.Tag(k); !exist || v != v1 { - t.Errorf("instance tags is mismatch, expect k:v %s:%s, in fact k:v %s:%s", k, v, k, v1) - } - } - } - - // deregister - err = r.Deregister(info) - assert.Nil(t, err) - - // resolve again - result, err = res.Resolve(context.Background(), target) - assert.Nil(t, err) - assert.Empty(t, result.Instances) - assert.Equal(t, "product", result.CacheKey) -} - -func TestZookeeperResolverWithAuth(t *testing.T) { - // register - r, err := NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "horizon", "horizon") - assert.Nil(t, err) - tags := map[string]string{"group": "blue", "idc": "hd1"} - addr, _ := net.ResolveTCPAddr("tcp", ":9999") - info := ®istry.Info{ServiceName: "product", Weight: 100, Tags: tags, Addr: addr} - err = r.Register(info) - assert.Nil(t, err) - - // resolve - res, err := NewZookeeperResolverWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "horizon", "horizon") - assert.Nil(t, err) - target := res.Target(context.Background(), &discovery.TargetInfo{Host: "product", Tags: nil}) - result, err := res.Resolve(context.Background(), target) - assert.Nil(t, err) - - // compare data - if len(result.Instances) == 0 { - t.Errorf("instance num mismatch, expect: %d, in fact: %d", 1, 0) - } else if len(result.Instances) == 1 { - instance := result.Instances[0] - host, port, err := net.SplitHostPort(instance.Address().String()) - assert.Nil(t, err) - local := utils.LocalIP() - if host != local { - t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) - } - if port != "9999" { - t.Errorf("instance port is mismatch, expect: %s, in fact: %s", "9999", port) - } - if info.Weight != instance.Weight() { - t.Errorf("instance weight is mismatch, expect: %d, in fact: %d", info.Weight, instance.Weight()) - } - for k, v := range info.Tags { - if v1, exist := instance.Tag(k); !exist || v != v1 { - t.Errorf("instance tags is mismatch, expect k:v %s:%s, in fact k:v %s:%s", k, v, k, v1) - } - } - } - - // deregister - err = r.Deregister(info) - assert.Nil(t, err) - - // resolve again - result, err = res.Resolve(context.Background(), target) - assert.Nil(t, err) - assert.Empty(t, result.Instances) - assert.Equal(t, "product", result.CacheKey) -} diff --git a/zookeeper/resolver.go b/zookeeper/resolver.go index 63fdfd1..3404915 100644 --- a/zookeeper/resolver.go +++ b/zookeeper/resolver.go @@ -65,9 +65,7 @@ func (z *zookeeperResolver) Resolve(ctx context.Context, desc string) (discovery if err != nil { return discovery.Result{}, err } - if len(eps) == 0 { - return discovery.Result{CacheKey: desc}, nil - } + instances, err := z.getInstances(eps, path) if err != nil { return discovery.Result{}, err diff --git a/zookeeper/zookeeper_test.go b/zookeeper/zookeeper_test.go index 14c3034..dbbbb62 100644 --- a/zookeeper/zookeeper_test.go +++ b/zookeeper/zookeeper_test.go @@ -17,11 +17,13 @@ package zookeeper import ( "context" "fmt" + "net" "testing" "time" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/client/discovery" "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/app/server/registry" @@ -68,11 +70,7 @@ func TestZookeeperRegistryAndDeregister(t *testing.T) { assert.Equal(t, opt.RegistryInfo.ServiceName, "hertz.test.demo") assert.Nil(t, opt.RegistryInfo.Tags) - // deregister - if err := opt.Registry.Deregister(opt.RegistryInfo); err != nil { - t.Errorf("HERTZ: Deregister error=%v", err) - } - + h.Shutdown(context.Background()) time.Sleep(5 * time.Second) status1, body1, err1 := newClient.Get(context.Background(), nil, addr, config.WithSD(true)) @@ -80,3 +78,107 @@ func TestZookeeperRegistryAndDeregister(t *testing.T) { assert.Equal(t, 0, status1) assert.Equal(t, "", string(body1)) } + +func TestZookeeperDiscovery(t *testing.T) { + // register + r, err := NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + assert.Nil(t, err) + tags := map[string]string{"group": "blue", "idc": "hd1"} + addr, _ := net.ResolveTCPAddr("tcp", ":9999") + info := ®istry.Info{ServiceName: "product", Weight: 100, Tags: tags, Addr: addr} + err = r.Register(info) + assert.Nil(t, err) + + // resolve + res, err := NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + assert.Nil(t, err) + target := res.Target(context.Background(), &discovery.TargetInfo{Host: "product", Tags: nil}) + result, err := res.Resolve(context.Background(), target) + assert.Nil(t, err) + + // compare data + if len(result.Instances) == 0 { + t.Errorf("instance num mismatch, expect: %d, in fact: %d", 1, 0) + } else if len(result.Instances) == 1 { + instance := result.Instances[0] + host, port, err := net.SplitHostPort(instance.Address().String()) + assert.Nil(t, err) + local := utils.LocalIP() + if host != local { + t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) + } + if port != "9999" { + t.Errorf("instance port is mismatch, expect: %s, in fact: %s", "9999", port) + } + if info.Weight != instance.Weight() { + t.Errorf("instance weight is mismatch, expect: %d, in fact: %d", info.Weight, instance.Weight()) + } + for k, v := range info.Tags { + if v1, exist := instance.Tag(k); !exist || v != v1 { + t.Errorf("instance tags is mismatch, expect k:v %s:%s, in fact k:v %s:%s", k, v, k, v1) + } + } + } + + // deregister + err = r.Deregister(info) + assert.Nil(t, err) + + // resolve again + result, err = res.Resolve(context.Background(), target) + assert.Nil(t, err) + assert.Empty(t, result.Instances) + assert.Equal(t, "product", result.CacheKey) +} + +func TestZookeeperResolverWithAuth(t *testing.T) { + // register + r, err := NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "horizon", "horizon") + assert.Nil(t, err) + tags := map[string]string{"group": "blue", "idc": "hd1"} + addr, _ := net.ResolveTCPAddr("tcp", ":9999") + info := ®istry.Info{ServiceName: "product", Weight: 100, Tags: tags, Addr: addr} + err = r.Register(info) + assert.Nil(t, err) + + // resolve + res, err := NewZookeeperResolverWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "horizon", "horizon") + assert.Nil(t, err) + target := res.Target(context.Background(), &discovery.TargetInfo{Host: "product", Tags: nil}) + result, err := res.Resolve(context.Background(), target) + assert.Nil(t, err) + + // compare data + if len(result.Instances) == 0 { + t.Errorf("instance num mismatch, expect: %d, in fact: %d", 1, 0) + } else if len(result.Instances) == 1 { + instance := result.Instances[0] + host, port, err := net.SplitHostPort(instance.Address().String()) + assert.Nil(t, err) + local := utils.LocalIP() + if host != local { + t.Errorf("instance host is mismatch, expect: %s, in fact: %s", local, host) + } + if port != "9999" { + t.Errorf("instance port is mismatch, expect: %s, in fact: %s", "9999", port) + } + if info.Weight != instance.Weight() { + t.Errorf("instance weight is mismatch, expect: %d, in fact: %d", info.Weight, instance.Weight()) + } + for k, v := range info.Tags { + if v1, exist := instance.Tag(k); !exist || v != v1 { + t.Errorf("instance tags is mismatch, expect k:v %s:%s, in fact k:v %s:%s", k, v, k, v1) + } + } + } + + // deregister + err = r.Deregister(info) + assert.Nil(t, err) + + // resolve again + result, err = res.Resolve(context.Background(), target) + assert.Nil(t, err) + assert.Empty(t, result.Instances) + assert.Equal(t, "product", result.CacheKey) +} From eaa0b1f3e930616beea02a95086928424c12f533 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 15:07:29 +0800 Subject: [PATCH 22/25] doc: first letter upper --- zookeeper/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/zookeeper/README.md b/zookeeper/README.md index 043bd9e..43a41b6 100644 --- a/zookeeper/README.md +++ b/zookeeper/README.md @@ -2,9 +2,9 @@ Zookeeper as service discovery for Hertz. -## how to use? +## How to use? -### server +### Server **[example/standard/server/main.go](example/standard/server/main.go)** @@ -74,19 +74,19 @@ func main() { ``` ## How to run example? -### run docker +### Run docker ```shell make prepare ``` -### run server +### Run server ```go go run ./example/standard/server/main.go ``` -### run client +### Run client ```go go run ./example/standard/client/main.go From f2c69750c0a66398ba8c4e315147d752aee2756b Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 15:10:21 +0800 Subject: [PATCH 23/25] fix: lint error --- zookeeper/zookeeper_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zookeeper/zookeeper_test.go b/zookeeper/zookeeper_test.go index dbbbb62..4f1ac08 100644 --- a/zookeeper/zookeeper_test.go +++ b/zookeeper/zookeeper_test.go @@ -70,7 +70,7 @@ func TestZookeeperRegistryAndDeregister(t *testing.T) { assert.Equal(t, opt.RegistryInfo.ServiceName, "hertz.test.demo") assert.Nil(t, opt.RegistryInfo.Tags) - h.Shutdown(context.Background()) + _ = h.Shutdown(context.Background()) time.Sleep(5 * time.Second) status1, body1, err1 := newClient.Get(context.Background(), nil, addr, config.WithSD(true)) From fe37dac297626a592181c2ec1b0713fa31f97dce Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 15:21:11 +0800 Subject: [PATCH 24/25] feat: optimize buildPath code --- zookeeper/registry.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/zookeeper/registry.go b/zookeeper/registry.go index 6c24b0d..1336131 100644 --- a/zookeeper/registry.go +++ b/zookeeper/registry.go @@ -113,20 +113,18 @@ func buildPath(info *registry.Info) (string, error) { if !strings.HasPrefix(info.ServiceName, Separator) { path = Separator + info.ServiceName } - - if host, port, err := net.SplitHostPort(info.Addr.String()); err == nil { - if port == "" { - return "", fmt.Errorf("registry info addr missing port") - } - if host == "" || host == "::" { - host = utils.LocalIP() - path = path + Separator + "[" + host + "]" + ":" + port - } else { - path = path + Separator + host + ":" + port - } - } else { + host, port, err := net.SplitHostPort(info.Addr.String()) + if err != nil { return "", fmt.Errorf("parse registry info addr error") } + if port == "" { + return "", fmt.Errorf("registry info addr missing port") + } + if host == "" || host == "::" { + host = utils.LocalIP() + } + path = path + Separator + net.JoinHostPort(host, port) + return path, nil } From 4846338d6c90544bf20924e011189d1e673c8695 Mon Sep 17 00:00:00 2001 From: zstone12 <522089185@qq.com> Date: Wed, 24 Aug 2022 15:45:36 +0800 Subject: [PATCH 25/25] style: add comment for test func --- zookeeper/zookeeper_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/zookeeper/zookeeper_test.go b/zookeeper/zookeeper_test.go index 4f1ac08..11012c9 100644 --- a/zookeeper/zookeeper_test.go +++ b/zookeeper/zookeeper_test.go @@ -33,7 +33,8 @@ import ( "github.com/stretchr/testify/assert" ) -func TestZookeeperRegistryAndDeregister(t *testing.T) { +// TestZookeeperRegistryWithHertz Test zookeeper registry complete workflow(service registry|service de-registry|service resolver)with hertz. +func TestZookeeperRegistryWithHertz(t *testing.T) { address := "127.0.0.1:8888" r, _ := NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) srvName := "hertz.test.demo" @@ -74,11 +75,12 @@ func TestZookeeperRegistryAndDeregister(t *testing.T) { time.Sleep(5 * time.Second) status1, body1, err1 := newClient.Get(context.Background(), nil, addr, config.WithSD(true)) - assert.NotNil(t, err1) + assert.EqualError(t, err1, "instance not found") assert.Equal(t, 0, status1) assert.Equal(t, "", string(body1)) } +// TestZookeeperDiscovery Test zookeeper registry complete workflow(service registry|service de-registry|service resolver). func TestZookeeperDiscovery(t *testing.T) { // register r, err := NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) @@ -131,7 +133,8 @@ func TestZookeeperDiscovery(t *testing.T) { assert.Equal(t, "product", result.CacheKey) } -func TestZookeeperResolverWithAuth(t *testing.T) { +// TestZookeeperDiscoveryWithAuth Test zookeeper registry with auth complete workflow(service registry|service de-registry|service resolver). +func TestZookeeperDiscoveryWithAuth(t *testing.T) { // register r, err := NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "horizon", "horizon") assert.Nil(t, err)