Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add zookeeper register #6

Merged
merged 25 commits into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c66a80c
feat: zookeeper init code
zstone12 Aug 23, 2022
1239e97
chore: simplify dupliate code && no eps return nil
zstone12 Aug 23, 2022
ade98b5
style: import style
zstone12 Aug 23, 2022
b603b82
chore: remove utils/entity folder && use Localp
zstone12 Aug 23, 2022
6bb181e
fix: typo
zstone12 Aug 23, 2022
9419e39
chore: change basic -> standard
zstone12 Aug 23, 2022
c077fe4
refactor: use local utils to get ipv4Address
zstone12 Aug 23, 2022
a72bb8a
fix: add cacheKey
zstone12 Aug 23, 2022
0dd2e6a
test: unit test assert nil
zstone12 Aug 23, 2022
c13e3fa
style: add license header
zstone12 Aug 23, 2022
9c78dcf
fix: handle host :: case
zstone12 Aug 23, 2022
bf4faa4
doc: add compatibility part
zstone12 Aug 23, 2022
d5d3596
refactor: use Localp instead of local utils
zstone12 Aug 23, 2022
6b6fa91
test: add assert for reslove
zstone12 Aug 23, 2022
d7d9b5a
test: add test with hertz
zstone12 Aug 23, 2022
446af24
style: add license header && gofumpt
zstone12 Aug 23, 2022
7c154de
style: add newline to end of file
zstone12 Aug 23, 2022
0b1fe39
doc: optimize README.md format
zstone12 Aug 23, 2022
f604a4a
fix: handle host :: case && optimize getInstances code
zstone12 Aug 24, 2022
c4afa34
fix: resolver & licences typo
zstone12 Aug 24, 2022
92ef25e
test: merge test file && remove judge len(ep)
zstone12 Aug 24, 2022
eaa0b1f
doc: first letter upper
zstone12 Aug 24, 2022
f2c6975
fix: lint error
zstone12 Aug 24, 2022
fe37dac
feat: optimize buildPath code
zstone12 Aug 24, 2022
4846338
style: add comment for test func
zstone12 Aug 24, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
25 changes: 25 additions & 0 deletions linceses/LICENSE-gozookeeper
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Copyright (c) 2013, Samuel Stauffer <samuel@descolada.com>
All rights reserved.

li-jin-gou marked this conversation as resolved.
Show resolved Hide resolved
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 <COPYRIGHT HOLDER> 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.
21 changes: 21 additions & 0 deletions linceses/LICENSE-testify
Original file line number Diff line number Diff line change
@@ -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.
5 changes: 5 additions & 0 deletions zookeeper/Makefile
Original file line number Diff line number Diff line change
@@ -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)
111 changes: 111 additions & 0 deletions zookeeper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# zookeeper (*This is a community driven project*)
zstone12 marked this conversation as resolved.
Show resolved Hide resolved

Zookeeper as service discovery for Hertz.

## how to use?

### server
li-jin-gou marked this conversation as resolved.
Show resolved Hide resolved

**[example/standard/server/main.go](example/standard/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, &registry.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/standard/client/main.go](example/standard/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

```shell
make prepare
```

### run server

```go
go run ./example/standard/server/main.go
```

### run client

```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"}
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"}
```

## 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)
131 changes: 131 additions & 0 deletions zookeeper/discovery_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// 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) {
li-jin-gou marked this conversation as resolved.
Show resolved Hide resolved
// 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 := &registry.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 := &registry.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)
}
45 changes: 45 additions & 0 deletions zookeeper/example/auth/client/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// 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))
}
}
Loading