Merge branch 'master' into crufting
This commit is contained in:
commit
4d4686d9be
@ -1,51 +0,0 @@
|
|||||||
# Etcd Source
|
|
||||||
|
|
||||||
The etcd source reads config from etcd key/values
|
|
||||||
|
|
||||||
This source supports etcd version 3 and beyond.
|
|
||||||
|
|
||||||
## Etcd Format
|
|
||||||
|
|
||||||
The etcd source expects keys under the default prefix `/micro/config` (prefix can be changed)
|
|
||||||
|
|
||||||
Values are expected to be JSON
|
|
||||||
|
|
||||||
```
|
|
||||||
// set database
|
|
||||||
etcdctl put /micro/config/database '{"address": "10.0.0.1", "port": 3306}'
|
|
||||||
// set cache
|
|
||||||
etcdctl put /micro/config/cache '{"address": "10.0.0.2", "port": 6379}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Keys are split on `/` so access becomes
|
|
||||||
|
|
||||||
```
|
|
||||||
conf.Get("micro", "config", "database")
|
|
||||||
```
|
|
||||||
|
|
||||||
## New Source
|
|
||||||
|
|
||||||
Specify source with data
|
|
||||||
|
|
||||||
```go
|
|
||||||
etcdSource := etcd.NewSource(
|
|
||||||
// optionally specify etcd address; default to localhost:8500
|
|
||||||
etcd.WithAddress("10.0.0.10:8500"),
|
|
||||||
// optionally specify prefix; defaults to /micro/config
|
|
||||||
etcd.WithPrefix("/my/prefix"),
|
|
||||||
// optionally strip the provided prefix from the keys, defaults to false
|
|
||||||
etcd.StripPrefix(true),
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Load Source
|
|
||||||
|
|
||||||
Load the source into config
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Create new config
|
|
||||||
conf := config.NewConfig()
|
|
||||||
|
|
||||||
// Load file source
|
|
||||||
conf.Load(etcdSource)
|
|
||||||
```
|
|
@ -1,134 +0,0 @@
|
|||||||
package etcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/micro/go-micro/config/source"
|
|
||||||
cetcd "go.etcd.io/etcd/clientv3"
|
|
||||||
"go.etcd.io/etcd/mvcc/mvccpb"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Currently a single etcd reader
|
|
||||||
type etcd struct {
|
|
||||||
prefix string
|
|
||||||
stripPrefix string
|
|
||||||
opts source.Options
|
|
||||||
client *cetcd.Client
|
|
||||||
cerr error
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultPrefix = "/micro/config/"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *etcd) Read() (*source.ChangeSet, error) {
|
|
||||||
if c.cerr != nil {
|
|
||||||
return nil, c.cerr
|
|
||||||
}
|
|
||||||
|
|
||||||
rsp, err := c.client.Get(context.Background(), c.prefix, cetcd.WithPrefix())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if rsp == nil || len(rsp.Kvs) == 0 {
|
|
||||||
return nil, fmt.Errorf("source not found: %s", c.prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
var kvs []*mvccpb.KeyValue
|
|
||||||
for _, v := range rsp.Kvs {
|
|
||||||
kvs = append(kvs, (*mvccpb.KeyValue)(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
data := makeMap(c.opts.Encoder, kvs, c.stripPrefix)
|
|
||||||
|
|
||||||
b, err := c.opts.Encoder.Encode(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error reading source: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cs := &source.ChangeSet{
|
|
||||||
Timestamp: time.Now(),
|
|
||||||
Source: c.String(),
|
|
||||||
Data: b,
|
|
||||||
Format: c.opts.Encoder.String(),
|
|
||||||
}
|
|
||||||
cs.Checksum = cs.Sum()
|
|
||||||
|
|
||||||
return cs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *etcd) String() string {
|
|
||||||
return "etcd"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *etcd) Watch() (source.Watcher, error) {
|
|
||||||
if c.cerr != nil {
|
|
||||||
return nil, c.cerr
|
|
||||||
}
|
|
||||||
cs, err := c.Read()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return newWatcher(c.prefix, c.stripPrefix, c.client.Watcher, cs, c.opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSource(opts ...source.Option) source.Source {
|
|
||||||
options := source.NewOptions(opts...)
|
|
||||||
|
|
||||||
var endpoints []string
|
|
||||||
|
|
||||||
// check if there are any addrs
|
|
||||||
addrs, ok := options.Context.Value(addressKey{}).([]string)
|
|
||||||
if ok {
|
|
||||||
for _, a := range addrs {
|
|
||||||
addr, port, err := net.SplitHostPort(a)
|
|
||||||
if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
|
|
||||||
port = "2379"
|
|
||||||
addr = a
|
|
||||||
endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port))
|
|
||||||
} else if err == nil {
|
|
||||||
endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(endpoints) == 0 {
|
|
||||||
endpoints = []string{"localhost:2379"}
|
|
||||||
}
|
|
||||||
|
|
||||||
config := cetcd.Config{
|
|
||||||
Endpoints: endpoints,
|
|
||||||
}
|
|
||||||
|
|
||||||
u, ok := options.Context.Value(authKey{}).(*authCreds)
|
|
||||||
if ok {
|
|
||||||
config.Username = u.Username
|
|
||||||
config.Password = u.Password
|
|
||||||
}
|
|
||||||
|
|
||||||
// use default config
|
|
||||||
client, err := cetcd.New(config)
|
|
||||||
|
|
||||||
prefix := DefaultPrefix
|
|
||||||
sp := ""
|
|
||||||
f, ok := options.Context.Value(prefixKey{}).(string)
|
|
||||||
if ok {
|
|
||||||
prefix = f
|
|
||||||
}
|
|
||||||
|
|
||||||
if b, ok := options.Context.Value(stripPrefixKey{}).(bool); ok && b {
|
|
||||||
sp = prefix
|
|
||||||
}
|
|
||||||
|
|
||||||
return &etcd{
|
|
||||||
prefix: prefix,
|
|
||||||
stripPrefix: sp,
|
|
||||||
opts: options,
|
|
||||||
client: client,
|
|
||||||
cerr: err,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package etcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/micro/go-micro/config/source"
|
|
||||||
)
|
|
||||||
|
|
||||||
type addressKey struct{}
|
|
||||||
type prefixKey struct{}
|
|
||||||
type stripPrefixKey struct{}
|
|
||||||
type authKey struct{}
|
|
||||||
|
|
||||||
type authCreds struct {
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithAddress sets the consul address
|
|
||||||
func WithAddress(a ...string) source.Option {
|
|
||||||
return func(o *source.Options) {
|
|
||||||
if o.Context == nil {
|
|
||||||
o.Context = context.Background()
|
|
||||||
}
|
|
||||||
o.Context = context.WithValue(o.Context, addressKey{}, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithPrefix sets the key prefix to use
|
|
||||||
func WithPrefix(p string) source.Option {
|
|
||||||
return func(o *source.Options) {
|
|
||||||
if o.Context == nil {
|
|
||||||
o.Context = context.Background()
|
|
||||||
}
|
|
||||||
o.Context = context.WithValue(o.Context, prefixKey{}, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StripPrefix indicates whether to remove the prefix from config entries, or leave it in place.
|
|
||||||
func StripPrefix(strip bool) source.Option {
|
|
||||||
return func(o *source.Options) {
|
|
||||||
if o.Context == nil {
|
|
||||||
o.Context = context.Background()
|
|
||||||
}
|
|
||||||
|
|
||||||
o.Context = context.WithValue(o.Context, stripPrefixKey{}, strip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auth allows you to specify username/password
|
|
||||||
func Auth(username, password string) source.Option {
|
|
||||||
return func(o *source.Options) {
|
|
||||||
if o.Context == nil {
|
|
||||||
o.Context = context.Background()
|
|
||||||
}
|
|
||||||
o.Context = context.WithValue(o.Context, authKey{}, &authCreds{Username: username, Password: password})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
package etcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/micro/go-micro/config/encoder"
|
|
||||||
"go.etcd.io/etcd/clientv3"
|
|
||||||
"go.etcd.io/etcd/mvcc/mvccpb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeEvMap(e encoder.Encoder, data map[string]interface{}, kv []*clientv3.Event, stripPrefix string) map[string]interface{} {
|
|
||||||
if data == nil {
|
|
||||||
data = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range kv {
|
|
||||||
switch mvccpb.Event_EventType(v.Type) {
|
|
||||||
case mvccpb.DELETE:
|
|
||||||
data = update(e, data, (*mvccpb.KeyValue)(v.Kv), "delete", stripPrefix)
|
|
||||||
default:
|
|
||||||
data = update(e, data, (*mvccpb.KeyValue)(v.Kv), "insert", stripPrefix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeMap(e encoder.Encoder, kv []*mvccpb.KeyValue, stripPrefix string) map[string]interface{} {
|
|
||||||
data := make(map[string]interface{})
|
|
||||||
|
|
||||||
for _, v := range kv {
|
|
||||||
data = update(e, data, v, "put", stripPrefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
func update(e encoder.Encoder, data map[string]interface{}, v *mvccpb.KeyValue, action, stripPrefix string) map[string]interface{} {
|
|
||||||
// remove prefix if non empty, and ensure leading / is removed as well
|
|
||||||
vkey := strings.TrimPrefix(strings.TrimPrefix(string(v.Key), stripPrefix), "/")
|
|
||||||
// split on prefix
|
|
||||||
haveSplit := strings.Contains(vkey, "/")
|
|
||||||
keys := strings.Split(vkey, "/")
|
|
||||||
|
|
||||||
var vals interface{}
|
|
||||||
e.Decode(v.Value, &vals)
|
|
||||||
|
|
||||||
if !haveSplit && len(keys) == 1 {
|
|
||||||
switch action {
|
|
||||||
case "delete":
|
|
||||||
data = make(map[string]interface{})
|
|
||||||
default:
|
|
||||||
v, ok := vals.(map[string]interface{})
|
|
||||||
if ok {
|
|
||||||
data = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
// set data for first iteration
|
|
||||||
kvals := data
|
|
||||||
// iterate the keys and make maps
|
|
||||||
for i, k := range keys {
|
|
||||||
kval, ok := kvals[k].(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
// create next map
|
|
||||||
kval = make(map[string]interface{})
|
|
||||||
// set it
|
|
||||||
kvals[k] = kval
|
|
||||||
}
|
|
||||||
|
|
||||||
// last key: write vals
|
|
||||||
if l := len(keys) - 1; i == l {
|
|
||||||
switch action {
|
|
||||||
case "delete":
|
|
||||||
delete(kvals, k)
|
|
||||||
default:
|
|
||||||
kvals[k] = vals
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// set kvals for next iterator
|
|
||||||
kvals = kval
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
package etcd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/micro/go-micro/config/source"
|
|
||||||
cetcd "go.etcd.io/etcd/clientv3"
|
|
||||||
)
|
|
||||||
|
|
||||||
type watcher struct {
|
|
||||||
opts source.Options
|
|
||||||
name string
|
|
||||||
stripPrefix string
|
|
||||||
|
|
||||||
sync.RWMutex
|
|
||||||
cs *source.ChangeSet
|
|
||||||
|
|
||||||
ch chan *source.ChangeSet
|
|
||||||
exit chan bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newWatcher(key, strip string, wc cetcd.Watcher, cs *source.ChangeSet, opts source.Options) (source.Watcher, error) {
|
|
||||||
w := &watcher{
|
|
||||||
opts: opts,
|
|
||||||
name: "etcd",
|
|
||||||
stripPrefix: strip,
|
|
||||||
cs: cs,
|
|
||||||
ch: make(chan *source.ChangeSet),
|
|
||||||
exit: make(chan bool),
|
|
||||||
}
|
|
||||||
|
|
||||||
ch := wc.Watch(context.Background(), key, cetcd.WithPrefix())
|
|
||||||
|
|
||||||
go w.run(wc, ch)
|
|
||||||
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *watcher) handle(evs []*cetcd.Event) {
|
|
||||||
w.RLock()
|
|
||||||
data := w.cs.Data
|
|
||||||
w.RUnlock()
|
|
||||||
|
|
||||||
var vals map[string]interface{}
|
|
||||||
|
|
||||||
// unpackage existing changeset
|
|
||||||
if err := w.opts.Encoder.Decode(data, &vals); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// update base changeset
|
|
||||||
d := makeEvMap(w.opts.Encoder, vals, evs, w.stripPrefix)
|
|
||||||
|
|
||||||
// pack the changeset
|
|
||||||
b, err := w.opts.Encoder.Encode(d)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// create new changeset
|
|
||||||
cs := &source.ChangeSet{
|
|
||||||
Timestamp: time.Now(),
|
|
||||||
Source: w.name,
|
|
||||||
Data: b,
|
|
||||||
Format: w.opts.Encoder.String(),
|
|
||||||
}
|
|
||||||
cs.Checksum = cs.Sum()
|
|
||||||
|
|
||||||
// set base change set
|
|
||||||
w.Lock()
|
|
||||||
w.cs = cs
|
|
||||||
w.Unlock()
|
|
||||||
|
|
||||||
// send update
|
|
||||||
w.ch <- cs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *watcher) run(wc cetcd.Watcher, ch cetcd.WatchChan) {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case rsp, ok := <-ch:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.handle(rsp.Events)
|
|
||||||
case <-w.exit:
|
|
||||||
wc.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *watcher) Next() (*source.ChangeSet, error) {
|
|
||||||
select {
|
|
||||||
case cs := <-w.ch:
|
|
||||||
return cs, nil
|
|
||||||
case <-w.exit:
|
|
||||||
return nil, errors.New("watcher stopped")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *watcher) Stop() error {
|
|
||||||
select {
|
|
||||||
case <-w.exit:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
close(w.exit)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
4
go.mod
4
go.mod
@ -7,7 +7,6 @@ require (
|
|||||||
github.com/beevik/ntp v0.2.0
|
github.com/beevik/ntp v0.2.0
|
||||||
github.com/bitly/go-simplejson v0.5.0
|
github.com/bitly/go-simplejson v0.5.0
|
||||||
github.com/bwmarrin/discordgo v0.19.0
|
github.com/bwmarrin/discordgo v0.19.0
|
||||||
github.com/coreos/etcd v3.3.13+incompatible // indirect
|
|
||||||
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c
|
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c
|
||||||
github.com/fsnotify/fsnotify v1.4.7
|
github.com/fsnotify/fsnotify v1.4.7
|
||||||
github.com/fsouza/go-dockerclient v1.4.1
|
github.com/fsouza/go-dockerclient v1.4.1
|
||||||
@ -36,9 +35,8 @@ require (
|
|||||||
github.com/nlopes/slack v0.5.0
|
github.com/nlopes/slack v0.5.0
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||||
go.etcd.io/etcd v3.3.13+incompatible
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
|
||||||
golang.org/x/net v0.0.0-20190606173856-1492cefac77f
|
golang.org/x/net v0.0.0-20190607181551-461777fb6f67
|
||||||
google.golang.org/grpc v1.21.1
|
google.golang.org/grpc v1.21.1
|
||||||
gopkg.in/go-playground/validator.v9 v9.29.0
|
gopkg.in/go-playground/validator.v9 v9.29.0
|
||||||
gopkg.in/src-d/go-git.v4 v4.11.0
|
gopkg.in/src-d/go-git.v4 v4.11.0
|
||||||
|
8
go.sum
8
go.sum
@ -21,8 +21,6 @@ github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wX
|
|||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M=
|
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M=
|
||||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ=
|
|
||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc=
|
github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc=
|
||||||
@ -194,8 +192,6 @@ github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQ
|
|||||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||||
github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro=
|
github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro=
|
||||||
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
|
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
|
||||||
go.etcd.io/etcd v3.3.13+incompatible h1:jCejD5EMnlGxFvcGRyEV4VGlENZc7oPQX6o0t7n3xbw=
|
|
||||||
go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@ -212,8 +208,8 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r
|
|||||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190606173856-1492cefac77f h1:IWHgpgFqnL5AhBUBZSgBdjl2vkQUEzcY+JNKWfcgAU0=
|
golang.org/x/net v0.0.0-20190607181551-461777fb6f67 h1:rJJxsykSlULwd2P2+pg/rtnwN2FrWp4IuCxOSyS0V00=
|
||||||
golang.org/x/net v0.0.0-20190606173856-1492cefac77f/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190607181551-461777fb6f67/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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user