Compare commits

..

51 Commits

Author SHA1 Message Date
ben-toogood
afe6861e2f Update the k8s deployment to use metadata labels & custom source (#1271) 2020-02-28 15:07:55 +00:00
ben-toogood
962567ef42 Implement config singleton (#1268)
* Implement config singleton

* Pass token in grpc request headers

* Refactor BearerScheme

* Fix typo
2020-02-28 12:58:27 +00:00
Asim Aslam
e21ed3a183 gen account on base32 decode failure (#1269) 2020-02-27 16:11:05 +00:00
64a5ce9607 various fixes (#1267)
* logger: remove Panic log level

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

* server/grpc: add missing Unlock in Subscribe error

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

* server: minor code change

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

* server/grpc: extend test suite with pub/sub testing

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

* server/grpc: fix invalid check and allow subscriber error to be returned

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

* server/grpc: add pubsub tests

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

* client/grpc: check for nil req/rsp

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-26 18:34:40 +00:00
Asim Aslam
d651b16acd generate pseudo accounts (#1264)
* generate pseudo accounts

* when you think you're being clever

* return garbage pseudo account when no token
2020-02-26 13:42:32 +00:00
Eric
1034837f69 Adjusting the BeforeStart () position (#1263)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-02-26 11:44:10 +03:00
Lars Lehtonen
80f2bfd5d0 config: remove unused sep variable (#1262) 2020-02-26 08:25:33 +00:00
Asim Aslam
6aaaf54275 add MICRO_AUTH_TOKEN, parse token in wrapper, preload config and othe… (#1261)
* add MICRO_AUTH_TOKEN, parse token in wrapper, preload config and other things

* fix wrapper panic
2020-02-25 22:15:44 +00:00
Di Wu
603d37b135 Set option and cli args to the service profile (#1259) 2020-02-25 16:42:42 +00:00
Eric
53c3bff819 add Panic & Panicf to logger (#1258)
* add Panic & Panicf to logger
2020-02-25 17:44:29 +03:00
ben-toogood
dcf859098b Fix k8s commands for github (#1257) 2020-02-25 11:39:03 +00:00
b4a743898e fix router panic (#1254)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-24 23:15:59 +00:00
ben-toogood
f1e7ea3020 Handle non IsNotExist errors in config (#1251)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-02-24 18:07:11 +00:00
ben-toogood
5e8d5834eb Dynamic Runtime source for k8s with github packages (#1252)
* Dynamic Runtime source for k8s

* Still check for source

* Replace / with - for k8s service names

* Simplify sourceForName function
2020-02-24 17:47:47 +00:00
ben-toogood
ffdf986aac Refactor auth: add token and store implementations (#1230)
* Refactor auth: add token and memory implementations

* Fix typo

* Remove memory auth (implemented already by the store implementation), revert default to noop

* Add grpc header

* Global Config

* config/global => util/config

* Rename package to remove confict

* Tweak

* Improve Error Handling
2020-02-24 15:07:27 +00:00
Jake Sanders
56f8115ea8 Rename PR job (#1250) 2020-02-24 14:16:51 +00:00
5b0175c2e5 allocations improvements and tunnel fixes (#1248)
* reduce allocations in tunnel code

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

* another allocation fix

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

* allocate maps with len if it known

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

* allocate key for send once

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-24 14:15:20 +00:00
Jake Sanders
01d88601c0 Split PR and merge tests (#1249) 2020-02-24 14:11:17 +00:00
Lars Lehtonen
d467236f8f broker/nats: remove unused setPublishOption() (#1234)
broker/nats: remove unused setSubscribeOption()
2020-02-24 13:49:27 +00:00
24d574ae71 server/grpc: add MaxConn option to limit max inflight requests (#1247)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-24 13:48:56 +00:00
cf0b39eaac logger fixes (#1244)
* logger: fix race conditions

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

* restore util/log for compatibility

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-24 13:07:40 +00:00
1f767ba18c update go modules (#1240)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-23 20:47:44 +00:00
Asim Aslam
915c424213 Add docker build (#1239) 2020-02-23 15:57:21 +00:00
117f56ebf7 prune util/log and user logger (#1237)
* prune util/log and user logger

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

* plaintext logger

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

* add newline

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-23 13:45:20 +00:00
Gao.QiLin
ceed8942fc Update README.md change godoc => go.dev (#1236)
* Update README.md add go dev

* Update README.zh-cn.md add go dev
2020-02-22 08:56:42 +00:00
d1e25e7ead add metadata set method (#1232)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-21 23:04:47 +03:00
Jake Sanders
7e24c0c1cf Also run tests on PR (#1233) 2020-02-21 17:57:07 +00:00
Jake Sanders
ca251ba111 Switch from Travis CI to GitHub Actions (#1231)
* Create Github Action to run tests on push

* -v

* Update tests.yml

* TODO: Fix tests

* Fix colours

* Delete .travis.yml

* Update tests.yml

* builds -> build
2020-02-21 17:43:50 +00:00
Asim Aslam
116855572b Add log level helper funtions (#1229) 2020-02-21 08:43:23 +00:00
Asim Aslam
ee977acfef strip SetGlobalLevel (#1228) 2020-02-21 08:28:21 +00:00
Sumanth Chinthagunta
3fa7c26946 logger with helper methods (#1216)
* support unix daemon socket

* refactor(logger): logger fields changed to map[string]interface{}

* improvement(logger): adding string to Level Parser

* improvement(logger): rename ParseLevel to GetLevel

* refactor(logger): adding basic logger

adding micro default logger, and refactor logger interface

* refactor(logger): moved basic logger to top level package

* refactor(logger): adding default logger
2020-02-21 07:57:59 +00:00
Lars Lehtonen
88457b812e tunnel: Prune Unused Functions (#1224)
* tunnel: remove unused link.setLoopback()

* tunnel: remove unused link.accept()

* tunnel: remove unused link.connect()
2020-02-20 17:05:49 +00:00
Asim Aslam
78df154a4d move log level setting to option (#1222) 2020-02-20 08:26:12 +00:00
Lars Lehtonen
c7eed618c2 server/grpc: Prune Unused Code (#1220)
* server/grpc: remove unused grpcServer.newCodec()

* server/grpc: remove unused defaultRPCCodecs
2020-02-19 20:58:22 +00:00
ben-toogood
36bcd3bd82 Improve JWT Package Errors (#1206)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-02-19 09:51:43 +01:00
Asim Aslam
f4118dc357 secure the grpc client (#1215)
* secure the grpc client

* make compile

* Add system cert pool

* Revert manually adding ca certs

* Tweak comment

Co-authored-by: ben-toogood <bentoogood@gmail.com>
2020-02-19 08:44:35 +00:00
58598d0fe0 fixes for safe conversation and avoid panics (#1213)
* fixes for safe convertation

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

* fix client publish panic

If broker connect returns error we dont check it status and use
it later to publish message, mostly this is unexpected because
broker connection failed and we cant use it.
Also proposed solution have benefit - we flag connection status
only when we have succeseful broker connection

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

* api/handler/broker: fix possible broker publish panic

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-18 23:05:38 +00:00
6248f05f74 add missing option to client.NewMessage (#1212)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-18 14:18:59 +03:00
ben-toogood
aa9a0a8d23 Fix Micro Proxy nil Transport Bug (#1208) 2020-02-17 12:28:48 +03:00
ben-toogood
1e40c86dfe Ignore gRPC Proxy (#1205) 2020-02-17 08:14:45 +00:00
Asim Aslam
9696efde02 reorder auth interface (#1204) 2020-02-16 19:36:45 +00:00
Asim Aslam
b3fc8be24e normalise proxy name (#1203) 2020-02-15 21:57:30 +00:00
Sumanth Chinthagunta
fc5339a368 [W.I.P] refactor(logger): logger fields changed to map[string]interface{} (#1198)
* support unix daemon socket

* refactor(logger): logger fields changed to map[string]interface{}

* improvement(logger): adding string to Level Parser

* improvement(logger): rename ParseLevel to GetLevel
2020-02-15 18:19:28 +00:00
Asim Aslam
964b7dee3f add tls config to server (#1202)
* add tls config

* add TLSConfig to acme provider
2020-02-15 15:10:26 +00:00
Asim Aslam
158949d0d0 accept Listen option in grpc server (#1201) 2020-02-15 14:09:24 +00:00
Asim Aslam
eed8a0bf50 delete proxy cached route before updating (#1200) 2020-02-15 12:05:22 +00:00
Asim Aslam
c691d116ab when the stream errors cleanup the connection (#1199) 2020-02-15 11:35:08 +00:00
Eric
cbe8b7dd09 Removed redundant spaces (#1196) 2020-02-14 10:32:02 +03:00
Asim Aslam
203486fd31 check for etcd watcher canceled value 2020-02-13 22:34:56 +00:00
Asim Aslam
d9b3b17582 set dial timeout in stream 2020-02-13 18:51:32 +00:00
ben-toogood
e080ecb43a Auth Improvements (#1195)
* Exclude Stats & Trace from Auth

* Update Excluded Endpoints Format

* Tweak Implementation
2020-02-13 14:07:14 +00:00
102 changed files with 1812 additions and 880 deletions

19
.github/workflows/docker.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Docker
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
name: Check out repository
- uses: elgohr/Publish-Docker-Github-Action@2.12
name: Build and Push Docker Image
with:
name: micro/go-micro
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

28
.github/workflows/pr.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: PR Sanity Check
on: pull_request
jobs:
prtest:
name: PR sanity check
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 code into the Go module directory
uses: actions/checkout@v2
- name: Get dependencies
run: |
go get -v -t -d ./...
- name: Run tests
id: tests
env:
IN_TRAVIS_CI: yes
run: go test -v ./...

51
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Run tests
on: [push]
jobs:
test:
name: Test repo
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 code into the Go module directory
uses: actions/checkout@v2
- name: Get dependencies
run: |
go get -v -t -d ./...
- name: Run tests
id: tests
env:
IN_TRAVIS_CI: yes
run: go test -v ./...
- name: Notify of test failure
if: failure()
uses: rtCamp/action-slack-notify@v2.0.0
env:
SLACK_CHANNEL: build
SLACK_COLOR: '#BF280A'
SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
SLACK_TITLE: Tests Failed
SLACK_USERNAME: GitHub Actions
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Notify of test success
if: success()
uses: rtCamp/action-slack-notify@v2.0.0
env:
SLACK_CHANNEL: build
SLACK_COLOR: '#1FAD2B'
SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
SLACK_TITLE: Tests Passed
SLACK_USERNAME: GitHub Actions
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}

View File

@@ -1,17 +0,0 @@
language: go
go:
- 1.13.x
env:
- GO111MODULE=on IN_TRAVIS_CI=yes
before_script:
- go install github.com/golangci/golangci-lint/cmd/golangci-lint
script:
# - golangci-lint run || true
# - go test -v -race ./... || true
- go test -v ./...
notifications:
slack:
secure: aEvhLbhujaGaKSrOokiG3//PaVHTIrc3fBpoRbCRqfZpyq6WREoapJJhF+tIpWWOwaC9GmChbD6aHo/jMUgwKXVyPSaNjiEL87YzUUpL8B2zslNp1rgfTg/LrzthOx3Q1TYwpaAl3to0fuHUVFX4yMeC2vuThq7WSXgMMxFCtbc=
cache:
directories:
- $GOPATH/pkg/mod

View File

@@ -1,4 +1,4 @@
# Go Micro [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/micro/go-micro?status.svg)](https://godoc.org/github.com/micro/go-micro) [![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 [![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 microservice development.

View File

@@ -1,4 +1,4 @@
# Go Micro [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![GoDoc](https://godoc.org/github.com/micro/go-micro?status.svg)](https://godoc.org/github.com/micro/go-micro) [![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 [![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的微服务开发框架。

View File

@@ -7,7 +7,7 @@ import (
"github.com/bwmarrin/discordgo"
"github.com/micro/go-micro/v2/agent/input"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
type discordConn struct {
@@ -74,7 +74,7 @@ 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 {
log.Log("[bot][loop][send]", err)
log.Error("[bot][loop][send]", err)
}
return nil
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/forestgiant/sliceutil"
"github.com/micro/go-micro/v2/agent/input"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
tgbotapi "gopkg.in/telegram-bot-api.v4"
)
@@ -104,7 +104,7 @@ func (tc *telegramConn) Send(event *input.Event) error {
if err != nil {
// probably it could be because of nested HTML tags -- telegram doesn't allow nested tags
log.Log("[telegram][Send] error:", err)
log.Error("[telegram][Send] error:", err)
msgConfig.Text = "This bot couldn't send the response (Internal error)"
tc.input.api.Send(msgConfig)
}

View File

@@ -8,12 +8,13 @@ import (
"net/url"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/gorilla/websocket"
"github.com/micro/go-micro/v2/api/handler"
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
const (
@@ -26,6 +27,7 @@ const (
)
type brokerHandler struct {
once atomic.Value
opts handler.Options
u websocket.Upgrader
}
@@ -42,7 +44,6 @@ type conn struct {
}
var (
once sync.Once
contentType = "text/plain"
)
@@ -135,7 +136,7 @@ func (c *conn) writeLoop() {
}()
if err != nil {
log.Log(err.Error())
log.Error(err.Error())
return
}
@@ -155,10 +156,15 @@ func (b *brokerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
br := b.opts.Service.Client().Options().Broker
// Setup the broker
once.Do(func() {
br.Init()
br.Connect()
})
if !b.once.Load().(bool) {
if err := br.Init(); err != nil {
http.Error(w, err.Error(), 500)
}
if err := br.Connect(); err != nil {
http.Error(w, err.Error(), 500)
}
b.once.Store(true)
}
// Parse
r.ParseForm()
@@ -208,7 +214,7 @@ func (b *brokerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ws, err := b.u.Upgrade(w, r, nil)
if err != nil {
log.Log(err.Error())
log.Error(err.Error())
return
}
@@ -235,7 +241,7 @@ func (b *brokerHandler) String() string {
}
func NewHandler(opts ...handler.Option) handler.Handler {
return &brokerHandler{
h := &brokerHandler{
u: websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
@@ -245,6 +251,8 @@ func NewHandler(opts ...handler.Option) handler.Handler {
},
opts: handler.NewOptions(opts...),
}
h.once.Store(true)
return h
}
func WithCors(cors map[string]bool, opts ...handler.Option) handler.Handler {

View File

@@ -2,6 +2,7 @@
package acme
import (
"crypto/tls"
"errors"
"net"
)
@@ -14,7 +15,10 @@ var (
// Provider is a ACME provider interface
type Provider interface {
NewListener(...string) (net.Listener, error)
// Listen returns a new listener
Listen(...string) (net.Listener, error)
// TLSConfig returns a tls config
TLSConfig(...string) (*tls.Config, error)
}
// The Let's Encrypt ACME endpoints

View File

@@ -3,7 +3,10 @@
package autocert
import (
"crypto/tls"
"log"
"net"
"os"
"github.com/micro/go-micro/v2/api/server/acme"
"golang.org/x/crypto/acme/autocert"
@@ -12,12 +15,30 @@ import (
// autoCertACME is the ACME provider from golang.org/x/crypto/acme/autocert
type autocertProvider struct{}
// NewListener implements acme.Provider
func (a *autocertProvider) NewListener(ACMEHosts ...string) (net.Listener, error) {
return autocert.NewListener(ACMEHosts...), nil
// Listen implements acme.Provider
func (a *autocertProvider) Listen(hosts ...string) (net.Listener, error) {
return autocert.NewListener(hosts...), nil
}
// TLSConfig returns a new tls config
func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
// create a new manager
m := &autocert.Manager{
Prompt: autocert.AcceptTOS,
}
if len(hosts) > 0 {
m.HostPolicy = autocert.HostWhitelist(hosts...)
}
dir := cacheDir()
if err := os.MkdirAll(dir, 0700); err != nil {
log.Printf("warning: autocert not using a cache: %v", err)
} else {
m.Cache = autocert.DirCache(dir)
}
return m.TLSConfig(), nil
}
// New returns an autocert acme.Provider
func New() acme.Provider {
func NewProvider() acme.Provider {
return &autocertProvider{}
}

View File

@@ -5,9 +5,9 @@ import (
)
func TestAutocert(t *testing.T) {
l := New()
l := NewProvider()
if _, ok := l.(*autocertProvider); !ok {
t.Error("New() didn't return an autocertProvider")
t.Error("NewProvider() didn't return an autocertProvider")
}
// TODO: Travis CI doesn't let us bind :443
// if _, err := l.NewListener(); err != nil {

View File

@@ -0,0 +1,37 @@
package autocert
import (
"os"
"path/filepath"
"runtime"
)
func homeDir() string {
if runtime.GOOS == "windows" {
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
}
if h := os.Getenv("HOME"); h != "" {
return h
}
return "/"
}
func cacheDir() string {
const base = "golang-autocert"
switch runtime.GOOS {
case "darwin":
return filepath.Join(homeDir(), "Library", "Caches", base)
case "windows":
for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
if v := os.Getenv(ev); v != "" {
return filepath.Join(v, base)
}
}
// Worst case:
return filepath.Join(homeDir(), base)
}
if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
return filepath.Join(xdg, base)
}
return filepath.Join(homeDir(), ".cache", base)
}

View File

@@ -2,6 +2,7 @@
package certmagic
import (
"crypto/tls"
"log"
"math/rand"
"net"
@@ -16,7 +17,8 @@ type certmagicProvider struct {
opts acme.Options
}
func (c *certmagicProvider) NewListener(ACMEHosts ...string) (net.Listener, error) {
// TODO: set self-contained options
func (c *certmagicProvider) setup() {
certmagic.Default.CA = c.opts.CA
if c.opts.ChallengeProvider != nil {
// Enabling DNS Challenge disables the other challenges
@@ -34,12 +36,20 @@ func (c *certmagicProvider) NewListener(ACMEHosts ...string) (net.Listener, erro
rand.Seed(time.Now().UnixNano())
randomDuration := (7 * 24 * time.Hour) + (time.Duration(rand.Intn(504)) * time.Hour)
certmagic.Default.RenewDurationBefore = randomDuration
}
return certmagic.Listen(ACMEHosts)
func (c *certmagicProvider) Listen(hosts ...string) (net.Listener, error) {
c.setup()
return certmagic.Listen(hosts)
}
func (c *certmagicProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
c.setup()
return certmagic.TLS(hosts)
}
// New returns a certmagic provider
func New(options ...acme.Option) acme.Provider {
func NewProvider(options ...acme.Option) acme.Provider {
opts := acme.DefaultOptions()
for _, o := range options {

View File

@@ -1,6 +1,7 @@
package certmagic
import (
"net"
"net/http"
"os"
"reflect"
@@ -19,8 +20,11 @@ func TestCertMagic(t *testing.T) {
if len(os.Getenv("IN_TRAVIS_CI")) != 0 {
t.Skip("Travis doesn't let us bind :443")
}
l, err := New().NewListener()
l, err := NewProvider().Listen()
if err != nil {
if _, ok := err.(*net.OpError); ok {
t.Skip("Run under non privileged user")
}
t.Fatal(err.Error())
}
l.Close()
@@ -36,10 +40,10 @@ func TestCertMagic(t *testing.T) {
t.Fatal(err.Error())
}
l, err = New(acme.AcceptToS(true),
l, err = NewProvider(acme.AcceptToS(true),
acme.CA(acme.LetsEncryptStagingCA),
acme.ChallengeProvider(p),
).NewListener()
).Listen()
if err != nil {
t.Fatal(err.Error())
@@ -180,7 +184,7 @@ func TestStorageImplementation(t *testing.T) {
// New interface doesn't return an error, so call it in case any log.Fatal
// happens
New(acme.Cache(s))
NewProvider(acme.Cache(s))
}
// Full test with a real zone, with against LE staging
@@ -207,7 +211,7 @@ func TestE2e(t *testing.T) {
t.Fatal(err.Error())
}
testProvider := New(
testProvider := NewProvider(
acme.AcceptToS(true),
acme.Cache(testStorage),
acme.CA(acme.LetsEncryptStagingCA),
@@ -215,7 +219,7 @@ func TestE2e(t *testing.T) {
acme.OnDemand(false),
)
listener, err := testProvider.NewListener("*.micro.mu", "micro.mu")
listener, err := testProvider.Listen("*.micro.mu", "micro.mu")
if err != nil {
t.Fatal(err.Error())
}

View File

@@ -10,7 +10,7 @@ import (
"github.com/gorilla/handlers"
"github.com/micro/go-micro/v2/api/server"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
type httpServer struct {
@@ -54,7 +54,7 @@ func (s *httpServer) Start() error {
if s.opts.EnableACME && s.opts.ACMEProvider != nil {
// should we check the address to make sure its using :443?
l, err = s.opts.ACMEProvider.NewListener(s.opts.ACMEHosts...)
l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...)
} else if s.opts.EnableTLS && s.opts.TLSConfig != nil {
l, err = tls.Listen("tcp", s.address, s.opts.TLSConfig)
} else {
@@ -65,7 +65,7 @@ func (s *httpServer) Start() error {
return err
}
log.Logf("HTTP API Listening on %s", l.Addr().String())
log.Infof("HTTP API Listening on %s", l.Addr().String())
s.mtx.Lock()
s.address = l.Addr().String()

View File

@@ -7,8 +7,6 @@ import (
// Auth providers authentication and authorization
type Auth interface {
// String to identify the package
String() string
// Init the auth package
Init(opts ...Option) error
// Options returns the options set
@@ -17,8 +15,10 @@ type Auth interface {
Generate(id string, opts ...GenerateOption) (*Account, error)
// Revoke an authorization Account
Revoke(token string) error
// Validate an account token
Validate(token string) (*Account, error)
// Verify an account token
Verify(token string) (*Account, error)
// String returns the implementation
String() string
}
// Resource is an entity such as a user or
@@ -31,7 +31,10 @@ type Resource struct {
// Role an account has
type Role struct {
// Name of the role
Name string
// The resource it has access
// TODO: potentially remove
Resource *Resource
}

View File

@@ -1,39 +1,122 @@
package auth
var (
DefaultAuth Auth = new(noop)
import (
"encoding/base32"
"sync"
"time"
)
type noop struct {
options Options
var (
DefaultAuth = NewAuth()
)
func genAccount(id string) *Account {
// return a pseudo account
return &Account{
Id: id,
Token: base32.StdEncoding.EncodeToString([]byte(id)),
Created: time.Now(),
Expiry: time.Now().Add(time.Hour * 24),
Metadata: make(map[string]string),
}
}
// String name of implementation
func (a *noop) String() string {
return "noop"
// NewAuth returns a new default registry which is memory
func NewAuth(opts ...Option) Auth {
var options Options
for _, o := range opts {
o(&options)
}
// Init the svc
func (a *noop) Init(...Option) error {
return &memory{
accounts: make(map[string]*Account),
opts: options,
}
}
// TODO: replace with https://github.com/nats-io/nkeys
// We'll then register public key in registry to use
type memory struct {
opts Options
// accounts
sync.RWMutex
accounts map[string]*Account
}
func (n *memory) Init(opts ...Option) error {
for _, o := range opts {
o(&n.opts)
}
return nil
}
// Options set in init
func (a *noop) Options() Options {
return a.options
func (n *memory) Options() Options {
return n.opts
}
// Generate a new auth Account
func (a *noop) Generate(id string, ops ...GenerateOption) (*Account, error) {
return nil, nil
func (n *memory) Generate(id string, opts ...GenerateOption) (*Account, error) {
var options GenerateOptions
for _, o := range opts {
o(&options)
}
// Revoke an authorization Account
func (a *noop) Revoke(token string) error {
// return a pseudo account
acc := genAccount(id)
// set opts
if len(options.Roles) > 0 {
acc.Roles = options.Roles
}
if options.Metadata != nil {
acc.Metadata = options.Metadata
}
// TODO: don't overwrite
n.Lock()
// maybe save by account id?
n.accounts[acc.Token] = acc
n.Unlock()
return acc, nil
}
func (n *memory) Revoke(token string) error {
n.Lock()
delete(n.accounts, token)
n.Unlock()
return nil
}
// Validate a account token
func (a *noop) Validate(token string) (*Account, error) {
return nil, nil
func (n *memory) Verify(token string) (*Account, error) {
n.RLock()
defer n.RUnlock()
if len(token) == 0 {
// pseudo account?
return genAccount(""), nil
}
// try get the local account if it exists
if acc, ok := n.accounts[token]; ok {
return acc, nil
}
// decode the token otherwise
b, err := base32.StdEncoding.DecodeString(token)
if err != nil {
return genAccount(""), nil
}
// return a pseudo account based on token/id
return &Account{
Id: string(b),
Token: token,
Created: time.Now(),
Expiry: time.Now().Add(time.Hour * 24),
Metadata: make(map[string]string),
}, nil
}
func (n *memory) String() string {
return "memory"
}

View File

@@ -1,6 +1,7 @@
package jwt
import (
"encoding/base64"
"errors"
"time"
@@ -8,14 +9,19 @@ import (
"github.com/micro/go-micro/v2/auth"
)
var (
// ErrInvalidPrivateKey is returned when the service provided an invalid private key
var ErrInvalidPrivateKey = errors.New("An invalid private key was provided")
ErrInvalidPrivateKey = errors.New("An invalid private key was provided")
// ErrEncodingToken is returned when the service encounters an error during encoding
var ErrEncodingToken = errors.New("An error occured while encoding the JWT")
ErrEncodingToken = errors.New("An error occured while encoding the JWT")
// ErrInvalidToken is returned when the token provided is not valid
var ErrInvalidToken = errors.New("An invalid token was provided")
ErrInvalidToken = errors.New("An invalid token was provided")
// ErrMissingToken is returned when no token is provided
ErrMissingToken = errors.New("A valid JWT is required")
)
// NewAuth returns a new instance of the Auth service
func NewAuth(opts ...auth.Option) auth.Auth {
@@ -56,7 +62,13 @@ type AuthClaims struct {
// Generate a new JWT
func (s *svc) Generate(id string, ops ...auth.GenerateOption) (*auth.Account, error) {
key, err := jwt.ParseRSAPrivateKeyFromPEM(s.options.PrivateKey)
// decode the private key
priv, err := base64.StdEncoding.DecodeString(s.options.PrivateKey)
if err != nil {
return nil, err
}
key, err := jwt.ParseRSAPrivateKeyFromPEM(priv)
if err != nil {
return nil, ErrEncodingToken
}
@@ -64,7 +76,7 @@ func (s *svc) Generate(id string, ops ...auth.GenerateOption) (*auth.Account, er
options := auth.NewGenerateOptions(ops...)
account := jwt.NewWithClaims(jwt.SigningMethodRS256, AuthClaims{
id, options.Roles, options.Metadata, jwt.StandardClaims{
Subject: "TODO",
Subject: id,
ExpiresAt: time.Now().Add(time.Hour * 24).Unix(),
},
})
@@ -87,10 +99,20 @@ func (s *svc) Revoke(token string) error {
return nil
}
// Validate a JWT
func (s *svc) Validate(token string) (*auth.Account, error) {
// Verify a JWT
func (s *svc) Verify(token string) (*auth.Account, error) {
if token == "" {
return nil, ErrMissingToken
}
// decode the public key
pub, err := base64.StdEncoding.DecodeString(s.options.PublicKey)
if err != nil {
return nil, err
}
res, err := jwt.ParseWithClaims(token, &AuthClaims{}, func(token *jwt.Token) (interface{}, error) {
return jwt.ParseRSAPublicKeyFromPEM(s.options.PublicKey)
return jwt.ParseRSAPublicKeyFromPEM(pub)
})
if err != nil {
return nil, err
@@ -100,7 +122,10 @@ func (s *svc) Validate(token string) (*auth.Account, error) {
return nil, ErrInvalidToken
}
claims := res.Claims.(*AuthClaims)
claims, ok := res.Claims.(*AuthClaims)
if !ok {
return nil, ErrInvalidToken
}
return &auth.Account{
Id: claims.Id,

View File

@@ -1,40 +1,50 @@
package auth
import (
b64 "encoding/base64"
)
type Options struct {
PublicKey []byte
PrivateKey []byte
Excludes []string
// Token is an auth token
Token string
// Public key base64 encoded
PublicKey string
// Private key base64 encoded
PrivateKey string
// Endpoints to exclude
Exclude []string
}
type Option func(o *Options)
// Excludes endpoints from auth
func Excludes(excludes ...string) Option {
// Exclude ecludes a set of endpoints from authorization
func Exclude(e ...string) Option {
return func(o *Options) {
o.Excludes = excludes
o.Exclude = e
}
}
// PublicKey is the JWT public key
func PublicKey(key string) Option {
return func(o *Options) {
o.PublicKey, _ = b64.StdEncoding.DecodeString(key)
o.PublicKey = key
}
}
// PrivateKey is the JWT private key
func PrivateKey(key string) Option {
return func(o *Options) {
o.PrivateKey, _ = b64.StdEncoding.DecodeString(key)
o.PrivateKey = key
}
}
// Token sets an auth token
func Token(t string) Option {
return func(o *Options) {
o.Token = t
}
}
type GenerateOptions struct {
// Metadata associated with the account
Metadata map[string]string
// Roles/scopes associated with the account
Roles []*Role
}

View File

@@ -1,5 +1,5 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: auth/service/proto/auth.proto
// source: micro/go-micro/auth/service/proto/auth.proto
package go_micro_auth
@@ -36,7 +36,7 @@ func (m *Account) Reset() { *m = Account{} }
func (m *Account) String() string { return proto.CompactTextString(m) }
func (*Account) ProtoMessage() {}
func (*Account) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{0}
return fileDescriptor_de609d4872dacc78, []int{0}
}
func (m *Account) XXX_Unmarshal(b []byte) error {
@@ -111,7 +111,7 @@ func (m *Role) Reset() { *m = Role{} }
func (m *Role) String() string { return proto.CompactTextString(m) }
func (*Role) ProtoMessage() {}
func (*Role) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{1}
return fileDescriptor_de609d4872dacc78, []int{1}
}
func (m *Role) XXX_Unmarshal(b []byte) error {
@@ -158,7 +158,7 @@ func (m *Resource) Reset() { *m = Resource{} }
func (m *Resource) String() string { return proto.CompactTextString(m) }
func (*Resource) ProtoMessage() {}
func (*Resource) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{2}
return fileDescriptor_de609d4872dacc78, []int{2}
}
func (m *Resource) XXX_Unmarshal(b []byte) error {
@@ -204,7 +204,7 @@ func (m *GenerateRequest) Reset() { *m = GenerateRequest{} }
func (m *GenerateRequest) String() string { return proto.CompactTextString(m) }
func (*GenerateRequest) ProtoMessage() {}
func (*GenerateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{3}
return fileDescriptor_de609d4872dacc78, []int{3}
}
func (m *GenerateRequest) XXX_Unmarshal(b []byte) error {
@@ -243,7 +243,7 @@ func (m *GenerateResponse) Reset() { *m = GenerateResponse{} }
func (m *GenerateResponse) String() string { return proto.CompactTextString(m) }
func (*GenerateResponse) ProtoMessage() {}
func (*GenerateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{4}
return fileDescriptor_de609d4872dacc78, []int{4}
}
func (m *GenerateResponse) XXX_Unmarshal(b []byte) error {
@@ -271,78 +271,78 @@ func (m *GenerateResponse) GetAccount() *Account {
return nil
}
type ValidateRequest struct {
type VerifyRequest struct {
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ValidateRequest) Reset() { *m = ValidateRequest{} }
func (m *ValidateRequest) String() string { return proto.CompactTextString(m) }
func (*ValidateRequest) ProtoMessage() {}
func (*ValidateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{5}
func (m *VerifyRequest) Reset() { *m = VerifyRequest{} }
func (m *VerifyRequest) String() string { return proto.CompactTextString(m) }
func (*VerifyRequest) ProtoMessage() {}
func (*VerifyRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{5}
}
func (m *ValidateRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValidateRequest.Unmarshal(m, b)
func (m *VerifyRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VerifyRequest.Unmarshal(m, b)
}
func (m *ValidateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ValidateRequest.Marshal(b, m, deterministic)
func (m *VerifyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_VerifyRequest.Marshal(b, m, deterministic)
}
func (m *ValidateRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ValidateRequest.Merge(m, src)
func (m *VerifyRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_VerifyRequest.Merge(m, src)
}
func (m *ValidateRequest) XXX_Size() int {
return xxx_messageInfo_ValidateRequest.Size(m)
func (m *VerifyRequest) XXX_Size() int {
return xxx_messageInfo_VerifyRequest.Size(m)
}
func (m *ValidateRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ValidateRequest.DiscardUnknown(m)
func (m *VerifyRequest) XXX_DiscardUnknown() {
xxx_messageInfo_VerifyRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ValidateRequest proto.InternalMessageInfo
var xxx_messageInfo_VerifyRequest proto.InternalMessageInfo
func (m *ValidateRequest) GetToken() string {
func (m *VerifyRequest) GetToken() string {
if m != nil {
return m.Token
}
return ""
}
type ValidateResponse struct {
type VerifyResponse struct {
Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ValidateResponse) Reset() { *m = ValidateResponse{} }
func (m *ValidateResponse) String() string { return proto.CompactTextString(m) }
func (*ValidateResponse) ProtoMessage() {}
func (*ValidateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{6}
func (m *VerifyResponse) Reset() { *m = VerifyResponse{} }
func (m *VerifyResponse) String() string { return proto.CompactTextString(m) }
func (*VerifyResponse) ProtoMessage() {}
func (*VerifyResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_de609d4872dacc78, []int{6}
}
func (m *ValidateResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValidateResponse.Unmarshal(m, b)
func (m *VerifyResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VerifyResponse.Unmarshal(m, b)
}
func (m *ValidateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ValidateResponse.Marshal(b, m, deterministic)
func (m *VerifyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_VerifyResponse.Marshal(b, m, deterministic)
}
func (m *ValidateResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ValidateResponse.Merge(m, src)
func (m *VerifyResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_VerifyResponse.Merge(m, src)
}
func (m *ValidateResponse) XXX_Size() int {
return xxx_messageInfo_ValidateResponse.Size(m)
func (m *VerifyResponse) XXX_Size() int {
return xxx_messageInfo_VerifyResponse.Size(m)
}
func (m *ValidateResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ValidateResponse.DiscardUnknown(m)
func (m *VerifyResponse) XXX_DiscardUnknown() {
xxx_messageInfo_VerifyResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ValidateResponse proto.InternalMessageInfo
var xxx_messageInfo_VerifyResponse proto.InternalMessageInfo
func (m *ValidateResponse) GetAccount() *Account {
func (m *VerifyResponse) GetAccount() *Account {
if m != nil {
return m.Account
}
@@ -360,7 +360,7 @@ func (m *RevokeRequest) Reset() { *m = RevokeRequest{} }
func (m *RevokeRequest) String() string { return proto.CompactTextString(m) }
func (*RevokeRequest) ProtoMessage() {}
func (*RevokeRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{7}
return fileDescriptor_de609d4872dacc78, []int{7}
}
func (m *RevokeRequest) XXX_Unmarshal(b []byte) error {
@@ -398,7 +398,7 @@ func (m *RevokeResponse) Reset() { *m = RevokeResponse{} }
func (m *RevokeResponse) String() string { return proto.CompactTextString(m) }
func (*RevokeResponse) ProtoMessage() {}
func (*RevokeResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_21300bfacc51fc2a, []int{8}
return fileDescriptor_de609d4872dacc78, []int{8}
}
func (m *RevokeResponse) XXX_Unmarshal(b []byte) error {
@@ -426,41 +426,43 @@ func init() {
proto.RegisterType((*Resource)(nil), "go.micro.auth.Resource")
proto.RegisterType((*GenerateRequest)(nil), "go.micro.auth.GenerateRequest")
proto.RegisterType((*GenerateResponse)(nil), "go.micro.auth.GenerateResponse")
proto.RegisterType((*ValidateRequest)(nil), "go.micro.auth.ValidateRequest")
proto.RegisterType((*ValidateResponse)(nil), "go.micro.auth.ValidateResponse")
proto.RegisterType((*VerifyRequest)(nil), "go.micro.auth.VerifyRequest")
proto.RegisterType((*VerifyResponse)(nil), "go.micro.auth.VerifyResponse")
proto.RegisterType((*RevokeRequest)(nil), "go.micro.auth.RevokeRequest")
proto.RegisterType((*RevokeResponse)(nil), "go.micro.auth.RevokeResponse")
}
func init() { proto.RegisterFile("auth/service/proto/auth.proto", fileDescriptor_21300bfacc51fc2a) }
var fileDescriptor_21300bfacc51fc2a = []byte{
// 429 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x4d, 0x6f, 0xd3, 0x40,
0x10, 0xad, 0x3f, 0xe2, 0x98, 0x89, 0xd2, 0x46, 0x03, 0x2a, 0x56, 0x44, 0x21, 0xb2, 0x40, 0x84,
0x8b, 0x83, 0xdc, 0x0b, 0x82, 0x0b, 0x15, 0xa0, 0x9e, 0x2a, 0xa4, 0x3d, 0x70, 0x5f, 0xec, 0x11,
0xb5, 0xe2, 0x78, 0xcd, 0x7a, 0x1d, 0xe1, 0xdf, 0xc0, 0x6f, 0xe5, 0x3f, 0x20, 0xaf, 0xbd, 0x69,
0xea, 0xb4, 0xaa, 0xd4, 0xdb, 0x7c, 0xbc, 0x79, 0xf3, 0xde, 0x68, 0x17, 0xce, 0x78, 0xad, 0xae,
0x57, 0x15, 0xc9, 0x6d, 0x96, 0xd0, 0xaa, 0x94, 0x42, 0x89, 0x55, 0x5b, 0x8a, 0x74, 0x88, 0xd3,
0x5f, 0x22, 0xda, 0x64, 0x89, 0x14, 0x51, 0x5b, 0x0c, 0xff, 0xda, 0x30, 0xbe, 0x48, 0x12, 0x51,
0x17, 0x0a, 0x8f, 0xc1, 0xce, 0xd2, 0xc0, 0x5a, 0x58, 0xcb, 0x27, 0xcc, 0xce, 0x52, 0x7c, 0x06,
0x23, 0x25, 0xd6, 0x54, 0x04, 0xb6, 0x2e, 0x75, 0x09, 0x06, 0x30, 0x4e, 0x24, 0x71, 0x45, 0x69,
0xe0, 0x2c, 0xac, 0xa5, 0xc3, 0x4c, 0x8a, 0xa7, 0xe0, 0xd1, 0x9f, 0x32, 0x93, 0x4d, 0xe0, 0xea,
0x46, 0x9f, 0xe1, 0x3b, 0x18, 0x49, 0x91, 0x53, 0x15, 0x8c, 0x16, 0xce, 0x72, 0x12, 0x3f, 0x8d,
0x6e, 0x49, 0x88, 0x98, 0xc8, 0x89, 0x75, 0x08, 0xfc, 0x0c, 0xfe, 0x86, 0x14, 0x4f, 0xb9, 0xe2,
0x81, 0xa7, 0xd1, 0xaf, 0x07, 0xe8, 0x5e, 0x6c, 0x74, 0xd5, 0xc3, 0xbe, 0x15, 0x4a, 0x36, 0x6c,
0x37, 0x35, 0xff, 0x04, 0xd3, 0x5b, 0x2d, 0x9c, 0x81, 0xb3, 0xa6, 0xa6, 0xb7, 0xd5, 0x86, 0xad,
0xaf, 0x2d, 0xcf, 0x6b, 0x32, 0xbe, 0x74, 0xf2, 0xd1, 0xfe, 0x60, 0x85, 0xdf, 0xc1, 0x6d, 0xd5,
0x20, 0x82, 0x5b, 0xf0, 0x0d, 0xf5, 0x43, 0x3a, 0xc6, 0x73, 0xf0, 0x25, 0x55, 0xa2, 0x96, 0x49,
0x37, 0x38, 0x89, 0x9f, 0x0f, 0x8d, 0xf4, 0x6d, 0xb6, 0x03, 0x86, 0x31, 0xf8, 0xa6, 0x7a, 0x27,
0x29, 0x82, 0xab, 0x9a, 0xd2, 0x28, 0xd1, 0x71, 0xf8, 0x05, 0x4e, 0x2e, 0xa9, 0x20, 0xc9, 0x15,
0x31, 0xfa, 0x5d, 0x53, 0xa5, 0xf0, 0x3d, 0x8c, 0x79, 0xe7, 0x5b, 0x4f, 0x4f, 0xe2, 0xd3, 0xbb,
0xaf, 0xc2, 0x0c, 0x2c, 0xfc, 0x0a, 0xb3, 0x1b, 0x92, 0xaa, 0x14, 0x45, 0x45, 0x8f, 0x60, 0x79,
0x0b, 0x27, 0x3f, 0x78, 0x9e, 0xa5, 0x7b, 0x52, 0x76, 0x8f, 0xc2, 0xda, 0x7b, 0x14, 0xed, 0xba,
0x1b, 0xe0, 0xa3, 0xd7, 0xbd, 0x81, 0x29, 0xa3, 0xad, 0x58, 0x3f, 0xb0, 0x6c, 0x06, 0xc7, 0x06,
0xd6, 0xad, 0x8a, 0xff, 0x59, 0xe0, 0x5e, 0xd4, 0xea, 0x1a, 0xaf, 0xc0, 0x37, 0xb6, 0xf1, 0xe5,
0x60, 0xdd, 0xe0, 0xa8, 0xf3, 0x57, 0xf7, 0xf6, 0x3b, 0xd6, 0xf0, 0xa8, 0xa5, 0x33, 0xb6, 0x0e,
0xe8, 0x06, 0x87, 0x39, 0xa0, 0x1b, 0xde, 0x23, 0x3c, 0xc2, 0x4b, 0xf0, 0x3a, 0xe1, 0xf8, 0xe2,
0xe0, 0xe9, 0xec, 0xd9, 0x9e, 0x9f, 0xdd, 0xd3, 0x35, 0x44, 0x3f, 0x3d, 0xfd, 0x97, 0xcf, 0xff,
0x07, 0x00, 0x00, 0xff, 0xff, 0x79, 0x35, 0xb2, 0x7e, 0xec, 0x03, 0x00, 0x00,
func init() {
proto.RegisterFile("micro/go-micro/auth/service/proto/auth.proto", fileDescriptor_de609d4872dacc78)
}
var fileDescriptor_de609d4872dacc78 = []byte{
// 432 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x53, 0x4b, 0x6f, 0xd3, 0x40,
0x10, 0xae, 0x1d, 0xe7, 0xc1, 0x44, 0x09, 0xd1, 0x80, 0x8a, 0x15, 0xf1, 0x88, 0x56, 0x20, 0x05,
0x09, 0x1c, 0xe4, 0x5e, 0x10, 0x5c, 0x28, 0x0f, 0xf5, 0x54, 0x21, 0xed, 0x81, 0xfb, 0xe2, 0x0c,
0xad, 0x95, 0xc4, 0x6b, 0xd6, 0xeb, 0x08, 0xff, 0x06, 0x7e, 0x28, 0x7f, 0x03, 0x79, 0xd7, 0x1b,
0x6a, 0xb7, 0xe5, 0x00, 0xb7, 0x79, 0x7c, 0xf3, 0xcd, 0xf7, 0x8d, 0x76, 0xe1, 0xc5, 0x2e, 0x4d,
0x94, 0x5c, 0x5d, 0xc8, 0x97, 0x36, 0x10, 0xa5, 0xbe, 0x5c, 0x15, 0xa4, 0xf6, 0x69, 0x42, 0xab,
0x5c, 0x49, 0x6d, 0x4b, 0x91, 0x09, 0x71, 0x72, 0x21, 0x23, 0x83, 0x8b, 0xea, 0x22, 0xfb, 0xe9,
0xc3, 0xf0, 0x34, 0x49, 0x64, 0x99, 0x69, 0x9c, 0x82, 0x9f, 0xae, 0x43, 0x6f, 0xe1, 0x2d, 0xef,
0x70, 0x3f, 0x5d, 0xe3, 0x7d, 0xe8, 0x6b, 0xb9, 0xa1, 0x2c, 0xf4, 0x4d, 0xc9, 0x26, 0x18, 0xc2,
0x30, 0x51, 0x24, 0x34, 0xad, 0xc3, 0xde, 0xc2, 0x5b, 0xf6, 0xb8, 0x4b, 0xf1, 0x18, 0x06, 0xf4,
0x23, 0x4f, 0x55, 0x15, 0x06, 0xa6, 0xd1, 0x64, 0xf8, 0x1c, 0xfa, 0x4a, 0x6e, 0xa9, 0x08, 0xfb,
0x8b, 0xde, 0x72, 0x1c, 0xdf, 0x8b, 0x5a, 0x12, 0x22, 0x2e, 0xb7, 0xc4, 0x2d, 0x02, 0xdf, 0xc1,
0x68, 0x47, 0x5a, 0xac, 0x85, 0x16, 0xe1, 0xc0, 0xa0, 0x9f, 0x76, 0xd0, 0x8d, 0xd8, 0xe8, 0xbc,
0x81, 0x7d, 0xca, 0xb4, 0xaa, 0xf8, 0x61, 0x6a, 0xfe, 0x16, 0x26, 0xad, 0x16, 0xce, 0xa0, 0xb7,
0xa1, 0xaa, 0xb1, 0x55, 0x87, 0xb5, 0xaf, 0xbd, 0xd8, 0x96, 0xe4, 0x7c, 0x99, 0xe4, 0x8d, 0xff,
0xda, 0x63, 0x9f, 0x21, 0xa8, 0xd5, 0x20, 0x42, 0x90, 0x89, 0x1d, 0x35, 0x43, 0x26, 0xc6, 0x13,
0x18, 0x29, 0x2a, 0x64, 0xa9, 0x12, 0x3b, 0x38, 0x8e, 0x1f, 0x74, 0x8d, 0x34, 0x6d, 0x7e, 0x00,
0xb2, 0x18, 0x46, 0xae, 0x7a, 0x23, 0x29, 0x42, 0xa0, 0xab, 0xdc, 0x29, 0x31, 0x31, 0xfb, 0x00,
0x77, 0xcf, 0x28, 0x23, 0x25, 0x34, 0x71, 0xfa, 0x5e, 0x52, 0xa1, 0xf1, 0x15, 0x0c, 0x85, 0xf5,
0x6d, 0xa6, 0xc7, 0xf1, 0xf1, 0xcd, 0x57, 0xe1, 0x0e, 0xc6, 0x3e, 0xc2, 0xec, 0x0f, 0x49, 0x91,
0xcb, 0xac, 0xa0, 0x7f, 0x60, 0x79, 0x06, 0x93, 0x2f, 0xa4, 0xd2, 0x6f, 0x95, 0x13, 0x72, 0x78,
0x12, 0xde, 0x95, 0x27, 0xc1, 0xde, 0xc3, 0xd4, 0xc1, 0xfe, 0x67, 0x15, 0xa7, 0xbd, 0xdc, 0xd0,
0xdf, 0x57, 0xcd, 0x60, 0xea, 0x60, 0x76, 0x55, 0xfc, 0xcb, 0x83, 0xe0, 0xb4, 0xd4, 0x97, 0x78,
0x0e, 0x23, 0x67, 0x19, 0x1f, 0x77, 0xd6, 0x75, 0x0e, 0x3a, 0x7f, 0x72, 0x6b, 0xdf, 0xb2, 0xb2,
0x23, 0x3c, 0x83, 0x81, 0x35, 0x85, 0x0f, 0x3b, 0xe0, 0xd6, 0x49, 0xe6, 0x8f, 0x6e, 0xe9, 0x5e,
0x25, 0xb2, 0x92, 0xaf, 0x11, 0xb5, 0x0c, 0x5f, 0x23, 0x6a, 0xfb, 0x64, 0x47, 0x5f, 0x07, 0xe6,
0x07, 0x9f, 0xfc, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x34, 0xce, 0x17, 0xf1, 0x03, 0x00, 0x00,
}

View File

@@ -1,16 +1,16 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: auth/service/proto/auth.proto
// source: micro/go-micro/auth/service/proto/auth.proto
package go_micro_auth
import (
fmt "fmt"
math "math"
context "context"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
client "github.com/micro/go-micro/v2/client"
server "github.com/micro/go-micro/v2/server"
)
@@ -35,7 +35,7 @@ var _ server.Option
type AuthService interface {
Generate(ctx context.Context, in *GenerateRequest, opts ...client.CallOption) (*GenerateResponse, error)
Validate(ctx context.Context, in *ValidateRequest, opts ...client.CallOption) (*ValidateResponse, error)
Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error)
Revoke(ctx context.Context, in *RevokeRequest, opts ...client.CallOption) (*RevokeResponse, error)
}
@@ -45,12 +45,6 @@ type authService struct {
}
func NewAuthService(name string, c client.Client) AuthService {
if c == nil {
c = client.NewClient()
}
if len(name) == 0 {
name = "go.micro.auth"
}
return &authService{
c: c,
name: name,
@@ -67,9 +61,9 @@ func (c *authService) Generate(ctx context.Context, in *GenerateRequest, opts ..
return out, nil
}
func (c *authService) Validate(ctx context.Context, in *ValidateRequest, opts ...client.CallOption) (*ValidateResponse, error) {
req := c.c.NewRequest(c.name, "Auth.Validate", in)
out := new(ValidateResponse)
func (c *authService) Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error) {
req := c.c.NewRequest(c.name, "Auth.Verify", in)
out := new(VerifyResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
@@ -91,14 +85,14 @@ func (c *authService) Revoke(ctx context.Context, in *RevokeRequest, opts ...cli
type AuthHandler interface {
Generate(context.Context, *GenerateRequest, *GenerateResponse) error
Validate(context.Context, *ValidateRequest, *ValidateResponse) error
Verify(context.Context, *VerifyRequest, *VerifyResponse) error
Revoke(context.Context, *RevokeRequest, *RevokeResponse) error
}
func RegisterAuthHandler(s server.Server, hdlr AuthHandler, opts ...server.HandlerOption) error {
type auth interface {
Generate(ctx context.Context, in *GenerateRequest, out *GenerateResponse) error
Validate(ctx context.Context, in *ValidateRequest, out *ValidateResponse) error
Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error
Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error
}
type Auth struct {
@@ -116,8 +110,8 @@ func (h *authHandler) Generate(ctx context.Context, in *GenerateRequest, out *Ge
return h.AuthHandler.Generate(ctx, in, out)
}
func (h *authHandler) Validate(ctx context.Context, in *ValidateRequest, out *ValidateResponse) error {
return h.AuthHandler.Validate(ctx, in, out)
func (h *authHandler) Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error {
return h.AuthHandler.Verify(ctx, in, out)
}
func (h *authHandler) Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error {

View File

@@ -4,7 +4,7 @@ package go.micro.auth;
service Auth {
rpc Generate(GenerateRequest) returns (GenerateResponse) {};
rpc Validate(ValidateRequest) returns (ValidateResponse) {};
rpc Verify(VerifyRequest) returns (VerifyResponse) {};
rpc Revoke(RevokeRequest) returns (RevokeResponse) {};
}
@@ -35,11 +35,11 @@ message GenerateResponse {
Account account = 1;
}
message ValidateRequest {
message VerifyRequest {
string token = 1;
}
message ValidateResponse {
message VerifyResponse {
Account account = 1;
}

View File

@@ -72,9 +72,9 @@ func (s *svc) Revoke(token string) error {
return err
}
// Validate an account token
func (s *svc) Validate(token string) (*auth.Account, error) {
resp, err := s.auth.Validate(context.Background(), &pb.ValidateRequest{Token: token})
// Verify an account token
func (s *svc) Verify(token string) (*auth.Account, error) {
resp, err := s.auth.Verify(context.Background(), &pb.VerifyRequest{Token: token})
if err != nil {
return nil, err
}

130
auth/store/store.go Normal file
View File

@@ -0,0 +1,130 @@
package store
import (
"bytes"
"encoding/gob"
"time"
"github.com/google/uuid"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/store"
)
type Auth struct {
store store.Store
opts auth.Options
}
// NewAuth returns an instance of store auth
func NewAuth(opts ...auth.Option) auth.Auth {
var options auth.Options
for _, o := range opts {
o(&options)
}
return &Auth{
store: store.DefaultStore,
opts: options,
}
}
// Init the auth package
func (a *Auth) Init(opts ...auth.Option) error {
for _, o := range opts {
o(&a.opts)
}
return nil
}
// Options returns the options set
func (a *Auth) Options() auth.Options {
return a.opts
}
// Generate a new auth Account
func (a *Auth) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
// generate the token
token, err := uuid.NewUUID()
if err != nil {
return nil, err
}
// parse the options
options := auth.NewGenerateOptions(opts...)
// construct the account
sa := auth.Account{
Id: id,
Token: token.String(),
Created: time.Now(),
Metadata: options.Metadata,
Roles: options.Roles,
}
// encode the data to bytes
// TODO: replace with json
buf := &bytes.Buffer{}
e := gob.NewEncoder(buf)
if err := e.Encode(sa); err != nil {
return nil, err
}
// write to the store
err = a.store.Write(&store.Record{
Key: token.String(),
Value: buf.Bytes(),
})
if err != nil {
return nil, err
}
// return the result
return &sa, nil
}
// Revoke an authorization Account
func (a *Auth) Revoke(token string) error {
records, err := a.store.Read(token, store.ReadSuffix())
if err != nil {
return err
}
if len(records) == 0 {
return errors.BadRequest("go.micro.auth", "token not found")
}
for _, r := range records {
if err := a.store.Delete(r.Key); err != nil {
return errors.InternalServerError("go.micro.auth", "error deleting from store")
}
}
return nil
}
// Verify an account token
func (a *Auth) Verify(token string) (*auth.Account, error) {
// lookup the record by token
records, err := a.store.Read(token, store.ReadSuffix())
if err == store.ErrNotFound || len(records) == 0 {
return nil, errors.Unauthorized("go.micro.auth", "invalid token")
} else if err != nil {
return nil, errors.InternalServerError("go.micro.auth", "error reading store")
}
// decode the result
// TODO: replace with json
b := bytes.NewBuffer(records[0].Value)
decoder := gob.NewDecoder(b)
var sa auth.Account
err = decoder.Decode(&sa)
// return the result
return &sa, err
}
// String returns the implementation
func (a *Auth) String() string {
return "store"
}

View File

@@ -11,9 +11,9 @@ import (
"time"
"github.com/micro/go-micro/v2/codec/json"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/addr"
"github.com/micro/go-micro/v2/util/log"
"github.com/nats-io/nats-server/v2/server"
nats "github.com/nats-io/nats.go"
)
@@ -167,7 +167,7 @@ func (n *natsBroker) serve(exit chan bool) error {
for _, node := range service.Nodes {
u, err := url.Parse("nats://" + node.Address)
if err != nil {
log.Log(err)
log.Info(err)
continue
}
// append to the cluster routes
@@ -242,7 +242,7 @@ func (n *natsBroker) serve(exit chan bool) error {
select {
case err := <-n.closeCh:
if err != nil {
log.Log(err)
log.Info(err)
}
case <-exit:
// deregister on exit

View File

@@ -6,16 +6,6 @@ import (
"github.com/micro/go-micro/v2/broker"
)
// setSubscribeOption returns a function to setup a context with given value
func setSubscribeOption(k, v interface{}) broker.SubscribeOption {
return func(o *broker.SubscribeOptions) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, k, v)
}
}
// setBrokerOption returns a function to setup a context with given value
func setBrokerOption(k, v interface{}) broker.Option {
return func(o *broker.Options) {
@@ -25,13 +15,3 @@ func setBrokerOption(k, v interface{}) broker.Option {
o.Context = context.WithValue(o.Context, k, v)
}
}
// setPublishOption returns a function to setup a context with given value
func setPublishOption(k, v interface{}) broker.PublishOption {
return func(o *broker.PublishOptions) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, k, v)
}
}

View File

@@ -13,9 +13,9 @@ import (
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/codec/json"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/addr"
"github.com/micro/go-micro/v2/util/log"
"github.com/nats-io/nats-server/v2/server"
nats "github.com/nats-io/nats.go"
)
@@ -164,7 +164,7 @@ func (n *natsBroker) serve(exit chan bool) error {
for _, node := range service.Nodes {
u, err := url.Parse("nats://" + node.Address)
if err != nil {
log.Log(err)
log.Error(err)
continue
}
// append to the cluster routes

View File

@@ -8,7 +8,7 @@ import (
"github.com/micro/go-micro/v2/broker"
pb "github.com/micro/go-micro/v2/broker/service/proto"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
type serviceBroker struct {

View File

@@ -3,7 +3,7 @@ package service
import (
"github.com/micro/go-micro/v2/broker"
pb "github.com/micro/go-micro/v2/broker/service/proto"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
type serviceSub struct {

View File

@@ -155,7 +155,7 @@ func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
m = new(codec.Message)
}
if m.Header == nil {
m.Header = make(map[string]string)
m.Header = make(map[string]string, len(md))
}
for k, v := range md {
m.Header[k] = strings.Join(v, ",")

View File

@@ -5,8 +5,10 @@ import (
"context"
"crypto/tls"
"fmt"
"net"
"os"
"sync"
"strings"
"sync/atomic"
"time"
"github.com/micro/go-micro/v2/broker"
@@ -16,6 +18,7 @@ import (
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/config"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
@@ -23,10 +26,14 @@ import (
gmetadata "google.golang.org/grpc/metadata"
)
var (
BearerScheme = "Bearer "
)
type grpcClient struct {
once sync.Once
opts client.Options
pool *pool
once atomic.Value
}
func init() {
@@ -36,14 +43,36 @@ func init() {
}
// secure returns the dial option for whether its a secure or insecure connection
func (g *grpcClient) secure() grpc.DialOption {
func (g *grpcClient) secure(addr string) grpc.DialOption {
// first we check if theres'a tls config
if g.opts.Context != nil {
if v := g.opts.Context.Value(tlsAuth{}); v != nil {
tls := v.(*tls.Config)
creds := credentials.NewTLS(tls)
// return tls config if it exists
return grpc.WithTransportCredentials(creds)
}
}
// default config
tlsConfig := &tls.Config{}
defaultCreds := grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))
// check if the address is prepended with https
if strings.HasPrefix(addr, "https://") {
return defaultCreds
}
// if no port is specified or port is 443 default to tls
_, port, err := net.SplitHostPort(addr)
// assuming with no port its going to be secured
if port == "443" {
return defaultCreds
} else if err != nil && strings.Contains(err.Error(), "missing port in address") {
return defaultCreds
}
// other fallback to insecure
return grpc.WithInsecure()
}
@@ -52,6 +81,10 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele
// get proxy
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
// default name
if prx == "service" {
prx = "go.micro.proxy"
}
service = prx
}
@@ -82,19 +115,28 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele
}
func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
var header map[string]string
address := node.Address
header := make(map[string]string)
header = make(map[string]string)
if md, ok := metadata.FromContext(ctx); ok {
header = make(map[string]string, len(md))
for k, v := range md {
header[k] = v
}
} else {
header = make(map[string]string)
}
// set timeout in nanoseconds
header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout)
// set the content type for the request
header["x-content-type"] = req.ContentType()
// set the authorization token if one is saved locally
if token, err := config.Get("token"); err == nil && len(token) > 0 {
header["authorization"] = BearerScheme + token
}
md := gmetadata.New(header)
ctx = gmetadata.NewOutgoingContext(ctx, md)
@@ -112,7 +154,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
grpcDialOptions := []grpc.DialOption{
grpc.WithDefaultCallOptions(grpc.ForceCodec(cf)),
grpc.WithTimeout(opts.DialTimeout),
g.secure(),
g.secure(address),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(maxRecvMsgSize),
grpc.MaxCallSendMsgSize(maxSendMsgSize),
@@ -154,13 +196,17 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
}
func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, opts client.CallOptions) (client.Stream, error) {
var header map[string]string
address := node.Address
header := make(map[string]string)
if md, ok := metadata.FromContext(ctx); ok {
header = make(map[string]string, len(md))
for k, v := range md {
header[k] = v
}
} else {
header = make(map[string]string)
}
// set timeout in nanoseconds
@@ -189,7 +235,8 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
grpcDialOptions := []grpc.DialOption{
grpc.WithDefaultCallOptions(grpc.ForceCodec(wc)),
g.secure(),
grpc.WithTimeout(opts.DialTimeout),
g.secure(address),
}
if opts := g.getGrpcDialOptions(); opts != nil {
@@ -217,6 +264,12 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
st, err := cc.NewStream(newCtx, desc, methodToGRPC(req.Service(), req.Endpoint()), grpcCallOptions...)
if err != nil {
// we need to cleanup as we dialled and created a context
// cancel the context
cancel()
// close the connection
cc.Close()
// now return the error
return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
}
@@ -339,6 +392,11 @@ func (g *grpcClient) NewRequest(service, method string, req interface{}, reqOpts
}
func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
if req == nil {
return errors.InternalServerError("go.micro.client", "req is nil")
} else if rsp == nil {
return errors.InternalServerError("go.micro.client", "rsp is nil")
}
// make a copy of call opts
callOpts := g.opts.CallOptions
for _, opt := range opts {
@@ -559,17 +617,15 @@ func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...clie
body = b
}
g.once.Do(func() {
g.opts.Broker.Connect()
})
if !g.once.Load().(bool) {
if err = g.opts.Broker.Connect(); err != nil {
return errors.InternalServerError("go.micro.client", err.Error())
}
g.once.Store(true)
}
topic := p.Topic()
// get proxy topic
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
options.Exchange = prx
}
// get the exchange
if len(options.Exchange) > 0 {
topic = options.Exchange
@@ -635,9 +691,9 @@ func newClient(opts ...client.Option) client.Client {
}
rc := &grpcClient{
once: sync.Once{},
opts: options,
}
rc.once.Store(false)
rc.pool = newPool(options.PoolSize, options.PoolTTL, rc.poolMaxIdle(), rc.poolMaxStreams())

View File

@@ -27,7 +27,7 @@ func (r *response) Header() map[string]string {
if err != nil {
return map[string]string{}
}
hdr := make(map[string]string)
hdr := make(map[string]string, len(md))
for k, v := range md {
hdr[k] = strings.Join(v, ",")
}

View File

@@ -291,6 +291,12 @@ func WithDialTimeout(d time.Duration) CallOption {
}
}
func WithMessageContentType(ct string) MessageOption {
return func(o *MessageOptions) {
o.ContentType = ct
}
}
// Request Options
func WithContentType(ct string) RequestOption {

View File

@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"os"
"sync"
"sync/atomic"
"time"
@@ -22,7 +21,7 @@ import (
)
type rpcClient struct {
once sync.Once
once atomic.Value
opts Options
pool pool.Pool
seq uint64
@@ -38,11 +37,11 @@ func newRpcClient(opt ...Option) Client {
)
rc := &rpcClient{
once: sync.Once{},
opts: opts,
pool: p,
seq: 0,
}
rc.once.Store(false)
c := Client(rc)
@@ -342,6 +341,10 @@ func (r *rpcClient) next(request Request, opts CallOptions) (selector.Next, erro
// get proxy
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
// default name
if prx == "service" {
prx = "go.micro.proxy"
}
service = prx
}
@@ -606,11 +609,6 @@ func (r *rpcClient) Publish(ctx context.Context, msg Message, opts ...PublishOpt
// set the topic
topic := msg.Topic()
// get proxy
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
options.Exchange = prx
}
// get the exchange
if len(options.Exchange) > 0 {
topic = options.Exchange
@@ -646,9 +644,12 @@ func (r *rpcClient) Publish(ctx context.Context, msg Message, opts ...PublishOpt
body = b.Bytes()
}
r.once.Do(func() {
r.opts.Broker.Connect()
})
if !r.once.Load().(bool) {
if err = r.opts.Broker.Connect(); err != nil {
return errors.InternalServerError("go.micro.client", err.Error())
}
r.once.Store(true)
}
return r.opts.Broker.Publish(topic, &broker.Message{
Header: md,

View File

@@ -2,6 +2,7 @@
package codec
import (
"errors"
"io"
)
@@ -12,6 +13,10 @@ const (
Event
)
var (
ErrInvalidMessage = errors.New("invalid message")
)
type MessageType int
// Takes in a connection/buffer and returns a new Codec

View File

@@ -25,13 +25,17 @@ func (c *Codec) ReadBody(b interface{}) error {
if err != nil {
return err
}
return proto.Unmarshal(buf, b.(proto.Message))
m, ok := b.(proto.Message)
if !ok {
return codec.ErrInvalidMessage
}
return proto.Unmarshal(buf, m)
}
func (c *Codec) Write(m *codec.Message, b interface{}) error {
p, ok := b.(proto.Message)
if !ok {
return nil
return codec.ErrInvalidMessage
}
buf, err := proto.Marshal(p)
if err != nil {

View File

@@ -56,8 +56,12 @@ func (c *protoCodec) Write(m *codec.Message, b interface{}) error {
if err != nil {
return err
}
// Of course this is a protobuf! Trust me or detonate the program.
data, err = proto.Marshal(b.(proto.Message))
// dont trust or incoming message
m, ok := b.(proto.Message)
if !ok {
return codec.ErrInvalidMessage
}
data, err = proto.Marshal(m)
if err != nil {
return err
}
@@ -100,7 +104,11 @@ func (c *protoCodec) Write(m *codec.Message, b interface{}) error {
}
}
case codec.Event:
data, err := proto.Marshal(b.(proto.Message))
m, ok := b.(proto.Message)
if !ok {
return codec.ErrInvalidMessage
}
data, err := proto.Marshal(m)
if err != nil {
return err
}

View File

@@ -11,13 +11,16 @@ import (
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/client/selector"
"github.com/micro/go-micro/v2/debug/profile"
"github.com/micro/go-micro/v2/debug/profile/http"
"github.com/micro/go-micro/v2/debug/profile/pprof"
"github.com/micro/go-micro/v2/debug/trace"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/runtime"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/store"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/util/log"
// clients
cgrpc "github.com/micro/go-micro/v2/client/grpc"
@@ -25,6 +28,7 @@ import (
// servers
"github.com/micro/cli/v2"
sgrpc "github.com/micro/go-micro/v2/server/grpc"
smucp "github.com/micro/go-micro/v2/server/mucp"
@@ -65,6 +69,7 @@ import (
// auth
jwtAuth "github.com/micro/go-micro/v2/auth/jwt"
sAuth "github.com/micro/go-micro/v2/auth/service"
storeAuth "github.com/micro/go-micro/v2/auth/store"
)
type Cmd interface {
@@ -244,6 +249,11 @@ var (
EnvVars: []string{"MICRO_AUTH"},
Usage: "Auth for role based access control, e.g. service",
},
&cli.StringFlag{
Name: "auth_token",
EnvVars: []string{"MICRO_AUTH_TOKEN"},
Usage: "Auth token used for client authentication",
},
&cli.StringFlag{
Name: "auth_public_key",
EnvVars: []string{"MICRO_AUTH_PUBLIC_KEY"},
@@ -257,7 +267,7 @@ var (
&cli.StringSliceFlag{
Name: "auth_exclude",
EnvVars: []string{"MICRO_AUTH_EXCLUDE"},
Usage: "Comma-separated list of endpoints excluded from authentication",
Usage: "Comma-separated list of endpoints excluded from authentication, e.g. Users.ListUsers",
},
}
@@ -314,8 +324,14 @@ var (
DefaultAuths = map[string]func(...auth.Option) auth.Auth{
"service": sAuth.NewAuth,
"store": storeAuth.NewAuth,
"jwt": jwtAuth.NewAuth,
}
DefaultProfiles = map[string]func(...profile.Option) profile.Profile{
"http": http.NewProfile,
"pprof": pprof.NewProfile,
}
)
func init() {
@@ -334,6 +350,7 @@ func newCmd(opts ...Option) Cmd {
Runtime: &runtime.DefaultRuntime,
Store: &store.DefaultStore,
Tracer: &trace.DefaultTracer,
Profile: &profile.DefaultProfile,
Brokers: DefaultBrokers,
Clients: DefaultClients,
@@ -345,6 +362,7 @@ func newCmd(opts ...Option) Cmd {
Stores: DefaultStores,
Tracers: DefaultTracers,
Auths: DefaultAuths,
Profiles: DefaultProfiles,
}
for _, o := range opts {
@@ -428,6 +446,16 @@ func (c *cmd) Before(ctx *cli.Context) error {
*c.opts.Auth = a()
}
// 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
@@ -583,6 +611,10 @@ func (c *cmd) Before(ctx *cli.Context) error {
}
}
if len(ctx.String("auth_token")) > 0 {
authOpts = append(authOpts, auth.Token(ctx.String("auth_token")))
}
if len(ctx.String("auth_public_key")) > 0 {
authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key")))
}
@@ -592,7 +624,7 @@ func (c *cmd) Before(ctx *cli.Context) error {
}
if len(ctx.StringSlice("auth_exclude")) > 0 {
authOpts = append(authOpts, auth.Excludes(ctx.StringSlice("auth_exclude")...))
authOpts = append(authOpts, auth.Exclude(ctx.StringSlice("auth_exclude")...))
}
if len(authOpts) > 0 {

View File

@@ -7,6 +7,7 @@ import (
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/client/selector"
"github.com/micro/go-micro/v2/debug/profile"
"github.com/micro/go-micro/v2/debug/trace"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/runtime"
@@ -32,6 +33,7 @@ type Options struct {
Store *store.Store
Tracer *trace.Tracer
Auth *auth.Auth
Profile *profile.Profile
Brokers map[string]func(...broker.Option) broker.Broker
Clients map[string]func(...client.Option) client.Client
@@ -43,6 +45,7 @@ type Options struct {
Stores map[string]func(...store.Option) store.Store
Tracers map[string]func(...trace.Option) trace.Tracer
Auths map[string]func(...auth.Option) auth.Auth
Profiles map[string]func(...profile.Option) profile.Profile
// Other options for implementations of the interface
// can be stored in a context
@@ -118,6 +121,12 @@ func Auth(a *auth.Auth) Option {
}
}
func Profile(p *profile.Profile) Option {
return func(o *Options) {
o.Profile = p
}
}
// New broker func
func NewBroker(name string, b func(...broker.Option) broker.Broker) Option {
return func(o *Options) {

View File

@@ -12,10 +12,6 @@ import (
"github.com/micro/go-micro/v2/config/source/file"
)
var (
sep = string(os.PathSeparator)
)
func createFileForIssue18(t *testing.T, content string) *os.File {
data := []byte(content)
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))

View File

@@ -6,7 +6,7 @@ import (
"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/util/log"
log "github.com/micro/go-micro/v2/logger"
)
var (

View File

@@ -1,13 +1,7 @@
package log
import (
"bufio"
"encoding/json"
"io"
"os"
"strings"
"sync"
"time"
"github.com/google/uuid"
"github.com/micro/go-micro/v2/util/ring"
@@ -25,106 +19,10 @@ type osLog struct {
type osStream struct {
stream chan Record
stop chan bool
}
// watch io stream
func (o *osLog) run() {
// save outputs
stdout := *os.Stdout
stderr := *os.Stderr
// new os pipe
r, w := io.Pipe()
// create new iopipes
r1, w1, _ := os.Pipe()
r2, w2, _ := os.Pipe()
// create tea readers
tee1 := io.TeeReader(r1, &stdout)
tee2 := io.TeeReader(r2, &stderr)
// start copying
go io.Copy(w, tee1)
go io.Copy(w, tee2)
// set default go log output
//log.SetOutput(w2)
// replace os stdout and os stderr
*os.Stdout = *w1
*os.Stderr = *w2
// this should short circuit everything
defer func() {
// reset stdout and stderr
*os.Stdout = stdout
*os.Stderr = stderr
//log.SetOutput(stderr)
// close all the outputs
r.Close()
r1.Close()
r2.Close()
w.Close()
w1.Close()
w2.Close()
}()
// read from standard error
scanner := bufio.NewReader(r)
for {
// read the line
line, err := scanner.ReadString('\n')
if err != nil {
return
}
// check if the line exists
if len(line) == 0 {
continue
}
// parse the record
var r Record
if line[0] == '{' {
json.Unmarshal([]byte(line), &r)
} else {
r = Record{
Timestamp: time.Now(),
Message: strings.TrimSuffix(line, "\n"),
Metadata: make(map[string]string),
}
}
o.Lock()
// write to the buffer
o.buffer.Put(r)
// check subs and send to stream
for id, sub := range o.subs {
// send to stream
select {
case <-sub.stop:
delete(o.subs, id)
case sub.stream <- r:
// send to stream
default:
// do not block
}
}
o.Unlock()
}
}
// Read reads log entries from the logger
func (o *osLog) Read(...ReadOption) ([]Record, error) {
o.once.Do(func() {
go o.run()
})
var records []Record
// read the last 100 records
@@ -137,29 +35,18 @@ func (o *osLog) Read(...ReadOption) ([]Record, error) {
// Write writes records to log
func (o *osLog) Write(r Record) error {
o.once.Do(func() {
go o.run()
})
// generate output
out := o.format(r) + "\n"
_, err := os.Stderr.Write([]byte(out))
return err
o.buffer.Put(r)
return nil
}
// Stream log records
func (o *osLog) Stream() (Stream, error) {
o.once.Do(func() {
go o.run()
})
o.Lock()
defer o.Unlock()
// create stream
st := &osStream{
stream: make(chan Record, 128),
stop: make(chan bool),
}
// save stream
@@ -173,12 +60,6 @@ func (o *osStream) Chan() <-chan Record {
}
func (o *osStream) Stop() error {
select {
case <-o.stop:
return nil
default:
close(o.stop)
}
return nil
}

View File

@@ -10,6 +10,24 @@ type Profile interface {
String() string
}
var (
DefaultProfile Profile = new(noop)
)
type noop struct{}
func (p *noop) Start() error {
return nil
}
func (p *noop) Stop() error {
return nil
}
func (p *noop) String() string {
return "noop"
}
type Options struct {
// Name to use for the profile
Name string

10
go.mod
View File

@@ -37,12 +37,12 @@ require (
github.com/leodido/go-urn v1.2.0 // indirect
github.com/lib/pq v1.3.0
github.com/lucas-clemente/quic-go v0.14.1
github.com/mholt/certmagic v0.9.1
github.com/micro/cli/v2 v2.1.2-0.20200203150404-894195727d9c
github.com/mholt/certmagic v0.9.3
github.com/micro/cli/v2 v2.1.2
github.com/micro/mdns v0.3.0
github.com/miekg/dns v1.1.27
github.com/mitchellh/hashstructure v1.0.0
github.com/nats-io/nats-server/v2 v2.1.2
github.com/nats-io/nats-server/v2 v2.1.4
github.com/nats-io/nats.go v1.9.1
github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
@@ -54,8 +54,8 @@ require (
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
go.etcd.io/bbolt v1.3.3 // indirect
go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 // indirect
google.golang.org/grpc v1.26.0
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect

21
go.sum
View File

@@ -280,10 +280,11 @@ 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.9.1 h1:wPzyouOyE+30NIQETJuhTB5ZQWz+0Hy038vaR5WWQDE=
github.com/mholt/certmagic v0.9.1/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
github.com/micro/cli/v2 v2.1.2-0.20200203150404-894195727d9c h1:oohy8v2QQeXfDe9/BaM0b+5wETzoMiemOs3fhPhnFTg=
github.com/micro/cli/v2 v2.1.2-0.20200203150404-894195727d9c/go.mod h1:EguNh6DAoWKm9nmk+k/Rg0H3lQnDxqzu5x5srOtGtYg=
github.com/mholt/certmagic v0.9.3 h1:RmzuNJ5mpFplDbyS41z+gGgE/py24IX6m0nHZ0yNTQU=
github.com/mholt/certmagic v0.9.3/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
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.18.0 h1:gP70EZVHpJuUIT0YWth192JmlIci+qMOEByHm83XE9E=
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/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@@ -309,8 +310,8 @@ github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY
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.2 h1:i2Ly0B+1+rzNZHHWtD4ZwKi+OU5l+uQo1iDHZ2PmiIc=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats-server/v2 v2.1.4 h1:BILRnsJ2Yb/fefiFbBWADpViGF69uh4sxe8poVDQ06g=
github.com/nats-io/nats-server/v2 v2.1.4/go.mod h1:Jw1Z28soD/QasIA2uWjXyM9El1jly3YwyFOuR8tH1rg=
github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
@@ -457,8 +458,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
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-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg=
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/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=
@@ -502,8 +503,8 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL
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-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0 h1:MsuvTghUPjX762sGLnGsxC3HM0B5r83wEtYcYR8/vRs=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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=

133
logger/default.go Normal file
View File

@@ -0,0 +1,133 @@
package logger
import (
"context"
"fmt"
"os"
"sync"
"time"
dlog "github.com/micro/go-micro/v2/debug/log"
)
type defaultLogger struct {
sync.RWMutex
opts Options
err error
}
// Init(opts...) should only overwrite provided options
func (l *defaultLogger) Init(opts ...Option) error {
for _, o := range opts {
o(&l.opts)
}
return nil
}
func (l *defaultLogger) String() string {
return "default"
}
func (l *defaultLogger) Fields(fields map[string]interface{}) Logger {
l.Lock()
l.opts.Fields = copyFields(fields)
l.Unlock()
return l
}
func (l *defaultLogger) Error(err error) Logger {
l.Lock()
l.err = err
l.Unlock()
return l
}
func copyFields(src map[string]interface{}) map[string]interface{} {
dst := make(map[string]interface{}, len(src))
for k, v := range src {
dst[k] = v
}
return dst
}
func (l *defaultLogger) Log(level Level, v ...interface{}) {
// TODO decide does we need to write message if log level not used?
if !l.opts.Level.Enabled(level) {
return
}
l.RLock()
fields := copyFields(l.opts.Fields)
if l.err != nil {
fields["error"] = l.err.Error()
}
l.RUnlock()
fields["level"] = level.String()
rec := dlog.Record{
Timestamp: time.Now(),
Message: fmt.Sprint(v...),
Metadata: make(map[string]string, len(fields)),
}
for k, v := range fields {
rec.Metadata[k] = fmt.Sprintf("%v", v)
}
dlog.DefaultLog.Write(rec)
t := rec.Timestamp.Format("2006-01-02 15:04:05")
fmt.Printf("%s %v\n", t, rec.Message)
}
func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) {
// TODO decide does we need to write message if log level not used?
if level < l.opts.Level {
return
}
l.RLock()
fields := copyFields(l.opts.Fields)
if l.err != nil {
fields["error"] = l.err.Error()
}
l.RUnlock()
fields["level"] = level.String()
rec := dlog.Record{
Timestamp: time.Now(),
Message: fmt.Sprintf(format, v...),
Metadata: make(map[string]string, len(fields)),
}
for k, v := range fields {
rec.Metadata[k] = fmt.Sprintf("%v", v)
}
dlog.DefaultLog.Write(rec)
t := rec.Timestamp.Format("2006-01-02 15:04:05")
fmt.Printf("%s %v\n", t, rec.Message)
}
func (n *defaultLogger) Options() Options {
return n.opts
}
// NewLogger builds a new logger based on options
func NewLogger(opts ...Option) Logger {
// Default options
options := Options{
Level: InfoLevel,
Fields: make(map[string]interface{}),
Out: os.Stderr,
Context: context.Background(),
}
l := &defaultLogger{opts: options}
if err := l.Init(opts...); err != nil {
l.Log(FatalLevel, err)
}
return l
}

View File

@@ -1,43 +0,0 @@
package logger
type FieldType uint8
type Encode func(*Field) string
type Field struct {
Key string
Type FieldType
Value interface{}
Encode Encode
}
func (f *Field) GetValue() interface{} {
if f.Encode != nil {
return f.Encode(f)
}
return f.Value
}
// preset common types for choosing encoder faster
const (
UnknownType FieldType = iota
BoolType
DurationType
Float64Type
Float32Type
Int64Type
Int32Type
Int16Type
Int8Type
Uint64Type
Uint32Type
Uint16Type
Uint8Type
StringType
TimeType
)
func Bool(key string, val bool) Field {
return Field{Key: key, Type: BoolType, Value: val}
}

View File

@@ -1,13 +1,112 @@
package logger
import "fmt"
type Level int8
const (
TraceLevel Level = iota - 1
// TraceLevel level. Designates finer-grained informational events than the Debug.
TraceLevel Level = iota - 2
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
DebugLevel
// InfoLevel is the default logging priority.
// General operational entries about what's going on inside the application.
InfoLevel
// WarnLevel level. Non-critical entries that deserve eyes.
WarnLevel
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
ErrorLevel
PanicLevel
// FatalLevel level. Logs and then calls `logger.Exit(1)`. highest level of severity.
FatalLevel
)
func (l Level) String() string {
switch l {
case TraceLevel:
return "trace"
case DebugLevel:
return "debug"
case InfoLevel:
return "info"
case WarnLevel:
return "warn"
case ErrorLevel:
return "error"
case FatalLevel:
return "fatal"
}
return ""
}
// Enabled returns true if the given level is at or above this level.
func (l Level) Enabled(lvl Level) bool {
return lvl >= l
}
// GetLevel converts a level string into a logger Level value.
// returns an error if the input string does not match known values.
func GetLevel(levelStr string) (Level, error) {
switch levelStr {
case TraceLevel.String():
return TraceLevel, nil
case DebugLevel.String():
return DebugLevel, nil
case InfoLevel.String():
return InfoLevel, nil
case WarnLevel.String():
return WarnLevel, nil
case ErrorLevel.String():
return ErrorLevel, nil
case FatalLevel.String():
return FatalLevel, nil
}
return InfoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to InfoLevel", levelStr)
}
func Info(args ...interface{}) {
DefaultLogger.Log(InfoLevel, args...)
}
func Infof(template string, args ...interface{}) {
DefaultLogger.Logf(InfoLevel, template, args...)
}
func Trace(args ...interface{}) {
DefaultLogger.Log(TraceLevel, args...)
}
func Tracef(template string, args ...interface{}) {
DefaultLogger.Logf(TraceLevel, template, args...)
}
func Debug(args ...interface{}) {
DefaultLogger.Log(DebugLevel, args...)
}
func Debugf(template string, args ...interface{}) {
DefaultLogger.Logf(DebugLevel, template, args...)
}
func Warn(args ...interface{}) {
DefaultLogger.Log(WarnLevel, args...)
}
func Warnf(template string, args ...interface{}) {
DefaultLogger.Logf(WarnLevel, template, args...)
}
func Error(args ...interface{}) {
DefaultLogger.Log(ErrorLevel, args...)
}
func Errorf(template string, args ...interface{}) {
DefaultLogger.Logf(ErrorLevel, template, args...)
}
func Fatal(args ...interface{}) {
DefaultLogger.Log(FatalLevel, args...)
}
func Fatalf(template string, args ...interface{}) {
DefaultLogger.Logf(FatalLevel, template, args...)
}

View File

@@ -1,49 +1,49 @@
// Package log provides a log interface
package logger
import (
"fmt"
"sync"
var (
// Default logger
DefaultLogger Logger = NewLogger()
)
// Logger is a generic logging interface
type Logger interface {
// Init initialises options
Init(options ...Option) error
// Level returns the logging level
Level() Level
// Log inserts a log entry. Arguments may be handled in the manner
// of fmt.Print, but the underlying logger may also decide to handle
// them differently.
Log(level Level, v ...interface{})
// Logf insets a log entry. Arguments are handled in the manner of
// fmt.Printf.
Logf(level Level, format string, v ...interface{})
// The Logger options
Options() Options
// Error set `error` field to be logged
Error(err error) Logger
// Fields set fields to always be logged
Fields(fields ...Field) Logger
// SetLevel updates the logging level.
SetLevel(Level)
Fields(fields map[string]interface{}) Logger
// Log writes a log entry
Log(level Level, v ...interface{})
// Logf writes a formatted log entry
Logf(level Level, format string, v ...interface{})
// String returns the name of logger
String() string
}
var (
mtx sync.Mutex
loggerMap = map[string]Logger{}
)
func Register(logger Logger) {
mtx.Lock()
defer mtx.Unlock()
loggerMap[logger.String()] = logger
func Init(opts ...Option) error {
return DefaultLogger.Init(opts...)
}
func GetLogger(name string) (Logger, error) {
l := loggerMap[name]
if l == nil {
return nil, fmt.Errorf("no such name logger found %s", name)
func Fields(fields map[string]interface{}) Logger {
return DefaultLogger.Fields(fields)
}
return l, nil
func Log(level Level, v ...interface{}) {
DefaultLogger.Log(level, v...)
}
func Logf(level Level, format string, v ...interface{}) {
DefaultLogger.Logf(level, format, v...)
}
func String() string {
return DefaultLogger.String()
}
func WithError(err error) Logger {
return DefaultLogger.Error(err)
}

View File

@@ -2,20 +2,48 @@ package logger
import (
"context"
"io"
)
// Option for load profiles maybe
// eg. yml
// micro:
// logger:
// name:
// dialect: zap/default/logrus
// zap:
// xxx:
// logrus:
// xxx:
type Option func(*Options)
type Options struct {
// The logging level the logger should log at. default is `InfoLevel`
Level Level
// fields to always be logged
Fields map[string]interface{}
// It's common to set this to a file, or leave it default which is `os.Stderr`
Out io.Writer
// Alternative options
Context context.Context
}
// WithFields set default fields for the logger
func WithFields(fields map[string]interface{}) Option {
return func(args *Options) {
args.Fields = fields
}
}
// WithLevel set default level for the logger
func WithLevel(level Level) Option {
return func(args *Options) {
args.Level = level
}
}
// WithOutput set default output writer for the logger
func WithOutput(out io.Writer) Option {
return func(args *Options) {
args.Out = out
}
}
func SetOption(k, v interface{}) Option {
return func(o *Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, k, v)
}
}

View File

@@ -22,6 +22,16 @@ func Copy(md Metadata) Metadata {
return cmd
}
// Set add key with val to metadata
func Set(ctx context.Context, k, v string) context.Context {
md, ok := FromContext(ctx)
if !ok {
md = make(Metadata)
}
md[k] = v
return context.WithValue(ctx, metaKey{}, md)
}
// Get returns a single value from metadata in the context
func Get(ctx context.Context, key string) (string, bool) {
md, ok := FromContext(ctx)
@@ -48,7 +58,7 @@ func FromContext(ctx context.Context) (Metadata, bool) {
}
// capitalise all values
newMD := make(map[string]string)
newMD := make(map[string]string, len(md))
for k, v := range md {
newMD[strings.Title(k)] = v
}

View File

@@ -6,6 +6,18 @@ import (
"testing"
)
func TestMetadataSet(t *testing.T) {
ctx := Set(context.TODO(), "Key", "val")
val, ok := Get(ctx, "Key")
if !ok {
t.Fatal("key Key not found")
}
if val != "val" {
t.Errorf("key Key with value val != %v", val)
}
}
func TestMetadataCopy(t *testing.T) {
md := Metadata{
"Foo": "bar",

View File

@@ -15,6 +15,7 @@ import (
"github.com/micro/go-micro/v2/client"
cmucp "github.com/micro/go-micro/v2/client/mucp"
rtr "github.com/micro/go-micro/v2/client/selector/router"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/network/resolver/dns"
pbNet "github.com/micro/go-micro/v2/network/service/proto"
"github.com/micro/go-micro/v2/proxy"
@@ -27,7 +28,6 @@ import (
bun "github.com/micro/go-micro/v2/tunnel/broker"
tun "github.com/micro/go-micro/v2/tunnel/transport"
"github.com/micro/go-micro/v2/util/backoff"
"github.com/micro/go-micro/v2/util/log"
pbUtil "github.com/micro/go-micro/v2/util/proto"
)

View File

@@ -10,6 +10,7 @@ import (
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/client/selector"
"github.com/micro/go-micro/v2/config/cmd"
"github.com/micro/go-micro/v2/debug/profile"
"github.com/micro/go-micro/v2/debug/trace"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/server"
@@ -25,6 +26,7 @@ type Options struct {
Server server.Server
Registry registry.Registry
Transport transport.Transport
Profile profile.Profile
// Before and After funcs
BeforeStart []func() error
@@ -99,6 +101,13 @@ func HandleSignal(b bool) Option {
}
}
// Profile to be used for debug profile
func Profile(p profile.Profile) Option {
return func(o *Options) {
o.Profile = p
}
}
// Server to be used for service
func Server(s server.Server) Option {
return func(o *Options) {

View File

@@ -15,11 +15,11 @@ import (
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/codec/bytes"
"github.com/micro/go-micro/v2/errors"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/proxy"
"github.com/micro/go-micro/v2/router"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/util/log"
)
// Proxy will transparently proxy requests to an endpoint.
@@ -203,22 +203,33 @@ func (p *Proxy) cacheRoutes(service string) ([]router.Route, error) {
// lookup the routes in the router
results, err := p.Router.Lookup(router.QueryService(service))
if err != nil {
// assumption that we're ok with stale routes
// otherwise return the error
return nil, err
}
// update the proxy cache
p.Lock()
// delete the existing reference to the service
delete(p.Routes, service)
for _, route := range results {
// create if does not exist
if _, ok := p.Routes[service]; !ok {
p.Routes[service] = make(map[uint64]router.Route)
}
// cache the route based on its unique hash
p.Routes[service][route.Hash()] = route
}
// make a copy of the service routes
routes := p.Routes[service]
p.Unlock()
// return routes to the caller
return toSlice(routes), nil
}

View File

@@ -7,8 +7,8 @@ import (
"sync"
"time"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
log "github.com/micro/go-micro/v2/util/log"
)
// Cache is the registry cache interface
@@ -339,7 +339,7 @@ func (c *cache) run() {
c.setStatus(err)
if a > 3 {
log.Log("rcache: ", err, " backing off ", d)
log.Info("rcache: ", err, " backing off ", d)
a = 0
}
@@ -362,7 +362,7 @@ func (c *cache) run() {
c.setStatus(err)
if b > 3 {
log.Log("rcache: ", err, " backing off ", d)
log.Info("rcache: ", err, " backing off ", d)
b = 0
}

View File

@@ -15,8 +15,8 @@ import (
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/log"
hash "github.com/mitchellh/hashstructure"
"go.uber.org/zap"
)

View File

@@ -48,6 +48,9 @@ func (ew *etcdWatcher) Next() (*registry.Result, error) {
if wresp.Err() != nil {
return nil, wresp.Err()
}
if wresp.Canceled {
return nil, errors.New("could not get next")
}
for _, ev := range wresp.Events {
service := decode(ev.Kv.Value)
var action string

View File

@@ -6,9 +6,9 @@ import (
"strings"
"sync"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/kubernetes/client"
"github.com/micro/go-micro/v2/util/log"
)
type k8sWatcher struct {
@@ -132,7 +132,7 @@ func (k *k8sWatcher) buildPodResults(pod *client.Pod, cache *client.Pod) []*regi
func (k *k8sWatcher) handleEvent(event client.Event) {
var pod client.Pod
if err := json.Unmarshal([]byte(event.Object), &pod); err != nil {
log.Log("K8s Watcher: Couldnt unmarshal event object from pod")
log.Info("K8s Watcher: Couldnt unmarshal event object from pod")
return
}

View File

@@ -7,8 +7,8 @@ import (
"time"
"github.com/google/uuid"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/log"
)
var (

View File

@@ -7,12 +7,12 @@ import (
)
func serviceToRecord(s *registry.Service, ttl time.Duration) *record {
metadata := make(map[string]string)
metadata := make(map[string]string, len(s.Metadata))
for k, v := range s.Metadata {
metadata[k] = v
}
nodes := make(map[string]*node)
nodes := make(map[string]*node, len(s.Nodes))
for _, n := range s.Nodes {
nodes[n.Id] = &node{
Node: n,
@@ -36,7 +36,7 @@ func serviceToRecord(s *registry.Service, ttl time.Duration) *record {
}
func recordToService(r *record) *registry.Service {
metadata := make(map[string]string)
metadata := make(map[string]string, len(r.Metadata))
for k, v := range r.Metadata {
metadata[k] = v
}
@@ -52,7 +52,7 @@ func recordToService(r *record) *registry.Service {
*response = *e.Response
}
metadata := make(map[string]string)
metadata := make(map[string]string, len(e.Metadata))
for k, v := range e.Metadata {
metadata[k] = v
}
@@ -68,7 +68,7 @@ func recordToService(r *record) *registry.Service {
nodes := make([]*registry.Node, len(r.Nodes))
i := 0
for _, n := range r.Nodes {
metadata := make(map[string]string)
metadata := make(map[string]string, len(n.Metadata))
for k, v := range n.Metadata {
metadata[k] = v
}

View File

@@ -10,8 +10,8 @@ import (
"time"
"github.com/google/uuid"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/util/log"
)
var (
@@ -357,22 +357,24 @@ func (r *router) advertiseEvents() error {
// routing table watcher
w, err = r.Watch()
if err != nil {
log.Logf("Error creating watcher: %v", err)
log.Errorf("Error creating watcher: %v", err)
time.Sleep(time.Second)
continue
}
}
if err := r.watchTable(w); err != nil {
log.Logf("Error watching table: %v", err)
log.Errorf("Error watching table: %v", err)
time.Sleep(time.Second)
}
if w != nil {
// reset
w.Stop()
w = nil
}
}
}
}()
for {
@@ -467,7 +469,9 @@ func (r *router) advertiseEvents() error {
a.penalty += Penalty
log.Debugf("Router advert %d for route %s %s event penalty: %f", hash, a.event.Route.Service, a.event.Route.Address, a.penalty)
case <-r.exit:
if w != nil {
w.Stop()
}
return nil
}
}
@@ -538,14 +542,14 @@ func (r *router) Start() error {
if w == nil {
w, err = r.options.Registry.Watch()
if err != nil {
log.Logf("failed creating registry watcher: %v", err)
log.Errorf("failed creating registry watcher: %v", err)
time.Sleep(time.Second)
continue
}
}
if err := r.watchRegistry(w); err != nil {
log.Logf("Error watching the registry: %v", err)
log.Errorf("Error watching the registry: %v", err)
time.Sleep(time.Second)
}
@@ -602,7 +606,7 @@ func (r *router) Advertise() (<-chan *Advert, error) {
return
default:
if err := r.advertiseEvents(); err != nil {
log.Logf("Error adveritising events: %v", err)
log.Errorf("Error adveritising events: %v", err)
}
}
}()
@@ -700,16 +704,15 @@ func (r *router) Stop() error {
// extract the events
r.drain()
r.sub.Lock()
// close advert subscribers
for id, sub := range r.subscribers {
// close the channel
close(sub)
// delete the subscriber
r.sub.Lock()
delete(r.subscribers, id)
r.sub.Unlock()
}
r.sub.Unlock()
}
// remove event chan

View File

@@ -6,8 +6,8 @@ import (
"testing"
"time"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry/memory"
"github.com/micro/go-micro/v2/util/log"
)
func routerTestSetup() Router {

View File

@@ -6,7 +6,7 @@ import (
"time"
"github.com/google/uuid"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
var (

View File

@@ -5,7 +5,7 @@ import (
"sync"
"time"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
type runtime struct {

View File

@@ -7,9 +7,9 @@ import (
"sync"
"time"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/runtime"
"github.com/micro/go-micro/v2/util/kubernetes/client"
"github.com/micro/go-micro/v2/util/log"
)
// action to take on runtime service
@@ -270,9 +270,9 @@ func (k *kubernetes) Create(s *runtime.Service, opts ...runtime.CreateOption) er
if len(options.Type) == 0 {
options.Type = k.options.Type
}
if len(k.options.Source) > 0 {
s.Source = k.options.Source
}
// determine the full source for this service
options.Source = k.sourceForService(s.Name)
service := newService(s, options)
@@ -330,6 +330,7 @@ func (k *kubernetes) Update(s *runtime.Service) error {
// create new kubernetes micro service
service := newService(s, runtime.CreateOptions{
Type: k.options.Type,
Source: k.sourceForService(s.Name),
})
// update build time annotation
@@ -432,3 +433,15 @@ func NewRuntime(opts ...runtime.Option) runtime.Runtime {
client: client,
}
}
// sourceForService determines the nested package name for github
// e.g src: docker.pkg.github.com/micro/services an srv: users/api
// would become docker.pkg.github.com/micro/services/users-api
func (k *kubernetes) sourceForService(name string) string {
if !strings.HasPrefix(k.options.Source, "docker.pkg.github.com") {
return k.options.Source
}
formattedName := strings.ReplaceAll(name, "/", "-")
return fmt.Sprintf("%v/%v", k.options.Source, formattedName)
}

View File

@@ -3,12 +3,11 @@ package kubernetes
import (
"encoding/json"
"strings"
"time"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/runtime"
"github.com/micro/go-micro/v2/util/kubernetes/api"
"github.com/micro/go-micro/v2/util/kubernetes/client"
"github.com/micro/go-micro/v2/util/log"
)
type service struct {
@@ -34,12 +33,15 @@ func newService(s *runtime.Service, c runtime.CreateOptions) *service {
kservice := client.NewService(name, version, c.Type)
kdeploy := client.NewDeployment(name, version, c.Type)
if len(s.Source) > 0 {
for i := range kdeploy.Spec.Template.PodSpec.Containers {
kdeploy.Spec.Template.PodSpec.Containers[i].Image = s.Source
kdeploy.Spec.Template.PodSpec.Containers[i].Command = []string{}
kdeploy.Spec.Template.PodSpec.Containers[i].Args = []string{name}
// ensure the metadata is set
if kdeploy.Spec.Template.Metadata.Annotations == nil {
kdeploy.Spec.Template.Metadata.Annotations = make(map[string]string)
}
// add the service metadata to the k8s labels, do this first so we
// don't override any labels used by the runtime, e.g. name
for k, v := range s.Metadata {
kdeploy.Metadata.Annotations[k] = v
}
// attach our values to the deployment; name, version, source
@@ -51,11 +53,16 @@ func newService(s *runtime.Service, c runtime.CreateOptions) *service {
kdeploy.Metadata.Annotations["owner"] = "micro"
kdeploy.Metadata.Annotations["group"] = "micro"
// set a build timestamp to the current time
if kdeploy.Spec.Template.Metadata.Annotations == nil {
kdeploy.Spec.Template.Metadata.Annotations = make(map[string]string)
// update the deployment is a custom source is provided
if len(c.Source) > 0 {
for i := range kdeploy.Spec.Template.PodSpec.Containers {
kdeploy.Spec.Template.PodSpec.Containers[i].Image = c.Source
kdeploy.Spec.Template.PodSpec.Containers[i].Command = []string{}
kdeploy.Spec.Template.PodSpec.Containers[i].Args = []string{name}
}
kdeploy.Metadata.Annotations["source"] = c.Source
}
kdeploy.Spec.Template.Metadata.Annotations["build"] = time.Now().Format(time.RFC3339)
// define the environment values used by the container
env := make([]client.EnvVar, 0, len(c.Env))
@@ -70,7 +77,7 @@ func newService(s *runtime.Service, c runtime.CreateOptions) *service {
}
// specify the command to exec
if len(c.Command) > 0 {
if strings.HasPrefix(c.Source, "github.com") && len(c.Command) > 0 {
kdeploy.Spec.Template.PodSpec.Containers[0].Command = c.Command
}

View File

@@ -9,8 +9,8 @@ import (
"path/filepath"
docker "github.com/fsouza/go-dockerclient"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/runtime/local/build"
"github.com/micro/go-micro/v2/util/log"
)
type Builder struct {

View File

@@ -53,6 +53,8 @@ type CreateOptions struct {
Type string
// Retries before failing deploy
Retries int
// Source of the service
Source string
}
// ReadOptions queries runtime services
@@ -72,6 +74,13 @@ func CreateType(t string) CreateOption {
}
}
// CreateSource sets the source of service to create
func CreateSource(t string) CreateOption {
return func(o *CreateOptions) {
o.Source = t
}
}
// WithCommand specifies the command to execute
func WithCommand(args ...string) CreateOption {
return func(o *CreateOptions) {

View File

@@ -6,10 +6,10 @@ import (
"sync"
"time"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/runtime/local/build"
"github.com/micro/go-micro/v2/runtime/local/process"
proc "github.com/micro/go-micro/v2/runtime/local/process/os"
"github.com/micro/go-micro/v2/util/log"
)
type service struct {

View File

@@ -35,6 +35,11 @@ func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error {
o(&options)
}
// set the default source from MICRO_RUNTIME_SOURCE
if len(svc.Source) == 0 {
svc.Source = s.options.Source
}
// runtime service create request
req := &pb.CreateRequest{
Service: &pb.Service{

View File

@@ -2,7 +2,6 @@ package grpc
import (
"encoding/json"
"fmt"
"strings"
b "bytes"
@@ -11,8 +10,6 @@ import (
"github.com/golang/protobuf/proto"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/codec/bytes"
"github.com/micro/go-micro/v2/codec/jsonrpc"
"github.com/micro/go-micro/v2/codec/protorpc"
"google.golang.org/grpc"
"google.golang.org/grpc/encoding"
"google.golang.org/grpc/metadata"
@@ -36,14 +33,6 @@ var (
"application/grpc+proto": protoCodec{},
"application/grpc+bytes": bytesCodec{},
}
defaultRPCCodecs = map[string]codec.NewCodec{
"application/json": jsonrpc.NewCodec,
"application/json-rpc": jsonrpc.NewCodec,
"application/protobuf": protorpc.NewCodec,
"application/proto-rpc": protorpc.NewCodec,
"application/octet-stream": protorpc.NewCodec,
}
)
func (w wrapCodec) String() string {
@@ -71,11 +60,19 @@ func (w wrapCodec) Unmarshal(data []byte, v interface{}) error {
}
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
return proto.Marshal(v.(proto.Message))
m, ok := v.(proto.Message)
if !ok {
return nil, codec.ErrInvalidMessage
}
return proto.Marshal(m)
}
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
return proto.Unmarshal(data, v.(proto.Message))
m, ok := v.(proto.Message)
if !ok {
return codec.ErrInvalidMessage
}
return proto.Unmarshal(data, m)
}
func (protoCodec) Name() string {
@@ -85,7 +82,6 @@ func (protoCodec) Name() string {
func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
if pb, ok := v.(proto.Message); ok {
s, err := jsonpbMarshaler.MarshalToString(pb)
return []byte(s), err
}
@@ -109,7 +105,7 @@ func (jsonCodec) Name() string {
func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
b, ok := v.(*[]byte)
if !ok {
return nil, fmt.Errorf("failed to marshal: %v is not type of *[]byte", v)
return nil, codec.ErrInvalidMessage
}
return *b, nil
}
@@ -117,7 +113,7 @@ func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
func (bytesCodec) Unmarshal(data []byte, v interface{}) error {
b, ok := v.(*[]byte)
if !ok {
return fmt.Errorf("failed to unmarshal: %v is not type of *[]byte", v)
return codec.ErrInvalidMessage
}
*b = data
return nil
@@ -144,7 +140,7 @@ func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
m = new(codec.Message)
}
if m.Header == nil {
m.Header = make(map[string]string)
m.Header = make(map[string]string, len(md))
}
for k, v := range md {
m.Header[k] = strings.Join(v, ",")

16
server/grpc/context.go Normal file
View File

@@ -0,0 +1,16 @@
package grpc
import (
"context"
"github.com/micro/go-micro/v2/server"
)
func setServerOption(k, v interface{}) server.Option {
return func(o *server.Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, k, v)
}
}

View File

@@ -16,15 +16,15 @@ import (
"github.com/golang/protobuf/proto"
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/codec"
"github.com/micro/go-micro/v2/errors"
log "github.com/micro/go-micro/v2/logger"
meta "github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/util/addr"
mgrpc "github.com/micro/go-micro/v2/util/grpc"
"github.com/micro/go-micro/v2/util/log"
mnet "github.com/micro/go-micro/v2/util/net"
"golang.org/x/net/netutil"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
@@ -143,9 +143,8 @@ func (g *grpcServer) getMaxMsgSize() int {
func (g *grpcServer) getCredentials() credentials.TransportCredentials {
if g.opts.Context != nil {
if v := g.opts.Context.Value(tlsAuth{}); v != nil {
tls := v.(*tls.Config)
return credentials.NewTLS(tls)
if v, ok := g.opts.Context.Value(tlsAuth{}).(*tls.Config); ok && v != nil {
return credentials.NewTLS(v)
}
}
return nil
@@ -156,21 +155,26 @@ func (g *grpcServer) getGrpcOptions() []grpc.ServerOption {
return nil
}
v := g.opts.Context.Value(grpcOptions{})
if v == nil {
return nil
}
opts, ok := v.([]grpc.ServerOption)
if !ok {
opts, ok := g.opts.Context.Value(grpcOptions{}).([]grpc.ServerOption)
if !ok || opts == nil {
return nil
}
return opts
}
func (g *grpcServer) getListener() net.Listener {
if g.opts.Context == nil {
return nil
}
if l, ok := g.opts.Context.Value(netListener{}).(net.Listener); ok && l != nil {
return l
}
return nil
}
func (g *grpcServer) handler(srv interface{}, stream grpc.ServerStream) error {
if g.wg != nil {
g.wg.Add(1)
@@ -354,8 +358,8 @@ func (g *grpcServer) processRequest(stream grpc.ServerStream, service *service,
fn := func(ctx context.Context, req server.Request, rsp interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
log.Log("panic recovered: ", r)
log.Logf(string(debug.Stack()))
log.Error("panic recovered: ", r)
log.Error(string(debug.Stack()))
err = errors.InternalServerError("go.micro.server", "panic recovered: %v", r)
}
}()
@@ -494,8 +498,8 @@ func (g *grpcServer) processStream(stream grpc.ServerStream, service *service, m
func (g *grpcServer) newGRPCCodec(contentType string) (encoding.Codec, error) {
codecs := make(map[string]encoding.Codec)
if g.opts.Context != nil {
if v := g.opts.Context.Value(codecsKey{}); v != nil {
codecs = v.(map[string]encoding.Codec)
if v, ok := g.opts.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && v != nil {
codecs = v
}
}
if c, ok := codecs[contentType]; ok {
@@ -507,16 +511,6 @@ func (g *grpcServer) newGRPCCodec(contentType string) (encoding.Codec, error) {
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
}
func (g *grpcServer) newCodec(contentType string) (codec.NewCodec, error) {
if cf, ok := g.opts.Codecs[contentType]; ok {
return cf, nil
}
if cf, ok := defaultRPCCodecs[contentType]; ok {
return cf, nil
}
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
}
func (g *grpcServer) Options() server.Options {
g.RLock()
opts := g.opts
@@ -561,11 +555,11 @@ func (g *grpcServer) Subscribe(sb server.Subscriber) error {
}
g.Lock()
_, ok = g.subscribers[sub]
if ok {
if _, ok = g.subscribers[sub]; ok {
g.Unlock()
return fmt.Errorf("subscriber %v already exists", sub)
}
g.subscribers[sub] = nil
g.Unlock()
return nil
@@ -664,7 +658,7 @@ func (g *grpcServer) Register() error {
g.Unlock()
if !registered {
log.Logf("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
log.Infof("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
}
// create registry options
@@ -699,7 +693,7 @@ func (g *grpcServer) Register() error {
opts = append(opts, broker.DisableAutoAck())
}
log.Logf("Subscribing to topic: %s", sb.Topic())
log.Infof("Subscribing to topic: %s", sb.Topic())
sub, err := config.Broker.Subscribe(sb.Topic(), handler, opts...)
if err != nil {
return err
@@ -751,7 +745,7 @@ func (g *grpcServer) Deregister() error {
Nodes: []*registry.Node{node},
}
log.Logf("Deregistering node: %s", node.Id)
log.Infof("Deregistering node: %s", node.Id)
if err := config.Registry.Deregister(service); err != nil {
return err
}
@@ -767,7 +761,7 @@ func (g *grpcServer) Deregister() error {
for sb, subs := range g.subscribers {
for _, sub := range subs {
log.Logf("Unsubscribing from topic: %s", sub.Topic())
log.Infof("Unsubscribing from topic: %s", sub.Topic())
sub.Unsubscribe()
}
g.subscribers[sb] = nil
@@ -788,12 +782,32 @@ func (g *grpcServer) Start() error {
config := g.Options()
// micro: config.Transport.Listen(config.Address)
ts, err := net.Listen("tcp", config.Address)
var ts net.Listener
if l := g.getListener(); l != nil {
ts = l
} else {
var err error
// check the tls config for secure connect
if tc := config.TLSConfig; tc != nil {
ts, err = tls.Listen("tcp", config.Address, tc)
// otherwise just plain tcp listener
} else {
ts, err = net.Listen("tcp", config.Address)
}
if err != nil {
return err
}
}
log.Logf("Server [grpc] Listening on %s", ts.Addr().String())
if g.opts.Context != nil {
if c, ok := g.opts.Context.Value(maxConnKey{}).(int); ok && c > 0 {
ts = netutil.LimitListener(ts, c)
}
}
log.Infof("Server [grpc] Listening on %s", ts.Addr().String())
g.Lock()
g.opts.Address = ts.Addr().String()
g.Unlock()
@@ -805,18 +819,18 @@ func (g *grpcServer) Start() error {
return err
}
log.Logf("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())
log.Infof("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())
}
// announce self to the world
if err := g.Register(); err != nil {
log.Log("Server register error: ", err)
log.Errorf("Server register error: ", err)
}
// micro: go ts.Accept(s.accept)
go func() {
if err := g.srv.Serve(ts); err != nil {
log.Log("gRPC Server start error: ", err)
log.Errorf("gRPC Server start error: ", err)
}
}()
@@ -838,7 +852,7 @@ func (g *grpcServer) Start() error {
// register self on interval
case <-t.C:
if err := g.Register(); err != nil {
log.Log("Server register error: ", err)
log.Error("Server register error: ", err)
}
// wait for exit
case ch = <-g.exit:
@@ -848,7 +862,7 @@ func (g *grpcServer) Start() error {
// deregister self
if err := g.Deregister(); err != nil {
log.Log("Server deregister error: ", err)
log.Error("Server deregister error: ", err)
}
// wait for waitgroup
@@ -873,7 +887,7 @@ func (g *grpcServer) Start() error {
// close transport
ch <- nil
log.Logf("Broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address())
log.Infof("Broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address())
// disconnect broker
config.Broker.Disconnect()
}()

View File

@@ -1,12 +1,19 @@
package grpc
package grpc_test
import (
"context"
"fmt"
"testing"
"github.com/micro/go-micro/v2"
bmemory "github.com/micro/go-micro/v2/broker/memory"
"github.com/micro/go-micro/v2/client"
gcli "github.com/micro/go-micro/v2/client/grpc"
"github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/registry/memory"
rmemory "github.com/micro/go-micro/v2/registry/memory"
"github.com/micro/go-micro/v2/server"
gsrv "github.com/micro/go-micro/v2/server/grpc"
tgrpc "github.com/micro/go-micro/v2/transport/grpc"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
@@ -14,7 +21,17 @@ import (
)
// server is used to implement helloworld.GreeterServer.
type testServer struct{}
type testServer struct {
msgCount int
}
func (s *testServer) Handle(ctx context.Context, msg *pb.Request) error {
s.msgCount++
return nil
}
func (s *testServer) HandleError(ctx context.Context, msg *pb.Request) error {
return fmt.Errorf("fake")
}
// TestHello implements helloworld.GreeterServer
func (s *testServer) Call(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
@@ -26,14 +43,75 @@ func (s *testServer) Call(ctx context.Context, req *pb.Request, rsp *pb.Response
return nil
}
func TestGRPCServer(t *testing.T) {
r := memory.NewRegistry()
s := NewServer(
/*
func BenchmarkServer(b *testing.B) {
r := rmemory.NewRegistry()
br := bmemory.NewBroker()
tr := tgrpc.NewTransport()
s := gsrv.NewServer(
server.Broker(br),
server.Name("foo"),
server.Registry(r),
server.Transport(tr),
)
c := gcli.NewClient(
client.Registry(r),
client.Broker(br),
client.Transport(tr),
)
ctx := context.TODO()
pb.RegisterTestHandler(s, &testServer{})
h := &testServer{}
pb.RegisterTestHandler(s, h)
if err := s.Start(); err != nil {
b.Fatalf("failed to start: %v", err)
}
// check registration
services, err := r.GetService("foo")
if err != nil || len(services) == 0 {
b.Fatalf("failed to get service: %v # %d", err, len(services))
}
defer func() {
if err := s.Stop(); err != nil {
b.Fatalf("failed to stop: %v", err)
}
}()
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.Call()
}
}
*/
func TestGRPCServer(t *testing.T) {
r := rmemory.NewRegistry()
b := bmemory.NewBroker()
tr := tgrpc.NewTransport()
s := gsrv.NewServer(
server.Broker(b),
server.Name("foo"),
server.Registry(r),
server.Transport(tr),
)
c := gcli.NewClient(
client.Registry(r),
client.Broker(b),
client.Transport(tr),
)
ctx := context.TODO()
h := &testServer{}
pb.RegisterTestHandler(s, h)
if err := micro.RegisterSubscriber("test_topic", s, h.Handle); err != nil {
t.Fatal(err)
}
if err := micro.RegisterSubscriber("error_topic", s, h.HandleError); err != nil {
t.Fatal(err)
}
if err := s.Start(); err != nil {
t.Fatalf("failed to start: %v", err)
@@ -51,6 +129,22 @@ func TestGRPCServer(t *testing.T) {
}
}()
pub := micro.NewEvent("test_topic", c)
pubErr := micro.NewEvent("error_topic", c)
cnt := 4
for i := 0; i < cnt; i++ {
if err = pub.Publish(ctx, &pb.Request{Name: fmt.Sprintf("msg %d", i)}); err != nil {
t.Fatal(err)
}
}
if h.msgCount != cnt {
t.Fatalf("pub/sub not work, or invalid message count %d", h.msgCount)
}
if err = pubErr.Publish(ctx, &pb.Request{}); err == nil {
t.Fatal("this must return error, as we return error from handler")
}
cc, err := grpc.Dial(s.Options().Address, grpc.WithInsecure())
if err != nil {
t.Fatalf("failed to dial server: %v", err)

View File

@@ -3,6 +3,7 @@ package grpc
import (
"context"
"crypto/tls"
"net"
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/codec"
@@ -14,9 +15,11 @@ import (
)
type codecsKey struct{}
type tlsAuth struct{}
type maxMsgSizeKey struct{}
type grpcOptions struct{}
type netListener struct{}
type maxMsgSizeKey struct{}
type maxConnKey struct{}
type tlsAuth struct{}
// gRPC Codec to be used to encode/decode requests for a given content type
func Codec(contentType string, c encoding.Codec) server.Option {
@@ -25,8 +28,8 @@ func Codec(contentType string, c encoding.Codec) server.Option {
if o.Context == nil {
o.Context = context.Background()
}
if v := o.Context.Value(codecsKey{}); v != nil {
codecs = v.(map[string]encoding.Codec)
if v, ok := o.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && v != nil {
codecs = v
}
codecs[contentType] = c
o.Context = context.WithValue(o.Context, codecsKey{}, codecs)
@@ -35,22 +38,22 @@ func Codec(contentType string, c encoding.Codec) server.Option {
// AuthTLS should be used to setup a secure authentication using TLS
func AuthTLS(t *tls.Config) server.Option {
return func(o *server.Options) {
if o.Context == nil {
o.Context = context.Background()
return setServerOption(tlsAuth{}, t)
}
o.Context = context.WithValue(o.Context, tlsAuth{}, t)
// MaxConn specifies maximum number of max simultaneous connections to server
func MaxConn(n int) server.Option {
return setServerOption(maxConnKey{}, n)
}
// Listener specifies the net.Listener to use instead of the default
func Listener(l net.Listener) server.Option {
return setServerOption(netListener{}, l)
}
// Options to be used to configure gRPC options
func Options(opts ...grpc.ServerOption) server.Option {
return func(o *server.Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, grpcOptions{}, opts)
}
return setServerOption(grpcOptions{}, opts)
}
//
@@ -58,51 +61,25 @@ func Options(opts ...grpc.ServerOption) server.Option {
// send. Default maximum message size is 4 MB.
//
func MaxMsgSize(s int) server.Option {
return func(o *server.Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, maxMsgSizeKey{}, s)
}
return setServerOption(maxMsgSizeKey{}, s)
}
func newOptions(opt ...server.Option) server.Options {
opts := server.Options{
Codecs: make(map[string]codec.NewCodec),
Metadata: map[string]string{},
Broker: broker.DefaultBroker,
Registry: registry.DefaultRegistry,
Transport: transport.DefaultTransport,
Address: server.DefaultAddress,
Name: server.DefaultName,
Id: server.DefaultId,
Version: server.DefaultVersion,
}
for _, o := range opt {
o(&opts)
}
if opts.Broker == nil {
opts.Broker = broker.DefaultBroker
}
if opts.Registry == nil {
opts.Registry = registry.DefaultRegistry
}
if opts.Transport == nil {
opts.Transport = transport.DefaultTransport
}
if len(opts.Address) == 0 {
opts.Address = server.DefaultAddress
}
if len(opts.Name) == 0 {
opts.Name = server.DefaultName
}
if len(opts.Id) == 0 {
opts.Id = server.DefaultId
}
if len(opts.Version) == 0 {
opts.Version = server.DefaultVersion
}
return opts
}

View File

@@ -14,8 +14,8 @@ import (
"unicode"
"unicode/utf8"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/util/log"
)
var (
@@ -86,7 +86,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
replyType = mtype.In(3)
contextType = mtype.In(1)
default:
log.Log("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
log.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
return nil
}
@@ -94,7 +94,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
// check stream type
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
if !argType.Implements(streamType) {
log.Log(mname, "argument does not implement Streamer interface:", argType)
log.Error(mname, "argument does not implement Streamer interface:", argType)
return nil
}
} else {
@@ -102,30 +102,30 @@ func prepareEndpoint(method reflect.Method) *methodType {
// First arg need not be a pointer.
if !isExportedOrBuiltinType(argType) {
log.Log(mname, "argument type not exported:", argType)
log.Error(mname, "argument type not exported:", argType)
return nil
}
if replyType.Kind() != reflect.Ptr {
log.Log("method", mname, "reply type not a pointer:", replyType)
log.Error("method", mname, "reply type not a pointer:", replyType)
return nil
}
// Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
log.Log("method", mname, "reply type not exported:", replyType)
log.Error("method", mname, "reply type not exported:", replyType)
return nil
}
}
// Endpoint() needs one out.
if mtype.NumOut() != 1 {
log.Log("method", mname, "has wrong number of outs:", mtype.NumOut())
log.Error("method", mname, "has wrong number of outs:", mtype.NumOut())
return nil
}
// The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError {
log.Log("method", mname, "returns", returnType.String(), "not error")
log.Error("method", mname, "returns", returnType.String(), "not error")
return nil
}
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
@@ -146,7 +146,7 @@ func (server *rServer) register(rcvr interface{}) error {
}
if !isExported(sname) {
s := "rpc Register: type " + sname + " is not exported"
log.Log(s)
log.Error(s)
return errors.New(s)
}
if _, present := server.serviceMap[sname]; present {
@@ -165,7 +165,7 @@ func (server *rServer) register(rcvr interface{}) error {
if len(s.method) == 0 {
s := "rpc Register: type " + sname + " has no exported methods of suitable type"
log.Log(s)
log.Error(s)
return errors.New(s)
}
server.serviceMap[s.name] = s

View File

@@ -9,10 +9,10 @@ import (
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/errors"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/util/log"
)
const (
@@ -171,8 +171,8 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
defer func() {
if r := recover(); r != nil {
log.Log("panic recovered: ", r)
log.Logf(string(debug.Stack()))
log.Error("panic recovered: ", r)
log.Error(string(debug.Stack()))
err = errors.InternalServerError("go.micro.server", "panic recovered: %v", r)
}
}()
@@ -188,7 +188,7 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
return err
}
hdr := make(map[string]string)
hdr := make(map[string]string, len(msg.Header))
for k, v := range msg.Header {
hdr[k] = v
}
@@ -246,18 +246,19 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
if g.wg != nil {
defer g.wg.Done()
}
results <- fn(ctx, &rpcMessage{
err := fn(ctx, &rpcMessage{
topic: sb.topic,
contentType: ct,
payload: req.Interface(),
header: msg.Header,
body: msg.Body,
})
results <- err
}()
}
var errors []string
for i := 0; i < len(sb.handlers); i++ {
if rerr := <-results; err != nil {
if rerr := <-results; rerr != nil {
errors = append(errors, rerr.Error())
}
}

View File

@@ -2,6 +2,7 @@ package server
import (
"context"
"crypto/tls"
"sync"
"time"
@@ -39,6 +40,9 @@ type Options struct {
// The router for requests
Router Router
// TLSConfig specifies tls.Config for secure serving
TLSConfig *tls.Config
// Other options for implementations of the interface
// can be stored in a context
Context context.Context
@@ -205,6 +209,26 @@ func RegisterInterval(t time.Duration) Option {
}
}
// TLSConfig specifies a *tls.Config
func TLSConfig(t *tls.Config) Option {
return func(o *Options) {
// set the internal tls
o.TLSConfig = t
// set the default transport if one is not
// already set. Required for Init call below.
if o.Transport == nil {
o.Transport = transport.DefaultTransport
}
// set the transport tls
o.Transport.Init(
transport.Secure(true),
transport.TLSConfig(t),
)
}
}
// WithRouter sets the request router
func WithRouter(r Router) Option {
return func(o *Options) {

View File

@@ -20,7 +20,7 @@ import (
"github.com/micro/go-micro/v2/codec"
merrors "github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
var (
@@ -141,7 +141,7 @@ func prepareMethod(method reflect.Method) *methodType {
replyType = mtype.In(3)
contextType = mtype.In(1)
default:
log.Log("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
log.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
return nil
}
@@ -149,7 +149,7 @@ func prepareMethod(method reflect.Method) *methodType {
// check stream type
streamType := reflect.TypeOf((*Stream)(nil)).Elem()
if !argType.Implements(streamType) {
log.Log(mname, "argument does not implement Stream interface:", argType)
log.Error(mname, "argument does not implement Stream interface:", argType)
return nil
}
} else {
@@ -157,30 +157,30 @@ func prepareMethod(method reflect.Method) *methodType {
// First arg need not be a pointer.
if !isExportedOrBuiltinType(argType) {
log.Log(mname, "argument type not exported:", argType)
log.Error(mname, "argument type not exported:", argType)
return nil
}
if replyType.Kind() != reflect.Ptr {
log.Log("method", mname, "reply type not a pointer:", replyType)
log.Error("method", mname, "reply type not a pointer:", replyType)
return nil
}
// Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
log.Log("method", mname, "reply type not exported:", replyType)
log.Error("method", mname, "reply type not exported:", replyType)
return nil
}
}
// Method needs one out.
if mtype.NumOut() != 1 {
log.Log("method", mname, "has wrong number of outs:", mtype.NumOut())
log.Error("method", mname, "has wrong number of outs:", mtype.NumOut())
return nil
}
// The return type of the method must be error.
if returnType := mtype.Out(0); returnType != typeOfError {
log.Log("method", mname, "returns", returnType.String(), "not error")
log.Error("method", mname, "returns", returnType.String(), "not error")
return nil
}
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
@@ -505,27 +505,23 @@ func (router *router) Subscribe(s Subscriber) error {
}
func (router *router) ProcessMessage(ctx context.Context, msg Message) (err error) {
defer func() {
// recover any panics
if r := recover(); r != nil {
log.Log("panic recovered: ", r)
log.Log(string(debug.Stack()))
log.Error("panic recovered: ", r)
log.Error(string(debug.Stack()))
err = merrors.InternalServerError("go.micro.server", "panic recovered: %v", r)
}
}()
router.su.RLock()
// get the subscribers by topic
subs, ok := router.subscribers[msg.Topic()]
if !ok {
router.su.RUnlock()
return nil
}
// unlock since we only need to get the subs
router.su.RUnlock()
if !ok {
return nil
}
var errResults []string

View File

@@ -15,11 +15,11 @@ import (
"github.com/micro/go-micro/v2/broker"
"github.com/micro/go-micro/v2/codec"
raw "github.com/micro/go-micro/v2/codec/bytes"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/metadata"
"github.com/micro/go-micro/v2/registry"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/util/addr"
log "github.com/micro/go-micro/v2/util/log"
mnet "github.com/micro/go-micro/v2/util/net"
"github.com/micro/go-micro/v2/util/socket"
)
@@ -85,7 +85,7 @@ func (s *rpcServer) HandleEvent(e broker.Event) error {
}
// copy headers
hdr := make(map[string]string)
hdr := make(map[string]string, len(msg.Header))
for k, v := range msg.Header {
hdr[k] = v
}
@@ -158,8 +158,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
// recover any panics
if r := recover(); r != nil {
log.Log("panic recovered: ", r)
log.Log(string(debug.Stack()))
log.Error("panic recovered: ", r)
log.Error(string(debug.Stack()))
}
}()
@@ -262,7 +262,7 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
ct := msg.Header["Content-Type"]
// copy the message headers
hdr := make(map[string]string)
hdr := make(map[string]string, len(msg.Header))
for k, v := range msg.Header {
hdr[k] = v
}
@@ -377,8 +377,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
// recover any panics for outbound process
if r := recover(); r != nil {
log.Log("panic recovered: ", r)
log.Log(string(debug.Stack()))
log.Error("panic recovered: ", r)
log.Error(string(debug.Stack()))
}
}()
@@ -409,8 +409,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
// recover any panics for call handler
if r := recover(); r != nil {
log.Log("panic recovered: ", r)
log.Log(string(debug.Stack()))
log.Error("panic recovered: ", r)
log.Error(string(debug.Stack()))
}
}()
@@ -608,7 +608,7 @@ func (s *rpcServer) Register() error {
s.RUnlock()
if !registered {
log.Logf("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
log.Infof("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
}
// create registry options
@@ -654,7 +654,7 @@ func (s *rpcServer) Register() error {
opts = append(opts, broker.DisableAutoAck())
}
log.Logf("Subscribing to topic: %s", sub.Topic())
log.Infof("Subscribing to topic: %s", sub.Topic())
sub, err := config.Broker.Subscribe(sb.Topic(), s.HandleEvent, opts...)
if err != nil {
return err
@@ -712,7 +712,7 @@ func (s *rpcServer) Deregister() error {
Nodes: []*registry.Node{node},
}
log.Logf("Registry [%s] Deregistering node: %s", config.Registry.String(), node.Id)
log.Infof("Registry [%s] Deregistering node: %s", config.Registry.String(), node.Id)
if err := config.Registry.Deregister(service); err != nil {
return err
}
@@ -734,7 +734,7 @@ func (s *rpcServer) Deregister() error {
for sb, subs := range s.subscribers {
for _, sub := range subs {
log.Logf("Unsubscribing %s from topic: %s", node.Id, sub.Topic())
log.Infof("Unsubscribing %s from topic: %s", node.Id, sub.Topic())
sub.Unsubscribe()
}
s.subscribers[sb] = nil
@@ -760,7 +760,7 @@ func (s *rpcServer) Start() error {
return err
}
log.Logf("Transport [%s] Listening on %s", config.Transport.String(), ts.Addr())
log.Infof("Transport [%s] Listening on %s", config.Transport.String(), ts.Addr())
// swap address
s.Lock()
@@ -775,15 +775,15 @@ func (s *rpcServer) Start() error {
bname := config.Broker.String()
log.Logf("Broker [%s] Connected to %s", bname, config.Broker.Address())
log.Infof("Broker [%s] Connected to %s", bname, config.Broker.Address())
// use RegisterCheck func before register
if err = s.opts.RegisterCheck(s.opts.Context); err != nil {
log.Logf("Server %s-%s register check error: %s", config.Name, config.Id, err)
log.Errorf("Server %s-%s register check error: %s", config.Name, config.Id, err)
} else {
// announce self to the world
if err = s.Register(); err != nil {
log.Logf("Server %s-%s register error: %s", config.Name, config.Id, err)
log.Errorf("Server %s-%s register error: %s", config.Name, config.Id, err)
}
}
@@ -804,7 +804,7 @@ func (s *rpcServer) Start() error {
// check the error and backoff
default:
if err != nil {
log.Logf("Accept error: %v", err)
log.Errorf("Accept error: %v", err)
time.Sleep(time.Second)
continue
}
@@ -837,17 +837,17 @@ func (s *rpcServer) Start() error {
s.RUnlock()
rerr := s.opts.RegisterCheck(s.opts.Context)
if rerr != nil && registered {
log.Logf("Server %s-%s register check error: %s, deregister it", config.Name, config.Id, err)
log.Errorf("Server %s-%s register check error: %s, deregister it", config.Name, config.Id, err)
// deregister self in case of error
if err := s.Deregister(); err != nil {
log.Logf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
log.Errorf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
}
} else if rerr != nil && !registered {
log.Logf("Server %s-%s register check error: %s", config.Name, config.Id, err)
log.Errorf("Server %s-%s register check error: %s", config.Name, config.Id, err)
continue
}
if err := s.Register(); err != nil {
log.Logf("Server %s-%s register error: %s", config.Name, config.Id, err)
log.Errorf("Server %s-%s register error: %s", config.Name, config.Id, err)
}
// wait for exit
case ch = <-s.exit:
@@ -863,7 +863,7 @@ func (s *rpcServer) Start() error {
if registered {
// deregister self
if err := s.Deregister(); err != nil {
log.Logf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
log.Errorf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
}
}
@@ -879,7 +879,7 @@ func (s *rpcServer) Start() error {
// close transport listener
ch <- ts.Close()
log.Logf("Broker [%s] Disconnected from %s", bname, config.Broker.Address())
log.Infof("Broker [%s] Disconnected from %s", bname, config.Broker.Address())
// disconnect the broker
config.Broker.Disconnect()

View File

@@ -10,8 +10,8 @@ import (
"github.com/google/uuid"
"github.com/micro/go-micro/v2/codec"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/registry"
log "github.com/micro/go-micro/v2/util/log"
)
// Server is a simple micro server abstraction
@@ -200,7 +200,7 @@ func Run() error {
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT)
log.Logf("Received signal %s", <-ch)
log.Infof("Received signal %s", <-ch)
return Stop()
}
@@ -208,13 +208,13 @@ func Run() error {
// Start starts the default server
func Start() error {
config := DefaultServer.Options()
log.Logf("Starting server %s id %s", config.Name, config.Id)
log.Infof("Starting server %s id %s", config.Name, config.Id)
return DefaultServer.Start()
}
// Stop stops the default server
func Stop() error {
log.Logf("Stopping server")
log.Infof("Stopping server")
return DefaultServer.Stop()
}

View File

@@ -11,15 +11,13 @@ import (
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/config/cmd"
"github.com/micro/go-micro/v2/debug/profile"
"github.com/micro/go-micro/v2/debug/profile/http"
"github.com/micro/go-micro/v2/debug/profile/pprof"
"github.com/micro/go-micro/v2/debug/service/handler"
"github.com/micro/go-micro/v2/debug/stats"
"github.com/micro/go-micro/v2/debug/trace"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/plugin"
"github.com/micro/go-micro/v2/server"
"github.com/micro/go-micro/v2/util/log"
"github.com/micro/go-micro/v2/util/config"
"github.com/micro/go-micro/v2/util/wrapper"
)
@@ -40,7 +38,7 @@ func newService(opts ...Option) Service {
authFn := func() auth.Auth { return service.opts.Auth }
// wrap client to inject From-Service header on any calls
options.Client = wrapper.FromService(serviceName, options.Client)
options.Client = wrapper.FromService(serviceName, options.Client, authFn)
options.Client = wrapper.TraceCall(serviceName, trace.DefaultTracer, options.Client)
// wrap the server to provide handler stats
@@ -101,9 +99,18 @@ func (s *service) Init(opts ...Option) {
cmd.Transport(&s.opts.Transport),
cmd.Client(&s.opts.Client),
cmd.Server(&s.opts.Server),
cmd.Profile(&s.opts.Profile),
); err != nil {
log.Fatal(err)
}
// TODO: replace Cmd.Init with config.Load
// Right now we're just going to load a token
// May need to re-read value on change
// TODO: should be scoped to micro/auth/token
if tk, _ := config.Get("token"); len(tk) > 0 {
s.opts.Auth.Init(auth.Token(tk))
}
})
}
@@ -175,34 +182,19 @@ func (s *service) Run() error {
)
// start the profiler
// TODO: set as an option to the service, don't just use pprof
if prof := os.Getenv("MICRO_DEBUG_PROFILE"); len(prof) > 0 {
var profiler profile.Profile
if s.opts.Profile != nil {
// to view mutex contention
runtime.SetMutexProfileFraction(5)
// to view blocking profile
runtime.SetBlockProfileRate(1)
switch prof {
case "http":
profiler = http.NewProfile()
default:
service := s.opts.Server.Options().Name
version := s.opts.Server.Options().Version
id := s.opts.Server.Options().Id
profiler = pprof.NewProfile(
profile.Name(service + "." + version + "." + id),
)
}
if err := profiler.Start(); err != nil {
if err := s.opts.Profile.Start(); err != nil {
return err
}
defer profiler.Stop()
defer s.opts.Profile.Stop()
}
log.Logf("Starting [service] %s", s.Name())
log.Infof("Starting [service] %s", s.Name())
if err := s.Start(); err != nil {
return err

View File

@@ -7,10 +7,8 @@ import (
"testing"
"github.com/micro/go-micro/v2/client"
"github.com/micro/go-micro/v2/debug/log/noop"
proto "github.com/micro/go-micro/v2/debug/service/proto"
"github.com/micro/go-micro/v2/registry/memory"
"github.com/micro/go-micro/v2/util/log"
"github.com/micro/go-micro/v2/util/test"
)
@@ -24,9 +22,6 @@ func testShutdown(wg *sync.WaitGroup, cancel func()) {
}
func testService(ctx context.Context, wg *sync.WaitGroup, name string) Service {
// set no op logger
log.SetLogger(noop.NewLog())
// add self
wg.Add(1)

View File

@@ -10,8 +10,8 @@ import (
"unicode"
"github.com/lib/pq"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/store"
"github.com/micro/go-micro/v2/util/log"
"github.com/pkg/errors"
)

View File

@@ -5,10 +5,10 @@ import (
"math"
"time"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/sync/leader/etcd"
"github.com/micro/go-micro/v2/sync/task"
"github.com/micro/go-micro/v2/sync/task/local"
"github.com/micro/go-micro/v2/util/log"
)
type syncCron struct {
@@ -35,7 +35,7 @@ func (c *syncCron) Schedule(s task.Schedule, t task.Command) error {
// leader election
e, err := c.opts.Leader.Elect(id)
if err != nil {
log.Logf("[cron] leader election error: %v", err)
log.Errorf("[cron] leader election error: %v", err)
time.Sleep(backoff(i))
i++
continue
@@ -55,9 +55,9 @@ func (c *syncCron) Schedule(s task.Schedule, t task.Command) error {
break Tick
}
log.Logf("[cron] executing command %s", t.Name)
log.Infof("[cron] executing command %s", t.Name)
if err := c.opts.Task.Run(t); err != nil {
log.Logf("[cron] error executing command %s: %v", t.Name, err)
log.Errorf("[cron] error executing command %s: %v", t.Name, err)
}
// leader revoked
case <-r:

View File

@@ -4,9 +4,9 @@ import (
"runtime/debug"
"github.com/micro/go-micro/v2/errors"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/transport"
pb "github.com/micro/go-micro/v2/transport/grpc/proto"
"github.com/micro/go-micro/v2/util/log"
"google.golang.org/grpc/peer"
)
@@ -30,7 +30,7 @@ func (m *microTransport) Stream(ts pb.Transport_StreamServer) (err error) {
defer func() {
if r := recover(); r != nil {
log.Log(r, string(debug.Stack()))
log.Error(r, string(debug.Stack()))
sock.Close()
err = errors.InternalServerError("go.micro.transport", "panic recovered: %v", r)
}

View File

@@ -156,7 +156,7 @@ func (h *httpTransportClient) Recv(m *Message) error {
m.Body = b
if m.Header == nil {
m.Header = make(map[string]string)
m.Header = make(map[string]string, len(rsp.Header))
}
for k, v := range rsp.Header {
@@ -193,10 +193,6 @@ func (h *httpTransportSocket) Recv(m *Message) error {
return errors.New("message passed in is nil")
}
if m.Header == nil {
m.Header = make(map[string]string)
}
// process http 1
if h.r.ProtoMajor == 1 {
// set timeout if its greater than 0
@@ -228,6 +224,10 @@ func (h *httpTransportSocket) Recv(m *Message) error {
r.Body.Close()
m.Body = b
if m.Header == nil {
m.Header = make(map[string]string, len(r.Header))
}
// set headers
for k, v := range r.Header {
if len(v) > 0 {

View File

@@ -5,7 +5,16 @@ import (
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"io"
"github.com/oxtoacart/bpool"
)
var (
// the local buffer pool
// gcmStandardNonceSize from crypto/cipher/gcm.go is 12 bytes
// 100 - is max size of pool
noncePool = bpool.NewBytePool(100, 12)
hashPool = bpool.NewBytePool(1024*32, 32)
)
// hash hahes the data into 32 bytes key and returns it
@@ -13,7 +22,10 @@ import (
func hash(key string) []byte {
hasher := sha256.New()
hasher.Write([]byte(key))
return hasher.Sum(nil)
out := hashPool.Get()
defer hashPool.Put(out[:0])
out = hasher.Sum(out[:0])
return out
}
// Encrypt encrypts data and returns the encrypted data
@@ -32,12 +44,13 @@ func Encrypt(data []byte, key string) ([]byte, error) {
return nil, err
}
// create a new byte array the size of the nonce
// get new byte array the size of the nonce from pool
// NOTE: we might use smaller nonce size in the future
nonce := make([]byte, gcm.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
nonce := noncePool.Get()
if _, err = rand.Read(nonce); err != nil {
return nil, err
}
defer noncePool.Put(nonce)
// NOTE: we prepend the nonce to the payload
// we need to do this as we need the same nonce

View File

@@ -8,8 +8,8 @@ import (
"time"
"github.com/google/uuid"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/util/log"
)
var (
@@ -131,6 +131,7 @@ func (t *tun) newSession(channel, sessionId string) (*session, bool) {
recv: make(chan *message, 128),
send: t.send,
errChan: make(chan error, 1),
key: t.token + channel + sessionId,
}
// save session
@@ -949,7 +950,7 @@ func (t *tun) connect() error {
// still connected but the tunnel died
if err != nil && t.connected {
log.Logf("Tunnel listener died: %v", err)
log.Errorf("Tunnel listener died: %v", err)
}
}()

View File

@@ -8,8 +8,8 @@ import (
"time"
"github.com/google/uuid"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/util/log"
)
type link struct {
@@ -107,32 +107,6 @@ func newLink(s transport.Socket) *link {
return l
}
func (l *link) connect(addr string) error {
c, err := l.transport.Dial(addr)
if err != nil {
return err
}
l.Lock()
l.Socket = c
l.Unlock()
return nil
}
func (l *link) accept(sock transport.Socket) error {
l.Lock()
l.Socket = sock
l.Unlock()
return nil
}
func (l *link) setLoopback(v bool) {
l.Lock()
l.loopback = v
l.Unlock()
}
// setRate sets the bits per second rate as a float64
func (l *link) setRate(bits int64, delta time.Duration) {
// rate of send in bits per nanosecond

View File

@@ -4,7 +4,7 @@ import (
"io"
"sync"
"github.com/micro/go-micro/v2/util/log"
log "github.com/micro/go-micro/v2/logger"
)
type tunListener struct {
@@ -77,6 +77,8 @@ func (t *tunListener) process() {
// create a new session session
sess = &session{
// the session key
key: t.token + m.channel + sessionId,
// the id of the remote side
tunnel: m.tunnel,
// the channel

View File

@@ -5,8 +5,8 @@ import (
"io"
"time"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/transport"
"github.com/micro/go-micro/v2/util/log"
)
// session is our pseudo session for transport.Socket
@@ -47,6 +47,8 @@ type session struct {
link string
// the error response
errChan chan error
// key for session encryption
key string
}
// message is sent over the send channel
@@ -326,22 +328,22 @@ func (s *session) Announce() error {
// Send is used to send a message
func (s *session) Send(m *transport.Message) error {
// encrypt the transport message payload
body, err := Encrypt(m.Body, s.token+s.channel+s.session)
body, err := Encrypt(m.Body, s.key)
if err != nil {
log.Debugf("failed to encrypt message body: %v", err)
return err
}
// make copy
// make copy, without rehash and realloc
data := &transport.Message{
Header: make(map[string]string),
Header: make(map[string]string, len(m.Header)),
Body: body,
}
// encrypt all the headers
for k, v := range m.Header {
// encrypt the transport message payload
val, err := Encrypt([]byte(v), s.token+s.channel+s.session)
val, err := Encrypt([]byte(v), s.key)
if err != nil {
log.Debugf("failed to encrypt message header %s: %v", k, err)
return err
@@ -387,14 +389,14 @@ func (s *session) Recv(m *transport.Message) error {
default:
}
//log.Tracef("Received %+v from recv backlog", msg)
log.Tracef("Received %+v from recv backlog", msg)
key := s.token + s.channel + msg.session
// decrypt the received payload using the token
// we have to used msg.session because multicast has a shared
// session id of "multicast" in this session struct on
// the listener side
body, err := Decrypt(msg.data.Body, s.token+s.channel+msg.session)
body, err := Decrypt(msg.data.Body, key)
if err != nil {
log.Debugf("failed to decrypt message body: %v", err)
return err
@@ -410,7 +412,7 @@ func (s *session) Recv(m *transport.Message) error {
return err
}
// encrypt the transport message payload
val, err := Decrypt([]byte(h), s.token+s.channel+msg.session)
val, err := Decrypt([]byte(h), key)
if err != nil {
log.Debugf("failed to decrypt message header %s: %v", k, err)
return err

90
util/config/config.go Normal file
View File

@@ -0,0 +1,90 @@
package config
import (
"io/ioutil"
"os"
"os/user"
"path/filepath"
"strings"
conf "github.com/micro/go-micro/v2/config"
"github.com/micro/go-micro/v2/config/source/file"
"github.com/micro/go-micro/v2/util/log"
)
// FileName for global micro config
const FileName = ".micro"
// config is a singleton which is required to ensure
// each function call doesn't load the .micro file
// from disk
var config = newConfig()
// Get a value from the .micro file
func Get(key string) (string, error) {
tk := config.Get(key).String("")
return strings.TrimSpace(tk), nil
}
// Set a value in the .micro file
func Set(key, value string) error {
// get the filepath
fp, err := filePath()
if err != nil {
return err
}
// set the value
config.Set(value, key)
// write to the file
return ioutil.WriteFile(fp, config.Bytes(), 0644)
}
func filePath() (string, error) {
usr, err := user.Current()
if err != nil {
return "", err
}
return filepath.Join(usr.HomeDir, FileName), nil
}
// newConfig returns a loaded config
func newConfig() conf.Config {
// get the filepath
fp, err := filePath()
if err != nil {
log.Error(err)
return conf.DefaultConfig
}
// write the file if it does not exist
if _, err := os.Stat(fp); os.IsNotExist(err) {
ioutil.WriteFile(fp, []byte{}, 0644)
} else if err != nil {
log.Error(err)
return conf.DefaultConfig
}
// create a new config
c, err := conf.NewConfig(
conf.WithSource(
file.NewSource(
file.WithPath(fp),
),
),
)
if err != nil {
log.Error(err)
return conf.DefaultConfig
}
// load the config
if err := c.Load(); err != nil {
log.Error(err)
return conf.DefaultConfig
}
// return the conf
return c
}

View File

@@ -12,8 +12,8 @@ import (
"path"
"strings"
log "github.com/micro/go-micro/v2/logger"
"github.com/micro/go-micro/v2/util/kubernetes/api"
"github.com/micro/go-micro/v2/util/log"
)
var (

View File

@@ -91,6 +91,8 @@ func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
func Format(v string) string {
// to lower case
v = strings.ToLower(v)
// / to dashes
v = strings.ReplaceAll(v, "/", "-")
// dots to dashes
v = strings.ReplaceAll(v, ".", "-")
// limit to 253 chars

View File

@@ -1,5 +1,7 @@
# Log
DEPRECATED: use github.com/micro/go-micro/v2/logger interface
This is the global logger for all micro based libraries.
## Set Logger

View File

@@ -1,13 +1,14 @@
// Package log is a global internal logger
// DEPRECATED: this is frozen package, use github.com/micro/go-micro/v2/logger
package log
import (
"fmt"
"os"
"sync/atomic"
"time"
"github.com/micro/go-micro/v2/debug/log"
dlog "github.com/micro/go-micro/v2/debug/log"
nlog "github.com/micro/go-micro/v2/logger"
)
// level is a log level
@@ -22,9 +23,13 @@ const (
LevelTrace
)
type elog struct {
dlog dlog.Log
}
var (
// the local logger
logger log.Log = log.DefaultLog
logger dlog.Log = &elog{}
// default log level is info
level = LevelInfo
@@ -33,6 +38,24 @@ var (
prefix string
)
func levelToLevel(l Level) nlog.Level {
switch l {
case LevelTrace:
return nlog.TraceLevel
case LevelDebug:
return nlog.DebugLevel
case LevelWarn:
return nlog.WarnLevel
case LevelInfo:
return nlog.InfoLevel
case LevelError:
return nlog.ErrorLevel
case LevelFatal:
return nlog.FatalLevel
}
return nlog.InfoLevel
}
func init() {
switch os.Getenv("MICRO_LOG_LEVEL") {
case "trace":
@@ -69,18 +92,24 @@ func (l Level) String() string {
}
}
func (el *elog) Read(opt ...dlog.ReadOption) ([]dlog.Record, error) {
return el.dlog.Read(opt...)
}
func (el *elog) Write(r dlog.Record) error {
return el.dlog.Write(r)
}
func (el *elog) Stream() (dlog.Stream, error) {
return el.dlog.Stream()
}
// Log makes use of github.com/micro/debug/log
func Log(v ...interface{}) {
if len(prefix) > 0 {
v = append([]interface{}{prefix, " "}, v...)
}
logger.Write(log.Record{
Timestamp: time.Now(),
Message: fmt.Sprint(v...),
Metadata: map[string]string{
"level": level.String(),
},
})
nlog.DefaultLogger.Log(levelToLevel(level), v)
}
// Logf makes use of github.com/micro/debug/log
@@ -88,13 +117,7 @@ func Logf(format string, v ...interface{}) {
if len(prefix) > 0 {
format = prefix + " " + format
}
logger.Write(log.Record{
Timestamp: time.Now(),
Message: fmt.Sprintf(format, v...),
Metadata: map[string]string{
"level": level.String(),
},
})
nlog.DefaultLogger.Log(levelToLevel(level), format, v)
}
// WithLevel logs with the level specified
@@ -166,22 +189,20 @@ func Errorf(format string, v ...interface{}) {
// Fatal logs with Log and then exits with os.Exit(1)
func Fatal(v ...interface{}) {
WithLevel(LevelFatal, v...)
os.Exit(1)
}
// Fatalf logs with Logf and then exits with os.Exit(1)
func Fatalf(format string, v ...interface{}) {
WithLevelf(LevelFatal, format, v...)
os.Exit(1)
}
// SetLogger sets the local logger
func SetLogger(l log.Log) {
func SetLogger(l dlog.Log) {
logger = l
}
// GetLogger returns the local logger
func GetLogger() log.Log {
func GetLogger() dlog.Log {
return logger
}

View File

@@ -15,6 +15,10 @@ import (
type clientWrapper struct {
client.Client
// Auth interface
auth func() auth.Auth
// headers to inject
headers metadata.Metadata
}
@@ -27,7 +31,7 @@ type traceWrapper struct {
var (
HeaderPrefix = "Micro-"
BearerSchema = "Bearer "
BearerScheme = "Bearer "
)
func (c *clientWrapper) setHeaders(ctx context.Context) context.Context {
@@ -35,6 +39,15 @@ func (c *clientWrapper) setHeaders(ctx context.Context) context.Context {
mda, _ := metadata.FromContext(ctx)
md := metadata.Copy(mda)
// get auth token
if a := c.auth(); a != nil {
tk := a.Options().Token
// if the token if exists and auth header isn't set then set it
if len(tk) > 0 && len(md["Authorization"]) == 0 {
md["Authorization"] = BearerScheme + tk
}
}
// set headers
for k, v := range c.headers {
if _, ok := md[k]; !ok {
@@ -75,10 +88,11 @@ func (c *traceWrapper) Call(ctx context.Context, req client.Request, rsp interfa
return err
}
// FromService wraps a client to inject From-Service header into metadata
func FromService(name string, c client.Client) client.Client {
// FromService wraps a client to inject service and auth metadata
func FromService(name string, c client.Client, fn func() auth.Auth) client.Client {
return &clientWrapper{
c,
fn,
metadata.Metadata{
HeaderPrefix + "From-Service": name,
},
@@ -145,18 +159,14 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
// get the auth.Auth interface
a := fn()
// Extract endpoint and remove service name prefix
// (e.g. Platform.ListServices => ListServices)
var endpoint string
if ec := strings.Split(req.Endpoint(), "."); len(ec) == 2 {
endpoint = ec[1]
// Check for debug endpoints which should be excluded from auth
if strings.HasPrefix(req.Endpoint(), "Debug.") {
return h(ctx, req, rsp)
}
// Check for endpoints excluded from auth. If the endpoint
// matches, execute the handler and return
excludes := append(a.Options().Excludes, "Stats", "Trace")
for _, e := range excludes {
if e == endpoint {
// Exclude any user excluded endpoints
for _, e := range a.Options().Exclude {
if e == req.Endpoint() {
return h(ctx, req, rsp)
}
}
@@ -166,15 +176,15 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
var token string
if header, ok := metadata.Get(ctx, "Authorization"); ok {
// Ensure the correct scheme is being used
if !strings.HasPrefix(header, BearerSchema) {
if !strings.HasPrefix(header, BearerScheme) {
return errors.Unauthorized("go.micro.auth", "invalid authorization header. expected Bearer schema")
}
token = header[len(BearerSchema):]
token = header[len(BearerScheme):]
}
// Validate the token
if _, err := a.Validate(token); err != nil {
// Verify the token
if _, err := a.Verify(token); err != nil {
return errors.Unauthorized("go.micro.auth", err.Error())
}

Some files were not shown because too many files have changed in this diff Show More