Compare commits

...

105 Commits

Author SHA1 Message Date
Dominic Wong
94bd1025a6 push tags to docker hub (#1766) 2020-07-03 11:30:59 +01:00
Dominic Wong
7be4a67673 MDNS registry fix for users on VPNs (#1759)
* filter out unsolicited responses
* send to local ip in case
* allow ip func to be passed in. add option for sending to 0.0.0.0
2020-07-03 11:30:59 +01:00
Di Wu
3e6ac73cfe Fix invalid usage for sync.WaitGroup (#1752)
* Custom private blocks

* Fix invalid usage for sync.WaitGroup

Co-authored-by: Asim Aslam <asim@aslam.me>
2020-07-03 11:30:59 +01:00
Colin Hoglund
aef6878ee0 config: use configured reader by default (#1717) 2020-07-03 11:30:59 +01:00
sunfuze
81aa8e0231 Fix config watch (#1670)
* add dirty overrite test case

* need version to figure out if config need update or not

* using nanosecond as version for two goroutine can run in same second

* config should check snapshot version when update

* set checksum of ChangeSet

Co-authored-by: Asim Aslam <asim@aslam.me>
2020-07-03 11:30:59 +01:00
Di Wu
c28f625cd4 Custom private blocks (#1705)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-07-03 11:30:59 +01:00
Dmitry Kozlov
5b161b88f7 Split long discord output message into the chunks by 2000 characters (#1704)
Signed-off-by: Dmitry Kozlov <dmitry.f.kozlov@gmail.com>
2020-07-03 11:30:59 +01:00
ben-toogood
cca8826a1f registry/mdns: fix nil host bug (#1703) 2020-07-03 11:30:59 +01:00
Dominic Wong
0327f30e3c Fix regex detection. Fixes #1663 (#1696) 2020-06-12 10:42:52 +01:00
Dominic Wong
0ce132eb8f Fix race condition when updating process being waited on (#1694) 2020-06-12 10:42:52 +01:00
Janos Dobronszki
00b76e0a64 Initialize selector before we make an auth.Generate call (#1693) 2020-06-12 10:42:52 +01:00
Dominic Wong
aec27be9b4 Fix race when opening DB for first time (#1691) 2020-06-12 10:42:52 +01:00
Dominic Wong
86dfcb819b Ignore "no such process" error (#1686)
* Cleanup how status is updated for service. Ignore "no such process" error as it could be that the pid died

* add nice error log to record process error exit
2020-06-12 10:42:52 +01:00
Janos Dobronszki
d613804b0a Sigterm instead of Sigkill (#1687)
Co-authored-by: Dominic Wong <domwongemail@googlemail.com>
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-06-12 10:42:52 +01:00
92e9d05432 api/handler/rpc: dont log error on normal websocket error code (#1688)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-06-12 10:42:52 +01:00
ben-toogood
8dfd93e915 util/wrapper: Add Static Client wrapper (#1685)
* util/wrapper: Add Static Client wrapper

* util/wrapper/static: pass address to stream too

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* add static client wrapper tests

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* server: fix error message spaces between words

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* server/{rpc,grpc}: replace log.Error with log.Errorf

* server/grpc: fix log typo

* server/rpc: fix log typo

Co-authored-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-06-12 10:42:52 +01:00
Dominic Wong
e5136332e3 Add build and test of micro to pre-release testing (#1684)
* fix up example test build

* build and test micro when cutting a new release
2020-06-12 10:42:52 +01:00
Dominic Wong
f10fd4b479 Build all micro/examples for release-X.X.X branches (#1683)
* Build all the examples on push to any release branch
2020-06-12 10:42:52 +01:00
ben-toogood
74368026a5 Fix incorrect namespace variable name (merge conflict) (#1677) 2020-06-12 10:42:52 +01:00
ben-toogood
fde1aa9d6a Move auth account creation to config/cmd (#1676) 2020-06-12 10:42:52 +01:00
ben-toogood
f45cdba9ba Apply wrappers to gRPC streams (#1675)
* Add wrappers to grpc streams

* Fix typo
2020-06-12 10:42:52 +01:00
Asim Aslam
b270860b79 Update README.md (#1695) 2020-06-10 10:22:53 +01:00
Asim Aslam
e7ba930236 Update FUNDING.yml (#1692) 2020-06-08 18:12:19 +01:00
Dominic Wong
aa679f7a73 Create PULL_REQUEST_TEMPLATE.md 2020-06-03 10:32:28 +01:00
Asim Aslam
7b379bf1f1 WIP: Add metadata to store record (#1604)
* Add metadata to store record

* Add metadata to cockroach store

* add metadata to store service implementation

* fix breaking cache test

* Test/fix cockroach metadata usage

* fix store memory metadata bug
2020-06-03 09:45:08 +01:00
Dominic Wong
e4e56b0f3f Merge pull request #1671 from sadwxqezc/fix-jwt
Fix jwt revoke
2020-06-02 09:27:14 +01:00
huanghuan.27@bytedance.com
219d29f664 fix jwt revoke 2020-06-02 10:26:33 +08:00
Asim Aslam
8fb138af06 Update README.md 2020-05-31 11:56:55 +01:00
Asim Aslam
a39e6515da Update README.md 2020-05-31 11:35:09 +01:00
Asim Aslam
2c7fd286de Update README.md 2020-05-31 11:34:49 +01:00
Asim Aslam
8aa2712b4d Delete README.zh-cn.md 2020-05-31 11:33:31 +01:00
Asim Aslam
b5c2121cef Update README.md 2020-05-31 11:31:41 +01:00
Asim Aslam
ca9b877646 Update README.md 2020-05-31 11:28:32 +01:00
Asim Aslam
ff49b4fc71 Update README.md 2020-05-31 11:27:54 +01:00
Asim Aslam
222431b57a Update README.md 2020-05-31 11:26:46 +01:00
Asim Aslam
ddb51529a7 Update README.md 2020-05-31 11:26:18 +01:00
Asim Aslam
7c048f331a Update README.md 2020-05-31 11:21:55 +01:00
Asim Aslam
8475183bbb Update README.md 2020-05-31 11:19:26 +01:00
Asim Aslam
10f35db3ed Update README.md 2020-05-31 11:16:20 +01:00
Asim Aslam
b68af8ab63 run go fmt 2020-05-30 11:00:43 +01:00
Asim Aslam
266602a3d6 Update README.md 2020-05-30 10:59:59 +01:00
mlboy
15d5142d9b fix: misspell (#1667) 2020-05-29 17:49:22 +01:00
Máximo Cuadros
0d88650511 go modules cleanup and remove wrong self import to v1 (#1658)
* Runtime local git, simply go-git code
* go modules cleanup and remove wrong self import to v1
* pin mergo v0.3.8 to avoid panics

Signed-off-by: Máximo Cuadros <mcuadros@gmail.com>
Co-authored-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-05-29 14:32:11 +03:00
Dominic Wong
8660370dc9 Merge pull request #1657 from xpunch/master
logger caller not trim in windows
2020-05-29 10:35:03 +01:00
Dominic Wong
73339dde85 Merge branch 'master' into master 2020-05-29 10:27:20 +01:00
Dominic Wong
3f354f3c30 Merge pull request #1661 from micro/bugfix/sock_pool_threads
fix locking of socket pool
2020-05-28 08:31:47 +01:00
potato
c08eb5f892 Merge branch 'master' into master 2020-05-28 10:19:53 +08:00
Dominic Wong
27e41c4ad5 fix locking of socket pool 2020-05-27 20:18:26 +01:00
Dominic Wong
1da8a640da Merge pull request #1660 from micro/bugfix/mdns_nil_host
Check ipv4 or ipv6 address is valid before assigning
2020-05-27 15:53:27 +01:00
Dominic Wong
e7ad031eb8 Check ipv4 or ipv6 address is valid before assigning 2020-05-27 15:47:12 +01:00
ben-toogood
192f548c83 Merge pull request #1659 from micro/config-srv-not-found
Handle config service not found errors
2020-05-27 12:24:33 +01:00
Ben Toogood
d85b4197b4 Return nil changeset and not blank 2020-05-27 12:20:31 +01:00
Ben Toogood
bb5f2e5525 Handle config service not found errors 2020-05-27 12:12:34 +01:00
ben-toogood
f00b696282 Merge pull request #1654 from micro/auth-scopes
Auth Improvements
2020-05-27 10:52:07 +01:00
Ben Toogood
e2d662608c Fix tests 2020-05-27 09:14:16 +01:00
Ben Toogood
9e9773c9c7 Only use namespace for cache key 2020-05-27 09:07:59 +01:00
potato
2f8e2487f7 Merge branch 'master' into master 2020-05-27 09:32:27 +08:00
Ben Toogood
d6c1fbf841 Fix web service auth name 2020-05-26 17:43:45 +01:00
Ben Toogood
c3b404bab0 Fix server calling across namespace 2020-05-26 17:35:06 +01:00
Ben Toogood
cd283654eb Cache Rules 2020-05-26 15:53:28 +01:00
Ben Toogood
5712cc9c62 Merge master 2020-05-26 15:52:21 +01:00
ben-toogood
be5a10a4d4 Merge pull request #1656 from micro/client-cache
Client Cache
2020-05-26 15:38:30 +01:00
Ben Toogood
b53a2c67f1 Merge branch 'master' of https://github.com/micro/go-micro into auth-scopes 2020-05-26 15:37:31 +01:00
johnson
cc79692d68 make caller filepath package/file style
this code is from zap
9a9fa7d4b5/zapcore/entry.go (L101)
2020-05-26 14:33:56 +08:00
potato
796a598b37 Merge pull request #7 from micro/master
go micro v2
2020-05-26 14:18:25 +08:00
Ben Toogood
73b4423682 Merge branch 'master' of https://github.com/micro/go-micro into client-cache 2020-05-24 20:36:22 +01:00
Ben Toogood
198e942889 Remove redundant test 2020-05-24 20:32:22 +01:00
Ben Toogood
95703e4565 Fixes and improved test coverage 2020-05-24 20:26:37 +01:00
Ben Toogood
2729569f66 Add Debug.Cache method 2020-05-24 18:45:57 +01:00
Ben Toogood
67146ecdc2 Client Cache tests 2020-05-24 18:05:23 +01:00
Asim Aslam
bd049a51e6 Update README.md 2020-05-23 16:47:23 +01:00
Asim Aslam
ffd89599a0 Update README.md 2020-05-23 16:46:50 +01:00
Ben Toogood
496293afa1 Use hash/fnv, add tests, fix request bug 2020-05-23 11:34:44 +01:00
Ben Toogood
7d7f4046e8 Client Cache 2020-05-22 16:52:24 +01:00
Ben Toogood
c800070477 Check for error before loading rules 2020-05-22 14:03:12 +01:00
Ben Toogood
877fe5fb0a Update web wildcard to enable /foo/bar/baz/* to verify /foo/bar/baz 2020-05-22 14:02:02 +01:00
Ben Toogood
dad011cab4 Fix noop issuer bug 2020-05-22 12:40:34 +01:00
Ben Toogood
f939200b34 Improve service auth log 2020-05-22 12:24:37 +01:00
Ben Toogood
9c072a372c Add auth scope constants 2020-05-22 11:37:12 +01:00
Ben Toogood
fbb91c6cb7 Auth wrapper tests 2020-05-22 10:44:18 +01:00
Ben Toogood
b2cf501952 Auth Rules tests & bug fixes 2020-05-22 09:31:15 +01:00
Ben Toogood
1fce0f02b6 Verify Namespace 2020-05-21 18:11:35 +01:00
Ben Toogood
12061bd006 Add account issuers 2020-05-21 16:41:55 +01:00
Ben Toogood
856c73b341 Remove roles (replaced with scope) 2020-05-21 14:56:17 +01:00
Ben Toogood
4de19805ba Remove redundant test 2020-05-21 12:33:58 +01:00
Ben Toogood
c09b871a6b Merge branch 'master' of https://github.com/micro/go-micro into auth-scopes 2020-05-21 12:32:52 +01:00
Ben Toogood
e876cb917d auth/service support for micro clients (rules from mutltiple namespaces 2020-05-21 12:25:47 +01:00
Ben Toogood
8f5ef012ff Update Rules.Delete proto 2020-05-21 12:07:22 +01:00
Ben Toogood
287992cef3 Fix service => service namespace bug 2020-05-21 11:35:07 +01:00
Ben Toogood
344ce061ce Verify Options 2020-05-20 16:49:52 +01:00
Ben Toogood
5d14970a55 Fix nil account bug 2020-05-20 16:11:34 +01:00
Janos Dobronszki
0615fe825f Auth invalid token fix (#1650) 2020-05-20 16:18:05 +02:00
Asim Aslam
6a661fd08c check if the db conn is nil before doing anything (#1652) 2020-05-20 14:03:38 +01:00
Ben Toogood
f6d9416a9e Add Rule to Auth interface 2020-05-20 11:59:01 +01:00
Asim Aslam
a29676b86a Registration Retry / Interval (#1651)
* Change the default ttl to 90 seconds

* add retries to registration

* Add retry to web register
2020-05-20 11:49:09 +01:00
Ben Toogood
dc10f88c12 Replace auth account.Namespace with account.Scopes 2020-05-19 18:17:17 +01:00
ben-toogood
e61edf6280 Merge pull request #1645 from micro/runtime-multitenancy
Runtime multi-tenancy
2020-05-19 17:06:11 +01:00
ben-toogood
3410a0949b Merge branch 'master' into runtime-multitenancy 2020-05-19 17:00:51 +01:00
Jake Sanders
9216a47724 fix client race (#1647) 2020-05-19 14:44:46 +01:00
ben-toogood
cf37d64819 Merge branch 'master' into runtime-multitenancy 2020-05-19 13:24:35 +01:00
Patrik Lindahl
f0c0f3d4c4 Fixes for #1560 (#1644)
close #1560

This fixes one of the reported data races and also allows for
having a different name on the micro.Service and web.Service.
This makes it possible to discover the two service variants separately.

Co-authored-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-05-19 14:11:26 +03:00
Ben Toogood
c4e3f8c336 Merge branch 'master' of https://github.com/micro/go-micro into runtime-multitenancy 2020-05-19 11:02:40 +01:00
Ben Toogood
8875719619 Default Runtime multi-tenancy 2020-05-19 11:01:06 +01:00
Ben Toogood
c19b349e96 Update runtime.Event struct 2020-05-19 10:14:07 +01:00
Ben Toogood
14155c7e02 Add runtime ErrNotFound 2020-05-19 09:28:00 +01:00
94 changed files with 4971 additions and 3286 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,3 +1,3 @@
# These are supported funding model platforms
github: asim
github: micro

10
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,10 @@
## Pull Request template
Please, go through these steps before clicking submit on this PR.
1. Make sure this PR targets the `develop` branch. We follow the git-flow branching model.
2. Give a descriptive title to your PR.
3. Provide a description of your changes.
4. Make sure you have some relevant tests.
5. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if applicable).
**PLEASE REMOVE THIS TEMPLATE BEFORE SUBMITTING**

View File

@@ -19,3 +19,4 @@ jobs:
name: micro/go-micro
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
tag_names: true

34
.github/workflows/micro-examples.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Build all github.com/micro/examples
on:
push:
branches:
- 'release-**'
jobs:
build:
name: Build repos
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
id: go
- name: Check out this code
uses: actions/checkout@v2
with:
path: 'go-micro'
- name: Check out code examples
uses: actions/checkout@v2
with:
repository: 'micro/examples'
path: 'examples'
- name: Build all
run: $GITHUB_WORKSPACE/go-micro/.github/workflows/scripts/build-all-examples.sh $GITHUB_SHA
working-directory: examples

34
.github/workflows/micro-main.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Build and test micro
on:
push:
branches:
- 'release-**'
jobs:
build:
name: Build and test micro
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
id: go
- name: Check out this code
uses: actions/checkout@v2
with:
path: 'go-micro'
- name: Check out micro
uses: actions/checkout@v2
with:
repository: 'micro/micro'
path: 'micro'
- name: Build all
run: $GITHUB_WORKSPACE/go-micro/.github/workflows/scripts/build-micro.sh $GITHUB_SHA
working-directory: micro

View File

@@ -0,0 +1,41 @@
#!/bin/bash
# set -x
function build_binary {
echo building $1
pushd $1
go build -o _main
local ret=$?
if [ $ret -gt 0 ]; then
failed=1
failed_arr+=($1)
fi
popd
}
function is_main {
grep "package main" -l -dskip $1/*.go > /dev/null 2>&1
}
function check_dir {
is_main $1
local ret=$?
if [ $ret == 0 ]; then
build_binary $1 $2
fi
for filename in $1/*; do
if [ -d $filename ]; then
check_dir $filename $2
fi
done
}
failed_arr=()
failed=0
go mod edit -replace github.com/micro/go-micro/v2=github.com/micro/go-micro/v2@$1
check_dir . $1
if [ $failed -gt 0 ]; then
echo Some builds failed
printf '%s\n' "${failed_arr[@]}"
fi
exit $failed

14
.github/workflows/scripts/build-micro.sh vendored Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
# set -x
failed=0
go mod edit -replace github.com/micro/go-micro/v2=github.com/micro/go-micro/v2@$1
# basic test, build the binary
go build
failed=$?
if [ $failed -gt 0 ]; then
exit $failed
fi
# unit tests
IN_TRAVIS_CI=yes go test -v ./...
# TODO integration tests

View File

@@ -1,23 +1,27 @@
# Go Micro [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/micro/go-micro?tab=doc) [![Travis CI](https://api.travis-ci.org/micro/go-micro.svg?branch=master)](https://travis-ci.org/micro/go-micro) [![Go Report Card](https://goreportcard.com/badge/micro/go-micro)](https://goreportcard.com/report/github.com/micro/go-micro) <a href="https://slack.micro.mu"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen" alt="Slack Widget"></a>
# Go Micro [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/micro/go-micro?tab=doc) [![Travis CI](https://api.travis-ci.org/micro/go-micro.svg?branch=master)](https://travis-ci.org/micro/go-micro) [![Go Report Card](https://goreportcard.com/badge/micro/go-micro)](https://goreportcard.com/report/github.com/micro/go-micro)
Go Micro is a framework for distributed systems development.
## Overview
Go Micro provides the core requirements for distributed systems development including RPC and Event driven communication.
The **micro** philosophy is sane defaults with a pluggable architecture. We provide defaults to get you started quickly
The **Micro** philosophy is sane defaults with a pluggable architecture. We provide defaults to get you started quickly
but everything can be easily swapped out.
<img src="https://micro.mu/docs/images/go-micro.svg" />
Plugins are available at [github.com/micro/go-plugins](https://github.com/micro/go-plugins).
Follow us on [Twitter](https://twitter.com/microhq) or join the [Community](https://micro.mu/slack).
## Features
Go Micro abstracts away the details of distributed systems. Here are the main features.
- **Authentication** - Auth is built in as a first class citizen. Authentication and authorization enable secure
zero trust networking by providing every service an identity and certificates. This additionally includes rule
based access control.
- **Dynamic Config** - Load and hot reload dynamic config from anywhere. The config interface provides a way to load application
level config from any source such as env vars, file, etcd. You can merge the sources and even define fallbacks.
- **Data Storage** - A simple data store interface to read, write and delete records. It includes support for memory, file and
CockroachDB by default. State and persistence becomes a core requirement beyond prototyping and Micro looks to build that into the framework.
- **Service Discovery** - Automatic service registration and name resolution. Service discovery is at the core of micro service
development. When service A needs to speak to service B it needs the location of that service. The default discovery mechanism is
multicast DNS (mdns), a zeroconf system.
@@ -30,13 +34,14 @@ across the services and retry a different node if there's a problem.
to seamlessly encode and decode Go types for you. Any variety of messages could be encoded and sent from different clients. The client
and server handle this by default. This includes protobuf and json by default.
- **Request/Response** - RPC based request/response with support for bidirectional streaming. We provide an abstraction for synchronous
communication. A request made to a service will be automatically resolved, load balanced, dialled and streamed. The default
transport is [gRPC](https://grpc.io/).
- **gRPC Transport** - gRPC based request/response with support for bidirectional streaming. We provide an abstraction for synchronous communication. A request made to a service will be automatically resolved, load balanced, dialled and streamed.
- **Async Messaging** - PubSub is built in as a first class citizen for asynchronous communication and event driven architectures.
Event notifications are a core pattern in micro service development. The default messaging system is a HTTP event message broker.
- **Synchronization** - Distributed systems are often built in an eventually consistent manner. Support for distributed locking and
leadership are built in as a Sync interface. When using an eventually consistent database or scheduling use the Sync interface.
- **Pluggable Interfaces** - Go Micro makes use of Go interfaces for each distributed system abstraction. Because of this these interfaces
are pluggable and allows Go Micro to be runtime agnostic. You can plugin any underlying technology. Find plugins in
[github.com/micro/go-plugins](https://github.com/micro/go-plugins).
@@ -47,9 +52,20 @@ To make use of Go Micro
```golang
import "github.com/micro/go-micro/v2"
// create a new service
service := micro.NewService(
micro.Name("helloworld"),
)
// initialise flags
service.Init()
// start the service
service.Run()
```
See the [docs](https://micro.mu/docs/framework.html) for detailed information on the architecture, installation and use of go-micro.
See the [docs](https://dev.m3o.com) for detailed information on the architecture, installation and use of go-micro.
## License

View File

@@ -1,36 +0,0 @@
# Go Micro [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/micro/go-micro?tab=doc) [![Travis CI](https://api.travis-ci.org/micro/go-micro.svg?branch=master)](https://travis-ci.org/micro/go-micro) [![Go Report Card](https://goreportcard.com/badge/micro/go-micro)](https://goreportcard.com/report/github.com/micro/go-micro)
Go Micro是基于Golang的微服务开发框架。
## 概览
Go Micro提供分布式系统开发的核心库包含RPC与事件驱动的通信机制。
**micro**的设计哲学是可插拔的架构理念,她提供可快速构建系统的组件,并且可以根据自身的需求剥离默认实现并自行定制。
<img src="https://micro.mu/docs/images/go-micro.svg" />
所有插件可在仓库[github.com/micro/go-plugins](https://github.com/micro/go-plugins)中找到。
可以订阅我们的[Twitter](https://twitter.com/microhq)或者加入[Slack](http://slack.micro.mu/)论坛。
## 特性
Go Micro把分布式系统的各种细节抽象出来。下面是它的主要特性。
- **服务发现Service Discovery** - 自动服务注册与名称解析。服务发现是微服务开发中的核心。当服务A要与服务B协作时它得知道B在哪里。默认的服务发现系统是Consul而multicast DNS (mdns组播)机制作为本地解决方案或者零依赖的P2P网络中的SWIM协议gossip
- **负载均衡Load Balancing** - 在服务发现之上构建了负载均衡机制。当我们得到一个服务的任意多个的实例节点时,我们要一个机制去决定要路由到哪一个节点。我们使用随机处理过的哈希负载均衡机制来保证对服务请求颁发的均匀分布,并且在发生问题时进行重试。
- **消息编码Message Encoding** - 支持基于内容类型content-type动态编码消息。客户端和服务端会一起使用content-type的格式来对Go进行无缝编/解码。各种各样的消息被编码会发送到不同的客户端客户端服服务端默认会处理这些消息。content-type默认包含proto-rpc和json-rpc。
- **Request/Response** - RPC通信基于支持双向流的请求/响应方式我们提供有抽象的同步通信机制。请求发送到服务时会自动解析、负载均衡、拨号、转成字节流。默认的传输协议是http/1.1而tls下使用http2协议。
- **异步消息Async Messaging** - 发布订阅PubSub头等功能内置在异步通信与事件驱动架构中。事件通知在微服务开发中处于核心位置。默认的消息传送使用点到点http/1.1激活tls时则使用http2。
- **可插拔接口Pluggable Interfaces** - Go Micro为每个分布式系统抽象出接口。因此Go Micro的接口都是可插拔的允许其在运行时不可知的情况下仍可支持。所以只要实现接口可以在内部使用任何的技术。更多插件请参考[github.com/micro/go-plugins](https://github.com/micro/go-plugins)。
## 快速上手
更多关于架构、安装的资料可以查看[文档](https://micro.mu/docs/cn/)。

View File

@@ -70,12 +70,32 @@ func (dc *discordConn) Recv(event *input.Event) error {
}
}
func ChunkString(s string, chunkSize int) []string {
var chunks []string
runes := []rune(s)
if len(runes) == 0 {
return []string{s}
}
for i := 0; i < len(runes); i += chunkSize {
nn := i + chunkSize
if nn > len(runes) {
nn = len(runes)
}
chunks = append(chunks, string(runes[i:nn]))
}
return chunks
}
func (dc *discordConn) Send(e *input.Event) error {
fields := strings.Split(e.To, ":")
_, err := dc.master.session.ChannelMessageSend(fields[0], string(e.Data))
if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error("[bot][loop][send]", err)
for _, chunk := range ChunkString(string(e.Data), 2000) {
_, err := dc.master.session.ChannelMessageSend(fields[0], chunk)
if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error("[bot][loop][send]", err)
}
}
}
return nil

View File

@@ -185,7 +185,11 @@ func writeLoop(rw io.ReadWriter, stream client.Stream) {
if err != nil {
if wserr, ok := err.(wsutil.ClosedError); ok {
switch wserr.Code {
case ws.StatusGoingAway:
// this happens when user leave the page
return
case ws.StatusNormalClosure, ws.StatusNoStatusRcvd:
// this happens when user close ws connection, or we don't get any status
return
}
}

View File

@@ -2,8 +2,6 @@ package resolver
import (
"net/http"
"github.com/micro/go-micro/v2/auth"
)
// NewOptions returns new initialised options
@@ -14,7 +12,7 @@ func NewOptions(opts ...Option) Options {
}
if options.Namespace == nil {
options.Namespace = StaticNamespace(auth.DefaultNamespace)
options.Namespace = StaticNamespace("go.micro")
}
return options

View File

@@ -188,7 +188,7 @@ func (r *registryRouter) store(services []*registry.Service) {
for _, p := range ep.Endpoint.Path {
var pcreok bool
if p[0] == '^' && p[len(p)-1] != '$' {
if p[0] == '^' && p[len(p)-1] == '$' {
pcrereg, err := regexp.CompilePOSIX(p)
if err == nil {
cep.pcreregs = append(cep.pcreregs, pcrereg)

View File

@@ -0,0 +1,34 @@
package registry
import (
"testing"
"github.com/micro/go-micro/v2/registry"
"github.com/stretchr/testify/assert"
)
func TestStoreRegex(t *testing.T) {
router := newRouter()
router.store([]*registry.Service{
{
Name: "Foobar",
Version: "latest",
Endpoints: []*registry.Endpoint{
{
Name: "foo",
Metadata: map[string]string{
"endpoint": "FooEndpoint",
"description": "Some description",
"method": "POST",
"path": "^/foo/$",
"handler": "rpc",
},
},
},
Metadata: map[string]string{},
},
},
)
assert.Len(t, router.ceps["Foobar.foo"].pcreregs, 1)
}

View File

@@ -34,7 +34,7 @@ func (c *certmagicProvider) setup() {
// randomness so they don't collide
// RenewalWindowRatio [0.33 - 0.50)
rand.Seed(time.Now().UnixNano())
randomRatio := float64(rand.Intn(17) + 33) * 0.01
randomRatio := float64(rand.Intn(17)+33) * 0.01
certmagic.Default.RenewalWindowRatio = randomRatio
}

View File

@@ -7,20 +7,23 @@ import (
"time"
)
const (
// BearerScheme used for Authorization header
BearerScheme = "Bearer "
// ScopePublic is the scope applied to a rule to allow access to the public
ScopePublic = ""
// ScopeAccount is the scope applied to a rule to limit to users with any valid account
ScopeAccount = "*"
)
var (
// ErrNotFound is returned when a resouce cannot be found
ErrNotFound = errors.New("not found")
// ErrEncodingToken is returned when the service encounters an error during encoding
ErrEncodingToken = errors.New("error encoding the token")
// ErrInvalidToken is returned when the token provided is not valid
// ErrInvalidToken is when the token provided is not valid
ErrInvalidToken = errors.New("invalid token provided")
// ErrInvalidRole is returned when the role provided was invalid
ErrInvalidRole = errors.New("invalid role")
// ErrForbidden is returned when a user does not have the necessary roles to access a resource
// ErrForbidden is when a user does not have the necessary scope to access a resource
ErrForbidden = errors.New("resource forbidden")
)
// Auth providers authentication and authorization
// Auth provides authentication and authorization
type Auth interface {
// Init the auth
Init(opts ...Option)
@@ -28,65 +31,38 @@ type Auth interface {
Options() Options
// Generate a new account
Generate(id string, opts ...GenerateOption) (*Account, error)
// Grant access to a resource
Grant(role string, res *Resource) error
// Revoke access to a resource
Revoke(role string, res *Resource) error
// Verify an account has access to a resource
Verify(acc *Account, res *Resource) error
// Verify an account has access to a resource using the rules
Verify(acc *Account, res *Resource, opts ...VerifyOption) error
// Inspect a token
Inspect(token string) (*Account, error)
// Token generated using refresh token
// Token generated using refresh token or credentials
Token(opts ...TokenOption) (*Token, error)
// Grant access to a resource
Grant(rule *Rule) error
// Revoke access to a resource
Revoke(rule *Rule) error
// Rules returns all the rules used to verify requests
Rules(...RulesOption) ([]*Rule, error)
// String returns the name of the implementation
String() string
}
// Resource is an entity such as a user or
type Resource struct {
// Name of the resource
Name string `json:"name"`
// Type of resource, e.g.
Type string `json:"type"`
// Endpoint resource e.g NotesService.Create
Endpoint string `json:"endpoint"`
// Namespace the resource belongs to
Namespace string `json:"namespace"`
}
// Account provided by an auth provider
type Account struct {
// ID of the account e.g. email
ID string `json:"id"`
// Type of the account, e.g. service
Type string `json:"type"`
// Provider who issued the account
Provider string `json:"provider"`
// Roles associated with the Account
Roles []string `json:"roles"`
// Issuer of the account
Issuer string `json:"issuer"`
// Any other associated metadata
Metadata map[string]string `json:"metadata"`
// Namespace the account belongs to
Namespace string `json:"namespace"`
// Scopes the account has access to
Scopes []string `json:"scopes"`
// Secret for the account, e.g. the password
Secret string `json:"secret"`
}
// HasRole returns a boolean indicating if the account has the given role
func (a *Account) HasRole(role string) bool {
if a.Roles == nil {
return false
}
for _, r := range a.Roles {
if r == role {
return true
}
}
return false
}
// Token can be short or long lived
type Token struct {
// The token to be used for accessing resources
@@ -99,15 +75,47 @@ type Token struct {
Expiry time.Time `json:"expiry"`
}
// Expired returns a boolean indicating if the token needs to be refreshed
func (t *Token) Expired() bool {
return t.Expiry.Unix() < time.Now().Unix()
}
// Resource is an entity such as a user or
type Resource struct {
// Name of the resource, e.g. go.micro.service.notes
Name string `json:"name"`
// Type of resource, e.g. service
Type string `json:"type"`
// Endpoint resource e.g NotesService.Create
Endpoint string `json:"endpoint"`
}
// Access defines the type of access a rule grants
type Access int
const (
// DefaultNamespace used for auth
DefaultNamespace = "go.micro"
// TokenCookieName is the name of the cookie which stores the auth token
TokenCookieName = "micro-token"
// BearerScheme used for Authorization header
BearerScheme = "Bearer "
// AccessGranted to a resource
AccessGranted Access = iota
// AccessDenied to a resource
AccessDenied
)
// Rule is used to verify access to a resource
type Rule struct {
// ID of the rule, e.g. "public"
ID string
// Scope the rule requires, a blank scope indicates open to the public and * indicates the rule
// applies to any valid account
Scope string
// Resource the rule applies to
Resource *Resource
// Access determines if the rule grants or denies access to the resource
Access Access
// Priority the rule should take when verifying a request, the higher the value the sooner the
// rule will be applied
Priority int32
}
type accountKey struct{}
// AccountFromContext gets the account from the context, which

View File

@@ -1,17 +0,0 @@
package auth
import "testing"
func TestHasRole(t *testing.T) {
if new(Account).HasRole("foo") {
t.Errorf("Expected the blank account to not have a role")
}
acc := Account{Roles: []string{"foo"}}
if !acc.HasRole("foo") {
t.Errorf("Expected the account to have the foo role")
}
if acc.HasRole("bar") {
t.Errorf("Expected the account to not have the bar role")
}
}

View File

@@ -49,35 +49,37 @@ func (n *noop) Generate(id string, opts ...GenerateOption) (*Account, error) {
options := NewGenerateOptions(opts...)
return &Account{
ID: id,
Roles: options.Roles,
Secret: options.Secret,
Metadata: options.Metadata,
Namespace: DefaultNamespace,
ID: id,
Secret: options.Secret,
Metadata: options.Metadata,
Scopes: options.Scopes,
Issuer: n.Options().Namespace,
}, nil
}
// Grant access to a resource
func (n *noop) Grant(role string, res *Resource) error {
func (n *noop) Grant(rule *Rule) error {
return nil
}
// Revoke access to a resource
func (n *noop) Revoke(role string, res *Resource) error {
func (n *noop) Revoke(rule *Rule) error {
return nil
}
// Rules used to verify requests
func (n *noop) Rules(opts ...RulesOption) ([]*Rule, error) {
return []*Rule{}, nil
}
// Verify an account has access to a resource
func (n *noop) Verify(acc *Account, res *Resource) error {
func (n *noop) Verify(acc *Account, res *Resource, opts ...VerifyOption) error {
return nil
}
// Inspect a token
func (n *noop) Inspect(token string) (*Account, error) {
return &Account{
ID: uuid.New().String(),
Namespace: DefaultNamespace,
}, nil
return &Account{ID: uuid.New().String(), Issuer: n.Options().Namespace}, nil
}
// Token generation using an account id and secret

View File

@@ -5,6 +5,7 @@ import (
"time"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/auth/rules"
"github.com/micro/go-micro/v2/auth/token"
jwtToken "github.com/micro/go-micro/v2/auth/token/jwt"
)
@@ -16,15 +17,10 @@ func NewAuth(opts ...auth.Option) auth.Auth {
return j
}
type rule struct {
role string
resource *auth.Resource
}
type jwt struct {
options auth.Options
jwt token.Provider
rules []*rule
rules []*auth.Rule
sync.Mutex
}
@@ -41,10 +37,6 @@ func (j *jwt) Init(opts ...auth.Option) {
o(&j.options)
}
if len(j.options.Namespace) == 0 {
j.options.Namespace = auth.DefaultNamespace
}
j.jwt = jwtToken.NewTokenProvider(
token.WithPrivateKey(j.options.PrivateKey),
token.WithPublicKey(j.options.PublicKey),
@@ -60,12 +52,11 @@ func (j *jwt) Options() auth.Options {
func (j *jwt) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
options := auth.NewGenerateOptions(opts...)
account := &auth.Account{
ID: id,
Type: options.Type,
Roles: options.Roles,
Provider: options.Provider,
Metadata: options.Metadata,
Namespace: options.Namespace,
ID: id,
Type: options.Type,
Scopes: options.Scopes,
Metadata: options.Metadata,
Issuer: j.Options().Namespace,
}
// generate a JWT secret which can be provided to the Token() method
@@ -80,84 +71,44 @@ func (j *jwt) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e
return account, nil
}
func (j *jwt) Grant(role string, res *auth.Resource) error {
func (j *jwt) Grant(rule *auth.Rule) error {
j.Lock()
defer j.Unlock()
j.rules = append(j.rules, &rule{role, res})
j.rules = append(j.rules, rule)
return nil
}
func (j *jwt) Revoke(role string, res *auth.Resource) error {
func (j *jwt) Revoke(rule *auth.Rule) error {
j.Lock()
defer j.Unlock()
rules := make([]*rule, 0, len(j.rules))
var ruleFound bool
for _, r := range rules {
if r.role == role && r.resource == res {
ruleFound = true
} else {
rules := []*auth.Rule{}
for _, r := range j.rules {
if r.ID != rule.ID {
rules = append(rules, r)
}
}
if !ruleFound {
return auth.ErrNotFound
}
j.rules = rules
return nil
}
func (j *jwt) Verify(acc *auth.Account, res *auth.Resource) error {
func (j *jwt) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error {
j.Lock()
if len(res.Namespace) == 0 {
res.Namespace = j.options.Namespace
}
rules := j.rules
j.Unlock()
defer j.Unlock()
for _, rule := range rules {
// validate the rule applies to the requested resource
if rule.resource.Namespace != "*" && rule.resource.Namespace != res.Namespace {
continue
}
if rule.resource.Type != "*" && rule.resource.Type != res.Type {
continue
}
if rule.resource.Name != "*" && rule.resource.Name != res.Name {
continue
}
if rule.resource.Endpoint != "*" && rule.resource.Endpoint != res.Endpoint {
continue
}
// a blank role indicates anyone can access the resource, even without an account
if rule.role == "" {
return nil
}
// all furter checks require an account
if acc == nil {
continue
}
// this rule allows any account access, allow the request
if rule.role == "*" {
return nil
}
// if the account has the necessary role, allow the request
for _, r := range acc.Roles {
if r == rule.role {
return nil
}
}
var options auth.VerifyOptions
for _, o := range opts {
o(&options)
}
// no rules matched, forbid the request
return auth.ErrForbidden
return rules.Verify(j.rules, acc, res)
}
func (j *jwt) Rules(opts ...auth.RulesOption) ([]*auth.Rule, error) {
j.Lock()
defer j.Unlock()
return j.rules, nil
}
func (j *jwt) Inspect(token string) (*auth.Account, error) {

View File

@@ -1,6 +1,7 @@
package auth
import (
"context"
"time"
"github.com/micro/go-micro/v2/auth/provider"
@@ -13,9 +14,6 @@ func NewOptions(opts ...Option) Options {
for _, o := range opts {
o(&options)
}
if len(options.Namespace) == 0 {
options.Namespace = DefaultNamespace
}
if options.Client == nil {
options.Client = client.DefaultClient
}
@@ -124,10 +122,8 @@ func WithClient(c client.Client) Option {
type GenerateOptions struct {
// Metadata associated with the account
Metadata map[string]string
// Roles/scopes associated with the account
Roles []string
// Namespace the account belongs too
Namespace string
// Scopes the account has access too
Scopes []string
// Provider of the account, e.g. oauth
Provider string
// Type of the account, e.g. user
@@ -159,20 +155,6 @@ func WithMetadata(md map[string]string) GenerateOption {
}
}
// WithRoles for the generated account
func WithRoles(rs ...string) GenerateOption {
return func(o *GenerateOptions) {
o.Roles = rs
}
}
// WithNamespace for the generated account
func WithNamespace(n string) GenerateOption {
return func(o *GenerateOptions) {
o.Namespace = n
}
}
// WithProvider for the generated account
func WithProvider(p string) GenerateOption {
return func(o *GenerateOptions) {
@@ -180,6 +162,13 @@ func WithProvider(p string) GenerateOption {
}
}
// WithScopes for the generated account
func WithScopes(s ...string) GenerateOption {
return func(o *GenerateOptions) {
o.Scopes = s
}
}
// NewGenerateOptions from a slice of options
func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
var options GenerateOptions
@@ -236,3 +225,27 @@ func NewTokenOptions(opts ...TokenOption) TokenOptions {
return options
}
type VerifyOptions struct {
Context context.Context
}
type VerifyOption func(o *VerifyOptions)
func VerifyContext(ctx context.Context) VerifyOption {
return func(o *VerifyOptions) {
o.Context = ctx
}
}
type RulesOptions struct {
Context context.Context
}
type RulesOption func(o *RulesOptions)
func RulesContext(ctx context.Context) RulesOption {
return func(o *RulesOptions) {
o.Context = ctx
}
}

93
auth/rules/rules.go Normal file
View File

@@ -0,0 +1,93 @@
package rules
import (
"fmt"
"sort"
"strings"
"github.com/micro/go-micro/v2/auth"
)
// Verify an account has access to a resource using the rules provided. If the account does not have
// access an error will be returned. If there are no rules provided which match the resource, an error
// will be returned
func Verify(rules []*auth.Rule, acc *auth.Account, res *auth.Resource) error {
// the rule is only to be applied if the type matches the resource or is catch-all (*)
validTypes := []string{"*", res.Type}
// the rule is only to be applied if the name matches the resource or is catch-all (*)
validNames := []string{"*", res.Name}
// rules can have wildcard excludes on endpoints since this can also be a path for web services,
// e.g. /foo/* would include /foo/bar. We also want to check for wildcards and the exact endpoint
validEndpoints := []string{"*", res.Endpoint}
if comps := strings.Split(res.Endpoint, "/"); len(comps) > 1 {
for i := 1; i < len(comps)+1; i++ {
wildcard := fmt.Sprintf("%v/*", strings.Join(comps[0:i], "/"))
validEndpoints = append(validEndpoints, wildcard)
}
}
// filter the rules to the ones which match the criteria above
filteredRules := make([]*auth.Rule, 0)
for _, rule := range rules {
if !include(validTypes, rule.Resource.Type) {
continue
}
if !include(validNames, rule.Resource.Name) {
continue
}
if !include(validEndpoints, rule.Resource.Endpoint) {
continue
}
filteredRules = append(filteredRules, rule)
}
// sort the filtered rules by priority, highest to lowest
sort.SliceStable(filteredRules, func(i, j int) bool {
return filteredRules[i].Priority > filteredRules[j].Priority
})
// loop through the rules and check for a rule which applies to this account
for _, rule := range filteredRules {
// a blank scope indicates the rule applies to everyone, even nil accounts
if rule.Scope == auth.ScopePublic && rule.Access == auth.AccessDenied {
return auth.ErrForbidden
} else if rule.Scope == auth.ScopePublic && rule.Access == auth.AccessGranted {
return nil
}
// all further checks require an account
if acc == nil {
continue
}
// this rule applies to any account
if rule.Scope == auth.ScopeAccount && rule.Access == auth.AccessDenied {
return auth.ErrForbidden
} else if rule.Scope == auth.ScopeAccount && rule.Access == auth.AccessGranted {
return nil
}
// if the account has the necessary scope
if include(acc.Scopes, rule.Scope) && rule.Access == auth.AccessDenied {
return auth.ErrForbidden
} else if include(acc.Scopes, rule.Scope) && rule.Access == auth.AccessGranted {
return nil
}
}
// if no rules matched then return forbidden
return auth.ErrForbidden
}
// include is a helper function which checks to see if the slice contains the value. includes is
// not case sensitive.
func include(slice []string, val string) bool {
for _, s := range slice {
if strings.ToLower(s) == strings.ToLower(val) {
return true
}
}
return false
}

290
auth/rules/rules_test.go Normal file
View File

@@ -0,0 +1,290 @@
package rules
import (
"testing"
"github.com/micro/go-micro/v2/auth"
)
func TestVerify(t *testing.T) {
srvResource := &auth.Resource{
Type: "service",
Name: "go.micro.service.foo",
Endpoint: "Foo.Bar",
}
webResource := &auth.Resource{
Type: "service",
Name: "go.micro.web.foo",
Endpoint: "/foo/bar",
}
catchallResource := &auth.Resource{
Type: "*",
Name: "*",
Endpoint: "*",
}
tt := []struct {
Name string
Rules []*auth.Rule
Account *auth.Account
Resource *auth.Resource
Error error
}{
{
Name: "NoRules",
Rules: []*auth.Rule{},
Account: nil,
Resource: srvResource,
Error: auth.ErrForbidden,
},
{
Name: "CatchallPublicAccount",
Account: &auth.Account{},
Resource: srvResource,
Rules: []*auth.Rule{
&auth.Rule{
Scope: "",
Resource: catchallResource,
},
},
},
{
Name: "CatchallPublicNoAccount",
Resource: srvResource,
Rules: []*auth.Rule{
&auth.Rule{
Scope: "",
Resource: catchallResource,
},
},
},
{
Name: "CatchallPrivateAccount",
Account: &auth.Account{},
Resource: srvResource,
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: catchallResource,
},
},
},
{
Name: "CatchallPrivateNoAccount",
Resource: srvResource,
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: catchallResource,
},
},
Error: auth.ErrForbidden,
},
{
Name: "CatchallServiceRuleMatch",
Resource: srvResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: &auth.Resource{
Type: srvResource.Type,
Name: srvResource.Name,
Endpoint: "*",
},
},
},
},
{
Name: "CatchallServiceRuleNoMatch",
Resource: srvResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: &auth.Resource{
Type: srvResource.Type,
Name: "wrongname",
Endpoint: "*",
},
},
},
Error: auth.ErrForbidden,
},
{
Name: "ExactRuleValidScope",
Resource: srvResource,
Account: &auth.Account{
Scopes: []string{"neededscope"},
},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "neededscope",
Resource: srvResource,
},
},
},
{
Name: "ExactRuleInvalidScope",
Resource: srvResource,
Account: &auth.Account{
Scopes: []string{"neededscope"},
},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "invalidscope",
Resource: srvResource,
},
},
Error: auth.ErrForbidden,
},
{
Name: "CatchallDenyWithAccount",
Resource: srvResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: catchallResource,
Access: auth.AccessDenied,
},
},
Error: auth.ErrForbidden,
},
{
Name: "CatchallDenyWithNoAccount",
Resource: srvResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: catchallResource,
Access: auth.AccessDenied,
},
},
Error: auth.ErrForbidden,
},
{
Name: "RulePriorityGrantFirst",
Resource: srvResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: catchallResource,
Access: auth.AccessGranted,
Priority: 1,
},
&auth.Rule{
Scope: "*",
Resource: catchallResource,
Access: auth.AccessDenied,
Priority: 0,
},
},
},
{
Name: "RulePriorityDenyFirst",
Resource: srvResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: catchallResource,
Access: auth.AccessGranted,
Priority: 0,
},
&auth.Rule{
Scope: "*",
Resource: catchallResource,
Access: auth.AccessDenied,
Priority: 1,
},
},
Error: auth.ErrForbidden,
},
{
Name: "WebExactEndpointValid",
Resource: webResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: webResource,
},
},
},
{
Name: "WebExactEndpointInalid",
Resource: webResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: &auth.Resource{
Type: webResource.Type,
Name: webResource.Name,
Endpoint: "invalidendpoint",
},
},
},
Error: auth.ErrForbidden,
},
{
Name: "WebWildcardEndpoint",
Resource: webResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: &auth.Resource{
Type: webResource.Type,
Name: webResource.Name,
Endpoint: "*",
},
},
},
},
{
Name: "WebWildcardPathEndpointValid",
Resource: webResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: &auth.Resource{
Type: webResource.Type,
Name: webResource.Name,
Endpoint: "/foo/*",
},
},
},
},
{
Name: "WebWildcardPathEndpointInvalid",
Resource: webResource,
Account: &auth.Account{},
Rules: []*auth.Rule{
&auth.Rule{
Scope: "*",
Resource: &auth.Resource{
Type: webResource.Type,
Name: webResource.Name,
Endpoint: "/bar/*",
},
},
},
Error: auth.ErrForbidden,
},
}
for _, tc := range tt {
t.Run(tc.Name, func(t *testing.T) {
if err := Verify(tc.Rules, tc.Account, tc.Resource); err != tc.Error {
t.Errorf("Expected %v but got %v", tc.Error, err)
}
})
}
}

View File

@@ -188,10 +188,9 @@ func (m *Token) GetExpiry() int64 {
type Account struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Roles []string `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty"`
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Namespace string `protobuf:"bytes,5,opt,name=namespace,proto3" json:"namespace,omitempty"`
Provider string `protobuf:"bytes,6,opt,name=provider,proto3" json:"provider,omitempty"`
Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"`
Issuer string `protobuf:"bytes,6,opt,name=issuer,proto3" json:"issuer,omitempty"`
Secret string `protobuf:"bytes,7,opt,name=secret,proto3" json:"secret,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@@ -237,13 +236,6 @@ func (m *Account) GetType() string {
return ""
}
func (m *Account) GetRoles() []string {
if m != nil {
return m.Roles
}
return nil
}
func (m *Account) GetMetadata() map[string]string {
if m != nil {
return m.Metadata
@@ -251,16 +243,16 @@ func (m *Account) GetMetadata() map[string]string {
return nil
}
func (m *Account) GetNamespace() string {
func (m *Account) GetScopes() []string {
if m != nil {
return m.Namespace
return m.Scopes
}
return ""
return nil
}
func (m *Account) GetProvider() string {
func (m *Account) GetIssuer() string {
if m != nil {
return m.Provider
return m.Issuer
}
return ""
}
@@ -276,7 +268,6 @@ type Resource struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Endpoint string `protobuf:"bytes,3,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
Namespace string `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -328,18 +319,10 @@ func (m *Resource) GetEndpoint() string {
return ""
}
func (m *Resource) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type GenerateRequest struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Roles []string `protobuf:"bytes,2,rep,name=roles,proto3" json:"roles,omitempty"`
Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Namespace string `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"`
Scopes []string `protobuf:"bytes,4,rep,name=scopes,proto3" json:"scopes,omitempty"`
Secret string `protobuf:"bytes,5,opt,name=secret,proto3" json:"secret,omitempty"`
Type string `protobuf:"bytes,6,opt,name=type,proto3" json:"type,omitempty"`
Provider string `protobuf:"bytes,7,opt,name=provider,proto3" json:"provider,omitempty"`
@@ -380,13 +363,6 @@ func (m *GenerateRequest) GetId() string {
return ""
}
func (m *GenerateRequest) GetRoles() []string {
if m != nil {
return m.Roles
}
return nil
}
func (m *GenerateRequest) GetMetadata() map[string]string {
if m != nil {
return m.Metadata
@@ -394,11 +370,11 @@ func (m *GenerateRequest) GetMetadata() map[string]string {
return nil
}
func (m *GenerateRequest) GetNamespace() string {
func (m *GenerateRequest) GetScopes() []string {
if m != nil {
return m.Namespace
return m.Scopes
}
return ""
return nil
}
func (m *GenerateRequest) GetSecret() string {
@@ -462,7 +438,7 @@ func (m *GenerateResponse) GetAccount() *Account {
}
type GrantRequest struct {
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
Scope string `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"`
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@@ -494,9 +470,9 @@ func (m *GrantRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_GrantRequest proto.InternalMessageInfo
func (m *GrantRequest) GetRole() string {
func (m *GrantRequest) GetScope() string {
if m != nil {
return m.Role
return m.Scope
}
return ""
}
@@ -540,7 +516,7 @@ func (m *GrantResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_GrantResponse proto.InternalMessageInfo
type RevokeRequest struct {
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
Scope string `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"`
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@@ -572,9 +548,9 @@ func (m *RevokeRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_RevokeRequest proto.InternalMessageInfo
func (m *RevokeRequest) GetRole() string {
func (m *RevokeRequest) GetScope() string {
if m != nil {
return m.Role
return m.Scope
}
return ""
}
@@ -799,7 +775,7 @@ func (m *TokenResponse) GetToken() *Token {
type Rule struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"`
Scope string `protobuf:"bytes,2,opt,name=scope,proto3" json:"scope,omitempty"`
Resource *Resource `protobuf:"bytes,3,opt,name=resource,proto3" json:"resource,omitempty"`
Access Access `protobuf:"varint,4,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"`
Priority int32 `protobuf:"varint,5,opt,name=priority,proto3" json:"priority,omitempty"`
@@ -840,9 +816,9 @@ func (m *Rule) GetId() string {
return ""
}
func (m *Rule) GetRole() string {
func (m *Rule) GetScope() string {
if m != nil {
return m.Role
return m.Scope
}
return ""
}
@@ -869,13 +845,10 @@ func (m *Rule) GetPriority() int32 {
}
type CreateRequest struct {
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
Access Access `protobuf:"varint,3,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"`
Priority int32 `protobuf:"varint,4,opt,name=priority,proto3" json:"priority,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Rule *Rule `protobuf:"bytes,1,opt,name=rule,proto3" json:"rule,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreateRequest) Reset() { *m = CreateRequest{} }
@@ -903,34 +876,13 @@ func (m *CreateRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_CreateRequest proto.InternalMessageInfo
func (m *CreateRequest) GetRole() string {
func (m *CreateRequest) GetRule() *Rule {
if m != nil {
return m.Role
}
return ""
}
func (m *CreateRequest) GetResource() *Resource {
if m != nil {
return m.Resource
return m.Rule
}
return nil
}
func (m *CreateRequest) GetAccess() Access {
if m != nil {
return m.Access
}
return Access_UNKNOWN
}
func (m *CreateRequest) GetPriority() int32 {
if m != nil {
return m.Priority
}
return 0
}
type CreateResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@@ -963,13 +915,10 @@ func (m *CreateResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_CreateResponse proto.InternalMessageInfo
type DeleteRequest struct {
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
Access Access `protobuf:"varint,3,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"`
Priority int32 `protobuf:"varint,4,opt,name=priority,proto3" json:"priority,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
@@ -997,34 +946,13 @@ func (m *DeleteRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo
func (m *DeleteRequest) GetRole() string {
func (m *DeleteRequest) GetId() string {
if m != nil {
return m.Role
return m.Id
}
return ""
}
func (m *DeleteRequest) GetResource() *Resource {
if m != nil {
return m.Resource
}
return nil
}
func (m *DeleteRequest) GetAccess() Access {
if m != nil {
return m.Access
}
return Access_UNKNOWN
}
func (m *DeleteRequest) GetPriority() int32 {
if m != nil {
return m.Priority
}
return 0
}
type DeleteResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@@ -1157,64 +1085,62 @@ func init() {
func init() { proto.RegisterFile("auth/service/proto/auth.proto", fileDescriptor_21300bfacc51fc2a) }
var fileDescriptor_21300bfacc51fc2a = []byte{
// 900 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xdd, 0x8e, 0xdb, 0x44,
0x14, 0x5e, 0xff, 0xc4, 0xc9, 0x9e, 0xfc, 0x6c, 0x34, 0xdd, 0x16, 0x2b, 0xed, 0x96, 0xad, 0x8b,
0xd0, 0x52, 0x41, 0x16, 0xa5, 0x37, 0x40, 0x6f, 0x58, 0x35, 0x51, 0x68, 0xa1, 0x41, 0x58, 0x45,
0xe5, 0x06, 0x55, 0xc6, 0x39, 0xb0, 0xd6, 0x66, 0x6d, 0x33, 0x33, 0x5e, 0x91, 0x1b, 0x24, 0xde,
0x81, 0x37, 0x80, 0x2b, 0x9e, 0x89, 0x7b, 0x5e, 0x03, 0xcd, 0x9f, 0x37, 0x76, 0x9c, 0xaa, 0x40,
0x2f, 0xb8, 0x9b, 0x33, 0xe7, 0xf8, 0xcc, 0xf7, 0x7d, 0xe7, 0xcc, 0xf1, 0xc0, 0x51, 0x54, 0xf0,
0xf3, 0x53, 0x86, 0xf4, 0x2a, 0x89, 0xf1, 0x34, 0xa7, 0x19, 0xcf, 0x4e, 0xc5, 0xd6, 0x58, 0x2e,
0x49, 0xff, 0x87, 0x6c, 0x7c, 0x99, 0xc4, 0x34, 0x1b, 0x8b, 0xcd, 0xe0, 0x26, 0xdc, 0xf8, 0x22,
0x61, 0xfc, 0x2c, 0x8e, 0xb3, 0x22, 0xe5, 0x2c, 0xc4, 0x1f, 0x0b, 0x64, 0x3c, 0x78, 0x0a, 0x87,
0xd5, 0x6d, 0x96, 0x67, 0x29, 0x43, 0x32, 0x81, 0x4e, 0xa4, 0xf7, 0x7c, 0xeb, 0xd8, 0x39, 0xe9,
0x4e, 0x6e, 0x8d, 0x2b, 0x09, 0xc7, 0xfa, 0x93, 0xb0, 0x8c, 0x0b, 0x7e, 0xb1, 0xa0, 0xf5, 0x3c,
0xbb, 0xc0, 0x94, 0xdc, 0x83, 0x5e, 0x14, 0xc7, 0xc8, 0xd8, 0x4b, 0x2e, 0x6c, 0xdf, 0x3a, 0xb6,
0x4e, 0xf6, 0xc3, 0xae, 0xda, 0x53, 0x21, 0xf7, 0xa1, 0x4f, 0xf1, 0x7b, 0x8a, 0xec, 0x5c, 0xc7,
0xd8, 0x32, 0xa6, 0xa7, 0x37, 0x55, 0x90, 0x0f, 0xed, 0x98, 0x62, 0xc4, 0x71, 0xe9, 0x3b, 0xc7,
0xd6, 0x89, 0x13, 0x1a, 0x93, 0xdc, 0x02, 0x0f, 0x7f, 0xca, 0x13, 0xba, 0xf6, 0x5d, 0xe9, 0xd0,
0x56, 0xf0, 0xab, 0x0d, 0x6d, 0x8d, 0x8c, 0x0c, 0xc0, 0x4e, 0x96, 0xfa, 0x6c, 0x3b, 0x59, 0x12,
0x02, 0x2e, 0x5f, 0xe7, 0xa8, 0x4f, 0x92, 0x6b, 0x72, 0x08, 0x2d, 0x9a, 0xad, 0x90, 0xf9, 0xce,
0xb1, 0x73, 0xb2, 0x1f, 0x2a, 0x83, 0x7c, 0x0a, 0x9d, 0x4b, 0xe4, 0xd1, 0x32, 0xe2, 0x91, 0xef,
0x4a, 0xf6, 0xef, 0x34, 0xb3, 0x1f, 0x3f, 0xd3, 0x61, 0xb3, 0x94, 0xd3, 0x75, 0x58, 0x7e, 0x45,
0xee, 0xc0, 0x7e, 0x1a, 0x5d, 0x22, 0xcb, 0xa3, 0x18, 0xfd, 0x96, 0x3c, 0xf0, 0x7a, 0x83, 0x8c,
0xa0, 0x93, 0xd3, 0xec, 0x2a, 0x59, 0x22, 0xf5, 0x3d, 0xe9, 0x2c, 0x6d, 0xc1, 0x8c, 0x61, 0x4c,
0x91, 0xfb, 0x6d, 0xe9, 0xd1, 0xd6, 0xe8, 0x11, 0xf4, 0x2b, 0x87, 0x91, 0x21, 0x38, 0x17, 0xb8,
0xd6, 0xfc, 0xc4, 0x52, 0x90, 0xb9, 0x8a, 0x56, 0x85, 0x61, 0xa8, 0x8c, 0x4f, 0xec, 0x8f, 0xac,
0x60, 0x05, 0x9d, 0x10, 0x59, 0x56, 0xd0, 0x18, 0x85, 0x0c, 0x02, 0x89, 0xfe, 0x50, 0xae, 0x1b,
0xa5, 0x19, 0x41, 0x07, 0xd3, 0x65, 0x9e, 0x25, 0x29, 0x97, 0xea, 0xef, 0x87, 0xa5, 0x5d, 0xa5,
0xe7, 0xd6, 0xe8, 0x05, 0xbf, 0xdb, 0x70, 0x30, 0xc7, 0x14, 0x69, 0xc4, 0x51, 0x37, 0xda, 0x56,
0x31, 0x4a, 0xe1, 0xed, 0x4d, 0xe1, 0x3f, 0xdb, 0x10, 0xde, 0x91, 0xc2, 0xbf, 0x5f, 0x13, 0xbe,
0x96, 0xf7, 0xf5, 0x0a, 0x50, 0x47, 0xb8, 0x21, 0x72, 0x6b, 0x53, 0xe4, 0x52, 0x07, 0xaf, 0xaa,
0x43, 0x59, 0xac, 0x76, 0xb5, 0x58, 0xff, 0xad, 0x28, 0x53, 0x18, 0x5e, 0xb3, 0xd1, 0xf7, 0xee,
0x43, 0x68, 0xeb, 0xfb, 0x24, 0x73, 0xec, 0xbe, 0x76, 0x26, 0x2c, 0x78, 0x01, 0xbd, 0x39, 0x8d,
0x52, 0x6e, 0x84, 0x26, 0xe0, 0x0a, 0x2d, 0x4d, 0x79, 0xc5, 0x9a, 0x3c, 0x84, 0x0e, 0xd5, 0xe5,
0x97, 0x30, 0xba, 0x93, 0xb7, 0x6a, 0x69, 0x4d, 0x77, 0x84, 0x65, 0x60, 0x70, 0x00, 0x7d, 0x9d,
0x58, 0x61, 0x0b, 0xbe, 0x81, 0x7e, 0x88, 0x57, 0xd9, 0x05, 0xbe, 0xf1, 0xa3, 0x86, 0x30, 0x30,
0x99, 0xf5, 0x59, 0xef, 0xc2, 0xe0, 0x49, 0xca, 0x72, 0x8c, 0x4b, 0x5e, 0x87, 0xd0, 0xda, 0x1c,
0x26, 0xca, 0x08, 0x1e, 0xc3, 0x41, 0x19, 0xf7, 0xaf, 0x25, 0xfc, 0x19, 0x7a, 0x72, 0xde, 0xec,
0xea, 0xd5, 0xeb, 0x6e, 0xb1, 0x2b, 0xdd, 0xb2, 0x35, 0xc3, 0x9c, 0x86, 0x19, 0x76, 0x0f, 0x7a,
0xd2, 0xf9, 0xb2, 0x32, 0xaf, 0xba, 0x72, 0x6f, 0xa6, 0x86, 0xd6, 0x23, 0xe8, 0xeb, 0xf3, 0x35,
0x85, 0x07, 0x9b, 0x5c, 0xbb, 0x93, 0xc3, 0x1a, 0x01, 0x15, 0xac, 0x15, 0xf8, 0xc3, 0x02, 0x37,
0x2c, 0x56, 0xd8, 0x34, 0xee, 0x64, 0x75, 0xec, 0x1d, 0xd5, 0x71, 0x5e, 0xb3, 0x3a, 0xe4, 0x03,
0xf0, 0xd4, 0xe4, 0x96, 0xd8, 0x07, 0x93, 0x9b, 0xdb, 0x7a, 0x22, 0x63, 0xa1, 0x0e, 0x52, 0xf7,
0x25, 0xc9, 0x68, 0xc2, 0xd7, 0xf2, 0x76, 0xb5, 0xc2, 0xd2, 0x0e, 0x7e, 0xb3, 0xa0, 0xff, 0x58,
0x8e, 0xf0, 0x37, 0xdd, 0x43, 0x1b, 0x28, 0x9d, 0x7f, 0x8a, 0xd2, 0xad, 0xa1, 0x1c, 0xc2, 0xc0,
0x80, 0xd4, 0xed, 0x28, 0x70, 0x4f, 0x71, 0x85, 0xff, 0x7b, 0xdc, 0x06, 0xa4, 0xc6, 0xdd, 0x87,
0xae, 0xf8, 0xbd, 0x9b, 0xbf, 0xfd, 0xc7, 0xd0, 0x53, 0xa6, 0xee, 0xb3, 0xf7, 0xa0, 0x45, 0x0b,
0x31, 0x84, 0xd5, 0x2f, 0xfe, 0x46, 0x1d, 0x6d, 0xb1, 0xc2, 0x50, 0x45, 0x3c, 0x18, 0x83, 0xa7,
0x90, 0x90, 0x2e, 0xb4, 0xbf, 0x5e, 0x7c, 0xbe, 0xf8, 0xf2, 0xc5, 0x62, 0xb8, 0x27, 0x8c, 0x79,
0x78, 0xb6, 0x78, 0x3e, 0x9b, 0x0e, 0x2d, 0x02, 0xe0, 0x4d, 0x67, 0x8b, 0x27, 0xb3, 0xe9, 0xd0,
0x9e, 0xfc, 0x65, 0x81, 0x7b, 0x56, 0xf0, 0x73, 0xf2, 0x0c, 0x3a, 0x66, 0xca, 0x91, 0xbb, 0xaf,
0x1e, 0xe6, 0xa3, 0xb7, 0x77, 0xfa, 0x35, 0x9f, 0x3d, 0xf2, 0x14, 0xda, 0xfa, 0xc2, 0x93, 0xa3,
0x5a, 0x74, 0x75, 0x60, 0x8c, 0xee, 0xee, 0x72, 0x97, 0xb9, 0xa6, 0xe6, 0xbd, 0x72, 0xbb, 0xf1,
0x82, 0xe9, 0x3c, 0x77, 0x9a, 0x9d, 0x26, 0xcb, 0xe4, 0x5b, 0xe8, 0x98, 0xe7, 0x13, 0xf9, 0x0a,
0x5c, 0x21, 0x30, 0x09, 0x6a, 0xdf, 0x34, 0x3c, 0xbd, 0x46, 0xf7, 0x5f, 0x19, 0x53, 0xa6, 0xff,
0xd3, 0x82, 0x96, 0x28, 0x04, 0x23, 0x73, 0xf0, 0x54, 0x5b, 0x92, 0x3a, 0xa4, 0xca, 0x95, 0x1a,
0x1d, 0xed, 0xf0, 0x96, 0xbc, 0xe7, 0xe0, 0xa9, 0x3e, 0xd9, 0x4a, 0x54, 0xe9, 0xf1, 0xad, 0x44,
0xb5, 0xe6, 0xda, 0x23, 0x67, 0x9a, 0xee, 0xa8, 0x81, 0x8a, 0x49, 0x72, 0xbb, 0xd1, 0x67, 0x52,
0x7c, 0xe7, 0xc9, 0xd7, 0xea, 0xc3, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xdf, 0x67, 0x3c, 0x6e,
0xce, 0x0a, 0x00, 0x00,
// 872 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x51, 0x8f, 0xdb, 0x44,
0x10, 0x3e, 0x27, 0xb1, 0x93, 0x9b, 0xc4, 0x77, 0xd1, 0xf6, 0x5a, 0xac, 0x94, 0x6b, 0xaf, 0x2e,
0x82, 0xa3, 0x82, 0x1c, 0x4a, 0x5f, 0x0a, 0x7d, 0xe1, 0xd4, 0x44, 0xa1, 0x85, 0x06, 0x61, 0x15,
0x21, 0x90, 0x50, 0x65, 0x9c, 0x81, 0xb3, 0x2e, 0x67, 0x9b, 0xdd, 0xf5, 0x89, 0xbc, 0x20, 0xf1,
0xc6, 0x8f, 0xe1, 0x27, 0xf1, 0xce, 0x1f, 0xe0, 0x07, 0x20, 0xef, 0xce, 0xba, 0xb1, 0xe3, 0x54,
0x15, 0x88, 0x37, 0xcf, 0xec, 0xb7, 0xb3, 0xf3, 0x7d, 0x3b, 0x33, 0x6b, 0x38, 0x0e, 0x73, 0x79,
0x71, 0x26, 0x90, 0x5f, 0xc7, 0x11, 0x9e, 0x65, 0x3c, 0x95, 0xe9, 0x59, 0xe1, 0x1a, 0xab, 0x4f,
0xe6, 0xfe, 0x94, 0x8e, 0xaf, 0xe2, 0x88, 0xa7, 0xe3, 0xc2, 0xe9, 0xdf, 0x84, 0x1b, 0x5f, 0xc4,
0x42, 0x9e, 0x47, 0x51, 0x9a, 0x27, 0x52, 0x04, 0xf8, 0x73, 0x8e, 0x42, 0xfa, 0xcf, 0xe0, 0xa8,
0xea, 0x16, 0x59, 0x9a, 0x08, 0x64, 0x13, 0xe8, 0x85, 0xe4, 0xf3, 0xac, 0x93, 0xf6, 0x69, 0x7f,
0x72, 0x6b, 0x5c, 0x09, 0x38, 0xa6, 0x2d, 0x41, 0x89, 0xf3, 0x7f, 0xb3, 0xc0, 0x7e, 0x91, 0x5e,
0x62, 0xc2, 0xee, 0xc1, 0x20, 0x8c, 0x22, 0x14, 0xe2, 0xa5, 0x2c, 0x6c, 0xcf, 0x3a, 0xb1, 0x4e,
0xf7, 0x83, 0xbe, 0xf6, 0x69, 0xc8, 0x7d, 0x70, 0x39, 0xfe, 0xc8, 0x51, 0x5c, 0x10, 0xa6, 0xa5,
0x30, 0x03, 0x72, 0x6a, 0x90, 0x07, 0xdd, 0x88, 0x63, 0x28, 0x71, 0xe9, 0xb5, 0x4f, 0xac, 0xd3,
0x76, 0x60, 0x4c, 0x76, 0x0b, 0x1c, 0xfc, 0x25, 0x8b, 0xf9, 0xda, 0xeb, 0xa8, 0x05, 0xb2, 0xfc,
0xbf, 0x2d, 0xe8, 0x52, 0x66, 0xec, 0x00, 0x5a, 0xf1, 0x92, 0xce, 0x6e, 0xc5, 0x4b, 0xc6, 0xa0,
0x23, 0xd7, 0x19, 0xd2, 0x49, 0xea, 0x9b, 0x7d, 0x0a, 0xbd, 0x2b, 0x94, 0xe1, 0x32, 0x94, 0xa1,
0xd7, 0x51, 0x3c, 0xdf, 0x69, 0xe6, 0x39, 0x7e, 0x4e, 0xb0, 0x59, 0x22, 0xf9, 0x3a, 0x28, 0x77,
0x15, 0x99, 0x88, 0x28, 0xcd, 0x50, 0x78, 0xf6, 0x49, 0xfb, 0x74, 0x3f, 0x20, 0xab, 0xf0, 0xc7,
0x42, 0xe4, 0xc8, 0x3d, 0x47, 0x9d, 0x47, 0x96, 0xc2, 0x63, 0xc4, 0x51, 0x7a, 0x5d, 0xed, 0xd7,
0xd6, 0xe8, 0x31, 0xb8, 0x95, 0x23, 0xd8, 0x10, 0xda, 0x97, 0xb8, 0xa6, 0xfc, 0x8b, 0x4f, 0x76,
0x04, 0xf6, 0x75, 0xb8, 0xca, 0x0d, 0x03, 0x6d, 0x7c, 0xd2, 0x7a, 0x64, 0xf9, 0x0b, 0xe8, 0x05,
0x28, 0xd2, 0x9c, 0x47, 0x58, 0xd0, 0x4c, 0xc2, 0x2b, 0xa4, 0x8d, 0xea, 0xbb, 0x91, 0xfa, 0x08,
0x7a, 0x98, 0x2c, 0xb3, 0x34, 0x4e, 0xa4, 0x52, 0x77, 0x3f, 0x28, 0x6d, 0xff, 0xf7, 0x16, 0x1c,
0xce, 0x31, 0x41, 0x1e, 0x4a, 0xa4, 0x52, 0xd9, 0x92, 0xf3, 0xb3, 0x0d, 0xe9, 0xda, 0x4a, 0xba,
0x0f, 0x6a, 0xd2, 0xd5, 0x22, 0xbc, 0x81, 0x84, 0x9d, 0xba, 0x84, 0x24, 0x95, 0xbd, 0x29, 0x55,
0xc9, 0xc6, 0xa9, 0xb2, 0xc9, 0x78, 0x7a, 0x1d, 0x2f, 0x91, 0x93, 0xb0, 0xa5, 0xfd, 0xdf, 0xa4,
0x9d, 0xc2, 0xf0, 0x15, 0x0f, 0xea, 0x8e, 0x8f, 0xa0, 0x4b, 0x55, 0xaf, 0x62, 0xec, 0x6e, 0x0e,
0x03, 0xf3, 0xbf, 0x85, 0xc1, 0x9c, 0x87, 0x89, 0x34, 0x62, 0x1e, 0x81, 0xad, 0x48, 0x52, 0x0e,
0xda, 0x60, 0x0f, 0xa1, 0xc7, 0xe9, 0x1a, 0x55, 0x22, 0xfd, 0xc9, 0x5b, 0xb5, 0xc0, 0xe6, 0x96,
0x83, 0x12, 0xe8, 0x1f, 0x82, 0x4b, 0xa1, 0x75, 0x76, 0xfe, 0x77, 0xe0, 0x06, 0x78, 0x9d, 0x5e,
0xe2, 0xff, 0x70, 0xd8, 0x10, 0x0e, 0x4c, 0x6c, 0x3a, 0xed, 0x5d, 0x38, 0x78, 0x9a, 0x88, 0x0c,
0xa3, 0x4d, 0x6e, 0x9b, 0x6d, 0xaf, 0x0d, 0xff, 0x09, 0x1c, 0x96, 0xb8, 0x7f, 0x2d, 0xe3, 0xaf,
0x30, 0x50, 0x93, 0x61, 0x57, 0x4d, 0xbe, 0xaa, 0x98, 0x56, 0xa5, 0x62, 0xb6, 0xa6, 0x4d, 0xbb,
0x61, 0xda, 0xdc, 0x83, 0x81, 0x5a, 0x7c, 0x59, 0x99, 0x2c, 0x7d, 0xe5, 0x9b, 0xe9, 0xf1, 0xf2,
0x18, 0x5c, 0x3a, 0x9f, 0x28, 0x3c, 0xd8, 0xe4, 0xda, 0x9f, 0x1c, 0xd5, 0x08, 0x68, 0x30, 0x29,
0xf0, 0x87, 0x05, 0x9d, 0x20, 0x5f, 0xe1, 0x56, 0xd6, 0xe5, 0xfd, 0xb4, 0x76, 0xdd, 0x4f, 0xfb,
0x0d, 0xef, 0x87, 0x7d, 0x08, 0x8e, 0x9e, 0xb2, 0x2a, 0xfb, 0x83, 0xc9, 0xcd, 0x6d, 0x45, 0x51,
0x88, 0x80, 0x40, 0xba, 0x6b, 0xe2, 0x94, 0xc7, 0x72, 0xad, 0x7a, 0xcc, 0x0e, 0x4a, 0xdb, 0x7f,
0x04, 0xee, 0x13, 0x35, 0x6d, 0x8d, 0xd8, 0xef, 0x41, 0x87, 0xe7, 0x2b, 0x24, 0xaa, 0x37, 0xea,
0xc9, 0xe4, 0x2b, 0x0c, 0x14, 0xa0, 0x28, 0x12, 0xb3, 0x93, 0x8a, 0xe4, 0x2e, 0xb8, 0x53, 0x5c,
0xe1, 0xce, 0x61, 0x52, 0x6c, 0x31, 0x00, 0xda, 0xe2, 0x42, 0xbf, 0x78, 0x99, 0xcc, 0x43, 0xf5,
0x31, 0x0c, 0xb4, 0x49, 0xc2, 0xbf, 0x0f, 0x76, 0x71, 0x96, 0x79, 0x9d, 0x1a, 0xb3, 0xd1, 0x88,
0x07, 0x63, 0x70, 0x34, 0x6d, 0xd6, 0x87, 0xee, 0xd7, 0x8b, 0xcf, 0x17, 0x5f, 0x7e, 0xb3, 0x18,
0xee, 0x15, 0xc6, 0x3c, 0x38, 0x5f, 0xbc, 0x98, 0x4d, 0x87, 0x16, 0x03, 0x70, 0xa6, 0xb3, 0xc5,
0xd3, 0xd9, 0x74, 0xd8, 0x9a, 0xfc, 0x65, 0x41, 0xe7, 0x3c, 0x97, 0x17, 0xec, 0x39, 0xf4, 0x4c,
0xeb, 0xb3, 0x3b, 0xaf, 0x9f, 0x6d, 0xa3, 0xbb, 0x3b, 0xd7, 0x89, 0xcf, 0x1e, 0x7b, 0x06, 0x5d,
0xea, 0x00, 0x76, 0x5c, 0x43, 0x57, 0x3b, 0x68, 0x74, 0x67, 0xd7, 0x72, 0x19, 0x6b, 0x6a, 0x9e,
0xda, 0xdb, 0x8d, 0x15, 0x47, 0x71, 0xde, 0x6e, 0x5e, 0x34, 0x51, 0x26, 0xdf, 0x43, 0xcf, 0xbc,
0xfc, 0xec, 0x2b, 0xe8, 0x14, 0x02, 0x33, 0xbf, 0xb6, 0xa7, 0xe1, 0xaf, 0x61, 0x74, 0xff, 0xb5,
0x98, 0x32, 0xfc, 0x9f, 0x16, 0xd8, 0xc5, 0x45, 0x08, 0x36, 0x07, 0x47, 0x57, 0x04, 0xab, 0xa7,
0x54, 0x29, 0xb1, 0xd1, 0xf1, 0x8e, 0xd5, 0x92, 0xf7, 0x1c, 0x1c, 0x5d, 0x27, 0x5b, 0x81, 0x2a,
0xf5, 0xb5, 0x15, 0xa8, 0x56, 0x5c, 0x7b, 0xec, 0x9c, 0xe8, 0x8e, 0x1a, 0xa8, 0x98, 0x20, 0xb7,
0x1b, 0xd7, 0x4c, 0x88, 0x1f, 0x1c, 0xf5, 0xa3, 0xf5, 0xf0, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff,
0x52, 0x12, 0xc2, 0xdb, 0x89, 0x09, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -35,10 +35,9 @@ message Token {
message Account {
string id = 1;
string type = 2;
repeated string roles = 3;
map<string, string> metadata = 4;
string namespace = 5;
string provider = 6;
repeated string scopes = 5;
string issuer = 6;
string secret = 7;
}
@@ -46,14 +45,12 @@ message Resource{
string name = 1;
string type = 2;
string endpoint = 3;
string namespace = 4;
}
message GenerateRequest {
string id = 1;
repeated string roles = 2;
map<string, string> metadata = 3;
string namespace = 4;
repeated string scopes = 4;
string secret = 5;
string type = 6;
string provider = 7;
@@ -64,14 +61,14 @@ message GenerateResponse {
}
message GrantRequest {
string role = 1;
string scope = 1;
Resource resource = 2;
}
message GrantResponse {}
message RevokeRequest {
string role = 1;
string scope = 1;
Resource resource = 2;
}
@@ -104,26 +101,20 @@ enum Access {
message Rule {
string id = 1;
string role = 2;
string scope = 2;
Resource resource = 3;
Access access = 4;
int32 priority = 5;
}
message CreateRequest {
string role = 1;
Resource resource = 2;
Access access = 3;
int32 priority = 4;
Rule rule = 1;
}
message CreateResponse {}
message DeleteRequest {
string role = 1;
Resource resource = 2;
Access access = 3;
int32 priority = 4;
string id = 1;
}
message DeleteResponse {}

View File

@@ -2,30 +2,23 @@ package service
import (
"context"
"fmt"
"sort"
"strings"
"sync"
"time"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/auth/rules"
pb "github.com/micro/go-micro/v2/auth/service/proto"
"github.com/micro/go-micro/v2/auth/token"
"github.com/micro/go-micro/v2/auth/token/jwt"
"github.com/micro/go-micro/v2/client"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/util/jitter"
)
// svc is the service implementation of the Auth interface
type svc struct {
options auth.Options
auth pb.AuthService
rule pb.RulesService
rules pb.RulesService
jwt token.Provider
rules []*pb.Rule
sync.Mutex
}
func (s *svc) String() string {
@@ -42,7 +35,7 @@ func (s *svc) Init(opts ...auth.Option) {
}
s.auth = pb.NewAuthService("go.micro.auth", s.options.Client)
s.rule = pb.NewRulesService("go.micro.auth", s.options.Client)
s.rules = pb.NewRulesService("go.micro.auth", s.options.Client)
// if we have a JWT public key passed as an option,
// we can decode tokens with the type "JWT" locally
@@ -53,8 +46,6 @@ func (s *svc) Init(opts ...auth.Option) {
}
func (s *svc) Options() auth.Options {
s.Lock()
defer s.Unlock()
return s.options
}
@@ -63,13 +54,12 @@ func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e
options := auth.NewGenerateOptions(opts...)
rsp, err := s.auth.Generate(context.TODO(), &pb.GenerateRequest{
Id: id,
Type: options.Type,
Secret: options.Secret,
Roles: options.Roles,
Metadata: options.Metadata,
Provider: options.Provider,
Namespace: options.Namespace,
Id: id,
Type: options.Type,
Secret: options.Secret,
Scopes: options.Scopes,
Metadata: options.Metadata,
Provider: options.Provider,
})
if err != nil {
return nil, err
@@ -79,90 +69,75 @@ func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e
}
// Grant access to a resource
func (s *svc) Grant(role string, res *auth.Resource) error {
_, err := s.rule.Create(context.TODO(), &pb.CreateRequest{
Role: role,
Access: pb.Access_GRANTED,
Resource: &pb.Resource{
Namespace: res.Namespace,
Type: res.Type,
Name: res.Name,
Endpoint: res.Endpoint,
func (s *svc) Grant(rule *auth.Rule) error {
access := pb.Access_UNKNOWN
if rule.Access == auth.AccessGranted {
access = pb.Access_GRANTED
} else if rule.Access == auth.AccessDenied {
access = pb.Access_DENIED
}
_, err := s.rules.Create(context.TODO(), &pb.CreateRequest{
Rule: &pb.Rule{
Id: rule.ID,
Scope: rule.Scope,
Priority: rule.Priority,
Access: access,
Resource: &pb.Resource{
Type: rule.Resource.Type,
Name: rule.Resource.Name,
Endpoint: rule.Resource.Endpoint,
},
},
})
return err
}
// Revoke access to a resource
func (s *svc) Revoke(role string, res *auth.Resource) error {
_, err := s.rule.Delete(context.TODO(), &pb.DeleteRequest{
Role: role,
Access: pb.Access_GRANTED,
Resource: &pb.Resource{
Namespace: res.Namespace,
Type: res.Type,
Name: res.Name,
Endpoint: res.Endpoint,
},
func (s *svc) Revoke(rule *auth.Rule) error {
_, err := s.rules.Delete(context.TODO(), &pb.DeleteRequest{
Id: rule.ID,
})
return err
}
func (s *svc) Rules(opts ...auth.RulesOption) ([]*auth.Rule, error) {
var options auth.RulesOptions
for _, o := range opts {
o(&options)
}
if options.Context == nil {
options.Context = context.TODO()
}
rsp, err := s.rules.List(options.Context, &pb.ListRequest{}, client.WithCache(time.Second*30))
if err != nil {
return nil, err
}
rules := make([]*auth.Rule, len(rsp.Rules))
for i, r := range rsp.Rules {
rules[i] = serializeRule(r)
}
return rules, nil
}
// Verify an account has access to a resource
func (s *svc) Verify(acc *auth.Account, res *auth.Resource) error {
// load the rules if none are loaded
s.loadRulesIfEmpty()
// set the namespace on the resource
if len(res.Namespace) == 0 {
res.Namespace = s.Options().Namespace
func (s *svc) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error {
var options auth.VerifyOptions
for _, o := range opts {
o(&options)
}
queries := [][]string{
{res.Namespace, res.Type, res.Name, res.Endpoint}, // check for specific role, e.g. service.foo.ListFoo:admin (role is checked in accessForRule)
{res.Namespace, res.Type, res.Name, "*"}, // check for wildcard endpoint, e.g. service.foo*
{res.Namespace, res.Type, "*"}, // check for wildcard name, e.g. service.*
{res.Namespace, "*"}, // check for wildcard type, e.g. *
{"*"}, // check for wildcard namespace
rs, err := s.Rules(auth.RulesContext(options.Context))
if err != nil {
return err
}
// endpoint is a url which can have wildcard excludes, e.g.
// "/foo/*" will allow "/foo/bar"
if comps := strings.Split(res.Endpoint, "/"); len(comps) > 1 {
for i := 1; i < len(comps); i++ {
wildcard := fmt.Sprintf("%v/*", strings.Join(comps[0:i], "/"))
queries = append(queries, []string{res.Type, res.Name, wildcard})
}
}
// set a default account id / namespace to log
logID := acc.ID
if len(logID) == 0 {
logID = "[no account]"
}
logNamespace := acc.Namespace
if len(logNamespace) == 0 {
logNamespace = "[no namespace]"
}
for _, q := range queries {
for _, rule := range s.listRules(q...) {
switch accessForRule(rule, acc, res) {
case pb.Access_UNKNOWN:
continue // rule did not specify access, check the next rule
case pb.Access_GRANTED:
log.Tracef("%v:%v granted access to %v:%v:%v:%v by rule %v", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, rule.Id)
return nil // rule grants the account access to the resource
case pb.Access_DENIED:
log.Tracef("%v:%v denied access to %v:%v:%v:%v by rule %v", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, rule.Id)
return auth.ErrForbidden // rule denies access to the resource
}
}
}
// no rules were found for the resource, default to denying access
log.Tracef("%v:%v denied access to %v:%v:%v:%v by lack of rule (%v rules found for namespace)", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, len(s.listRules(res.Namespace)))
return auth.ErrForbidden
return rules.Verify(rs, acc, res)
}
// Inspect a token
@@ -198,91 +173,6 @@ func (s *svc) Token(opts ...auth.TokenOption) (*auth.Token, error) {
return serializeToken(rsp.Token), nil
}
var ruleJoinKey = ":"
// accessForRule returns a rule status, indicating if a rule permits access to a
// resource for a given account
func accessForRule(rule *pb.Rule, acc *auth.Account, res *auth.Resource) pb.Access {
// a blank role permits access to the public
if rule.Role == "" {
return rule.Access
}
// a * role permits access to any user
if rule.Role == "*" && acc != nil {
return rule.Access
}
for _, role := range acc.Roles {
if rule.Role == role {
return rule.Access
}
// allow user.anything if role is user.*
if strings.HasSuffix(rule.Role, ".*") && strings.HasPrefix(rule.Role, role+".") {
return rule.Access
}
}
return pb.Access_UNKNOWN
}
// listRules gets all the rules from the store which match the filters.
// filters are namespace, type, name and then endpoint.
func (s *svc) listRules(filters ...string) []*pb.Rule {
s.Lock()
defer s.Unlock()
var rules []*pb.Rule
for _, r := range s.rules {
if len(filters) > 0 && r.Resource.Namespace != filters[0] {
continue
}
if len(filters) > 1 && r.Resource.Type != filters[1] {
continue
}
if len(filters) > 2 && r.Resource.Name != filters[2] {
continue
}
if len(filters) > 3 && r.Resource.Endpoint != filters[3] {
continue
}
rules = append(rules, r)
}
// sort rules by priority
sort.Slice(rules, func(i, j int) bool {
return rules[i].Priority < rules[j].Priority
})
return rules
}
// loadRules retrieves the rules from the auth service
func (s *svc) loadRules() {
rsp, err := s.rule.List(context.TODO(), &pb.ListRequest{})
s.Lock()
defer s.Unlock()
if err != nil {
log.Errorf("Error listing rules: %v", err)
return
}
s.rules = rsp.Rules
}
func (s *svc) loadRulesIfEmpty() {
s.Lock()
rules := s.rules
s.Unlock()
if len(rules) == 0 {
s.loadRules()
}
}
func serializeToken(t *pb.Token) *auth.Token {
return &auth.Token{
AccessToken: t.AccessToken,
@@ -294,12 +184,32 @@ func serializeToken(t *pb.Token) *auth.Token {
func serializeAccount(a *pb.Account) *auth.Account {
return &auth.Account{
ID: a.Id,
Roles: a.Roles,
Secret: a.Secret,
Metadata: a.Metadata,
Provider: a.Provider,
Namespace: a.Namespace,
ID: a.Id,
Secret: a.Secret,
Issuer: a.Issuer,
Metadata: a.Metadata,
Scopes: a.Scopes,
}
}
func serializeRule(r *pb.Rule) *auth.Rule {
var access auth.Access
if r.Access == pb.Access_GRANTED {
access = auth.AccessGranted
} else {
access = auth.AccessDenied
}
return &auth.Rule{
ID: r.Id,
Scope: r.Scope,
Access: access,
Priority: r.Priority,
Resource: &auth.Resource{
Type: r.Resource.Type,
Name: r.Resource.Name,
Endpoint: r.Resource.Endpoint,
},
}
}
@@ -310,22 +220,9 @@ func NewAuth(opts ...auth.Option) auth.Auth {
options.Client = client.DefaultClient
}
service := &svc{
return &svc{
auth: pb.NewAuthService("go.micro.auth", options.Client),
rule: pb.NewRulesService("go.micro.auth", options.Client),
rules: pb.NewRulesService("go.micro.auth", options.Client),
options: options,
}
// load rules periodically from the auth service
go func() {
ruleTimer := time.NewTicker(time.Second * 30)
for {
<-ruleTimer.C
time.Sleep(jitter.Do(time.Second * 5))
service.loadRules()
}
}()
return service
}

View File

@@ -1,26 +0,0 @@
package service
import (
"testing"
pb "github.com/micro/go-micro/v2/auth/service/proto"
)
func TestListRulesSorting(t *testing.T) {
s := &svc{
rules: []*pb.Rule{
&pb.Rule{Priority: 1},
&pb.Rule{Priority: 3},
&pb.Rule{Priority: 2},
},
}
var priorities []int32
for _, r := range s.listRules() {
priorities = append(priorities, r.Priority)
}
if priorities[0] != 1 || priorities[1] != 2 || priorities[2] != 3 {
t.Errorf("Incorrect Rule Sequence")
}
}

View File

@@ -32,10 +32,10 @@ func TestInspect(t *testing.T) {
t.Run("Valid token", func(t *testing.T) {
md := map[string]string{"foo": "bar"}
roles := []string{"admin"}
scopes := []string{"admin"}
subject := "test"
tok, err := b.Generate(&auth.Account{ID: subject, Roles: roles, Metadata: md})
tok, err := b.Generate(&auth.Account{ID: subject, Scopes: scopes, Metadata: md})
if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err)
}
@@ -47,8 +47,8 @@ func TestInspect(t *testing.T) {
if tok2.ID != subject {
t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.ID, subject)
}
if len(tok2.Roles) != len(roles) {
t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles))
if len(tok2.Scopes) != len(scopes) {
t.Errorf("Inspect returned %v scopes, expected %v", len(tok2.Scopes), len(scopes))
}
if len(tok2.Metadata) != len(md) {
t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md)

View File

@@ -11,11 +11,9 @@ import (
// authClaims to be encoded in the JWT
type authClaims struct {
Type string `json:"type"`
Roles []string `json:"roles"`
Provider string `json:"provider"`
Metadata map[string]string `json:"metadata"`
Namespace string `json:"namespace"`
Type string `json:"type"`
Scopes []string `json:"scopes"`
Metadata map[string]string `json:"metadata"`
jwt.StandardClaims
}
@@ -52,8 +50,9 @@ func (j *JWT) Generate(acc *auth.Account, opts ...token.GenerateOption) (*token.
// generate the JWT
expiry := time.Now().Add(options.Expiry)
t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{
acc.Type, acc.Roles, acc.Provider, acc.Metadata, acc.Namespace, jwt.StandardClaims{
acc.Type, acc.Scopes, acc.Metadata, jwt.StandardClaims{
Subject: acc.ID,
Issuer: acc.Issuer,
ExpiresAt: expiry.Unix(),
},
})
@@ -97,12 +96,11 @@ func (j *JWT) Inspect(t string) (*auth.Account, error) {
// return the token
return &auth.Account{
ID: claims.Subject,
Type: claims.Type,
Roles: claims.Roles,
Provider: claims.Provider,
Metadata: claims.Metadata,
Namespace: claims.Namespace,
ID: claims.Subject,
Issuer: claims.Issuer,
Type: claims.Type,
Scopes: claims.Scopes,
Metadata: claims.Metadata,
}, nil
}

View File

@@ -42,10 +42,10 @@ func TestInspect(t *testing.T) {
t.Run("Valid token", func(t *testing.T) {
md := map[string]string{"foo": "bar"}
roles := []string{"admin"}
scopes := []string{"admin"}
subject := "test"
acc := &auth.Account{ID: subject, Roles: roles, Metadata: md}
acc := &auth.Account{ID: subject, Scopes: scopes, Metadata: md}
tok, err := j.Generate(acc)
if err != nil {
t.Fatalf("Generate returned %v error, expected nil", err)
@@ -58,8 +58,8 @@ func TestInspect(t *testing.T) {
if acc.ID != subject {
t.Errorf("Inspect returned %v as the token subject, expected %v", acc.ID, subject)
}
if len(tok2.Roles) != len(roles) {
t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles))
if len(tok2.Scopes) != len(scopes) {
t.Errorf("Inspect returned %v scopes, expected %v", len(tok2.Scopes), len(scopes))
}
if len(tok2.Metadata) != len(md) {
t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md)

66
client/cache.go Normal file
View File

@@ -0,0 +1,66 @@
package client
import (
"context"
"encoding/json"
"fmt"
"hash/fnv"
"time"
"github.com/micro/go-micro/v2/metadata"
cache "github.com/patrickmn/go-cache"
)
// NewCache returns an initialised cache.
func NewCache() *Cache {
return &Cache{
cache: cache.New(cache.NoExpiration, 30*time.Second),
}
}
// Cache for responses
type Cache struct {
cache *cache.Cache
}
// Get a response from the cache
func (c *Cache) Get(ctx context.Context, req *Request) (interface{}, bool) {
return c.cache.Get(key(ctx, req))
}
// Set a response in the cache
func (c *Cache) Set(ctx context.Context, req *Request, rsp interface{}, expiry time.Duration) {
c.cache.Set(key(ctx, req), rsp, expiry)
}
// List the key value pairs in the cache
func (c *Cache) List() map[string]string {
items := c.cache.Items()
rsp := make(map[string]string, len(items))
for k, v := range items {
bytes, _ := json.Marshal(v.Object)
rsp[k] = string(bytes)
}
return rsp
}
// key returns a hash for the context and request
func key(ctx context.Context, req *Request) string {
ns, _ := metadata.Get(ctx, "Micro-Namespace")
bytes, _ := json.Marshal(map[string]interface{}{
"namespace": ns,
"request": map[string]interface{}{
"service": (*req).Service(),
"endpoint": (*req).Endpoint(),
"method": (*req).Method(),
"body": (*req).Body(),
},
})
h := fnv.New64()
h.Write(bytes)
return fmt.Sprintf("%x", h.Sum(nil))
}

76
client/cache_test.go Normal file
View File

@@ -0,0 +1,76 @@
package client
import (
"context"
"testing"
"time"
"github.com/micro/go-micro/v2/metadata"
)
func TestCache(t *testing.T) {
ctx := context.TODO()
req := NewRequest("go.micro.service.foo", "Foo.Bar", nil)
t.Run("CacheMiss", func(t *testing.T) {
if _, ok := NewCache().Get(ctx, &req); ok {
t.Errorf("Expected to get no result from Get")
}
})
t.Run("CacheHit", func(t *testing.T) {
c := NewCache()
rsp := "theresponse"
c.Set(ctx, &req, rsp, time.Minute)
if res, ok := c.Get(ctx, &req); !ok {
t.Errorf("Expected a result, got nothing")
} else if res != rsp {
t.Errorf("Expected '%v' result, got '%v'", rsp, res)
}
})
}
func TestCacheKey(t *testing.T) {
ctx := context.TODO()
req1 := NewRequest("go.micro.service.foo", "Foo.Bar", nil)
req2 := NewRequest("go.micro.service.foo", "Foo.Baz", nil)
req3 := NewRequest("go.micro.service.foo", "Foo.Baz", "customquery")
t.Run("IdenticalRequests", func(t *testing.T) {
key1 := key(ctx, &req1)
key2 := key(ctx, &req1)
if key1 != key2 {
t.Errorf("Expected the keys to match for identical requests and context")
}
})
t.Run("DifferentRequestEndpoints", func(t *testing.T) {
key1 := key(ctx, &req1)
key2 := key(ctx, &req2)
if key1 == key2 {
t.Errorf("Expected the keys to differ for different request endpoints")
}
})
t.Run("DifferentRequestBody", func(t *testing.T) {
key1 := key(ctx, &req2)
key2 := key(ctx, &req3)
if key1 == key2 {
t.Errorf("Expected the keys to differ for different request bodies")
}
})
t.Run("DifferentMetadata", func(t *testing.T) {
mdCtx := metadata.Set(context.TODO(), "Micro-Namespace", "bar")
key1 := key(mdCtx, &req1)
key2 := key(ctx, &req1)
if key1 == key2 {
t.Errorf("Expected the keys to differ for different metadata")
}
})
}

View File

@@ -6,6 +6,7 @@ import (
"crypto/tls"
"fmt"
"net"
"reflect"
"strings"
"sync/atomic"
"time"
@@ -173,7 +174,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
return grr
}
func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, opts client.CallOptions) (client.Stream, error) {
func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
var header map[string]string
address := node.Address
@@ -199,7 +200,7 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
cf, err := g.newGRPCCodec(req.ContentType())
if err != nil {
return nil, errors.InternalServerError("go.micro.client", err.Error())
return errors.InternalServerError("go.micro.client", err.Error())
}
var dialCtx context.Context
@@ -224,7 +225,7 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
cc, err := grpc.DialContext(dialCtx, address, grpcDialOptions...)
if err != nil {
return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
}
desc := &grpc.StreamDesc{
@@ -252,7 +253,7 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
// close the connection
cc.Close()
// now return the error
return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
}
codec := &grpcCodec{
@@ -265,21 +266,25 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
r.codec = codec
}
rsp := &response{
conn: cc,
// setup the stream response
stream := &grpcStream{
context: ctx,
request: req,
response: &response{
conn: cc,
stream: st,
codec: cf,
gcodec: codec,
},
stream: st,
codec: cf,
gcodec: codec,
conn: cc,
cancel: cancel,
}
return &grpcStream{
context: ctx,
request: req,
response: rsp,
stream: st,
conn: cc,
cancel: cancel,
}, nil
// set the stream as the response
val := reflect.ValueOf(rsp).Elem()
val.Set(reflect.ValueOf(stream).Elem())
return nil
}
func (g *grpcClient) poolMaxStreams() int {
@@ -506,6 +511,14 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli
default:
}
// make a copy of stream
gstream := g.stream
// wrap the call in reverse
for i := len(callOpts.CallWrappers); i > 0; i-- {
gstream = callOpts.CallWrappers[i-1](gstream)
}
call := func(i int) (client.Stream, error) {
// call backoff first. Someone may want an initial start delay
t, err := callOpts.Backoff(ctx, req, i)
@@ -527,7 +540,10 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
}
stream, err := g.stream(ctx, node, req, callOpts)
// make the call
stream := &grpcStream{}
err = g.stream(ctx, node, req, stream, callOpts)
g.opts.Selector.Mark(service, node, err)
return stream, err
}

View File

@@ -29,6 +29,9 @@ type Options struct {
PoolSize int
PoolTTL time.Duration
// Response cache
Cache *Cache
// Middleware for client
Wrappers []Wrapper
@@ -59,6 +62,8 @@ type CallOptions struct {
StreamTimeout time.Duration
// Use the services own auth token
ServiceToken bool
// Duration to cache the response for
CacheExpiry time.Duration
// Middleware for low level call func
CallWrappers []CallWrapper
@@ -91,6 +96,7 @@ type RequestOptions struct {
func NewOptions(options ...Option) Options {
opts := Options{
Cache: NewCache(),
Context: context.Background(),
ContentType: DefaultContentType,
Codecs: make(map[string]codec.NewCodec),
@@ -324,6 +330,14 @@ func WithServiceToken() CallOption {
}
}
// WithCache is a CallOption which sets the duration the response
// shoull be cached for
func WithCache(c time.Duration) CallOption {
return func(o *CallOptions) {
o.CacheExpiry = c
}
}
func WithMessageContentType(ct string) MessageOption {
return func(o *MessageOptions) {
o.ContentType = ct

View File

@@ -114,8 +114,7 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request,
return errors.InternalServerError("go.micro.client", "connection error: %v", err)
}
seq := atomic.LoadUint64(&r.seq)
atomic.AddUint64(&r.seq, 1)
seq := atomic.AddUint64(&r.seq, 1) - 1
codec := newRpcCodec(msg, c, cf, "")
rsp := &rpcResponse{
@@ -232,8 +231,7 @@ func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request
}
// increment the sequence number
seq := atomic.LoadUint64(&r.seq)
atomic.AddUint64(&r.seq, 1)
seq := atomic.AddUint64(&r.seq, 1) - 1
id := fmt.Sprintf("%v", seq)
// create codec with stream id

View File

@@ -27,6 +27,7 @@ import (
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/store"
"github.com/micro/go-micro/v2/transport"
authutil "github.com/micro/go-micro/v2/util/auth"
"github.com/micro/go-micro/v2/util/wrapper"
// clients
@@ -278,6 +279,7 @@ var (
Name: "auth_namespace",
EnvVars: []string{"MICRO_AUTH_NAMESPACE"},
Usage: "Namespace for the services auth account",
Value: "go.micro",
},
&cli.StringFlag{
Name: "auth_public_key",
@@ -467,13 +469,16 @@ func (c *cmd) Options() Options {
func (c *cmd) Before(ctx *cli.Context) error {
// If flags are set then use them otherwise do nothing
var authOpts []auth.Option
var serverOpts []server.Option
var clientOpts []client.Option
// setup a client to use when calling the runtime
// setup a client to use when calling the runtime. It is important the auth client is wrapped
// after the cache client since the wrappers are applied in reverse order and the cache will use
// some of the headers set by the auth client.
authFn := func() auth.Auth { return *c.opts.Auth }
microClient := wrapper.AuthClient(authFn, grpc.NewClient())
cacheFn := func() *client.Cache { return (*c.opts.Client).Options().Cache }
microClient := wrapper.CacheClient(cacheFn, grpc.NewClient())
microClient = wrapper.AuthClient(authFn, microClient)
// Set the store
if name := ctx.String("store"); len(name) > 0 {
@@ -505,26 +510,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
*c.opts.Tracer = r()
}
// Set the auth
if name := ctx.String("auth"); len(name) > 0 {
a, ok := c.opts.Auths[name]
if !ok {
return fmt.Errorf("Unsupported auth: %s", name)
}
*c.opts.Auth = a(auth.WithClient(microClient))
serverOpts = append(serverOpts, server.Auth(*c.opts.Auth))
}
// Set the profile
if name := ctx.String("profile"); len(name) > 0 {
p, ok := c.opts.Profiles[name]
if !ok {
return fmt.Errorf("Unsupported profile: %s", name)
}
*c.opts.Profile = p()
}
// Set the client
if name := ctx.String("client"); len(name) > 0 {
// only change if we have the client and type differs
@@ -541,16 +526,58 @@ func (c *cmd) Before(ctx *cli.Context) error {
}
}
// Set the broker
if name := ctx.String("broker"); len(name) > 0 && (*c.opts.Broker).String() != name {
b, ok := c.opts.Brokers[name]
// Setup auth
authOpts := []auth.Option{auth.WithClient(microClient)}
if len(ctx.String("auth_id")) > 0 || len(ctx.String("auth_secret")) > 0 {
authOpts = append(authOpts, auth.Credentials(
ctx.String("auth_id"), ctx.String("auth_secret"),
))
}
if len(ctx.String("auth_public_key")) > 0 {
authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key")))
}
if len(ctx.String("auth_private_key")) > 0 {
authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key")))
}
if len(ctx.String("auth_namespace")) > 0 {
authOpts = append(authOpts, auth.Namespace(ctx.String("auth_namespace")))
}
if name := ctx.String("auth_provider"); len(name) > 0 {
p, ok := DefaultAuthProviders[name]
if !ok {
return fmt.Errorf("Broker %s not found", name)
return fmt.Errorf("AuthProvider %s not found", name)
}
*c.opts.Broker = b()
serverOpts = append(serverOpts, server.Broker(*c.opts.Broker))
clientOpts = append(clientOpts, client.Broker(*c.opts.Broker))
var provOpts []provider.Option
clientID := ctx.String("auth_provider_client_id")
clientSecret := ctx.String("auth_provider_client_secret")
if len(clientID) > 0 || len(clientSecret) > 0 {
provOpts = append(provOpts, provider.Credentials(clientID, clientSecret))
}
if e := ctx.String("auth_provider_endpoint"); len(e) > 0 {
provOpts = append(provOpts, provider.Endpoint(e))
}
if r := ctx.String("auth_provider_redirect"); len(r) > 0 {
provOpts = append(provOpts, provider.Redirect(r))
}
if s := ctx.String("auth_provider_scope"); len(s) > 0 {
provOpts = append(provOpts, provider.Scope(s))
}
authOpts = append(authOpts, auth.Provider(p(provOpts...)))
}
// Set the auth
if name := ctx.String("auth"); len(name) > 0 {
a, ok := c.opts.Auths[name]
if !ok {
return fmt.Errorf("Unsupported auth: %s", name)
}
*c.opts.Auth = a(authOpts...)
serverOpts = append(serverOpts, server.Auth(*c.opts.Auth))
} else {
(*c.opts.Auth).Init(authOpts...)
}
// Set the registry
@@ -575,6 +602,34 @@ func (c *cmd) Before(ctx *cli.Context) error {
}
}
// generate the services auth account
serverID := (*c.opts.Server).Options().Id
if err := authutil.Generate(serverID, c.App().Name, (*c.opts.Auth)); err != nil {
return err
}
// Set the profile
if name := ctx.String("profile"); len(name) > 0 {
p, ok := c.opts.Profiles[name]
if !ok {
return fmt.Errorf("Unsupported profile: %s", name)
}
*c.opts.Profile = p()
}
// Set the broker
if name := ctx.String("broker"); len(name) > 0 && (*c.opts.Broker).String() != name {
b, ok := c.opts.Brokers[name]
if !ok {
return fmt.Errorf("Broker %s not found", name)
}
*c.opts.Broker = b()
serverOpts = append(serverOpts, server.Broker(*c.opts.Broker))
clientOpts = append(clientOpts, client.Broker(*c.opts.Broker))
}
// Set the selector
if name := ctx.String("selector"); len(name) > 0 && (*c.opts.Selector).String() != name {
s, ok := c.opts.Selectors[name]
@@ -686,50 +741,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
}
}
if len(ctx.String("auth_id")) > 0 || len(ctx.String("auth_secret")) > 0 {
authOpts = append(authOpts, auth.Credentials(
ctx.String("auth_id"), ctx.String("auth_secret"),
))
}
if len(ctx.String("auth_namespace")) > 0 {
authOpts = append(authOpts, auth.Namespace(ctx.String("auth_namespace")))
}
if len(ctx.String("auth_public_key")) > 0 {
authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key")))
}
if len(ctx.String("auth_private_key")) > 0 {
authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key")))
}
if name := ctx.String("auth_provider"); len(name) > 0 {
p, ok := DefaultAuthProviders[name]
if !ok {
return fmt.Errorf("AuthProvider %s not found", name)
}
var provOpts []provider.Option
clientID := ctx.String("auth_provider_client_id")
clientSecret := ctx.String("auth_provider_client_secret")
if len(clientID) > 0 || len(clientSecret) > 0 {
provOpts = append(provOpts, provider.Credentials(clientID, clientSecret))
}
if e := ctx.String("auth_provider_endpoint"); len(e) > 0 {
provOpts = append(provOpts, provider.Endpoint(e))
}
if r := ctx.String("auth_provider_redirect"); len(r) > 0 {
provOpts = append(provOpts, provider.Redirect(r))
}
if s := ctx.String("auth_provider_scope"); len(s) > 0 {
provOpts = append(provOpts, provider.Scope(s))
}
authOpts = append(authOpts, auth.Provider(p(provOpts...)))
}
(*c.opts.Auth).Init(authOpts...)
if ctx.String("config") == "service" {
opt := config.WithSource(configSrv.NewSource(configSrc.WithClient(microClient)))
if err := (*c.opts.Config).Init(opt); err != nil {

View File

@@ -41,7 +41,6 @@ func newConfig(opts ...Option) (Config, error) {
func (c *config) Init(opts ...Option) error {
c.opts = Options{
Loader: memory.NewLoader(),
Reader: json.NewReader(),
}
c.exit = make(chan bool)
@@ -49,6 +48,11 @@ func (c *config) Init(opts ...Option) error {
o(&c.opts)
}
// default loader uses the configured reader
if c.opts.Loader == nil {
c.opts.Loader = memory.NewLoader(memory.WithReader(c.opts.Reader))
}
err := c.opts.Loader.Load(c.opts.Source...)
if err != nil {
return err
@@ -82,6 +86,11 @@ func (c *config) run() {
c.Lock()
if c.snap.Version >= snap.Version {
c.Unlock()
continue
}
// save
c.snap = snap

View File

@@ -4,12 +4,15 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
"github.com/micro/go-micro/v2/config/source"
"github.com/micro/go-micro/v2/config/source/env"
"github.com/micro/go-micro/v2/config/source/file"
"github.com/micro/go-micro/v2/config/source/memory"
)
func createFileForIssue18(t *testing.T, content string) *os.File {
@@ -127,3 +130,37 @@ func TestConfigMerge(t *testing.T) {
actualHost)
}
}
func equalS(t *testing.T, actual, expect string) {
if actual != expect {
t.Errorf("Expected %s but got %s", actual, expect)
}
}
func TestConfigWatcherDirtyOverrite(t *testing.T) {
n := runtime.GOMAXPROCS(0)
defer runtime.GOMAXPROCS(n)
runtime.GOMAXPROCS(1)
l := 100
ss := make([]source.Source, l, l)
for i := 0; i < l; i++ {
ss[i] = memory.NewSource(memory.WithJSON([]byte(fmt.Sprintf(`{"key%d": "val%d"}`, i, i))))
}
conf, _ := NewConfig()
for _, s := range ss {
_ = conf.Load(s)
}
runtime.Gosched()
for i, _ := range ss {
k := fmt.Sprintf("key%d", i)
v := fmt.Sprintf("val%d", i)
equalS(t, conf.Get(k).String(""), v)
}
}

View File

@@ -32,19 +32,21 @@ type memory struct {
watchers *list.List
}
type updateValue struct {
version string
value reader.Value
}
type watcher struct {
exit chan bool
path []string
value reader.Value
reader reader.Reader
updates chan reader.Value
version string
updates chan updateValue
}
func (m *memory) watch(idx int, s source.Source) {
m.Lock()
m.sets = append(m.sets, &source.ChangeSet{Source: s.String()})
m.Unlock()
// watches a source for changes
watch := func(idx int, s source.Watcher) error {
for {
@@ -70,7 +72,7 @@ func (m *memory) watch(idx int, s source.Source) {
m.vals, _ = m.opts.Reader.Values(set)
m.snap = &loader.Snapshot{
ChangeSet: set,
Version: fmt.Sprintf("%d", time.Now().Unix()),
Version: genVer(),
}
m.Unlock()
@@ -141,7 +143,7 @@ func (m *memory) reload() error {
m.vals, _ = m.opts.Reader.Values(set)
m.snap = &loader.Snapshot{
ChangeSet: set,
Version: fmt.Sprintf("%d", time.Now().Unix()),
Version: genVer(),
}
m.Unlock()
@@ -159,11 +161,23 @@ func (m *memory) update() {
for e := m.watchers.Front(); e != nil; e = e.Next() {
watchers = append(watchers, e.Value.(*watcher))
}
vals := m.vals
snap := m.snap
m.RUnlock()
for _, w := range watchers {
if w.version >= snap.Version {
continue
}
uv := updateValue{
version: m.snap.Version,
value: vals.Get(w.path...),
}
select {
case w.updates <- m.vals.Get(w.path...):
case w.updates <- uv:
default:
}
}
@@ -226,7 +240,7 @@ func (m *memory) Sync() error {
m.vals = vals
m.snap = &loader.Snapshot{
ChangeSet: set,
Version: fmt.Sprintf("%d", time.Now().Unix()),
Version: genVer(),
}
m.Unlock()
@@ -285,6 +299,7 @@ func (m *memory) Get(path ...string) (reader.Value, error) {
}
// ok we're going hardcore now
return nil, errors.New("no values")
}
@@ -333,7 +348,8 @@ func (m *memory) Watch(path ...string) (loader.Watcher, error) {
path: path,
value: value,
reader: m.opts.Reader,
updates: make(chan reader.Value, 1),
updates: make(chan updateValue, 1),
version: m.snap.Version,
}
e := m.watchers.PushBack(w)
@@ -355,28 +371,43 @@ func (m *memory) String() string {
}
func (w *watcher) Next() (*loader.Snapshot, error) {
update := func(v reader.Value) *loader.Snapshot {
w.value = v
cs := &source.ChangeSet{
Data: v.Bytes(),
Format: w.reader.String(),
Source: "memory",
Timestamp: time.Now(),
}
cs.Checksum = cs.Sum()
return &loader.Snapshot{
ChangeSet: cs,
Version: w.version,
}
}
for {
select {
case <-w.exit:
return nil, errors.New("watcher stopped")
case v := <-w.updates:
case uv := <-w.updates:
if uv.version <= w.version {
continue
}
v := uv.value
w.version = uv.version
if bytes.Equal(w.value.Bytes(), v.Bytes()) {
continue
}
w.value = v
cs := &source.ChangeSet{
Data: v.Bytes(),
Format: w.reader.String(),
Source: "memory",
Timestamp: time.Now(),
}
cs.Sum()
return &loader.Snapshot{
ChangeSet: cs,
Version: fmt.Sprintf("%d", time.Now().Unix()),
}, nil
return update(v), nil
}
}
}
@@ -386,10 +417,16 @@ func (w *watcher) Stop() error {
case <-w.exit:
default:
close(w.exit)
close(w.updates)
}
return nil
}
func genVer() string {
return fmt.Sprintf("%d", time.Now().UnixNano())
}
func NewLoader(opts ...loader.Option) loader.Loader {
options := loader.Options{
Reader: json.NewReader(),
@@ -406,7 +443,10 @@ func NewLoader(opts ...loader.Option) loader.Loader {
sources: options.Source,
}
m.sets = make([]*source.ChangeSet, len(options.Source))
for i, s := range options.Source {
m.sets[i] = &source.ChangeSet{Source: s.String()}
go m.watch(i, s)
}

View File

@@ -42,6 +42,7 @@ func (s *memory) Watch() (source.Watcher, error) {
}
func (m *memory) Write(cs *source.ChangeSet) error {
m.Update(cs)
return nil
}

View File

@@ -2,10 +2,12 @@ package service
import (
"context"
"net/http"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/config/source"
proto "github.com/micro/go-micro/v2/config/source/service/proto"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/logger"
)
@@ -29,7 +31,9 @@ func (m *service) Read() (set *source.ChangeSet, err error) {
Namespace: m.namespace,
Path: m.path,
})
if err != nil {
if verr, ok := err.(*errors.Error); ok && verr.Code == http.StatusNotFound {
return nil, nil
} else if err != nil {
return nil, err
}

View File

@@ -5,6 +5,7 @@ import (
"context"
"time"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/debug/log"
proto "github.com/micro/go-micro/v2/debug/service/proto"
"github.com/micro/go-micro/v2/debug/stats"
@@ -13,11 +14,12 @@ import (
)
// NewHandler returns an instance of the Debug Handler
func NewHandler() *Debug {
func NewHandler(c client.Client) *Debug {
return &Debug{
log: log.DefaultLog,
stats: stats.DefaultStats,
trace: trace.DefaultTracer,
cache: c.Options().Cache,
}
}
@@ -30,6 +32,8 @@ type Debug struct {
stats stats.Stats
// the tracer
trace trace.Tracer
// the cache
cache *client.Cache
}
func (d *Debug) Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error {
@@ -164,3 +168,9 @@ func (d *Debug) Log(ctx context.Context, stream server.Stream) error {
return nil
}
// Cache returns all the key value pairs in the client cache
func (d *Debug) Cache(ctx context.Context, req *proto.CacheRequest, rsp *proto.CacheResponse) error {
rsp.Values = d.cache.List()
return nil
}

View File

@@ -582,6 +582,76 @@ func (m *Span) GetType() SpanType {
return SpanType_INBOUND
}
type CacheRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CacheRequest) Reset() { *m = CacheRequest{} }
func (m *CacheRequest) String() string { return proto.CompactTextString(m) }
func (*CacheRequest) ProtoMessage() {}
func (*CacheRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_df91f41a5db378e6, []int{9}
}
func (m *CacheRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CacheRequest.Unmarshal(m, b)
}
func (m *CacheRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CacheRequest.Marshal(b, m, deterministic)
}
func (m *CacheRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_CacheRequest.Merge(m, src)
}
func (m *CacheRequest) XXX_Size() int {
return xxx_messageInfo_CacheRequest.Size(m)
}
func (m *CacheRequest) XXX_DiscardUnknown() {
xxx_messageInfo_CacheRequest.DiscardUnknown(m)
}
var xxx_messageInfo_CacheRequest proto.InternalMessageInfo
type CacheResponse struct {
Values map[string]string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CacheResponse) Reset() { *m = CacheResponse{} }
func (m *CacheResponse) String() string { return proto.CompactTextString(m) }
func (*CacheResponse) ProtoMessage() {}
func (*CacheResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_df91f41a5db378e6, []int{10}
}
func (m *CacheResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CacheResponse.Unmarshal(m, b)
}
func (m *CacheResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CacheResponse.Marshal(b, m, deterministic)
}
func (m *CacheResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CacheResponse.Merge(m, src)
}
func (m *CacheResponse) XXX_Size() int {
return xxx_messageInfo_CacheResponse.Size(m)
}
func (m *CacheResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CacheResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CacheResponse proto.InternalMessageInfo
func (m *CacheResponse) GetValues() map[string]string {
if m != nil {
return m.Values
}
return nil
}
func init() {
proto.RegisterEnum("SpanType", SpanType_name, SpanType_value)
proto.RegisterType((*HealthRequest)(nil), "HealthRequest")
@@ -595,50 +665,56 @@ func init() {
proto.RegisterType((*TraceResponse)(nil), "TraceResponse")
proto.RegisterType((*Span)(nil), "Span")
proto.RegisterMapType((map[string]string)(nil), "Span.MetadataEntry")
proto.RegisterType((*CacheRequest)(nil), "CacheRequest")
proto.RegisterType((*CacheResponse)(nil), "CacheResponse")
proto.RegisterMapType((map[string]string)(nil), "CacheResponse.ValuesEntry")
}
func init() { proto.RegisterFile("debug/service/proto/debug.proto", fileDescriptor_df91f41a5db378e6) }
var fileDescriptor_df91f41a5db378e6 = []byte{
// 594 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xdb, 0x6e, 0xd3, 0x40,
0x10, 0x8d, 0xed, 0x38, 0xb1, 0xa7, 0x8d, 0xa9, 0x96, 0x8b, 0x2c, 0x73, 0x69, 0x65, 0x09, 0x29,
0x5c, 0xe4, 0x40, 0x79, 0x41, 0xf0, 0x86, 0x8a, 0x04, 0x52, 0x69, 0xa5, 0x6d, 0xfb, 0x01, 0x5b,
0x7b, 0xe4, 0x1a, 0xea, 0x0b, 0xbb, 0xeb, 0x4a, 0xf9, 0x16, 0xbe, 0x80, 0x37, 0x7e, 0x86, 0xff,
0x41, 0x7b, 0x71, 0x1b, 0x0b, 0xa1, 0x3e, 0xf0, 0xb6, 0xe7, 0xec, 0xec, 0xc9, 0xcc, 0xc9, 0xf1,
0xc0, 0x6e, 0x81, 0xe7, 0x7d, 0xb9, 0x12, 0xc8, 0xaf, 0xaa, 0x1c, 0x57, 0x1d, 0x6f, 0x65, 0xbb,
0xd2, 0x5c, 0xa6, 0xcf, 0xe9, 0x33, 0x58, 0x7c, 0x42, 0x76, 0x29, 0x2f, 0x28, 0x7e, 0xef, 0x51,
0x48, 0x12, 0xc3, 0xdc, 0x56, 0xc7, 0xce, 0x9e, 0xb3, 0x0c, 0xe9, 0x00, 0xd3, 0x25, 0x44, 0x43,
0xa9, 0xe8, 0xda, 0x46, 0x20, 0x79, 0x00, 0x33, 0x21, 0x99, 0xec, 0x85, 0x2d, 0xb5, 0x28, 0x5d,
0xc2, 0xf6, 0x89, 0x64, 0x52, 0xdc, 0xae, 0xf9, 0xdb, 0x81, 0x85, 0x2d, 0xb5, 0x9a, 0x8f, 0x20,
0x94, 0x55, 0x8d, 0x42, 0xb2, 0xba, 0xd3, 0xd5, 0x53, 0x7a, 0x43, 0x68, 0x25, 0xc9, 0xb8, 0xc4,
0x22, 0x76, 0xf5, 0xdd, 0x00, 0x55, 0x2f, 0x7d, 0xa7, 0x0a, 0x63, 0x4f, 0x5f, 0x58, 0xa4, 0xf8,
0x1a, 0xeb, 0x96, 0xaf, 0xe3, 0xa9, 0xe1, 0x0d, 0x52, 0x4a, 0xf2, 0x82, 0x23, 0x2b, 0x44, 0xec,
0x1b, 0x25, 0x0b, 0x49, 0x04, 0x6e, 0x99, 0xc7, 0x33, 0x4d, 0xba, 0x65, 0x4e, 0x12, 0x08, 0xb8,
0x19, 0x44, 0xc4, 0x73, 0xcd, 0x5e, 0x63, 0xa5, 0x8e, 0x9c, 0xb7, 0x5c, 0xc4, 0x81, 0x51, 0x37,
0x28, 0xfd, 0x0a, 0x70, 0xd8, 0x96, 0xb7, 0xce, 0x6f, 0x1c, 0xe4, 0xc8, 0x6a, 0x3d, 0x4e, 0x40,
0x2d, 0x22, 0xf7, 0xc0, 0xcf, 0xdb, 0xbe, 0x91, 0x7a, 0x18, 0x8f, 0x1a, 0xa0, 0x58, 0x51, 0x35,
0x39, 0xea, 0x51, 0x3c, 0x6a, 0x40, 0xfa, 0xcb, 0x81, 0x19, 0xc5, 0xbc, 0xe5, 0xc5, 0xdf, 0xe6,
0x79, 0x9b, 0xe6, 0xbd, 0x86, 0xa0, 0x46, 0xc9, 0x0a, 0x26, 0x59, 0xec, 0xee, 0x79, 0xcb, 0xad,
0xfd, 0xfb, 0x99, 0x79, 0x98, 0x7d, 0xb1, 0xfc, 0xc7, 0x46, 0xf2, 0x35, 0xbd, 0x2e, 0x53, 0x9d,
0xd7, 0x28, 0x04, 0x2b, 0x8d, 0xad, 0x21, 0x1d, 0x60, 0xf2, 0x1e, 0x16, 0xa3, 0x47, 0x64, 0x07,
0xbc, 0x6f, 0xb8, 0xb6, 0x03, 0xaa, 0xa3, 0x6a, 0xf7, 0x8a, 0x5d, 0xf6, 0xa8, 0x67, 0x0b, 0xa9,
0x01, 0xef, 0xdc, 0xb7, 0x4e, 0xfa, 0x04, 0xb6, 0x4f, 0x39, 0xcb, 0x71, 0x30, 0x28, 0x02, 0xb7,
0x2a, 0xec, 0x53, 0xb7, 0x2a, 0xd2, 0x97, 0xb0, 0xb0, 0xf7, 0x36, 0x15, 0x0f, 0xc1, 0x17, 0x1d,
0x6b, 0x54, 0xd0, 0x54, 0xdf, 0x7e, 0x76, 0xd2, 0xb1, 0x86, 0x1a, 0x2e, 0xfd, 0xe1, 0xc2, 0x54,
0x61, 0xf5, 0x83, 0x52, 0x3d, 0xb3, 0x4a, 0x06, 0x58, 0x71, 0x77, 0x10, 0x57, 0x9e, 0x77, 0x8c,
0xa3, 0x35, 0x37, 0xa4, 0x16, 0x11, 0x02, 0xd3, 0x86, 0xd5, 0xc6, 0xdc, 0x90, 0xea, 0xf3, 0x66,
0xde, 0xfc, 0x71, 0xde, 0x12, 0x08, 0x8a, 0x9e, 0x33, 0x59, 0xb5, 0x8d, 0xcd, 0xca, 0x35, 0x26,
0xab, 0x0d, 0xa3, 0xe7, 0xba, 0xe1, 0xbb, 0xba, 0xe1, 0x7f, 0xda, 0xfc, 0x18, 0xa6, 0x72, 0xdd,
0xa1, 0x0e, 0x51, 0xb4, 0x1f, 0xea, 0xe2, 0xd3, 0x75, 0x87, 0x54, 0xd3, 0xff, 0xe5, 0xf5, 0xf3,
0xa7, 0x10, 0x0c, 0x72, 0x64, 0x0b, 0xe6, 0x9f, 0x8f, 0x3e, 0x1c, 0x9f, 0x1d, 0x1d, 0xec, 0x4c,
0xc8, 0x36, 0x04, 0xc7, 0x67, 0xa7, 0x06, 0x39, 0xfb, 0x3f, 0x1d, 0xf0, 0x0f, 0xd4, 0x62, 0x20,
0xbb, 0xe0, 0x1d, 0xb6, 0x25, 0xd9, 0xca, 0x6e, 0x12, 0x9c, 0xcc, 0x6d, 0x50, 0xd2, 0xc9, 0x2b,
0x87, 0xbc, 0x80, 0x99, 0x59, 0x04, 0x24, 0xca, 0x46, 0xcb, 0x23, 0xb9, 0x93, 0x8d, 0x37, 0x44,
0x3a, 0x21, 0x4b, 0xf0, 0xf5, 0x07, 0x4e, 0x16, 0xd9, 0xe6, 0x4e, 0x48, 0xa2, 0x6c, 0xf4, 0xdd,
0x9b, 0x4a, 0xfd, 0xa7, 0x93, 0x45, 0xb6, 0x19, 0x8e, 0x24, 0xca, 0x46, 0x59, 0x48, 0x27, 0xe7,
0x33, 0xbd, 0xbb, 0xde, 0xfc, 0x09, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x42, 0x7f, 0x05, 0xde, 0x04,
0x00, 0x00,
// 646 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xdb, 0x6e, 0xd3, 0x4a,
0x14, 0x8d, 0xed, 0x38, 0xb1, 0x77, 0x62, 0x9f, 0x6a, 0xce, 0x45, 0x96, 0x0f, 0xd0, 0xca, 0x12,
0x52, 0xb8, 0x68, 0x02, 0xe1, 0x85, 0xcb, 0x1b, 0x14, 0x09, 0xa4, 0xd2, 0x4a, 0xd3, 0x96, 0xf7,
0xa9, 0x3d, 0x4a, 0x03, 0xf5, 0x85, 0x99, 0x71, 0xa5, 0xbc, 0xf0, 0x23, 0xfc, 0x04, 0xff, 0x82,
0xf8, 0x1f, 0x34, 0x17, 0xb7, 0xb6, 0x10, 0xaa, 0x10, 0x6f, 0x5e, 0x6b, 0xaf, 0xd9, 0xd9, 0x7b,
0x69, 0x65, 0xc3, 0x6e, 0xc1, 0xce, 0xda, 0xf5, 0x52, 0x30, 0x7e, 0xb9, 0xc9, 0xd9, 0xb2, 0xe1,
0xb5, 0xac, 0x97, 0x9a, 0xc3, 0xfa, 0x3b, 0xbb, 0x07, 0xd1, 0x1b, 0x46, 0x2f, 0xe4, 0x39, 0x61,
0x9f, 0x5a, 0x26, 0x24, 0x4a, 0x60, 0x6a, 0xd5, 0x89, 0xb3, 0xe7, 0x2c, 0x42, 0xd2, 0xc1, 0x6c,
0x01, 0x71, 0x27, 0x15, 0x4d, 0x5d, 0x09, 0x86, 0xfe, 0x83, 0x89, 0x90, 0x54, 0xb6, 0xc2, 0x4a,
0x2d, 0xca, 0x16, 0x30, 0x3f, 0x96, 0x54, 0x8a, 0x9b, 0x7b, 0x7e, 0x77, 0x20, 0xb2, 0x52, 0xdb,
0xf3, 0x16, 0x84, 0x72, 0x53, 0x32, 0x21, 0x69, 0xd9, 0x68, 0xf5, 0x98, 0x5c, 0x13, 0xba, 0x93,
0xa4, 0x5c, 0xb2, 0x22, 0x71, 0x75, 0xad, 0x83, 0x6a, 0x96, 0xb6, 0x51, 0xc2, 0xc4, 0xd3, 0x05,
0x8b, 0x14, 0x5f, 0xb2, 0xb2, 0xe6, 0xdb, 0x64, 0x6c, 0x78, 0x83, 0x54, 0x27, 0x79, 0xce, 0x19,
0x2d, 0x44, 0xe2, 0x9b, 0x4e, 0x16, 0xa2, 0x18, 0xdc, 0x75, 0x9e, 0x4c, 0x34, 0xe9, 0xae, 0x73,
0x94, 0x42, 0xc0, 0xcd, 0x22, 0x22, 0x99, 0x6a, 0xf6, 0x0a, 0xab, 0xee, 0x8c, 0xf3, 0x9a, 0x8b,
0x24, 0x30, 0xdd, 0x0d, 0xca, 0x3e, 0x00, 0x1c, 0xd4, 0xeb, 0x1b, 0xf7, 0x37, 0x0e, 0x72, 0x46,
0x4b, 0xbd, 0x4e, 0x40, 0x2c, 0x42, 0xff, 0x80, 0x9f, 0xd7, 0x6d, 0x25, 0xf5, 0x32, 0x1e, 0x31,
0x40, 0xb1, 0x62, 0x53, 0xe5, 0x4c, 0xaf, 0xe2, 0x11, 0x03, 0xb2, 0xaf, 0x0e, 0x4c, 0x08, 0xcb,
0x6b, 0x5e, 0xfc, 0x6c, 0x9e, 0xd7, 0x37, 0xef, 0x31, 0x04, 0x25, 0x93, 0xb4, 0xa0, 0x92, 0x26,
0xee, 0x9e, 0xb7, 0x98, 0xad, 0xfe, 0xc5, 0xe6, 0x21, 0x7e, 0x67, 0xf9, 0xd7, 0x95, 0xe4, 0x5b,
0x72, 0x25, 0x53, 0x93, 0x97, 0x4c, 0x08, 0xba, 0x36, 0xb6, 0x86, 0xa4, 0x83, 0xe9, 0x0b, 0x88,
0x06, 0x8f, 0xd0, 0x0e, 0x78, 0x1f, 0xd9, 0xd6, 0x2e, 0xa8, 0x3e, 0xd5, 0xb8, 0x97, 0xf4, 0xa2,
0x65, 0x7a, 0xb7, 0x90, 0x18, 0xf0, 0xdc, 0x7d, 0xea, 0x64, 0x77, 0x60, 0x7e, 0xc2, 0x69, 0xce,
0x3a, 0x83, 0x62, 0x70, 0x37, 0x85, 0x7d, 0xea, 0x6e, 0x8a, 0xec, 0x21, 0x44, 0xb6, 0x6e, 0x53,
0xf1, 0x3f, 0xf8, 0xa2, 0xa1, 0x95, 0x0a, 0x9a, 0x9a, 0xdb, 0xc7, 0xc7, 0x0d, 0xad, 0x88, 0xe1,
0xb2, 0x2f, 0x2e, 0x8c, 0x15, 0x56, 0x3f, 0x28, 0xd5, 0x33, 0xdb, 0xc9, 0x00, 0xdb, 0xdc, 0xed,
0x9a, 0x2b, 0xcf, 0x1b, 0xca, 0x99, 0x35, 0x37, 0x24, 0x16, 0x21, 0x04, 0xe3, 0x8a, 0x96, 0xc6,
0xdc, 0x90, 0xe8, 0xef, 0x7e, 0xde, 0xfc, 0x61, 0xde, 0x52, 0x08, 0x8a, 0x96, 0x53, 0xb9, 0xa9,
0x2b, 0x9b, 0x95, 0x2b, 0x8c, 0x96, 0x3d, 0xa3, 0xa7, 0x7a, 0xe0, 0xbf, 0xf5, 0xc0, 0xbf, 0xb4,
0xf9, 0x36, 0x8c, 0xe5, 0xb6, 0x61, 0x3a, 0x44, 0xf1, 0x2a, 0xd4, 0xe2, 0x93, 0x6d, 0xc3, 0x88,
0xa6, 0xff, 0xcc, 0xeb, 0x18, 0xe6, 0xaf, 0x68, 0x7e, 0xde, 0x79, 0x9d, 0x7d, 0x86, 0xc8, 0x62,
0xeb, 0xed, 0x0a, 0x26, 0x5a, 0xdd, 0x99, 0x9b, 0xe2, 0x41, 0x1d, 0xbf, 0xd7, 0x45, 0x33, 0xb2,
0x55, 0xa6, 0xcf, 0x60, 0xd6, 0xa3, 0x7f, 0x67, 0x9e, 0xfb, 0x77, 0x21, 0xe8, 0xd6, 0x43, 0x33,
0x98, 0xbe, 0x3d, 0x7c, 0x79, 0x74, 0x7a, 0xb8, 0xbf, 0x33, 0x42, 0x73, 0x08, 0x8e, 0x4e, 0x4f,
0x0c, 0x72, 0x56, 0xdf, 0x1c, 0xf0, 0xf7, 0xd5, 0xa1, 0x42, 0xbb, 0xe0, 0x1d, 0xd4, 0x6b, 0x34,
0xc3, 0xd7, 0xff, 0xa8, 0x74, 0x6a, 0x83, 0x9b, 0x8d, 0x1e, 0x39, 0xe8, 0x01, 0x4c, 0xcc, 0x61,
0x42, 0x31, 0x1e, 0x1c, 0xb3, 0xf4, 0x2f, 0x3c, 0xbc, 0x58, 0xd9, 0x08, 0x2d, 0xc0, 0xd7, 0x07,
0x07, 0x45, 0xb8, 0x7f, 0xa3, 0xd2, 0x18, 0x0f, 0xee, 0x90, 0x51, 0xea, 0x10, 0xa2, 0x08, 0xf7,
0xc3, 0x9a, 0xc6, 0x78, 0x90, 0x4d, 0xa3, 0xd4, 0x96, 0xa1, 0x08, 0xf7, 0xad, 0x4e, 0xe3, 0xa1,
0x93, 0xd9, 0xe8, 0x6c, 0xa2, 0xaf, 0xee, 0x93, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x22, 0x65,
0x99, 0x10, 0x98, 0x05, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -657,6 +733,7 @@ type DebugClient interface {
Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error)
Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error)
Trace(ctx context.Context, in *TraceRequest, opts ...grpc.CallOption) (*TraceResponse, error)
Cache(ctx context.Context, in *CacheRequest, opts ...grpc.CallOption) (*CacheResponse, error)
}
type debugClient struct {
@@ -726,12 +803,22 @@ func (c *debugClient) Trace(ctx context.Context, in *TraceRequest, opts ...grpc.
return out, nil
}
func (c *debugClient) Cache(ctx context.Context, in *CacheRequest, opts ...grpc.CallOption) (*CacheResponse, error) {
out := new(CacheResponse)
err := c.cc.Invoke(ctx, "/Debug/Cache", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// DebugServer is the server API for Debug service.
type DebugServer interface {
Log(*LogRequest, Debug_LogServer) error
Health(context.Context, *HealthRequest) (*HealthResponse, error)
Stats(context.Context, *StatsRequest) (*StatsResponse, error)
Trace(context.Context, *TraceRequest) (*TraceResponse, error)
Cache(context.Context, *CacheRequest) (*CacheResponse, error)
}
// UnimplementedDebugServer can be embedded to have forward compatible implementations.
@@ -750,6 +837,9 @@ func (*UnimplementedDebugServer) Stats(ctx context.Context, req *StatsRequest) (
func (*UnimplementedDebugServer) Trace(ctx context.Context, req *TraceRequest) (*TraceResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Trace not implemented")
}
func (*UnimplementedDebugServer) Cache(ctx context.Context, req *CacheRequest) (*CacheResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Cache not implemented")
}
func RegisterDebugServer(s *grpc.Server, srv DebugServer) {
s.RegisterService(&_Debug_serviceDesc, srv)
@@ -830,6 +920,24 @@ func _Debug_Trace_Handler(srv interface{}, ctx context.Context, dec func(interfa
return interceptor(ctx, in, info, handler)
}
func _Debug_Cache_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CacheRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DebugServer).Cache(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/Debug/Cache",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DebugServer).Cache(ctx, req.(*CacheRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Debug_serviceDesc = grpc.ServiceDesc{
ServiceName: "Debug",
HandlerType: (*DebugServer)(nil),
@@ -846,6 +954,10 @@ var _Debug_serviceDesc = grpc.ServiceDesc{
MethodName: "Trace",
Handler: _Debug_Trace_Handler,
},
{
MethodName: "Cache",
Handler: _Debug_Cache_Handler,
},
},
Streams: []grpc.StreamDesc{
{

View File

@@ -46,6 +46,7 @@ type DebugService interface {
Health(ctx context.Context, in *HealthRequest, opts ...client.CallOption) (*HealthResponse, error)
Stats(ctx context.Context, in *StatsRequest, opts ...client.CallOption) (*StatsResponse, error)
Trace(ctx context.Context, in *TraceRequest, opts ...client.CallOption) (*TraceResponse, error)
Cache(ctx context.Context, in *CacheRequest, opts ...client.CallOption) (*CacheResponse, error)
}
type debugService struct {
@@ -139,6 +140,16 @@ func (c *debugService) Trace(ctx context.Context, in *TraceRequest, opts ...clie
return out, nil
}
func (c *debugService) Cache(ctx context.Context, in *CacheRequest, opts ...client.CallOption) (*CacheResponse, error) {
req := c.c.NewRequest(c.name, "Debug.Cache", in)
out := new(CacheResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Debug service
type DebugHandler interface {
@@ -146,6 +157,7 @@ type DebugHandler interface {
Health(context.Context, *HealthRequest, *HealthResponse) error
Stats(context.Context, *StatsRequest, *StatsResponse) error
Trace(context.Context, *TraceRequest, *TraceResponse) error
Cache(context.Context, *CacheRequest, *CacheResponse) error
}
func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.HandlerOption) error {
@@ -154,6 +166,7 @@ func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.Han
Health(ctx context.Context, in *HealthRequest, out *HealthResponse) error
Stats(ctx context.Context, in *StatsRequest, out *StatsResponse) error
Trace(ctx context.Context, in *TraceRequest, out *TraceResponse) error
Cache(ctx context.Context, in *CacheRequest, out *CacheResponse) error
}
type Debug struct {
debug
@@ -217,3 +230,7 @@ func (h *debugHandler) Stats(ctx context.Context, in *StatsRequest, out *StatsRe
func (h *debugHandler) Trace(ctx context.Context, in *TraceRequest, out *TraceResponse) error {
return h.DebugHandler.Trace(ctx, in, out)
}
func (h *debugHandler) Cache(ctx context.Context, in *CacheRequest, out *CacheResponse) error {
return h.DebugHandler.Cache(ctx, in, out)
}

View File

@@ -1,10 +1,11 @@
syntax = "proto3";
service Debug {
rpc Log(LogRequest) returns (stream Record) {};
rpc Health(HealthRequest) returns (HealthResponse) {};
rpc Stats(StatsRequest) returns (StatsResponse) {};
rpc Log(LogRequest) returns (stream Record) {};
rpc Health(HealthRequest) returns (HealthResponse) {};
rpc Stats(StatsRequest) returns (StatsResponse) {};
rpc Trace(TraceRequest) returns (TraceResponse) {};
rpc Cache(CacheRequest) returns (CacheResponse) {};
}
message HealthRequest {
@@ -97,3 +98,9 @@ message Span {
map<string,string> metadata = 7;
SpanType type = 8;
}
message CacheRequest {}
message CacheResponse {
map<string, string> values = 1;
}

27
go.mod
View File

@@ -2,12 +2,19 @@ module github.com/micro/go-micro/v2
go 1.13
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.8
require (
github.com/BurntSushi/toml v0.3.1
github.com/bitly/go-simplejson v0.5.0
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/bwmarrin/discordgo v0.20.2
github.com/caddyserver/certmagic v0.10.6
github.com/coreos/bbolt v1.3.3 // indirect
github.com/coreos/etcd v3.3.18+incompatible
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/davecgh/go-spew v1.1.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
@@ -18,7 +25,8 @@ require (
github.com/fsouza/go-dockerclient v1.6.0
github.com/ghodss/yaml v1.0.0
github.com/go-acme/lego/v3 v3.4.0
github.com/go-git/go-git/v5 v5.0.0
github.com/go-git/go-git/v5 v5.1.0
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee
github.com/gobwas/pool v0.2.0 // indirect
github.com/gobwas/ws v1.0.3
@@ -26,16 +34,19 @@ require (
github.com/golang/protobuf v1.4.0
github.com/google/uuid v1.1.1
github.com/gorilla/handlers v1.4.2
github.com/gorilla/websocket v1.4.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.9.5 // indirect
github.com/hashicorp/hcl v1.0.0
github.com/hpcloud/tail v1.0.0
github.com/imdario/mergo v0.3.8
github.com/imdario/mergo v0.3.9
github.com/jonboulle/clockwork v0.1.0 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/kr/pretty v0.1.0
github.com/lib/pq v1.3.0
github.com/lucas-clemente/quic-go v0.14.1
github.com/micro/cli/v2 v2.1.2
github.com/micro/go-micro v1.18.0
github.com/miekg/dns v1.1.27
github.com/mitchellh/hashstructure v1.0.0
github.com/nats-io/nats-server/v2 v2.1.6 // indirect
@@ -44,16 +55,20 @@ require (
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/soheilhy/cmux v0.1.4 // indirect
github.com/stretchr/testify v1.4.0
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc // indirect
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
go.etcd.io/bbolt v1.3.4
go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1
google.golang.org/grpc v1.26.0
google.golang.org/protobuf v1.22.0
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/telegram-bot-api.v4 v4.6.4
sigs.k8s.io/yaml v1.1.0 // indirect
)

99
go.sum
View File

@@ -30,10 +30,8 @@ github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvd
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c h1:YMP6olTU903X3gxQJckdmiP8/zkSMq4kN3uipsU9XjU=
github.com/Microsoft/hcsshim v0.8.7-0.20191101173118-65519b62243c/go.mod h1:7xhjOwRV2+0HXGmM0jxaEu+ZiXJFoVZOTfL/dmqbrD8=
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
@@ -55,7 +53,6 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -65,14 +62,10 @@ github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngE
github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/bwmarrin/discordgo v0.20.1/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/bwmarrin/discordgo v0.20.2 h1:nA7jiTtqUA9lT93WL2jPjUp8ZTEInRujBdx1C9gkr20=
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/caddyserver/certmagic v0.10.6 h1:sCya6FmfaN74oZE46kqfaFOVoROD/mF36rTQfjN7TZc=
github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU=
github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -87,7 +80,6 @@ github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
@@ -96,7 +88,6 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.18+incompatible h1:Zz1aXgDrFFi1nadh58tA9ktt06cmPTwNNP3dXwIq1lE=
github.com/coreos/etcd v3.3.18+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
@@ -111,12 +102,10 @@ github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMEl
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
@@ -124,7 +113,6 @@ github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s9
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23 h1:oqgGT9O61YAYvI41EBsLePOr+LE6roB0xY4gpkZuFSE=
github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
@@ -138,7 +126,6 @@ github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1 h1:jFGzikHboUMRXmMBt
github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1/go.mod h1:HvODWzv6Y6kBf3Ah2WzN1bHjDUezGLaAhwuWVwfpEJs=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch/v5 v5.0.0 h1:dKTrUeykyQwKb/kx7Z+4ukDs6l+4L41HqG1XHnhX7WE=
@@ -151,14 +138,12 @@ github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c h1:pBgVXWDXj
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c/go.mod h1:pFdJbAhRf7rh6YYMUdIQGyzne6zYL1tCUW8QV2B3UfY=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsouza/go-dockerclient v1.4.4/go.mod h1:PrwszSL5fbmsESocROrOGq/NULMXRw+bajY0ltzD6MA=
github.com/fsouza/go-dockerclient v1.6.0 h1:f7j+AX94143JL1H3TiqSMkM4EcLDI0De1qD4GGn3Hig=
github.com/fsouza/go-dockerclient v1.6.0/go.mod h1:YWwtNPuL4XTX1SKJQk86cWPmmqwx+4np9qfPbb+znGc=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
github.com/go-acme/lego/v3 v3.4.0 h1:deB9NkelA+TfjGHVw8J7iKl/rMtffcGMWSMmptvMv0A=
github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
@@ -169,18 +154,13 @@ github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agR
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk=
github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U=
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
@@ -199,7 +179,6 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -267,7 +246,6 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
@@ -276,11 +254,9 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@@ -290,8 +266,6 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
@@ -302,28 +276,21 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
github.com/lucas-clemente/quic-go v0.12.1/go.mod h1:UXJJPE4RfFef/xPO5wQm0tITK8gNfqwTxjbE7s3Vb8s=
github.com/lucas-clemente/quic-go v0.13.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
github.com/lucas-clemente/quic-go v0.14.1 h1:c1aKoBZKOPA+49q96B1wGkibyPP0AxYh45WuAoq+87E=
github.com/lucas-clemente/quic-go v0.14.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
github.com/marten-seemann/chacha20 v0.2.0 h1:f40vqzzx+3GdOmzQoItkLX5WLvHgPgyYqFFIO5Gh4hQ=
github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE=
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
github.com/marten-seemann/qtls v0.4.1 h1:YlT8QP3WCCvvok7MGEZkMldXbyqgr8oFg5/n8Gtbkks=
github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@@ -332,21 +299,9 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mholt/certmagic v0.7.5/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ=
github.com/mholt/certmagic v0.8.3/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ=
github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA=
github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk=
github.com/micro/cli/v2 v2.1.2 h1:43J1lChg/rZCC1rvdqZNFSQDrGT7qfMrtp6/ztpIkEM=
github.com/micro/cli/v2 v2.1.2/go.mod h1:EguNh6DAoWKm9nmk+k/Rg0H3lQnDxqzu5x5srOtGtYg=
github.com/micro/go-micro v1.16.0/go.mod h1:A0F58bHLh2m0LAI9QyhvmbN8c1cxhAZo3cM6s+iDsrM=
github.com/micro/go-micro v1.18.0 h1:gP70EZVHpJuUIT0YWth192JmlIci+qMOEByHm83XE9E=
github.com/micro/go-micro v1.18.0/go.mod h1:klwUJL1gkdY1MHFyz+fFJXn52dKcty4hoe95Mp571AA=
github.com/micro/mdns v0.3.0 h1:bYycYe+98AXR3s8Nq5qvt6C573uFTDPIYzJemWON0QE=
github.com/micro/mdns v0.3.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc=
github.com/micro/protoc-gen-micro v1.0.0/go.mod h1:C8ij4DJhapBmypcT00AXdb0cZ675/3PqUO02buWWqbE=
github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -365,18 +320,12 @@ github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8d
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.0/go.mod h1:r5y0WgCag0dTj/qiHkHrXAcKQ/f5GMOZaEGdoxxnJ4I=
github.com/nats-io/nats-server/v2 v2.1.6 h1:qAaHZaS8pRRNQLFaiBA1rq5WynyEGp9DFgmMfoaiXGY=
github.com/nats-io/nats-server/v2 v2.1.6/go.mod h1:BL1NOtaBQ5/y97djERRVWNouMW7GT3gxnmbE/eC8u8A=
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nats.go v1.9.2 h1:oDeERm3NcZVrPpdR/JpGdWHMv3oJ8yY30YwxKq+DU2s=
github.com/nats-io/nats.go v1.9.2/go.mod h1:AjGArbfyR50+afOUotNX2Xs5SYHf+CoOa5HH1eEl2HE=
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.4 h1:aEsHIssIk6ETN5m2/MD8Y4B2X7FfXrBAUdkyRvbVYzA=
github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
@@ -385,7 +334,6 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249 h1:Pr5gZa2VcmktVwq0lyC39MsN5tz356vC/pQHKvq+QBo=
github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
@@ -416,7 +364,6 @@ github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgF
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -452,8 +399,6 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
@@ -467,11 +412,8 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
@@ -480,7 +422,6 @@ github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc h1:yUaosFVTJwnltaHbSNC3i82I92quFs+OFPRl8kNMVwo=
github.com/tmc/grpc-websocket-proxy v0.0.0-20200122045848-3419fae592fc/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
@@ -496,7 +437,6 @@ github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@@ -508,38 +448,32 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191108234033-bd318be0434a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -581,11 +515,11 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191011234655-491137f69257/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191109021931-daa7c04131f5/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -603,11 +537,9 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -617,19 +549,19 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@@ -655,9 +587,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -689,7 +619,6 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1 h1:aQktFqmDE2yjveXJlVIfslDFmFnUXSqG0i6KRcJAeMc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@@ -699,8 +628,6 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -720,8 +647,6 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@@ -730,12 +655,6 @@ gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g=
gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=

View File

@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
@@ -55,9 +54,28 @@ func copyFields(src map[string]interface{}) map[string]interface{} {
return dst
}
// logCallerfilePath returns a package/file:line description of the caller,
// preserving only the leaf directory name and file name.
func logCallerfilePath(loggingFilePath string) string {
parts := strings.Split(loggingFilePath, string(filepath.Separator))
return parts[len(parts)-1]
// To make sure we trim the path correctly on Windows too, we
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
// because the path given originates from Go stdlib, specifically
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
// Windows.
//
// See https://github.com/golang/go/issues/3335
// and https://github.com/golang/go/issues/18151
//
// for discussion on the issue on Go side.
idx := strings.LastIndexByte(loggingFilePath, '/')
if idx == -1 {
return loggingFilePath
}
idx = strings.LastIndexByte(loggingFilePath[:idx], '/')
if idx == -1 {
return loggingFilePath
}
return loggingFilePath[idx+1:]
}
func (l *defaultLogger) Log(level Level, v ...interface{}) {

View File

@@ -252,7 +252,7 @@ func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error
continue
}
srv, err := mdns.NewServer(&mdns.Config{Zone: s})
srv, err := mdns.NewServer(&mdns.Config{Zone: s, LocalhostChecking: true})
if err != nil {
gerr = err
continue
@@ -353,10 +353,10 @@ func (m *mdnsRegistry) GetService(service string, opts ...GetOption) ([]*Service
}
addr := ""
// prefer ipv4 addrs
if e.AddrV4 != nil {
if len(e.AddrV4) > 0 {
addr = e.AddrV4.String()
// else use ipv6
} else if e.AddrV6 != nil {
} else if len(e.AddrV6) > 0 {
addr = "[" + e.AddrV6.String() + "]"
} else {
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
@@ -563,9 +563,7 @@ func (m *mdnsWatcher) Next() (*Result, error) {
if len(m.wo.Service) > 0 && txt.Service != m.wo.Service {
continue
}
var action string
if e.TTL == 0 {
action = "delete"
} else {
@@ -584,9 +582,18 @@ func (m *mdnsWatcher) Next() (*Result, error) {
continue
}
var addr string
if len(e.AddrV4) > 0 {
addr = e.AddrV4.String()
} else if len(e.AddrV6) > 0 {
addr = "[" + e.AddrV6.String() + "]"
} else {
addr = e.Addr.String()
}
service.Nodes = append(service.Nodes, &Node{
Id: strings.TrimSuffix(e.Name, suffix),
Address: fmt.Sprintf("%s:%d", e.AddrV4.String(), e.Port),
Address: fmt.Sprintf("%s:%d", addr, e.Port),
Metadata: txt.Metadata,
})

View File

@@ -18,6 +18,9 @@ import (
"github.com/micro/go-micro/v2/runtime/local/git"
)
// defaultNamespace to use if not provided as an option
const defaultNamespace = "default"
type runtime struct {
sync.RWMutex
// options configure runtime
@@ -28,9 +31,9 @@ type runtime struct {
start chan *service
// indicates if we're running
running bool
// the service map
// TODO: track different versions of the same service
services map[string]*service
// namespaces stores services grouped by namespace, e.g. namespaces["foo"]["go.micro.auth:latest"]
// would return the latest version of go.micro.auth from the foo namespace
namespaces map[string]map[string]*service
}
// NewRuntime creates new local runtime and returns it
@@ -48,10 +51,10 @@ func NewRuntime(opts ...Option) Runtime {
_ = os.MkdirAll(path, 0755)
return &runtime{
options: options,
closed: make(chan bool),
start: make(chan *service, 128),
services: make(map[string]*service),
options: options,
closed: make(chan bool),
start: make(chan *service, 128),
namespaces: make(map[string]map[string]*service),
}
}
@@ -190,7 +193,7 @@ func (r *runtime) run(events <-chan Event) {
defer t.Stop()
// process event processes an incoming event
processEvent := func(event Event, service *service) error {
processEvent := func(event Event, service *service, ns string) error {
// get current vals
r.RLock()
name := service.Name
@@ -203,11 +206,11 @@ func (r *runtime) run(events <-chan Event) {
}
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime updating service %s", name)
logger.Debugf("Runtime updating service %s in %v namespace", name, ns)
}
// this will cause a delete followed by created
if err := r.Update(service.Service); err != nil {
if err := r.Update(service.Service, UpdateNamespace(ns)); err != nil {
return err
}
@@ -224,18 +227,20 @@ func (r *runtime) run(events <-chan Event) {
case <-t.C:
// check running services
r.RLock()
for _, service := range r.services {
if !service.ShouldStart() {
continue
}
for _, sevices := range r.namespaces {
for _, service := range sevices {
if !service.ShouldStart() {
continue
}
// TODO: check service error
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime starting %s", service.Name)
}
if err := service.Start(); err != nil {
// TODO: check service error
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime error starting %s: %v", service.Name, err)
logger.Debugf("Runtime starting %s", service.Name)
}
if err := service.Start(); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime error starting %s: %v", service.Name, err)
}
}
}
}
@@ -260,17 +265,27 @@ func (r *runtime) run(events <-chan Event) {
// NOTE: we only handle Update events for now
switch event.Type {
case Update:
if len(event.Service) > 0 {
if event.Service != nil {
ns := defaultNamespace
if event.Options != nil && len(event.Options.Namespace) > 0 {
ns = event.Options.Namespace
}
r.RLock()
service, ok := r.services[fmt.Sprintf("%v:%v", event.Service, event.Version)]
r.RUnlock()
if !ok {
if _, ok := r.namespaces[ns]; !ok {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime unknown service: %s", event.Service)
logger.Debugf("Runtime unknown namespace: %s", ns)
}
r.RUnlock()
continue
}
if err := processEvent(event, service); err != nil {
service, ok := r.namespaces[ns][fmt.Sprintf("%v:%v", event.Service.Name, event.Service.Version)]
r.RUnlock()
if !ok {
logger.Debugf("Runtime unknown service: %s", event.Service)
}
if err := processEvent(event, service, ns); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime error updating service %s: %v", event.Service, err)
}
@@ -279,14 +294,16 @@ func (r *runtime) run(events <-chan Event) {
}
r.RLock()
services := r.services
namespaces := r.namespaces
r.RUnlock()
// if blank service was received we update all services
for _, service := range services {
if err := processEvent(event, service); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime error updating service %s: %v", service.Name, err)
for ns, services := range namespaces {
for _, service := range services {
if err := processEvent(event, service, ns); err != nil {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime error updating service %s: %v", service.Name, err)
}
}
}
}
@@ -320,20 +337,25 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error {
r.Lock()
defer r.Unlock()
if _, ok := r.services[serviceKey(s)]; ok {
return errors.New("service already running")
}
var options CreateOptions
for _, o := range opts {
o(&options)
}
if len(options.Namespace) == 0 {
options.Namespace = defaultNamespace
}
if len(options.Command) == 0 {
options.Command = []string{"go"}
options.Args = []string{"run", "."}
}
if _, ok := r.namespaces[options.Namespace]; !ok {
r.namespaces[options.Namespace] = make(map[string]*service)
}
if _, ok := r.namespaces[options.Namespace][serviceKey(s)]; ok {
return errors.New("service already running")
}
// create new service
service := newService(s, options)
@@ -351,9 +373,8 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error {
if err := service.Start(); err != nil {
return err
}
// save service
r.services[serviceKey(s)] = service
r.namespaces[options.Namespace][serviceKey(s)] = service
return nil
}
@@ -481,6 +502,9 @@ func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) {
for _, o := range opts {
o(&gopts)
}
if len(gopts.Namespace) == 0 {
gopts.Namespace = defaultNamespace
}
save := func(k, v string) bool {
if len(k) == 0 {
@@ -492,7 +516,11 @@ func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) {
//nolint:prealloc
var services []*Service
for _, service := range r.services {
if _, ok := r.namespaces[gopts.Namespace]; !ok {
return make([]*Service, 0), nil
}
for _, service := range r.namespaces[gopts.Namespace] {
if !save(gopts.Service, service.Name) {
continue
}
@@ -507,22 +535,40 @@ func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) {
return services, nil
}
// Update attemps to update the service
// Update attempts to update the service
func (r *runtime) Update(s *Service, opts ...UpdateOption) error {
var options UpdateOptions
for _, o := range opts {
o(&options)
}
if len(options.Namespace) == 0 {
options.Namespace = defaultNamespace
}
err := r.checkoutSourceIfNeeded(s)
if err != nil {
return err
}
r.Lock()
service, ok := r.services[serviceKey(s)]
srvs, ok := r.namespaces[options.Namespace]
r.Unlock()
if !ok {
return errors.New("Service not found")
}
err = service.Stop()
if err != nil {
r.Lock()
service, ok := srvs[serviceKey(s)]
r.Unlock()
if !ok {
return errors.New("Service not found")
}
if err := service.Stop(); err != nil && err.Error() != "no such process" {
logger.Errorf("Error stopping service %s: %s", service.Name, err)
return err
}
return service.Start()
}
@@ -531,24 +577,41 @@ func (r *runtime) Delete(s *Service, opts ...DeleteOption) error {
r.Lock()
defer r.Unlock()
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime deleting service %s", s.Name)
var options DeleteOptions
for _, o := range opts {
o(&options)
}
if s, ok := r.services[serviceKey(s)]; ok {
// check if running
if !s.Running() {
delete(r.services, s.key())
return nil
}
// otherwise stop it
if err := s.Stop(); err != nil {
return err
}
// delete it
delete(r.services, s.key())
if len(options.Namespace) == 0 {
options.Namespace = defaultNamespace
}
srvs, ok := r.namespaces[options.Namespace]
if !ok {
return nil
}
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime deleting service %s", s.Name)
}
service, ok := srvs[serviceKey(s)]
if !ok {
return nil
}
// check if running
if !service.Running() {
delete(srvs, service.key())
r.namespaces[options.Namespace] = srvs
return nil
}
// otherwise stop it
if err := service.Stop(); err != nil {
return err
}
// delete it
delete(srvs, service.key())
r.namespaces[options.Namespace] = srvs
return nil
}
@@ -602,12 +665,15 @@ func (r *runtime) Stop() error {
r.running = false
// stop all the services
for _, service := range r.services {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime stopping %s", service.Name)
for _, services := range r.namespaces {
for _, service := range services {
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
logger.Debugf("Runtime stopping %s", service.Name)
}
service.Stop()
}
service.Stop()
}
// stop the scheduler
if r.options.Scheduler != nil {
return r.options.Scheduler.Close()

View File

@@ -167,11 +167,10 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
// parse out deployment status and inject into service metadata
if len(kdep.Status.Conditions) > 0 {
svc.Metadata["status"] = kdep.Status.Conditions[0].Type
svc.Status(kdep.Status.Conditions[0].Type, nil)
svc.Metadata["started"] = kdep.Status.Conditions[0].LastUpdateTime
delete(svc.Metadata, "error")
} else {
svc.Metadata["status"] = "n/a"
svc.Status("n/a", nil)
}
// get the real status
@@ -214,8 +213,7 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
}
}
// TODO: set from terminated
svc.Metadata["status"] = status
svc.Status(status, nil)
}
// save deployment
@@ -252,12 +250,12 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
case runtime.Update:
// only process if there's an actual service
// we do not update all the things individually
if len(event.Service) == 0 {
if event.Service == nil {
continue
}
// format the name
name := client.Format(event.Service)
name := client.Format(event.Service.Name)
// set the default labels
labels := map[string]string{
@@ -265,8 +263,8 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
"name": name,
}
if len(event.Version) > 0 {
labels["version"] = event.Version
if len(event.Service.Version) > 0 {
labels["version"] = event.Service.Version
}
// get the deployment status

View File

@@ -3,6 +3,7 @@ package kubernetes
import (
"encoding/json"
"strings"
"time"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/runtime"
@@ -185,8 +186,10 @@ func (s *service) Update(k client.Client, opts ...client.UpdateOption) error {
}
func (s *service) Status(status string, err error) {
s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
if err == nil {
s.Metadata["status"] = status
delete(s.Metadata, "error")
return
}
s.Metadata["status"] = "error"

View File

@@ -74,27 +74,18 @@ func (g libGitter) Checkout(repo, branchOrCommit string) error {
if err != nil {
return err
}
isCommit := func(s string) bool {
return strings.ContainsAny(s, "0123456789") && len(s) == 40
}
if isCommit(branchOrCommit) {
err = worktree.Checkout(&git.CheckoutOptions{
if plumbing.IsHash(branchOrCommit) {
return worktree.Checkout(&git.CheckoutOptions{
Hash: plumbing.NewHash(branchOrCommit),
Force: true,
})
if err != nil {
return err
}
} else {
err = worktree.Checkout(&git.CheckoutOptions{
Branch: plumbing.NewBranchReferenceName(branchOrCommit),
Force: true,
})
if err != nil {
return err
}
}
return nil
return worktree.Checkout(&git.CheckoutOptions{
Branch: plumbing.NewBranchReferenceName(branchOrCommit),
Force: true,
})
}
func (g libGitter) RepoDir(repo string) string {

View File

@@ -68,8 +68,7 @@ func (p *Process) Kill(pid *process.PID) error {
// now kill it
// using -ve PID kills the process group which we created in Fork()
return syscall.Kill(-id, syscall.SIGKILL)
return syscall.Kill(-id, syscall.SIGTERM)
}
func (p *Process) Wait(pid *process.PID) error {

View File

@@ -6,8 +6,8 @@ import (
"path/filepath"
"strings"
"github.com/go-git/go-git/v5"
"github.com/micro/go-micro/v2/runtime/local/source"
git "gopkg.in/src-d/go-git.v4"
)
// Source retrieves source code

View File

@@ -85,14 +85,16 @@ func (t EventType) String() string {
// Event is notification event
type Event struct {
// ID of the event
ID string
// Type is event type
Type EventType
// Timestamp is event timestamp
Timestamp time.Time
// Service is the name of the service
Service string
// Version of the build
Version string
// Service the event relates to
Service *Service
// Options to use when processing the event
Options *CreateOptions
}
// Service is runtime service

View File

@@ -93,7 +93,7 @@ func (s *service) Running() bool {
return s.running
}
// Start stars the service
// Start starts the service
func (s *service) Start() error {
s.Lock()
defer s.Unlock()
@@ -110,10 +110,7 @@ func (s *service) Start() error {
if s.Metadata == nil {
s.Metadata = make(map[string]string)
}
s.Metadata["status"] = "starting"
// delete any existing error
delete(s.Metadata, "error")
s.Status("starting", nil)
// TODO: pull source & build binary
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
@@ -122,17 +119,15 @@ func (s *service) Start() error {
p, err := s.Process.Fork(s.Exec)
if err != nil {
s.Metadata["status"] = "error"
s.Metadata["error"] = err.Error()
s.Status("error", err)
return err
}
// set the pid
s.PID = p
// set to running
s.running = true
// set status
s.Metadata["status"] = "running"
s.Status("running", nil)
// set started
s.Metadata["started"] = time.Now().Format(time.RFC3339)
@@ -146,6 +141,18 @@ func (s *service) Start() error {
return nil
}
// Status updates the status of the service. Assumes it's called under a lock as it mutates state
func (s *service) Status(status string, err error) {
s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
s.Metadata["status"] = status
if err == nil {
delete(s.Metadata, "error")
return
}
s.Metadata["error"] = err.Error()
}
// Stop stops the service
func (s *service) Stop() error {
s.Lock()
@@ -163,18 +170,17 @@ func (s *service) Stop() error {
}
// set status
s.Metadata["status"] = "stopping"
s.Status("stopping", nil)
// kill the process
err := s.Process.Kill(s.PID)
if err != nil {
return err
if err == nil {
// wait for it to exit
s.Process.Wait(s.PID)
}
// wait for it to exit
s.Process.Wait(s.PID)
// set status
s.Metadata["status"] = "stopped"
s.Status("stopped", err)
// return the kill error
return err
@@ -191,21 +197,32 @@ func (s *service) Error() error {
// Wait waits for the service to finish running
func (s *service) Wait() {
// wait for process to exit
err := s.Process.Wait(s.PID)
s.RLock()
thisPID := s.PID
s.RUnlock()
err := s.Process.Wait(thisPID)
s.Lock()
defer s.Unlock()
if s.PID.ID != thisPID.ID {
// trying to update when it's already been switched out, ignore
logger.Warnf("Trying to update a process status but PID doesn't match. Old %s, New %s. Skipping update.", thisPID.ID, s.PID.ID)
return
}
// save the error
if err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Errorf("Service %s terminated with error %s", s.Name, err)
}
s.retries++
s.Metadata["status"] = "error"
s.Metadata["error"] = err.Error()
s.Status("error", err)
s.Metadata["retries"] = strconv.Itoa(s.retries)
s.err = err
} else {
s.Metadata["status"] = "done"
s.Status("done", nil)
}
// no longer running

View File

@@ -166,9 +166,7 @@ type CreateOptions struct {
// create type of service
Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"`
// image to use
Image string `protobuf:"bytes,6,opt,name=image,proto3" json:"image,omitempty"`
// namespace to use
Namespace string `protobuf:"bytes,7,opt,name=namespace,proto3" json:"namespace,omitempty"`
Image string `protobuf:"bytes,6,opt,name=image,proto3" json:"image,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -241,13 +239,6 @@ func (m *CreateOptions) GetImage() string {
return ""
}
func (m *CreateOptions) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type CreateRequest struct {
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
Options *CreateOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
@@ -332,9 +323,7 @@ type ReadOptions struct {
// version of the service
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
// type of service
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
// namespace of service
Namespace string `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -386,13 +375,6 @@ func (m *ReadOptions) GetType() string {
return ""
}
func (m *ReadOptions) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type ReadRequest struct {
Options *ReadOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@@ -472,8 +454,6 @@ func (m *ReadResponse) GetServices() []*Service {
}
type DeleteOptions struct {
// namespace of the service
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -504,13 +484,6 @@ func (m *DeleteOptions) XXX_DiscardUnknown() {
var xxx_messageInfo_DeleteOptions proto.InternalMessageInfo
func (m *DeleteOptions) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type DeleteRequest struct {
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
Options *DeleteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
@@ -590,8 +563,6 @@ func (m *DeleteResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo
type UpdateOptions struct {
// namespace of the service
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -622,13 +593,6 @@ func (m *UpdateOptions) XXX_DiscardUnknown() {
var xxx_messageInfo_UpdateOptions proto.InternalMessageInfo
func (m *UpdateOptions) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type UpdateRequest struct {
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
Options *UpdateOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
@@ -708,8 +672,6 @@ func (m *UpdateResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo
type ListOptions struct {
// namespace to list from
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -740,13 +702,6 @@ func (m *ListOptions) XXX_DiscardUnknown() {
var xxx_messageInfo_ListOptions proto.InternalMessageInfo
func (m *ListOptions) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type ListRequest struct {
Options *ListOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
@@ -826,8 +781,6 @@ func (m *ListResponse) GetServices() []*Service {
}
type LogsOptions struct {
// namespace of the service
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -858,13 +811,6 @@ func (m *LogsOptions) XXX_DiscardUnknown() {
var xxx_messageInfo_LogsOptions proto.InternalMessageInfo
func (m *LogsOptions) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type LogsRequest struct {
// service to request logs for
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
@@ -1031,52 +977,50 @@ func init() {
}
var fileDescriptor_2434d8152598889b = []byte{
// 711 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x4d, 0x6f, 0xd3, 0x4c,
0x10, 0xae, 0x63, 0x27, 0x69, 0x27, 0x6f, 0x5e, 0x55, 0xab, 0x0a, 0x99, 0xf2, 0x15, 0x99, 0x03,
0x45, 0xa8, 0x2e, 0x4a, 0x85, 0xf8, 0x3a, 0x96, 0x94, 0x4b, 0x2b, 0x24, 0x23, 0x7e, 0xc0, 0xe2,
0x8c, 0x22, 0x8b, 0xda, 0x6b, 0xbc, 0xeb, 0x48, 0x3d, 0x71, 0xe4, 0x8f, 0x70, 0xe7, 0x67, 0x70,
0xe6, 0x1f, 0xa1, 0xfd, 0x8a, 0x3f, 0x1a, 0x47, 0xad, 0xaa, 0xde, 0x76, 0xc6, 0xb3, 0xb3, 0xcf,
0xf3, 0xcc, 0xec, 0xac, 0xe1, 0x69, 0x51, 0x66, 0x22, 0x49, 0xf1, 0x88, 0x63, 0xb1, 0x4c, 0x62,
0x3c, 0xca, 0x0b, 0x26, 0xd8, 0x91, 0xf1, 0x86, 0xca, 0x22, 0xbb, 0x0b, 0x16, 0xa6, 0x49, 0x5c,
0xb0, 0xd0, 0xf8, 0x83, 0xbf, 0x0e, 0x0c, 0x3f, 0xeb, 0x1d, 0x84, 0x80, 0x97, 0xd1, 0x14, 0x7d,
0x67, 0xe2, 0x1c, 0xec, 0x44, 0x6a, 0x4d, 0x7c, 0x18, 0x2e, 0xb1, 0xe0, 0x09, 0xcb, 0xfc, 0x9e,
0x72, 0x5b, 0x93, 0xdc, 0x83, 0x01, 0x67, 0x65, 0x11, 0xa3, 0xef, 0xaa, 0x0f, 0xc6, 0x22, 0x27,
0xb0, 0x9d, 0xa2, 0xa0, 0x73, 0x2a, 0xa8, 0xef, 0x4d, 0xdc, 0x83, 0xd1, 0xf4, 0x59, 0xd8, 0x3e,
0x36, 0x34, 0x47, 0x86, 0xe7, 0x26, 0x72, 0x96, 0x89, 0xe2, 0x32, 0x5a, 0x6d, 0xdc, 0x7f, 0x0f,
0xe3, 0xc6, 0x27, 0xb2, 0x0b, 0xee, 0x37, 0xbc, 0x34, 0xd0, 0xe4, 0x92, 0xec, 0x41, 0x7f, 0x49,
0x2f, 0x4a, 0x34, 0xb8, 0xb4, 0xf1, 0xae, 0xf7, 0xc6, 0x09, 0x52, 0xe8, 0xcf, 0x96, 0x98, 0x09,
0x49, 0x48, 0x5c, 0xe6, 0x2b, 0x42, 0x72, 0x4d, 0x1e, 0xc2, 0x8e, 0x44, 0xc0, 0x05, 0x4d, 0x73,
0xb5, 0xd5, 0x8d, 0x2a, 0x87, 0xa4, 0x6b, 0xf4, 0x33, 0xac, 0xac, 0x59, 0x17, 0xc2, 0x6b, 0x08,
0x11, 0xfc, 0x76, 0x60, 0x7c, 0x52, 0x20, 0x15, 0xf8, 0x29, 0x17, 0x09, 0xcb, 0xb8, 0x8c, 0x8d,
0x59, 0x9a, 0xd2, 0x6c, 0xee, 0x3b, 0x13, 0x57, 0xc6, 0x1a, 0x53, 0x22, 0xa2, 0xc5, 0x82, 0xfb,
0x3d, 0xe5, 0x56, 0x6b, 0x49, 0x0d, 0xb3, 0xa5, 0xef, 0x2a, 0x97, 0x5c, 0x4a, 0x69, 0x59, 0x29,
0xf2, 0x52, 0x98, 0xa3, 0x8c, 0xb5, 0xe2, 0xd3, 0xaf, 0xf1, 0xd9, 0x83, 0x7e, 0x92, 0xd2, 0x05,
0xfa, 0x03, 0x2d, 0x83, 0x32, 0x24, 0x4b, 0x59, 0x3e, 0x9e, 0xd3, 0x18, 0xfd, 0xa1, 0xfa, 0x52,
0x39, 0x82, 0x1f, 0x16, 0x70, 0x84, 0xdf, 0x4b, 0xe4, 0x82, 0x1c, 0x57, 0xb4, 0xa5, 0x56, 0xa3,
0xe9, 0xfd, 0xce, 0x92, 0x55, 0x8a, 0xbc, 0x85, 0x21, 0xd3, 0x84, 0x95, 0x8e, 0xa3, 0xe9, 0x93,
0xab, 0x9b, 0x1a, 0xba, 0x44, 0x36, 0x3e, 0xd8, 0x85, 0xff, 0x2d, 0x00, 0x9e, 0xb3, 0x8c, 0x63,
0xc0, 0x61, 0x14, 0x21, 0x9d, 0xd7, 0x14, 0xac, 0x03, 0x5a, 0x5f, 0x87, 0x56, 0x43, 0x5a, 0x75,
0xdc, 0x66, 0xb5, 0x2b, 0x1d, 0xbc, 0xb6, 0x0e, 0xa7, 0xfa, 0x50, 0xab, 0xc2, 0xeb, 0x8a, 0x90,
0x56, 0xe1, 0xd1, 0x55, 0x42, 0x35, 0x90, 0x15, 0x9d, 0x19, 0xfc, 0xa7, 0xf3, 0x68, 0x32, 0xe4,
0x15, 0x6c, 0x1b, 0xb8, 0x5c, 0x35, 0xc0, 0x46, 0x3d, 0x57, 0xa1, 0xc1, 0x21, 0x8c, 0x3f, 0xe0,
0x05, 0x56, 0x7d, 0xd4, 0x40, 0xef, 0xac, 0xa9, 0xa2, 0x0e, 0xbf, 0xf3, 0x2a, 0x36, 0x50, 0x35,
0xaa, 0x68, 0x01, 0x98, 0x2a, 0x1e, 0xc2, 0xf8, 0x4b, 0x3e, 0xa7, 0x37, 0x60, 0xa0, 0xc3, 0xef,
0x9c, 0x41, 0x03, 0x55, 0x83, 0x81, 0x05, 0x60, 0x18, 0xbc, 0x80, 0xd1, 0x59, 0xc2, 0xc5, 0xf5,
0xf0, 0x9f, 0xea, 0xe0, 0x9b, 0xf4, 0x4f, 0x2d, 0x79, 0xa3, 0x7f, 0x74, 0x9e, 0xdb, 0xf5, 0x8f,
0xc4, 0xce, 0x16, 0xfc, 0x7a, 0xd8, 0x7f, 0x39, 0x3a, 0xda, 0x82, 0xef, 0xbe, 0x71, 0x72, 0xd0,
0x8b, 0x02, 0x69, 0xaa, 0xe4, 0xdd, 0x8e, 0x8c, 0x25, 0x27, 0x4f, 0xcc, 0xca, 0x4c, 0xa8, 0x0b,
0xe7, 0x46, 0xda, 0x90, 0x5e, 0x9e, 0x64, 0xe6, 0xb6, 0xb9, 0x91, 0x36, 0xea, 0xd2, 0xf4, 0x3b,
0xa5, 0xa9, 0xb0, 0x57, 0xd2, 0xfc, 0x71, 0x60, 0xe7, 0x8c, 0x2d, 0x22, 0x8c, 0x59, 0x31, 0x6f,
0x0e, 0x6f, 0xa7, 0x3d, 0xbc, 0x67, 0xb5, 0x97, 0xa7, 0xa7, 0x64, 0x7b, 0xbe, 0xf6, 0x14, 0x9d,
0xac, 0xeb, 0xed, 0x91, 0x4a, 0xa4, 0xc8, 0xb9, 0x9c, 0xa9, 0xe6, 0x0d, 0x30, 0xe6, 0xad, 0x5e,
0xa5, 0xe9, 0x4f, 0x17, 0x86, 0x91, 0x06, 0x41, 0xce, 0x61, 0xa0, 0xe7, 0x1f, 0xe9, 0x9c, 0x99,
0xa6, 0x2e, 0xfb, 0x93, 0xee, 0x00, 0xd3, 0xb2, 0x5b, 0xe4, 0x23, 0x78, 0x72, 0xfe, 0x90, 0x8e,
0x79, 0x65, 0x53, 0x3d, 0xee, 0xfa, 0xbc, 0x4a, 0x74, 0x0e, 0x03, 0x7d, 0xa3, 0x49, 0xe7, 0x14,
0xd8, 0x80, 0xab, 0x35, 0x0c, 0x54, 0x3a, 0x7d, 0xbd, 0x48, 0xe7, 0x95, 0xdc, 0x90, 0xae, 0x75,
0x33, 0xb7, 0xc8, 0x29, 0x78, 0xb2, 0x47, 0x48, 0x47, 0xef, 0xd8, 0x54, 0x0f, 0x36, 0x14, 0x3d,
0xd8, 0x7a, 0xe9, 0x7c, 0x1d, 0xa8, 0x9f, 0xa1, 0xe3, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8e,
0x6c, 0x03, 0x59, 0x33, 0x09, 0x00, 0x00,
// 683 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x6e, 0xd3, 0x40,
0x14, 0xad, 0xe3, 0x3c, 0xda, 0x1b, 0x42, 0xab, 0x51, 0x85, 0x4c, 0x79, 0x45, 0x66, 0x41, 0xd9,
0x38, 0x28, 0x15, 0xe2, 0xb5, 0x2c, 0x09, 0x9b, 0x46, 0x48, 0x46, 0xfd, 0x80, 0xc1, 0xb9, 0x8a,
0x2c, 0x6a, 0x8f, 0xf1, 0x8c, 0x23, 0x65, 0xc5, 0x92, 0x35, 0xff, 0xc0, 0xbf, 0xb0, 0xe6, 0x8f,
0xd0, 0xbc, 0xfc, 0x48, 0xeb, 0x48, 0xa8, 0xea, 0x6e, 0xce, 0xf5, 0xcc, 0x9d, 0x73, 0xce, 0x9d,
0x7b, 0x65, 0x78, 0x9e, 0x17, 0xa9, 0x88, 0x13, 0x9c, 0x70, 0xcc, 0xd7, 0x71, 0x84, 0x93, 0x2c,
0x67, 0x82, 0x4d, 0x4c, 0x34, 0x50, 0x88, 0x1c, 0xad, 0x58, 0x90, 0xc4, 0x51, 0xce, 0x02, 0x13,
0xf7, 0xff, 0x3a, 0x30, 0xf8, 0xa2, 0x4f, 0x10, 0x02, 0xdd, 0x94, 0x26, 0xe8, 0x39, 0x63, 0xe7,
0xf4, 0x20, 0x54, 0x6b, 0xe2, 0xc1, 0x60, 0x8d, 0x39, 0x8f, 0x59, 0xea, 0x75, 0x54, 0xd8, 0x42,
0xf2, 0x00, 0xfa, 0x9c, 0x15, 0x79, 0x84, 0x9e, 0xab, 0x3e, 0x18, 0x44, 0xce, 0x61, 0x3f, 0x41,
0x41, 0x97, 0x54, 0x50, 0xaf, 0x3b, 0x76, 0x4f, 0x87, 0xd3, 0x17, 0xc1, 0xf6, 0xb5, 0x81, 0xb9,
0x32, 0x58, 0x98, 0x9d, 0xb3, 0x54, 0xe4, 0x9b, 0xb0, 0x3c, 0x78, 0xf2, 0x01, 0x46, 0x8d, 0x4f,
0xe4, 0x08, 0xdc, 0x6f, 0xb8, 0x31, 0xd4, 0xe4, 0x92, 0x1c, 0x43, 0x6f, 0x4d, 0xaf, 0x0a, 0x34,
0xbc, 0x34, 0x78, 0xdf, 0x79, 0xeb, 0xf8, 0x09, 0xf4, 0x66, 0x6b, 0x4c, 0x85, 0x14, 0x24, 0x36,
0x59, 0x29, 0x48, 0xae, 0xc9, 0x63, 0x38, 0x90, 0x0c, 0xb8, 0xa0, 0x49, 0xa6, 0x8e, 0xba, 0x61,
0x15, 0x90, 0x72, 0x8d, 0x7f, 0x46, 0x95, 0x85, 0x75, 0x23, 0xba, 0x0d, 0x23, 0xfc, 0x5f, 0x0e,
0x8c, 0xce, 0x73, 0xa4, 0x02, 0x3f, 0x67, 0x22, 0x66, 0x29, 0x97, 0x7b, 0x23, 0x96, 0x24, 0x34,
0x5d, 0x7a, 0xce, 0xd8, 0x95, 0x7b, 0x0d, 0x94, 0x8c, 0x68, 0xbe, 0xe2, 0x5e, 0x47, 0x85, 0xd5,
0x5a, 0x4a, 0xc3, 0x74, 0xed, 0xb9, 0x2a, 0x24, 0x97, 0xd2, 0x5a, 0x56, 0x88, 0xac, 0x10, 0xe6,
0x2a, 0x83, 0x4a, 0x3d, 0xbd, 0x9a, 0x9e, 0x63, 0xe8, 0xc5, 0x09, 0x5d, 0xa1, 0xd7, 0xd7, 0x36,
0x28, 0xe0, 0xff, 0xb0, 0x94, 0x42, 0xfc, 0x5e, 0x20, 0x17, 0xe4, 0xac, 0x12, 0x26, 0xdd, 0x18,
0x4e, 0x1f, 0xb6, 0x16, 0xa5, 0xd2, 0xfc, 0x0e, 0x06, 0x4c, 0x4b, 0x52, 0x4e, 0x0d, 0xa7, 0xcf,
0xae, 0x1f, 0x6a, 0x28, 0x0f, 0xed, 0x7e, 0xff, 0x08, 0xee, 0x5b, 0x02, 0x3c, 0x63, 0x29, 0x47,
0xff, 0x12, 0x86, 0x21, 0xd2, 0x65, 0xcd, 0xa3, 0x3a, 0xa1, 0x9b, 0x9d, 0xde, 0x7a, 0x72, 0x56,
0xbf, 0x5b, 0xe9, 0xf7, 0xe7, 0x3a, 0xad, 0xd5, 0xf9, 0xa6, 0xa2, 0xac, 0x75, 0x3e, 0xb9, 0x4e,
0xb9, 0x46, 0xa3, 0x22, 0x3c, 0x83, 0x7b, 0x3a, 0x8f, 0xa6, 0x4b, 0x5e, 0xc3, 0xbe, 0x21, 0xc4,
0x55, 0x11, 0x77, 0x3a, 0x56, 0x6e, 0xf5, 0x0f, 0x61, 0xf4, 0x11, 0xaf, 0xb0, 0x74, 0x44, 0x56,
0x42, 0x07, 0xee, 0xbc, 0x12, 0x8d, 0x7b, 0x1b, 0x95, 0xb0, 0x04, 0x4c, 0x25, 0x0e, 0x61, 0x74,
0x99, 0x2d, 0x69, 0x83, 0xa3, 0x0e, 0xdc, 0x39, 0xc7, 0xc6, 0xbd, 0x0d, 0x8e, 0x96, 0x80, 0xe1,
0x38, 0x82, 0xe1, 0x45, 0xcc, 0x85, 0x65, 0x38, 0xd7, 0xf0, 0x7f, 0xaa, 0x5c, 0x3b, 0xde, 0xa8,
0xb2, 0xce, 0x73, 0xbb, 0x2a, 0x4b, 0x76, 0x6c, 0xc5, 0x2d, 0xbb, 0xdf, 0x8e, 0xc6, 0x96, 0x5e,
0xfb, 0xdb, 0x96, 0x43, 0x53, 0xe4, 0x48, 0x13, 0x65, 0xd1, 0x7e, 0x68, 0x90, 0xec, 0xe2, 0x88,
0x15, 0xa9, 0x50, 0x4f, 0xdb, 0x0d, 0x35, 0x90, 0x51, 0x1e, 0xa7, 0x11, 0xaa, 0x31, 0xe0, 0x86,
0x1a, 0xd4, 0xc5, 0xf7, 0x5a, 0xc5, 0x57, 0xec, 0x2a, 0xf1, 0x7f, 0x1c, 0x38, 0xb8, 0x60, 0xab,
0x10, 0x23, 0x96, 0x2f, 0x9b, 0x83, 0xd0, 0xd9, 0x1e, 0x84, 0xb3, 0xda, 0x14, 0xef, 0x28, 0x63,
0x5e, 0xde, 0x78, 0x8b, 0x4e, 0xd6, 0x36, 0xc7, 0xa5, 0x13, 0x09, 0x72, 0x2e, 0xe7, 0x93, 0x99,
0xa7, 0x06, 0xde, 0x6a, 0xc2, 0x4f, 0x7f, 0xba, 0x30, 0x08, 0x35, 0x09, 0xb2, 0x80, 0xbe, 0x9e,
0x34, 0xa4, 0x75, 0x3a, 0x99, 0xba, 0x9c, 0x8c, 0xdb, 0x37, 0x98, 0x67, 0xb7, 0x47, 0x3e, 0x41,
0x57, 0xce, 0x01, 0xd2, 0x32, 0x37, 0x6c, 0xaa, 0xa7, 0x6d, 0x9f, 0xcb, 0x44, 0x0b, 0xe8, 0xeb,
0xbe, 0x23, 0xad, 0xbd, 0xba, 0x83, 0xd7, 0x56, 0xcb, 0xaa, 0x74, 0xba, 0x45, 0x48, 0x6b, 0x5b,
0xed, 0x48, 0xb7, 0xd5, 0x5d, 0x7b, 0x64, 0x0e, 0x5d, 0xf9, 0x46, 0x48, 0xcb, 0xdb, 0xb1, 0xa9,
0x1e, 0xed, 0x28, 0xba, 0xbf, 0xf7, 0xca, 0xf9, 0xda, 0x57, 0x3f, 0x16, 0x67, 0xff, 0x02, 0x00,
0x00, 0xff, 0xff, 0xe1, 0x5b, 0x52, 0x93, 0x7f, 0x08, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -41,8 +41,6 @@ message CreateOptions {
string type = 5;
// image to use
string image = 6;
// namespace to use
string namespace = 7;
}
message CreateRequest {
@@ -59,8 +57,6 @@ message ReadOptions {
string version = 2;
// type of service
string type = 3;
// namespace of service
string namespace = 4;
}
message ReadRequest {
@@ -72,8 +68,6 @@ message ReadResponse {
}
message DeleteOptions {
// namespace of the service
string namespace = 1;
}
message DeleteRequest {
@@ -84,8 +78,6 @@ message DeleteRequest {
message DeleteResponse {}
message UpdateOptions {
// namespace of the service
string namespace = 1;
}
message UpdateRequest {
@@ -96,8 +88,6 @@ message UpdateRequest {
message UpdateResponse {}
message ListOptions {
// namespace to list from
string namespace = 1;
}
message ListRequest {
@@ -109,8 +99,6 @@ message ListResponse {
}
message LogsOptions {
// namespace of the service
string namespace = 1;
}
message LogsRequest{

View File

@@ -54,12 +54,11 @@ func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error {
Metadata: svc.Metadata,
},
Options: &pb.CreateOptions{
Command: options.Command,
Args: options.Args,
Env: options.Env,
Type: options.Type,
Image: options.Image,
Namespace: options.Namespace,
Command: options.Command,
Args: options.Args,
Env: options.Env,
Type: options.Type,
Image: options.Image,
},
}
@@ -84,9 +83,6 @@ func (s *svc) Logs(service *runtime.Service, opts ...runtime.LogsOption) (runtim
Service: service.Name,
Stream: options.Stream,
Count: options.Count,
Options: &pb.LogsOptions{
Namespace: options.Namespace,
},
})
if err != nil {
return nil, err
@@ -176,10 +172,9 @@ func (s *svc) Read(opts ...runtime.ReadOption) ([]*runtime.Service, error) {
// runtime service create request
req := &pb.ReadRequest{
Options: &pb.ReadOptions{
Service: options.Service,
Version: options.Version,
Type: options.Type,
Namespace: options.Namespace,
Service: options.Service,
Version: options.Version,
Type: options.Type,
},
}
@@ -220,9 +215,6 @@ func (s *svc) Update(svc *runtime.Service, opts ...runtime.UpdateOption) error {
Source: svc.Source,
Metadata: svc.Metadata,
},
Options: &pb.UpdateOptions{
Namespace: options.Namespace,
},
}
if _, err := s.runtime.Update(options.Context, req); err != nil {
@@ -250,9 +242,6 @@ func (s *svc) Delete(svc *runtime.Service, opts ...runtime.DeleteOption) error {
Source: svc.Source,
Metadata: svc.Metadata,
},
Options: &pb.DeleteOptions{
Namespace: options.Namespace,
},
}
if _, err := s.runtime.Delete(options.Context, req); err != nil {

View File

@@ -22,6 +22,7 @@ import (
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/util/addr"
"github.com/micro/go-micro/v2/util/backoff"
mgrpc "github.com/micro/go-micro/v2/util/grpc"
mnet "github.com/micro/go-micro/v2/util/net"
"golang.org/x/net/netutil"
@@ -566,16 +567,36 @@ func (g *grpcServer) Subscribe(sb server.Subscriber) error {
}
func (g *grpcServer) Register() error {
g.RLock()
rsvc := g.rsvc
config := g.opts
g.RUnlock()
regFunc := func(service *registry.Service) error {
var regErr error
for i := 0; i < 3; i++ {
// set the ttl
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
// attempt to register
if err := config.Registry.Register(service, rOpts...); err != nil {
// set the error
regErr = err
// backoff then retry
time.Sleep(backoff.Do(i + 1))
continue
}
// success so nil error
regErr = nil
break
}
return regErr
}
// if service already filled, reuse it and return early
if rsvc != nil {
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
if err := config.Registry.Register(rsvc, rOpts...); err != nil {
if err := regFunc(rsvc); err != nil {
return err
}
return nil
@@ -677,10 +698,8 @@ func (g *grpcServer) Register() error {
}
}
// create registry options
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
if err := config.Registry.Register(service, rOpts...); err != nil {
// register the service
if err := regFunc(service); err != nil {
return err
}

View File

@@ -87,7 +87,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
contextType = mtype.In(1)
default:
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
logger.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
}
return nil
}
@@ -97,7 +97,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
if !argType.Implements(streamType) {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error(mname, "argument does not implement Streamer interface:", argType)
logger.Errorf("%v argument does not implement Streamer interface: %v", mname, argType)
}
return nil
}
@@ -107,14 +107,14 @@ func prepareEndpoint(method reflect.Method) *methodType {
// First arg need not be a pointer.
if !isExportedOrBuiltinType(argType) {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error(mname, "argument type not exported:", argType)
logger.Errorf("%v argument type not exported: %v", mname, argType)
}
return nil
}
if replyType.Kind() != reflect.Ptr {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error("method", mname, "reply type not a pointer:", replyType)
logger.Errorf("method %v reply type not a pointer: %v", mname, replyType)
}
return nil
}
@@ -122,7 +122,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
// Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error("method", mname, "reply type not exported:", replyType)
logger.Errorf("method %v reply type not exported: %v", mname, replyType)
}
return nil
}
@@ -131,14 +131,14 @@ func prepareEndpoint(method reflect.Method) *methodType {
// Endpoint() needs one out.
if mtype.NumOut() != 1 {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error("method", mname, "has wrong number of outs:", mtype.NumOut())
logger.Errorf("method %v has wrong number of outs: %v", mname, mtype.NumOut())
}
return nil
}
// The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error("method", mname, "returns", returnType.String(), "not error")
logger.Errorf("method %v returns %v not error", mname, returnType.String())
}
return nil
}
@@ -156,7 +156,7 @@ func (server *rServer) register(rcvr interface{}) error {
s.rcvr = reflect.ValueOf(rcvr)
sname := reflect.Indirect(s.rcvr).Type().Name()
if sname == "" {
logger.Fatal("rpc: no service name for type", s.typ.String())
logger.Fatalf("rpc: no service name for type %v", s.typ.String())
}
if !isExported(sname) {
s := "rpc Register: type " + sname + " is not exported"

View File

@@ -1,350 +1,324 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.22.0
// protoc v3.6.1
// source: github.com/micro/go-micro/server/proto/server.proto
// source: server/proto/server.proto
package go_micro_server
import (
context "context"
fmt "fmt"
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type HandleRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
Endpoint string `protobuf:"bytes,2,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"`
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
Endpoint string `protobuf:"bytes,2,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *HandleRequest) Reset() {
*x = HandleRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HandleRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HandleRequest) ProtoMessage() {}
func (x *HandleRequest) ProtoReflect() protoreflect.Message {
mi := &file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HandleRequest.ProtoReflect.Descriptor instead.
func (m *HandleRequest) Reset() { *m = HandleRequest{} }
func (m *HandleRequest) String() string { return proto.CompactTextString(m) }
func (*HandleRequest) ProtoMessage() {}
func (*HandleRequest) Descriptor() ([]byte, []int) {
return file_github_com_micro_go_micro_server_proto_server_proto_rawDescGZIP(), []int{0}
return fileDescriptor_1959cecd4d1121a1, []int{0}
}
func (x *HandleRequest) GetService() string {
if x != nil {
return x.Service
func (m *HandleRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HandleRequest.Unmarshal(m, b)
}
func (m *HandleRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HandleRequest.Marshal(b, m, deterministic)
}
func (m *HandleRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_HandleRequest.Merge(m, src)
}
func (m *HandleRequest) XXX_Size() int {
return xxx_messageInfo_HandleRequest.Size(m)
}
func (m *HandleRequest) XXX_DiscardUnknown() {
xxx_messageInfo_HandleRequest.DiscardUnknown(m)
}
var xxx_messageInfo_HandleRequest proto.InternalMessageInfo
func (m *HandleRequest) GetService() string {
if m != nil {
return m.Service
}
return ""
}
func (x *HandleRequest) GetEndpoint() string {
if x != nil {
return x.Endpoint
func (m *HandleRequest) GetEndpoint() string {
if m != nil {
return m.Endpoint
}
return ""
}
func (x *HandleRequest) GetProtocol() string {
if x != nil {
return x.Protocol
func (m *HandleRequest) GetProtocol() string {
if m != nil {
return m.Protocol
}
return ""
}
type HandleResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *HandleResponse) Reset() {
*x = HandleResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *HandleResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HandleResponse) ProtoMessage() {}
func (x *HandleResponse) ProtoReflect() protoreflect.Message {
mi := &file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HandleResponse.ProtoReflect.Descriptor instead.
func (m *HandleResponse) Reset() { *m = HandleResponse{} }
func (m *HandleResponse) String() string { return proto.CompactTextString(m) }
func (*HandleResponse) ProtoMessage() {}
func (*HandleResponse) Descriptor() ([]byte, []int) {
return file_github_com_micro_go_micro_server_proto_server_proto_rawDescGZIP(), []int{1}
return fileDescriptor_1959cecd4d1121a1, []int{1}
}
func (m *HandleResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HandleResponse.Unmarshal(m, b)
}
func (m *HandleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HandleResponse.Marshal(b, m, deterministic)
}
func (m *HandleResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_HandleResponse.Merge(m, src)
}
func (m *HandleResponse) XXX_Size() int {
return xxx_messageInfo_HandleResponse.Size(m)
}
func (m *HandleResponse) XXX_DiscardUnknown() {
xxx_messageInfo_HandleResponse.DiscardUnknown(m)
}
var xxx_messageInfo_HandleResponse proto.InternalMessageInfo
type SubscribeRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"`
Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *SubscribeRequest) Reset() {
*x = SubscribeRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SubscribeRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SubscribeRequest) ProtoMessage() {}
func (x *SubscribeRequest) ProtoReflect() protoreflect.Message {
mi := &file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SubscribeRequest.ProtoReflect.Descriptor instead.
func (m *SubscribeRequest) Reset() { *m = SubscribeRequest{} }
func (m *SubscribeRequest) String() string { return proto.CompactTextString(m) }
func (*SubscribeRequest) ProtoMessage() {}
func (*SubscribeRequest) Descriptor() ([]byte, []int) {
return file_github_com_micro_go_micro_server_proto_server_proto_rawDescGZIP(), []int{2}
return fileDescriptor_1959cecd4d1121a1, []int{2}
}
func (x *SubscribeRequest) GetTopic() string {
if x != nil {
return x.Topic
func (m *SubscribeRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SubscribeRequest.Unmarshal(m, b)
}
func (m *SubscribeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SubscribeRequest.Marshal(b, m, deterministic)
}
func (m *SubscribeRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_SubscribeRequest.Merge(m, src)
}
func (m *SubscribeRequest) XXX_Size() int {
return xxx_messageInfo_SubscribeRequest.Size(m)
}
func (m *SubscribeRequest) XXX_DiscardUnknown() {
xxx_messageInfo_SubscribeRequest.DiscardUnknown(m)
}
var xxx_messageInfo_SubscribeRequest proto.InternalMessageInfo
func (m *SubscribeRequest) GetTopic() string {
if m != nil {
return m.Topic
}
return ""
}
type SubscribeResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *SubscribeResponse) Reset() {
*x = SubscribeResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SubscribeResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SubscribeResponse) ProtoMessage() {}
func (x *SubscribeResponse) ProtoReflect() protoreflect.Message {
mi := &file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SubscribeResponse.ProtoReflect.Descriptor instead.
func (m *SubscribeResponse) Reset() { *m = SubscribeResponse{} }
func (m *SubscribeResponse) String() string { return proto.CompactTextString(m) }
func (*SubscribeResponse) ProtoMessage() {}
func (*SubscribeResponse) Descriptor() ([]byte, []int) {
return file_github_com_micro_go_micro_server_proto_server_proto_rawDescGZIP(), []int{3}
return fileDescriptor_1959cecd4d1121a1, []int{3}
}
var File_github_com_micro_go_micro_server_proto_server_proto protoreflect.FileDescriptor
var file_github_com_micro_go_micro_server_proto_server_proto_rawDesc = []byte{
0x0a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x63,
0x72, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76,
0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x61, 0x0a, 0x0d, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a,
0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x10, 0x0a, 0x0e, 0x48, 0x61, 0x6e,
0x64, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x0a, 0x10, 0x53,
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x14, 0x0a, 0x05, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x74, 0x6f, 0x70, 0x69, 0x63, 0x22, 0x13, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xab, 0x01, 0x0a, 0x06, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x4b, 0x0a, 0x06, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x12,
0x1e, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x1f, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x54, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12,
0x21, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x2e, 0x73, 0x65,
0x72, 0x76, 0x65, 0x72, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
func (m *SubscribeResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SubscribeResponse.Unmarshal(m, b)
}
func (m *SubscribeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SubscribeResponse.Marshal(b, m, deterministic)
}
func (m *SubscribeResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_SubscribeResponse.Merge(m, src)
}
func (m *SubscribeResponse) XXX_Size() int {
return xxx_messageInfo_SubscribeResponse.Size(m)
}
func (m *SubscribeResponse) XXX_DiscardUnknown() {
xxx_messageInfo_SubscribeResponse.DiscardUnknown(m)
}
var (
file_github_com_micro_go_micro_server_proto_server_proto_rawDescOnce sync.Once
file_github_com_micro_go_micro_server_proto_server_proto_rawDescData = file_github_com_micro_go_micro_server_proto_server_proto_rawDesc
)
var xxx_messageInfo_SubscribeResponse proto.InternalMessageInfo
func file_github_com_micro_go_micro_server_proto_server_proto_rawDescGZIP() []byte {
file_github_com_micro_go_micro_server_proto_server_proto_rawDescOnce.Do(func() {
file_github_com_micro_go_micro_server_proto_server_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_micro_go_micro_server_proto_server_proto_rawDescData)
})
return file_github_com_micro_go_micro_server_proto_server_proto_rawDescData
func init() {
proto.RegisterType((*HandleRequest)(nil), "go.micro.server.HandleRequest")
proto.RegisterType((*HandleResponse)(nil), "go.micro.server.HandleResponse")
proto.RegisterType((*SubscribeRequest)(nil), "go.micro.server.SubscribeRequest")
proto.RegisterType((*SubscribeResponse)(nil), "go.micro.server.SubscribeResponse")
}
var file_github_com_micro_go_micro_server_proto_server_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_github_com_micro_go_micro_server_proto_server_proto_goTypes = []interface{}{
(*HandleRequest)(nil), // 0: go.micro.server.HandleRequest
(*HandleResponse)(nil), // 1: go.micro.server.HandleResponse
(*SubscribeRequest)(nil), // 2: go.micro.server.SubscribeRequest
(*SubscribeResponse)(nil), // 3: go.micro.server.SubscribeResponse
}
var file_github_com_micro_go_micro_server_proto_server_proto_depIdxs = []int32{
0, // 0: go.micro.server.Server.Handle:input_type -> go.micro.server.HandleRequest
2, // 1: go.micro.server.Server.Subscribe:input_type -> go.micro.server.SubscribeRequest
1, // 2: go.micro.server.Server.Handle:output_type -> go.micro.server.HandleResponse
3, // 3: go.micro.server.Server.Subscribe:output_type -> go.micro.server.SubscribeResponse
2, // [2:4] is the sub-list for method output_type
0, // [0:2] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
func init() { proto.RegisterFile("server/proto/server.proto", fileDescriptor_1959cecd4d1121a1) }
var fileDescriptor_1959cecd4d1121a1 = []byte{
// 223 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2c, 0x4e, 0x2d, 0x2a,
0x4b, 0x2d, 0xd2, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7, 0x87, 0x70, 0xf4, 0xc0, 0x1c, 0x21, 0xfe,
0xf4, 0x7c, 0xbd, 0xdc, 0xcc, 0xe4, 0xa2, 0x7c, 0x3d, 0x88, 0xb0, 0x52, 0x22, 0x17, 0xaf, 0x47,
0x62, 0x5e, 0x4a, 0x4e, 0x6a, 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71, 0x89, 0x90, 0x04, 0x17, 0x3b,
0x48, 0x2a, 0x33, 0x39, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x08, 0xc6, 0x15, 0x92, 0xe2,
0xe2, 0x48, 0xcd, 0x4b, 0x29, 0xc8, 0xcf, 0xcc, 0x2b, 0x91, 0x60, 0x02, 0x4b, 0xc1, 0xf9, 0x20,
0x39, 0xb0, 0x05, 0xc9, 0xf9, 0x39, 0x12, 0xcc, 0x10, 0x39, 0x18, 0x5f, 0x49, 0x80, 0x8b, 0x0f,
0x66, 0x45, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x92, 0x06, 0x97, 0x40, 0x70, 0x69, 0x52, 0x71,
0x72, 0x51, 0x66, 0x12, 0xdc, 0x5e, 0x11, 0x2e, 0xd6, 0x92, 0xfc, 0x82, 0xcc, 0x64, 0xa8, 0xad,
0x10, 0x8e, 0x92, 0x30, 0x97, 0x20, 0x92, 0x4a, 0x88, 0x76, 0xa3, 0xd5, 0x8c, 0x5c, 0x6c, 0xc1,
0x60, 0xe7, 0x0b, 0x79, 0x73, 0xb1, 0x41, 0xcc, 0x16, 0x92, 0xd3, 0x43, 0xf3, 0x9a, 0x1e, 0x8a,
0xbf, 0xa4, 0xe4, 0x71, 0xca, 0x43, 0x1d, 0xc5, 0x20, 0x14, 0xc2, 0xc5, 0x09, 0xb7, 0x4c, 0x48,
0x11, 0x43, 0x3d, 0xba, 0x93, 0xa5, 0x94, 0xf0, 0x29, 0x81, 0x99, 0x9a, 0xc4, 0x06, 0x0e, 0x08,
0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x3f, 0x79, 0x80, 0x96, 0x01, 0x00, 0x00,
}
func init() { file_github_com_micro_go_micro_server_proto_server_proto_init() }
func file_github_com_micro_go_micro_server_proto_server_proto_init() {
if File_github_com_micro_go_micro_server_proto_server_proto != nil {
return
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// ServerClient is the client API for Server service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ServerClient interface {
Handle(ctx context.Context, in *HandleRequest, opts ...grpc.CallOption) (*HandleResponse, error)
Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (*SubscribeResponse, error)
}
type serverClient struct {
cc *grpc.ClientConn
}
func NewServerClient(cc *grpc.ClientConn) ServerClient {
return &serverClient{cc}
}
func (c *serverClient) Handle(ctx context.Context, in *HandleRequest, opts ...grpc.CallOption) (*HandleResponse, error) {
out := new(HandleResponse)
err := c.cc.Invoke(ctx, "/go.micro.server.Server/Handle", in, out, opts...)
if err != nil {
return nil, err
}
if !protoimpl.UnsafeEnabled {
file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HandleRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*HandleResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubscribeRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_github_com_micro_go_micro_server_proto_server_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubscribeResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
return out, nil
}
func (c *serverClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (*SubscribeResponse, error) {
out := new(SubscribeResponse)
err := c.cc.Invoke(ctx, "/go.micro.server.Server/Subscribe", in, out, opts...)
if err != nil {
return nil, err
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_github_com_micro_go_micro_server_proto_server_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
return out, nil
}
// ServerServer is the server API for Server service.
type ServerServer interface {
Handle(context.Context, *HandleRequest) (*HandleResponse, error)
Subscribe(context.Context, *SubscribeRequest) (*SubscribeResponse, error)
}
// UnimplementedServerServer can be embedded to have forward compatible implementations.
type UnimplementedServerServer struct {
}
func (*UnimplementedServerServer) Handle(ctx context.Context, req *HandleRequest) (*HandleResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Handle not implemented")
}
func (*UnimplementedServerServer) Subscribe(ctx context.Context, req *SubscribeRequest) (*SubscribeResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Subscribe not implemented")
}
func RegisterServerServer(s *grpc.Server, srv ServerServer) {
s.RegisterService(&_Server_serviceDesc, srv)
}
func _Server_Handle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HandleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServerServer).Handle(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/go.micro.server.Server/Handle",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServerServer).Handle(ctx, req.(*HandleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Server_Subscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SubscribeRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServerServer).Subscribe(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/go.micro.server.Server/Subscribe",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServerServer).Subscribe(ctx, req.(*SubscribeRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Server_serviceDesc = grpc.ServiceDesc{
ServiceName: "go.micro.server.Server",
HandlerType: (*ServerServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Handle",
Handler: _Server_Handle_Handler,
},
GoTypes: file_github_com_micro_go_micro_server_proto_server_proto_goTypes,
DependencyIndexes: file_github_com_micro_go_micro_server_proto_server_proto_depIdxs,
MessageInfos: file_github_com_micro_go_micro_server_proto_server_proto_msgTypes,
}.Build()
File_github_com_micro_go_micro_server_proto_server_proto = out.File
file_github_com_micro_go_micro_server_proto_server_proto_rawDesc = nil
file_github_com_micro_go_micro_server_proto_server_proto_goTypes = nil
file_github_com_micro_go_micro_server_proto_server_proto_depIdxs = nil
{
MethodName: "Subscribe",
Handler: _Server_Subscribe_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "server/proto/server.proto",
}

View File

@@ -1,5 +1,5 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: github.com/micro/go-micro/server/proto/server.proto
// source: server/proto/server.proto
package go_micro_server

View File

@@ -140,7 +140,7 @@ func prepareMethod(method reflect.Method) *methodType {
replyType = mtype.In(3)
contextType = mtype.In(1)
default:
log.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
log.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
return nil
}
@@ -148,7 +148,7 @@ func prepareMethod(method reflect.Method) *methodType {
// check stream type
streamType := reflect.TypeOf((*Stream)(nil)).Elem()
if !argType.Implements(streamType) {
log.Error(mname, "argument does not implement Stream interface:", argType)
log.Errorf("%v argument does not implement Stream interface: %v", mname, argType)
return nil
}
} else {
@@ -156,30 +156,30 @@ func prepareMethod(method reflect.Method) *methodType {
// First arg need not be a pointer.
if !isExportedOrBuiltinType(argType) {
log.Error(mname, "argument type not exported:", argType)
log.Errorf("%v argument type not exported: %v", mname, argType)
return nil
}
if replyType.Kind() != reflect.Ptr {
log.Error("method", mname, "reply type not a pointer:", replyType)
log.Errorf("method %v reply type not a pointer: %v", mname, replyType)
return nil
}
// Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
log.Error("method", mname, "reply type not exported:", replyType)
log.Errorf("method %v reply type not exported: %v", mname, replyType)
return nil
}
}
// Method needs one out.
if mtype.NumOut() != 1 {
log.Error("method", mname, "has wrong number of outs:", mtype.NumOut())
log.Errorf("method %v has wrong number of outs: %v", mname, mtype.NumOut())
return nil
}
// The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError {
log.Error("method", mname, "returns", returnType.String(), "not error")
log.Errorf("method %v returns %v not error", mname, returnType.String())
return nil
}
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
@@ -508,7 +508,7 @@ func (router *router) ProcessMessage(ctx context.Context, msg Message) (err erro
defer func() {
// recover any panics
if r := recover(); r != nil {
log.Error("panic recovered: ", r)
log.Errorf("panic recovered: %v", r)
log.Error(string(debug.Stack()))
err = merrors.InternalServerError("go.micro.server", "panic recovered: %v", r)
}

View File

@@ -20,6 +20,7 @@ import (
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/util/addr"
"github.com/micro/go-micro/v2/util/backoff"
mnet "github.com/micro/go-micro/v2/util/net"
"github.com/micro/go-micro/v2/util/socket"
)
@@ -362,11 +363,12 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
r = rpcRouter{h: handler}
}
// wait for two coroutines to exit
// serve the request and process the outbound messages
wg.Add(2)
// process the outbound messages from the socket
go func(id string, psock *socket.Socket) {
// wait for processing to exit
wg.Add(1)
defer func() {
// TODO: don't hack this but if its grpc just break out of the stream
// We do this because the underlying connection is h2 and its a stream
@@ -404,9 +406,6 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
// serve the request in a go routine as this may be a stream
go func(id string, psock *socket.Socket) {
// add to the waitgroup
wg.Add(1)
defer func() {
// release the socket
pool.Release(psock)
@@ -514,18 +513,39 @@ func (s *rpcServer) Subscribe(sb Subscriber) error {
}
func (s *rpcServer) Register() error {
s.RLock()
rsvc := s.rsvc
config := s.Options()
s.RUnlock()
if rsvc != nil {
regFunc := func(service *registry.Service) error {
// create registry options
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
if err := config.Registry.Register(rsvc, rOpts...); err != nil {
return err
var regErr error
for i := 0; i < 3; i++ {
// attempt to register
if err := config.Registry.Register(service, rOpts...); err != nil {
// set the error
regErr = err
// backoff then retry
time.Sleep(backoff.Do(i + 1))
continue
}
// success so nil error
regErr = nil
break
}
return regErr
}
// have we registered before?
if rsvc != nil {
if err := regFunc(rsvc); err != nil {
return err
}
return nil
}
@@ -635,10 +655,8 @@ func (s *rpcServer) Register() error {
}
}
// create registry options
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
if err := config.Registry.Register(service, rOpts...); err != nil {
// register the service
if err := regFunc(service); err != nil {
return err
}

View File

@@ -125,7 +125,7 @@ type Handler interface {
}
// Subscriber interface represents a subscription to a given topic using
// a specific subscriber function or object with endpoints. It mirrors
// a specific subscriber function or object with endpoints. It mirrors
// the handler in its behaviour.
type Subscriber interface {
Topic() string
@@ -145,7 +145,7 @@ var (
DefaultRouter = newRpcRouter()
DefaultRegisterCheck = func(context.Context) error { return nil }
DefaultRegisterInterval = time.Second * 30
DefaultRegisterTTL = time.Minute
DefaultRegisterTTL = time.Second * 90
// NewServer creates a new server
NewServer func(...Option) Server = newRpcServer

View File

@@ -17,7 +17,6 @@ import (
"github.com/micro/go-micro/v2/plugin"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/store"
authutil "github.com/micro/go-micro/v2/util/auth"
signalutil "github.com/micro/go-micro/v2/util/signal"
"github.com/micro/go-micro/v2/util/wrapper"
)
@@ -35,13 +34,14 @@ func newService(opts ...Option) Service {
// service name
serviceName := options.Server.Options().Name
// authFn returns the auth, we pass as a function since auth
// has not yet been set at this point.
// we pass functions to the wrappers since the values can change during initialisation
authFn := func() auth.Auth { return options.Server.Options().Auth }
cacheFn := func() *client.Cache { return options.Client.Options().Cache }
// wrap client to inject From-Service header on any calls
options.Client = wrapper.FromService(serviceName, options.Client)
options.Client = wrapper.TraceCall(serviceName, trace.DefaultTracer, options.Client)
options.Client = wrapper.CacheClient(cacheFn, options.Client)
options.Client = wrapper.AuthClient(authFn, options.Client)
// wrap the server to provide handler stats
@@ -175,15 +175,10 @@ func (s *service) Stop() error {
}
func (s *service) Run() error {
// generate an auth account
if err := authutil.Generate(s.Server().Options().Id, s.Name(), s.Options().Auth); err != nil {
return err
}
// register the debug handler
s.opts.Server.Handle(
s.opts.Server.NewHandler(
handler.NewHandler(),
handler.NewHandler(s.opts.Client),
server.InternalHandler(true),
),
)

View File

@@ -28,16 +28,19 @@ func TestCache(t *testing.T) {
_, err := cachedStore.Read("test")
assert.Equal(store.ErrNotFound, err, "Read non existant key")
r1 := &store.Record{
Key: "aaa",
Value: []byte("bbb"),
Key: "aaa",
Value: []byte("bbb"),
Metadata: map[string]interface{}{},
}
r2 := &store.Record{
Key: "aaaa",
Value: []byte("bbbb"),
Key: "aaaa",
Value: []byte("bbbb"),
Metadata: map[string]interface{}{},
}
r3 := &store.Record{
Key: "aaaaa",
Value: []byte("bbbbb"),
Key: "aaaaa",
Value: []byte("bbbbb"),
Metadata: map[string]interface{}{},
}
// Write 3 records directly to l2
l2.Write(r1)

View File

@@ -11,6 +11,7 @@ import (
"time"
"github.com/lib/pq"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/store"
"github.com/pkg/errors"
)
@@ -26,11 +27,11 @@ var (
re = regexp.MustCompile("[^a-zA-Z0-9]+")
statements = map[string]string{
"list": "SELECT key, value, expiry FROM %s.%s;",
"read": "SELECT key, value, expiry FROM %s.%s WHERE key = $1;",
"readMany": "SELECT key, value, expiry FROM %s.%s WHERE key LIKE $1;",
"readOffset": "SELECT key, value, expiry FROM %s.%s WHERE key LIKE $1 ORDER BY key DESC LIMIT $2 OFFSET $3;",
"write": "INSERT INTO %s.%s(key, value, expiry) VALUES ($1, $2::bytea, $3) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, expiry = EXCLUDED.expiry;",
"list": "SELECT key, value, metadata, expiry FROM %s.%s;",
"read": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key = $1;",
"readMany": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key LIKE $1;",
"readOffset": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key LIKE $1 ORDER BY key DESC LIMIT $2 OFFSET $3;",
"write": "INSERT INTO %s.%s(key, value, metadata, expiry) VALUES ($1, $2::bytea, $3, $4) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, metadata = EXCLUDED.metadata, expiry = EXCLUDED.expiry;",
"delete": "DELETE FROM %s.%s WHERE key = $1;",
}
)
@@ -87,6 +88,10 @@ func (s *sqlStore) createDB(database, table string) error {
}
func (s *sqlStore) initDB(database, table string) error {
if s.db == nil {
return errors.New("Database connection not initialised")
}
// Create the namespace's database
_, err := s.db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s;", database))
if err != nil {
@@ -103,6 +108,7 @@ func (s *sqlStore) initDB(database, table string) error {
(
key text NOT NULL,
value bytea,
metadata JSONB,
expiry timestamp with time zone,
CONSTRAINT %s_pkey PRIMARY KEY (key)
);`, table, table))
@@ -116,6 +122,12 @@ func (s *sqlStore) initDB(database, table string) error {
return err
}
// Create Metadata Index
_, err = s.db.Exec(fmt.Sprintf(`CREATE INDEX IF NOT EXISTS "%s" ON %s.%s USING GIN ("metadata");`, "metadata_index_"+table, database, table))
if err != nil {
return err
}
return nil
}
@@ -222,9 +234,15 @@ func (s *sqlStore) List(opts ...store.ListOption) ([]string, error) {
for rows.Next() {
record := &store.Record{}
if err := rows.Scan(&record.Key, &record.Value, &timehelper); err != nil {
metadata := make(Metadata)
if err := rows.Scan(&record.Key, &record.Value, &metadata, &timehelper); err != nil {
return keys, err
}
// set the metadata
record.Metadata = toMetadata(&metadata)
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
@@ -276,12 +294,18 @@ func (s *sqlStore) Read(key string, opts ...store.ReadOption) ([]*store.Record,
row := st.QueryRow(key)
record := &store.Record{}
if err := row.Scan(&record.Key, &record.Value, &timehelper); err != nil {
metadata := make(Metadata)
if err := row.Scan(&record.Key, &record.Value, &metadata, &timehelper); err != nil {
if err == sql.ErrNoRows {
return records, store.ErrNotFound
}
return records, err
}
// set the metadata
record.Metadata = toMetadata(&metadata)
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
@@ -341,9 +365,15 @@ func (s *sqlStore) read(key string, options store.ReadOptions) ([]*store.Record,
for rows.Next() {
record := &store.Record{}
if err := rows.Scan(&record.Key, &record.Value, &timehelper); err != nil {
metadata := make(Metadata)
if err := rows.Scan(&record.Key, &record.Value, &metadata, &timehelper); err != nil {
return records, err
}
// set the metadata
record.Metadata = toMetadata(&metadata)
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
@@ -386,10 +416,15 @@ func (s *sqlStore) Write(r *store.Record, opts ...store.WriteOption) error {
}
defer st.Close()
metadata := make(Metadata)
for k, v := range r.Metadata {
metadata[k] = v
}
if r.Expiry != 0 {
_, err = st.Exec(r.Key, r.Value, time.Now().Add(r.Expiry))
_, err = st.Exec(r.Key, r.Value, metadata, time.Now().Add(r.Expiry))
} else {
_, err = st.Exec(r.Key, r.Value, nil)
_, err = st.Exec(r.Key, r.Value, metadata, nil)
}
if err != nil {
@@ -456,7 +491,11 @@ func NewStore(opts ...store.Option) store.Store {
// mark known databases
s.databases = make(map[string]bool)
// best-effort configure the store
s.configure()
if err := s.configure(); err != nil {
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
logger.Error("Error configuring store ", err)
}
}
// return store
return s

View File

@@ -0,0 +1,45 @@
package cockroach
import (
"database/sql/driver"
"encoding/json"
"errors"
)
// https://github.com/upper/db/blob/master/postgresql/custom_types.go#L43
type Metadata map[string]interface{}
// Scan satisfies the sql.Scanner interface.
func (m *Metadata) Scan(src interface{}) error {
source, ok := src.([]byte)
if !ok {
return errors.New("Type assertion .([]byte) failed.")
}
var i interface{}
err := json.Unmarshal(source, &i)
if err != nil {
return err
}
*m, ok = i.(map[string]interface{})
if !ok {
return errors.New("Type assertion .(map[string]interface{}) failed.")
}
return nil
}
// Value satisfies the driver.Valuer interface.
func (m Metadata) Value() (driver.Value, error) {
j, err := json.Marshal(m)
return j, err
}
func toMetadata(m *Metadata) map[string]interface{} {
md := make(map[string]interface{})
for k, v := range *m {
md[k] = v
}
return md
}

View File

@@ -54,6 +54,7 @@ type fileHandle struct {
type record struct {
Key string
Value []byte
Metadata map[string]interface{}
ExpiresAt time.Time
}
@@ -104,7 +105,6 @@ func (f *fileStore) getDB(database, table string) (*fileHandle, error) {
}
k := key(database, table)
f.RLock()
fd, ok := f.handles[k]
f.RUnlock()
@@ -114,6 +114,13 @@ func (f *fileStore) getDB(database, table string) (*fileHandle, error) {
return fd, nil
}
// double check locking
f.Lock()
defer f.Unlock()
if fd, ok := f.handles[k]; ok {
return fd, nil
}
// create a directory /tmp/micro
dir := filepath.Join(DefaultDir, database)
// create the database handle
@@ -124,18 +131,16 @@ func (f *fileStore) getDB(database, table string) (*fileHandle, error) {
dbPath := filepath.Join(dir, fname)
// create new db handle
// Bolt DB only allows one process to open the file R/W so make sure we're doing this under a lock
db, err := bolt.Open(dbPath, 0700, &bolt.Options{Timeout: 5 * time.Second})
if err != nil {
return nil, err
}
f.Lock()
fd = &fileHandle{
key: k,
db: db,
}
f.handles[k] = fd
f.Unlock()
return fd, nil
}
@@ -221,6 +226,11 @@ func (m *fileStore) get(fd *fileHandle, k string) (*store.Record, error) {
newRecord := &store.Record{}
newRecord.Key = storedRecord.Key
newRecord.Value = storedRecord.Value
newRecord.Metadata = make(map[string]interface{})
for k, v := range storedRecord.Metadata {
newRecord.Metadata[k] = v
}
if !storedRecord.ExpiresAt.IsZero() {
if storedRecord.ExpiresAt.Before(time.Now()) {
@@ -238,10 +248,16 @@ func (m *fileStore) set(fd *fileHandle, r *store.Record) error {
item := &record{}
item.Key = r.Key
item.Value = r.Value
item.Metadata = make(map[string]interface{})
if r.Expiry != 0 {
item.ExpiresAt = time.Now().Add(r.Expiry)
}
for k, v := range r.Metadata {
item.Metadata[k] = v
}
// marshal the data
data, _ := json.Marshal(item)
@@ -348,6 +364,7 @@ func (m *fileStore) Write(r *store.Record, opts ...store.WriteOption) error {
newRecord := store.Record{}
newRecord.Key = r.Key
newRecord.Value = r.Value
newRecord.Metadata = make(map[string]interface{})
newRecord.Expiry = r.Expiry
if !writeOpts.Expiry.IsZero() {
@@ -357,6 +374,10 @@ func (m *fileStore) Write(r *store.Record, opts ...store.WriteOption) error {
newRecord.Expiry = writeOpts.TTL
}
for k, v := range r.Metadata {
newRecord.Metadata[k] = v
}
return m.set(fd, &newRecord)
}

View File

@@ -33,9 +33,10 @@ type memoryStore struct {
store *cache.Cache
}
type internalRecord struct {
type storeRecord struct {
key string
value []byte
metadata map[string]interface{}
expiresAt time.Time
}
@@ -56,26 +57,36 @@ func (m *memoryStore) prefix(database, table string) string {
func (m *memoryStore) get(prefix, key string) (*store.Record, error) {
key = m.key(prefix, key)
var storedRecord *internalRecord
var storedRecord *storeRecord
r, found := m.store.Get(key)
if !found {
return nil, store.ErrNotFound
}
storedRecord, ok := r.(*internalRecord)
storedRecord, ok := r.(*storeRecord)
if !ok {
return nil, errors.New("Retrieved a non *internalRecord from the cache")
return nil, errors.New("Retrieved a non *storeRecord from the cache")
}
// Copy the record on the way out
newRecord := &store.Record{}
newRecord.Key = strings.TrimPrefix(storedRecord.key, prefix+"/")
newRecord.Value = make([]byte, len(storedRecord.value))
newRecord.Metadata = make(map[string]interface{})
// copy the value into the new record
copy(newRecord.Value, storedRecord.value)
// check if we need to set the expiry
if !storedRecord.expiresAt.IsZero() {
newRecord.Expiry = time.Until(storedRecord.expiresAt)
}
// copy in the metadata
for k, v := range storedRecord.metadata {
newRecord.Metadata[k] = v
}
return newRecord, nil
}
@@ -84,15 +95,24 @@ func (m *memoryStore) set(prefix string, r *store.Record) {
// copy the incoming record and then
// convert the expiry in to a hard timestamp
i := &internalRecord{}
i := &storeRecord{}
i.key = r.Key
i.value = make([]byte, len(r.Value))
i.metadata = make(map[string]interface{})
// copy the the value
copy(i.value, r.Value)
// set the expiry
if r.Expiry != 0 {
i.expiresAt = time.Now().Add(r.Expiry)
}
// set the metadata
for k, v := range r.Metadata {
i.metadata[k] = v
}
m.store.Set(key, i, r.Expiry)
}
@@ -199,6 +219,7 @@ func (m *memoryStore) Write(r *store.Record, opts ...store.WriteOption) error {
newRecord := store.Record{}
newRecord.Key = r.Key
newRecord.Value = make([]byte, len(r.Value))
newRecord.Metadata = make(map[string]interface{})
copy(newRecord.Value, r.Value)
newRecord.Expiry = r.Expiry
@@ -208,6 +229,11 @@ func (m *memoryStore) Write(r *store.Record, opts ...store.WriteOption) error {
if writeOpts.TTL != 0 {
newRecord.Expiry = writeOpts.TTL
}
for k, v := range r.Metadata {
newRecord.Metadata[k] = v
}
m.set(prefix, &newRecord)
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: store/service/proto/store.proto
// source: github.com/micro/go-micro/store/service/proto/store.proto
package go_micro_store

View File

@@ -11,6 +11,13 @@ service Store {
rpc Tables(TablesRequest) returns (TablesResponse) {};
}
message Field {
// type of value e.g string, int, int64, bool, float64
string type = 1;
// the actual value
string value = 2;
}
message Record {
// key of the record
string key = 1;
@@ -18,6 +25,8 @@ message Record {
bytes value = 2;
// time.Duration (signed int64 nanoseconds)
int64 expiry = 3;
// the associated metadata
map<string,Field> metadata = 4;
}
message ReadOptions {

View File

@@ -3,7 +3,9 @@ package service
import (
"context"
"fmt"
"io"
"reflect"
"time"
"github.com/micro/go-micro/v2/client"
@@ -137,10 +139,21 @@ func (s *serviceStore) Read(key string, opts ...store.ReadOption) ([]*store.Reco
records := make([]*store.Record, 0, len(rsp.Records))
for _, val := range rsp.Records {
metadata := make(map[string]interface{})
for k, v := range val.Metadata {
switch v.Type {
// TODO: parse all types
default:
metadata[k] = v
}
}
records = append(records, &store.Record{
Key: val.Key,
Value: val.Value,
Expiry: time.Duration(val.Expiry) * time.Second,
Key: val.Key,
Value: val.Value,
Expiry: time.Duration(val.Expiry) * time.Second,
Metadata: metadata,
})
}
@@ -163,11 +176,21 @@ func (s *serviceStore) Write(record *store.Record, opts ...store.WriteOption) er
Table: options.Table,
}
metadata := make(map[string]*pb.Field)
for k, v := range record.Metadata {
metadata[k] = &pb.Field{
Type: reflect.TypeOf(v).String(),
Value: fmt.Sprintf("%v", v),
}
}
_, err := s.Client.Write(s.Context(), &pb.WriteRequest{
Record: &pb.Record{
Key: record.Key,
Value: record.Value,
Expiry: int64(record.Expiry.Seconds()),
Key: record.Key,
Value: record.Value,
Expiry: int64(record.Expiry.Seconds()),
Metadata: metadata,
},
Options: writeOpts}, client.WithAddress(s.Nodes...))
if err != nil && errors.Equal(err, errors.NotFound("", "")) {

View File

@@ -36,7 +36,12 @@ type Store interface {
// Record is an item stored or retrieved from a Store
type Record struct {
Key string `json:"key"`
Value []byte `json:"value"`
// The key to store the record
Key string `json:"key"`
// The value within the record
Value []byte `json:"value"`
// Any associated metadata for indexing
Metadata map[string]interface{} `json:"metadata"`
// Time to expire a record: TODO: change to timestamp
Expiry time.Duration `json:"expiry,omitempty"`
}

View File

@@ -17,6 +17,15 @@ func init() {
}
}
// AppendPrivateBlocks append private network blocks
func AppendPrivateBlocks(bs ...string) {
for _, b := range bs {
if _, block, err := net.ParseCIDR(b); err == nil {
privateBlocks = append(privateBlocks, block)
}
}
}
func isPrivateIP(ipAddr string) bool {
ip := net.ParseIP(ipAddr)
for _, priv := range privateBlocks {
@@ -68,7 +77,7 @@ func Extract(addr string) (string, error) {
for _, iface := range ifaces {
ifaceAddrs, err := iface.Addrs()
if err != nil {
// ignore error, interface can dissapear from system
// ignore error, interface can disappear from system
continue
}
if iface.Flags&net.FlagLoopback != 0 {

View File

@@ -56,3 +56,24 @@ func TestExtractor(t *testing.T) {
}
}
func TestAppendPrivateBlocks(t *testing.T) {
tests := []struct {
addr string
expect bool
}{
{addr: "9.134.71.34", expect: true},
{addr: "8.10.110.34", expect: false}, // not in private blocks
}
AppendPrivateBlocks("9.134.0.0/16")
for _, test := range tests {
t.Run(test.addr, func(t *testing.T) {
res := isPrivateIP(test.addr)
if res != test.expect {
t.Fatalf("expected %t got %t", test.expect, res)
}
})
}
}

View File

@@ -18,17 +18,17 @@ func Generate(id string, name string, a auth.Auth) error {
// if no credentials were provided, generate an account
if len(accID) == 0 || len(accSecret) == 0 {
name := fmt.Sprintf("%v-%v", name, id)
opts := []auth.GenerateOption{
auth.WithType("service"),
auth.WithRoles("service"),
auth.WithNamespace(a.Options().Namespace),
auth.WithScopes("service"),
}
acc, err := a.Generate(name, opts...)
if err != nil {
return err
}
logger.Infof("Auth [%v] Authenticated as %v in the %v namespace", a, name, acc.Namespace)
logger.Debugf("Auth [%v] Authenticated as %v issued by %v", a, name, acc.Issuer)
accID = acc.ID
accSecret = acc.Secret
@@ -64,7 +64,7 @@ func Generate(id string, name string, a auth.Auth) error {
// generate the first token
tok, err := a.Token(
auth.WithCredentials(accID, accSecret),
auth.WithToken(tok.RefreshToken),
auth.WithExpiry(time.Minute*10),
)
if err != nil {

View File

@@ -6,7 +6,7 @@ import (
"path/filepath"
"sync"
"github.com/micro/go-micro/errors"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/server"
proto "github.com/micro/go-micro/v2/util/file/proto"

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: micro/go-micro/util/file/proto/file.proto
// source: util/file/proto/file.proto
package go_micro_server

View File

@@ -32,7 +32,7 @@ type Request struct {
err error
}
// Params is the object to pass in to set paramaters
// Params is the object to pass in to set parameters
// on a request.
type Params struct {
LabelSelector map[string]string

View File

@@ -34,7 +34,8 @@ type ServiceEntry struct {
// complete is used to check if we have all the info we need
func (s *ServiceEntry) complete() bool {
return (s.AddrV4 != nil || s.AddrV6 != nil || s.Addr != nil) && s.Port != 0 && s.hasTXT
return (len(s.AddrV4) > 0 || len(s.AddrV6) > 0 || len(s.Addr) > 0) && s.Port != 0 && s.hasTXT
}
// QueryParam is used to customize how a Lookup is performed
@@ -347,15 +348,21 @@ func (c *client) query(params *QueryParam) error {
select {
case resp := <-msgCh:
inp := messageToEntry(resp, inprogress)
if inp == nil {
continue
}
if len(resp.Question) == 0 || resp.Question[0].Name != m.Question[0].Name {
// discard anything which we've not asked for
continue
}
// Check if this entry is complete
if inp.complete() {
if inp.sent {
continue
}
inp.sent = true
select {
case params.Entries <- inp:

View File

@@ -2,13 +2,13 @@ package mdns
import (
"fmt"
"log"
"math/rand"
"net"
"sync"
"sync/atomic"
"time"
log "github.com/micro/go-micro/v2/logger"
"github.com/miekg/dns"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
@@ -39,6 +39,10 @@ var (
}
)
// GetMachineIP is a func which returns the outbound IP of this machine.
// Used by the server to determine whether to attempt send the response on a local address
type GetMachineIP func() net.IP
// Config is used to configure the mDNS server
type Config struct {
// Zone must be provided to support responding to queries
@@ -51,9 +55,15 @@ type Config struct {
// Port If it is not 0, replace the port 5353 with this port number.
Port int
// GetMachineIP is a function to return the IP of the local machine
GetMachineIP GetMachineIP
// LocalhostChecking if enabled asks the server to also send responses to 0.0.0.0 if the target IP
// is this host (as defined by GetMachineIP). Useful in case machine is on a VPN which blocks comms on non standard ports
LocalhostChecking bool
}
// mDNS server is used to listen for mDNS queries and respond if we
// Server is an mDNS server used to listen for mDNS queries and respond if we
// have a matching local record
type Server struct {
config *Config
@@ -65,6 +75,8 @@ type Server struct {
shutdownCh chan struct{}
shutdownLock sync.Mutex
wg sync.WaitGroup
outboundIP net.IP
}
// NewServer is used to create a new mDNS server from a config
@@ -118,11 +130,17 @@ func NewServer(config *Config) (*Server, error) {
}
}
ipFunc := getOutboundIP
if config.GetMachineIP != nil {
ipFunc = config.GetMachineIP
}
s := &Server{
config: config,
ipv4List: ipv4List,
ipv6List: ipv6List,
shutdownCh: make(chan struct{}),
outboundIP: ipFunc(),
}
go s.recv(s.ipv4List)
@@ -176,7 +194,7 @@ func (s *Server) recv(c *net.UDPConn) {
continue
}
if err := s.parsePacket(buf[:n], from); err != nil {
log.Printf("[ERR] mdns: Failed to handle query: %v", err)
log.Errorf("[ERR] mdns: Failed to handle query: %v", err)
}
}
}
@@ -185,7 +203,7 @@ func (s *Server) recv(c *net.UDPConn) {
func (s *Server) parsePacket(packet []byte, from net.Addr) error {
var msg dns.Msg
if err := msg.Unpack(packet); err != nil {
log.Printf("[ERR] mdns: Failed to unpack packet: %v", err)
log.Errorf("[ERR] mdns: Failed to unpack packet: %v", err)
return err
}
// TODO: This is a bit of a hack
@@ -278,8 +296,8 @@ func (s *Server) handleQuery(query *dns.Msg, from net.Addr) error {
// caveats in the RFC), so set the Compress bit (part of the dns library
// API, not part of the DNS packet) to true.
Compress: true,
Answer: answer,
Question: query.Question,
Answer: answer,
}
}
@@ -302,7 +320,6 @@ func (s *Server) handleQuery(query *dns.Msg, from net.Addr) error {
// both. The return values are DNS records for each transmission type.
func (s *Server) handleQuestion(q dns.Question) (multicastRecs, unicastRecs []dns.RR) {
records := s.config.Zone.Records(q)
if len(records) == 0 {
return nil, nil
}
@@ -365,7 +382,7 @@ func (s *Server) probe() {
for i := 0; i < 3; i++ {
if err := s.SendMulticast(q); err != nil {
log.Println("[ERR] mdns: failed to send probe:", err.Error())
log.Errorf("[ERR] mdns: failed to send probe:", err.Error())
}
time.Sleep(time.Duration(randomizer.Intn(250)) * time.Millisecond)
}
@@ -391,7 +408,7 @@ func (s *Server) probe() {
timer := time.NewTimer(timeout)
for i := 0; i < 3; i++ {
if err := s.SendMulticast(resp); err != nil {
log.Println("[ERR] mdns: failed to send announcement:", err.Error())
log.Errorf("[ERR] mdns: failed to send announcement:", err.Error())
}
select {
case <-timer.C:
@@ -404,7 +421,7 @@ func (s *Server) probe() {
}
}
// multicastResponse us used to send a multicast response packet
// SendMulticast us used to send a multicast response packet
func (s *Server) SendMulticast(msg *dns.Msg) error {
buf, err := msg.Pack()
if err != nil {
@@ -430,13 +447,23 @@ func (s *Server) sendResponse(resp *dns.Msg, from net.Addr) error {
// Determine the socket to send from
addr := from.(*net.UDPAddr)
if addr.IP.To4() != nil {
_, err = s.ipv4List.WriteToUDP(buf, addr)
return err
} else {
_, err = s.ipv6List.WriteToUDP(buf, addr)
return err
conn := s.ipv4List
backupTarget := net.IPv4zero
if addr.IP.To4() == nil {
conn = s.ipv6List
backupTarget = net.IPv6zero
}
_, err = conn.WriteToUDP(buf, addr)
// If the address we're responding to is this machine then we can also attempt sending on 0.0.0.0
// This covers the case where this machine is using a VPN and certain ports are blocked so the response never gets there
// Sending two responses is OK
if s.config.LocalhostChecking && addr.IP.Equal(s.outboundIP) {
// ignore any errors, this is best efforts
conn.WriteToUDP(buf, &net.UDPAddr{IP: backupTarget, Port: addr.Port})
}
return err
}
func (s *Server) unregister() error {
@@ -474,3 +501,17 @@ func setCustomPort(port int) {
}
}
}
// getOutboundIP returns the IP address of this machine as seen when dialling out
func getOutboundIP() net.IP {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
// no net connectivity maybe so fallback
return nil
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP
}

View File

@@ -7,7 +7,7 @@ import (
func TestServer_StartStop(t *testing.T) {
s := makeService(t)
serv, err := NewServer(&Config{Zone: s})
serv, err := NewServer(&Config{Zone: s, LocalhostChecking: true})
if err != nil {
t.Fatalf("err: %v", err)
}
@@ -15,7 +15,7 @@ func TestServer_StartStop(t *testing.T) {
}
func TestServer_Lookup(t *testing.T) {
serv, err := NewServer(&Config{Zone: makeServiceWithServiceName(t, "_foobar._tcp")})
serv, err := NewServer(&Config{Zone: makeServiceWithServiceName(t, "_foobar._tcp"), LocalhostChecking: true})
if err != nil {
t.Fatalf("err: %v", err)
}

View File

@@ -5,6 +5,7 @@ import (
"context"
"sync"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/debug/service/handler"
"github.com/micro/go-micro/v2/proxy"
"github.com/micro/go-micro/v2/server"
@@ -42,7 +43,7 @@ func New(name string, p proxy.Proxy) *Server {
server.DefaultRouter.Handle(
// inject the debug handler
server.DefaultRouter.NewHandler(
handler.NewHandler(),
handler.NewHandler(client.DefaultClient),
server.InternalHandler(true),
),
)

View File

@@ -19,12 +19,18 @@ func (p *Pool) Get(id string) (*Socket, bool) {
}
p.RUnlock()
// create new socket
socket = New(id)
// save socket
p.Lock()
defer p.Unlock()
// double checked locking
socket, ok = p.pool[id]
if ok {
return socket, ok
}
// create new socket
socket = New(id)
p.pool[id] = socket
p.Unlock()
// return socket
return socket, false
}

View File

@@ -2,8 +2,8 @@ package wrapper
import (
"context"
"reflect"
"strings"
"time"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/client"
@@ -156,9 +156,14 @@ func (a *authWrapper) Call(ctx context.Context, req client.Request, rsp interfac
return a.Client.Call(ctx, req, rsp, opts...)
}
// set the namespace header if it has not been set (e.g. on a service to service request)
if _, ok := metadata.Get(ctx, "Micro-Namespace"); !ok {
ctx = metadata.Set(ctx, "Micro-Namespace", aa.Options().Namespace)
}
// check to see if we have a valid access token
aaOpts := aa.Options()
if aaOpts.Token != nil && aaOpts.Token.Expiry.Unix() > time.Now().Unix() {
if aaOpts.Token != nil && !aaOpts.Token.Expired() {
ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+aaOpts.Token.AccessToken)
return a.Client.Call(ctx, req, rsp, opts...)
}
@@ -186,20 +191,28 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
// Extract the token if present. Note: if noop is being used
// then the token can be blank without erroring
var token string
var account *auth.Account
if header, ok := metadata.Get(ctx, "Authorization"); ok {
// Ensure the correct scheme is being used
if !strings.HasPrefix(header, auth.BearerScheme) {
return errors.Unauthorized(req.Service(), "invalid authorization header. expected Bearer schema")
}
token = header[len(auth.BearerScheme):]
// Strip the prefix and inspect the resulting token
account, _ = a.Inspect(strings.TrimPrefix(header, auth.BearerScheme))
}
// Inspect the token and get the account
account, err := a.Inspect(token)
if err != nil {
account = &auth.Account{Namespace: a.Options().Namespace}
// Extract the namespace header
ns, ok := metadata.Get(ctx, "Micro-Namespace")
if !ok {
ns = a.Options().Namespace
ctx = metadata.Set(ctx, "Micro-Namespace", ns)
}
// Check the issuer matches the services namespace. TODO: Stop allowing go.micro to access
// any namespace and instead check for the server issuer.
if account != nil && account.Issuer != ns && account.Issuer != "go.micro" {
return errors.Forbidden(req.Service(), "Account was not issued by %v", ns)
}
// construct the resource
@@ -210,15 +223,15 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
}
// Verify the caller has access to the resource
err = a.Verify(account, res)
if err != nil && len(account.ID) > 0 {
err := a.Verify(account, res, auth.VerifyContext(ctx))
if err != nil && account != nil {
return errors.Forbidden(req.Service(), "Forbidden call made to %v:%v by %v", req.Service(), req.Endpoint(), account.ID)
} else if err != nil {
return errors.Unauthorized(req.Service(), "Unauthorised call made to %v:%v", req.Service(), req.Endpoint())
return errors.Unauthorized(req.Service(), "Unauthorized call made to %v:%v", req.Service(), req.Endpoint())
}
// There is an account, set it in the context
if len(account.ID) > 0 {
if account != nil {
ctx = auth.ContextWithAccount(ctx, account)
}
@@ -227,3 +240,73 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
}
}
}
type cacheWrapper struct {
cacheFn func() *client.Cache
client.Client
}
// Call executes the request. If the CacheExpiry option was set, the response will be cached using
// a hash of the metadata and request as the key.
func (c *cacheWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
// parse the options
var options client.CallOptions
for _, o := range opts {
o(&options)
}
// if the client doesn't have a cacbe setup don't continue
cache := c.cacheFn()
if cache == nil {
return c.Client.Call(ctx, req, rsp, opts...)
}
// if the cache expiry is not set, execute the call without the cache
if options.CacheExpiry == 0 {
return c.Client.Call(ctx, req, rsp, opts...)
}
// if the response is nil don't call the cache since we can't assign the response
if rsp == nil {
return c.Client.Call(ctx, req, rsp, opts...)
}
// check to see if there is a response cached, if there is assign it
if r, ok := cache.Get(ctx, &req); ok {
val := reflect.ValueOf(rsp).Elem()
val.Set(reflect.ValueOf(r).Elem())
return nil
}
// don't cache the result if there was an error
if err := c.Client.Call(ctx, req, rsp, opts...); err != nil {
return err
}
// set the result in the cache
cache.Set(ctx, &req, rsp, options.CacheExpiry)
return nil
}
// CacheClient wraps requests with the cache wrapper
func CacheClient(cacheFn func() *client.Cache, c client.Client) client.Client {
return &cacheWrapper{cacheFn, c}
}
type staticClient struct {
address string
client.Client
}
func (s *staticClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
return s.Client.Call(ctx, req, rsp, append(opts, client.WithAddress(s.address))...)
}
func (s *staticClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
return s.Client.Stream(ctx, req, append(opts, client.WithAddress(s.address))...)
}
// StaticClient sets an address on every call
func StaticClient(address string, c client.Client) client.Client {
return &staticClient{address, c}
}

View File

@@ -0,0 +1,72 @@
package wrapper_test
import (
"context"
"testing"
"github.com/micro/go-micro/v2/broker"
bmemory "github.com/micro/go-micro/v2/broker/memory"
"github.com/micro/go-micro/v2/client"
rmemory "github.com/micro/go-micro/v2/registry/memory"
"github.com/micro/go-micro/v2/server"
tmemory "github.com/micro/go-micro/v2/transport/memory"
wrapper "github.com/micro/go-micro/v2/util/wrapper"
)
type TestFoo struct {
}
type TestReq struct{}
type TestRsp struct {
Data string
}
func (h *TestFoo) Bar(ctx context.Context, req *TestReq, rsp *TestRsp) error {
rsp.Data = "pass"
return nil
}
func TestStaticClientWrapper(t *testing.T) {
var err error
req := client.NewRequest("go.micro.service.foo", "TestFoo.Bar", &TestReq{}, client.WithContentType("application/json"))
rsp := &TestRsp{}
reg := rmemory.NewRegistry()
brk := bmemory.NewBroker(broker.Registry(reg))
tr := tmemory.NewTransport()
srv := server.NewServer(
server.Broker(brk),
server.Registry(reg),
server.Name("go.micro.service.foo"),
server.Address("127.0.0.1:0"),
server.Transport(tr),
)
if err = srv.Handle(srv.NewHandler(&TestFoo{})); err != nil {
t.Fatal(err)
}
if err = srv.Start(); err != nil {
t.Fatal(err)
}
cli := client.NewClient(
client.Registry(reg),
client.Broker(brk),
client.Transport(tr),
)
w1 := wrapper.StaticClient("xxx_localhost:12345", cli)
if err = w1.Call(context.TODO(), req, nil); err == nil {
t.Fatal("address xxx_#localhost:12345 must not exists and call must be failed")
}
w2 := wrapper.StaticClient(srv.Options().Address, cli)
if err = w2.Call(context.TODO(), req, rsp); err != nil {
t.Fatal(err)
} else if rsp.Data != "pass" {
t.Fatalf("something wrong with response: %#+v", rsp)
}
}

View File

@@ -2,9 +2,16 @@ package wrapper
import (
"context"
"net/http"
"reflect"
"testing"
"time"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/server"
)
func TestWrapper(t *testing.T) {
@@ -49,5 +56,407 @@ func TestWrapper(t *testing.T) {
}
}
}
}
type testAuth struct {
verifyCount int
inspectCount int
namespace string
inspectAccount *auth.Account
verifyError error
auth.Auth
}
func (a *testAuth) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error {
a.verifyCount = a.verifyCount + 1
return a.verifyError
}
func (a *testAuth) Inspect(token string) (*auth.Account, error) {
a.inspectCount = a.inspectCount + 1
return a.inspectAccount, nil
}
func (a *testAuth) Options() auth.Options {
return auth.Options{Namespace: a.namespace}
}
type testRequest struct {
service string
endpoint string
server.Request
}
func (r testRequest) Service() string {
return r.service
}
func (r testRequest) Endpoint() string {
return r.endpoint
}
func TestAuthHandler(t *testing.T) {
h := func(ctx context.Context, req server.Request, rsp interface{}) error {
return nil
}
debugReq := testRequest{service: "go.micro.service.foo", endpoint: "Debug.Foo"}
serviceReq := testRequest{service: "go.micro.service.foo", endpoint: "Foo.Bar"}
// Debug endpoints should be excluded from auth so auth.Verify should never get called
t.Run("DebugEndpoint", func(t *testing.T) {
a := testAuth{}
handler := AuthHandler(func() auth.Auth {
return &a
})
err := handler(h)(context.TODO(), debugReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
if a.verifyCount != 0 {
t.Errorf("Did not expect verify to be called")
}
})
// If the Authorization header is blank, no error should be returned and verify not called
t.Run("BlankAuthorizationHeader", func(t *testing.T) {
a := testAuth{}
handler := AuthHandler(func() auth.Auth {
return &a
})
err := handler(h)(context.TODO(), serviceReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
if a.inspectCount != 0 {
t.Errorf("Did not expect inspect to be called")
}
})
// If the Authorization header is invalid, an error should be returned and verify not called
t.Run("InvalidAuthorizationHeader", func(t *testing.T) {
a := testAuth{}
handler := AuthHandler(func() auth.Auth {
return &a
})
ctx := metadata.Set(context.TODO(), "Authorization", "Invalid")
err := handler(h)(ctx, serviceReq, nil)
if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusUnauthorized {
t.Errorf("Expected unauthorized error but got %v", err)
}
if a.inspectCount != 0 {
t.Errorf("Did not expect inspect to be called")
}
})
// If the Authorization header is valid, no error should be returned and verify should called
t.Run("ValidAuthorizationHeader", func(t *testing.T) {
a := testAuth{}
handler := AuthHandler(func() auth.Auth {
return &a
})
ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token")
err := handler(h)(ctx, serviceReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
if a.inspectCount != 1 {
t.Errorf("Expected inspect to be called")
}
})
// If the namespace header was not set on the request, the wrapper should set it to the auths
// own namespace
t.Run("BlankNamespaceHeader", func(t *testing.T) {
a := testAuth{namespace: "mynamespace"}
handler := AuthHandler(func() auth.Auth {
return &a
})
inCtx := context.TODO()
h := func(ctx context.Context, req server.Request, rsp interface{}) error {
inCtx = ctx
return nil
}
err := handler(h)(inCtx, serviceReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
if ns, _ := metadata.Get(inCtx, "Micro-Namespace"); ns != a.namespace {
t.Errorf("Expected namespace to be set to %v but was %v", a.namespace, ns)
}
})
t.Run("ValidNamespaceHeader", func(t *testing.T) {
a := testAuth{namespace: "mynamespace"}
handler := AuthHandler(func() auth.Auth {
return &a
})
inNs := "reqnamespace"
inCtx := metadata.Set(context.TODO(), "Micro-Namespace", inNs)
h := func(ctx context.Context, req server.Request, rsp interface{}) error {
inCtx = ctx
return nil
}
err := handler(h)(inCtx, serviceReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
if ns, _ := metadata.Get(inCtx, "Micro-Namespace"); ns != inNs {
t.Errorf("Expected namespace to remain as %v but was set to %v", inNs, ns)
}
})
// If the callers account was set but the issuer didn't match that of the request, the request
// should be forbidden
t.Run("InvalidAccountIssuer", func(t *testing.T) {
a := testAuth{
namespace: "validnamespace",
inspectAccount: &auth.Account{Issuer: "invalidnamespace"},
}
handler := AuthHandler(func() auth.Auth {
return &a
})
ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token")
err := handler(h)(ctx, serviceReq, nil)
if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusForbidden {
t.Errorf("Expected forbidden error but got %v", err)
}
})
t.Run("ValidAccountIssuer", func(t *testing.T) {
a := testAuth{
namespace: "validnamespace",
inspectAccount: &auth.Account{Issuer: "validnamespace"},
}
handler := AuthHandler(func() auth.Auth {
return &a
})
ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token")
err := handler(h)(ctx, serviceReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
})
// If the caller had a nil account and verify returns an error, the request should be unauthorised
t.Run("NilAccountUnauthorized", func(t *testing.T) {
a := testAuth{verifyError: auth.ErrForbidden}
handler := AuthHandler(func() auth.Auth {
return &a
})
err := handler(h)(context.TODO(), serviceReq, nil)
if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusUnauthorized {
t.Errorf("Expected unauthorizard error but got %v", err)
}
})
t.Run("AccountForbidden", func(t *testing.T) {
a := testAuth{verifyError: auth.ErrForbidden, inspectAccount: &auth.Account{}}
handler := AuthHandler(func() auth.Auth {
return &a
})
ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token")
err := handler(h)(ctx, serviceReq, nil)
if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusForbidden {
t.Errorf("Expected forbidden error but got %v", err)
}
})
t.Run("AccountValid", func(t *testing.T) {
a := testAuth{inspectAccount: &auth.Account{}}
handler := AuthHandler(func() auth.Auth {
return &a
})
ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token")
err := handler(h)(ctx, serviceReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
})
// If an account is returned from inspecting the token, it should be set in the context
t.Run("ContextWithAccount", func(t *testing.T) {
accID := "myaccountid"
a := testAuth{inspectAccount: &auth.Account{ID: accID}}
handler := AuthHandler(func() auth.Auth {
return &a
})
inCtx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token")
h := func(ctx context.Context, req server.Request, rsp interface{}) error {
inCtx = ctx
return nil
}
err := handler(h)(inCtx, serviceReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
if acc, ok := auth.AccountFromContext(inCtx); !ok {
t.Errorf("Expected an account to be set in the context")
} else if acc.ID != accID {
t.Errorf("Expected the account in the context to have the ID %v but it actually had %v", accID, acc.ID)
}
})
// If verify returns an error the handler should not be called
t.Run("HandlerNotCalled", func(t *testing.T) {
a := testAuth{verifyError: auth.ErrForbidden}
handler := AuthHandler(func() auth.Auth {
return &a
})
var handlerCalled bool
h := func(ctx context.Context, req server.Request, rsp interface{}) error {
handlerCalled = true
return nil
}
ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token")
err := handler(h)(ctx, serviceReq, nil)
if verr, ok := err.(*errors.Error); !ok || verr.Code != http.StatusUnauthorized {
t.Errorf("Expected unauthorizard error but got %v", err)
}
if handlerCalled {
t.Errorf("Expected the handler to not be called")
}
})
// If verify does not return an error the handler should be called
t.Run("HandlerNotCalled", func(t *testing.T) {
a := testAuth{}
handler := AuthHandler(func() auth.Auth {
return &a
})
var handlerCalled bool
h := func(ctx context.Context, req server.Request, rsp interface{}) error {
handlerCalled = true
return nil
}
ctx := metadata.Set(context.TODO(), "Authorization", auth.BearerScheme+"Token")
err := handler(h)(ctx, serviceReq, nil)
if err != nil {
t.Errorf("Expected nil error but got %v", err)
}
if !handlerCalled {
t.Errorf("Expected the handler be called")
}
})
}
type testClient struct {
callCount int
callRsp interface{}
client.Client
}
func (c *testClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
c.callCount++
if c.callRsp != nil {
val := reflect.ValueOf(rsp).Elem()
val.Set(reflect.ValueOf(c.callRsp).Elem())
}
return nil
}
type testRsp struct {
value string
}
func TestCacheWrapper(t *testing.T) {
req := client.NewRequest("go.micro.service.foo", "Foo.Bar", nil)
t.Run("NilCache", func(t *testing.T) {
cli := new(testClient)
w := CacheClient(func() *client.Cache {
return nil
}, cli)
// perfroming two requests should increment the call count by two indicating the cache wasn't
// used even though the WithCache option was passed.
w.Call(context.TODO(), req, nil, client.WithCache(time.Minute))
w.Call(context.TODO(), req, nil, client.WithCache(time.Minute))
if cli.callCount != 2 {
t.Errorf("Expected the client to have been called twice")
}
})
t.Run("OptionNotSet", func(t *testing.T) {
cli := new(testClient)
cache := client.NewCache()
w := CacheClient(func() *client.Cache {
return cache
}, cli)
// perfroming two requests should increment the call count by two since we didn't pass the WithCache
// option to Call.
w.Call(context.TODO(), req, nil)
w.Call(context.TODO(), req, nil)
if cli.callCount != 2 {
t.Errorf("Expected the client to have been called twice")
}
})
t.Run("OptionSet", func(t *testing.T) {
val := "foo"
cli := &testClient{callRsp: &testRsp{value: val}}
cache := client.NewCache()
w := CacheClient(func() *client.Cache {
return cache
}, cli)
// perfroming two requests should increment the call count by once since the second request should
// have used the cache. The correct value should be set on both responses and no errors should
// be returned.
rsp1 := &testRsp{}
rsp2 := &testRsp{}
err1 := w.Call(context.TODO(), req, rsp1, client.WithCache(time.Minute))
err2 := w.Call(context.TODO(), req, rsp2, client.WithCache(time.Minute))
if err1 != nil {
t.Errorf("Expected nil error, got %v", err1)
}
if err2 != nil {
t.Errorf("Expected nil error, got %v", err2)
}
if rsp1.value != val {
t.Errorf("Expected %v to be assigned to the value, got %v", val, rsp1.value)
}
if rsp2.value != val {
t.Errorf("Expected %v to be assigned to the value, got %v", val, rsp2.value)
}
if cli.callCount != 1 {
t.Errorf("Expected the client to be called 1 time, was actually called %v time(s)", cli.callCount)
}
})
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/micro/go-micro/v2/registry"
maddr "github.com/micro/go-micro/v2/util/addr"
authutil "github.com/micro/go-micro/v2/util/auth"
"github.com/micro/go-micro/v2/util/backoff"
mhttp "github.com/micro/go-micro/v2/util/http"
mnet "github.com/micro/go-micro/v2/util/net"
signalutil "github.com/micro/go-micro/v2/util/signal"
@@ -112,8 +113,8 @@ func (s *service) run(exit chan bool) {
}
func (s *service) register() error {
s.RLock()
defer s.RUnlock()
s.Lock()
defer s.Unlock()
if s.srv == nil {
return nil
@@ -138,12 +139,29 @@ func (s *service) register() error {
return err
}
return r.Register(s.srv, registry.RegisterTTL(s.opts.RegisterTTL))
var regErr error
// try three times if necessary
for i := 0; i < 3; i++ {
// attempt to register
if err := r.Register(s.srv, registry.RegisterTTL(s.opts.RegisterTTL)); err != nil {
// set the error
regErr = err
// backoff then retry
time.Sleep(backoff.Do(i + 1))
continue
}
// success so nil error
regErr = nil
break
}
return regErr
}
func (s *service) deregister() error {
s.RLock()
defer s.RUnlock()
s.Lock()
defer s.Unlock()
if s.srv == nil {
return nil
@@ -406,7 +424,9 @@ func (s *service) Init(opts ...Option) error {
s.RLock()
// pass in own name and version
serviceOpts = append(serviceOpts, micro.Name(s.opts.Name))
if s.opts.Service.Name() == "" {
serviceOpts = append(serviceOpts, micro.Name(s.opts.Name))
}
serviceOpts = append(serviceOpts, micro.Version(s.opts.Version))
s.RUnlock()
@@ -424,7 +444,7 @@ func (s *service) Init(opts ...Option) error {
func (s *service) Run() error {
// generate an auth account
srvID := s.opts.Service.Server().Options().Id
srvName := s.opts.Service.Name()
srvName := s.Options().Name
if err := authutil.Generate(srvID, srvName, s.opts.Service.Options().Auth); err != nil {
return err
}

View File

@@ -31,7 +31,7 @@ var (
DefaultAddress = ":0"
// for registration
DefaultRegisterTTL = time.Minute
DefaultRegisterTTL = time.Second * 90
DefaultRegisterInterval = time.Second * 30
// static directory