From 5e6491b7b07ec81b1d39ebdf30c090760abe5a24 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 30 May 2019 23:11:13 +0100 Subject: [PATCH 01/18] add config --- config/README.md | 29 ++ config/config.go | 94 +++++++ config/default.go | 253 ++++++++++++++++++ config/default_test.go | 101 +++++++ config/encoder/encoder.go | 8 + config/encoder/hcl/hcl.go | 26 ++ config/encoder/json/json.go | 25 ++ config/encoder/toml/toml.go | 32 +++ config/encoder/xml/xml.go | 25 ++ config/encoder/yaml/yaml.go | 24 ++ config/issue18_test.go | 60 +++++ config/loader/loader.go | 63 +++++ config/loader/memory/memory.go | 415 +++++++++++++++++++++++++++++ config/loader/memory/options.go | 21 ++ config/options.go | 28 ++ config/reader/json/json.go | 83 ++++++ config/reader/json/json_test.go | 43 +++ config/reader/json/values.go | 208 +++++++++++++++ config/reader/json/values_test.go | 39 +++ config/reader/options.go | 42 +++ config/reader/preprocessor.go | 23 ++ config/reader/preprocessor_test.go | 73 +++++ config/reader/reader.go | 36 +++ config/source/changeset.go | 13 + config/source/cli/README.md | 71 +++++ config/source/cli/cli.go | 146 ++++++++++ config/source/cli/cli_test.go | 65 +++++ config/source/cli/options.go | 20 ++ config/source/cli/util.go | 50 ++++ config/source/consul/README.md | 49 ++++ config/source/consul/consul.go | 121 +++++++++ config/source/consul/options.go | 63 +++++ config/source/consul/util.go | 49 ++++ config/source/consul/watcher.go | 96 +++++++ config/source/env/README.md | 96 +++++++ config/source/env/env.go | 142 ++++++++++ config/source/env/env_test.go | 112 ++++++++ config/source/env/options.go | 49 ++++ config/source/env/watcher.go | 26 ++ config/source/file/README.md | 70 +++++ config/source/file/file.go | 65 +++++ config/source/file/file_test.go | 37 +++ config/source/file/format.go | 15 ++ config/source/file/format_test.go | 31 +++ config/source/file/options.go | 19 ++ config/source/file/watcher.go | 66 +++++ config/source/flag/README.md | 47 ++++ config/source/flag/flag.go | 97 +++++++ config/source/flag/flag_test.go | 66 +++++ config/source/flag/options.go | 20 ++ config/source/memory/README.md | 44 +++ config/source/memory/memory.go | 93 +++++++ config/source/memory/options.go | 32 +++ config/source/memory/watcher.go | 23 ++ config/source/noop.go | 25 ++ config/source/options.go | 38 +++ config/source/source.go | 28 ++ config/value.go | 49 ++++ 58 files changed, 3784 insertions(+) create mode 100644 config/README.md create mode 100644 config/config.go create mode 100644 config/default.go create mode 100644 config/default_test.go create mode 100644 config/encoder/encoder.go create mode 100644 config/encoder/hcl/hcl.go create mode 100644 config/encoder/json/json.go create mode 100644 config/encoder/toml/toml.go create mode 100644 config/encoder/xml/xml.go create mode 100644 config/encoder/yaml/yaml.go create mode 100644 config/issue18_test.go create mode 100644 config/loader/loader.go create mode 100644 config/loader/memory/memory.go create mode 100644 config/loader/memory/options.go create mode 100644 config/options.go create mode 100644 config/reader/json/json.go create mode 100644 config/reader/json/json_test.go create mode 100644 config/reader/json/values.go create mode 100644 config/reader/json/values_test.go create mode 100644 config/reader/options.go create mode 100644 config/reader/preprocessor.go create mode 100644 config/reader/preprocessor_test.go create mode 100644 config/reader/reader.go create mode 100644 config/source/changeset.go create mode 100644 config/source/cli/README.md create mode 100644 config/source/cli/cli.go create mode 100644 config/source/cli/cli_test.go create mode 100644 config/source/cli/options.go create mode 100644 config/source/cli/util.go create mode 100644 config/source/consul/README.md create mode 100644 config/source/consul/consul.go create mode 100644 config/source/consul/options.go create mode 100644 config/source/consul/util.go create mode 100644 config/source/consul/watcher.go create mode 100644 config/source/env/README.md create mode 100644 config/source/env/env.go create mode 100644 config/source/env/env_test.go create mode 100644 config/source/env/options.go create mode 100644 config/source/env/watcher.go create mode 100644 config/source/file/README.md create mode 100644 config/source/file/file.go create mode 100644 config/source/file/file_test.go create mode 100644 config/source/file/format.go create mode 100644 config/source/file/format_test.go create mode 100644 config/source/file/options.go create mode 100644 config/source/file/watcher.go create mode 100644 config/source/flag/README.md create mode 100644 config/source/flag/flag.go create mode 100644 config/source/flag/flag_test.go create mode 100644 config/source/flag/options.go create mode 100644 config/source/memory/README.md create mode 100644 config/source/memory/memory.go create mode 100644 config/source/memory/options.go create mode 100644 config/source/memory/watcher.go create mode 100644 config/source/noop.go create mode 100644 config/source/options.go create mode 100644 config/source/source.go create mode 100644 config/value.go diff --git a/config/README.md b/config/README.md new file mode 100644 index 00000000..f1265f51 --- /dev/null +++ b/config/README.md @@ -0,0 +1,29 @@ +# Config [![GoDoc](https://godoc.org/github.com/micro/go-micro/config?status.svg)](https://godoc.org/github.com/micro/go-micro/config) + +Go Config is a pluggable dynamic config library. + +Most config in applications are statically configured or include complex logic to load from multiple sources. +Go Config makes this easy, pluggable and mergeable. You'll never have to deal with config in the same way again. + +## Features + +- **Dynamic Loading** - Load configuration from multiple source as and when needed. Go Config manages watching config sources +in the background and automatically merges and updates an in memory view. + +- **Pluggable Sources** - Choose from any number of sources to load and merge config. The backend source is abstracted away into +a standard format consumed internally and decoded via encoders. Sources can be env vars, flags, file, etcd, k8s configmap, etc. + +- **Mergeable Config** - If you specify multiple sources of config, regardless of format, they will be merged and presented in +a single view. This massively simplifies priority order loading and changes based on environment. + +- **Observe Changes** - Optionally watch the config for changes to specific values. Hot reload your app using Go Config's watcher. +You don't have to handle ad-hoc hup reloading or whatever else, just keep reading the config and watch for changes if you need +to be notified. + +- **Sane Defaults** - In case config loads badly or is completely wiped away for some unknown reason, you can specify fallback +values when accessing any config values directly. This ensures you'll always be reading some sane default in the event of a problem. + +## Getting Started + +For detailed information or architecture, installation and general usage see the [docs](https://micro.mu/docs/go-config.html) + diff --git a/config/config.go b/config/config.go new file mode 100644 index 00000000..020c71d5 --- /dev/null +++ b/config/config.go @@ -0,0 +1,94 @@ +// Package config is an interface for dynamic configuration. +package config + +import ( + "context" + + "github.com/micro/go-micro/config/loader" + "github.com/micro/go-micro/config/reader" + "github.com/micro/go-micro/config/source" + "github.com/micro/go-micro/config/source/file" +) + +// Config is an interface abstraction for dynamic configuration +type Config interface { + // provide the reader.Values interface + reader.Values + // Stop the config loader/watcher + Close() error + // Load config sources + Load(source ...source.Source) error + // Force a source changeset sync + Sync() error + // Watch a value for changes + Watch(path ...string) (Watcher, error) +} + +// Watcher is the config watcher +type Watcher interface { + Next() (reader.Value, error) + Stop() error +} + +type Options struct { + Loader loader.Loader + Reader reader.Reader + Source []source.Source + + // for alternative data + Context context.Context +} + +type Option func(o *Options) + +var ( + // Default Config Manager + DefaultConfig = NewConfig() +) + +// NewConfig returns new config +func NewConfig(opts ...Option) Config { + return newConfig(opts...) +} + +// Return config as raw json +func Bytes() []byte { + return DefaultConfig.Bytes() +} + +// Return config as a map +func Map() map[string]interface{} { + return DefaultConfig.Map() +} + +// Scan values to a go type +func Scan(v interface{}) error { + return DefaultConfig.Scan(v) +} + +// Force a source changeset sync +func Sync() error { + return DefaultConfig.Sync() +} + +// Get a value from the config +func Get(path ...string) reader.Value { + return DefaultConfig.Get(path...) +} + +// Load config sources +func Load(source ...source.Source) error { + return DefaultConfig.Load(source...) +} + +// Watch a value for changes +func Watch(path ...string) (Watcher, error) { + return DefaultConfig.Watch(path...) +} + +// LoadFile is short hand for creating a file source and loading it +func LoadFile(path string) error { + return Load(file.NewSource( + file.WithPath(path), + )) +} diff --git a/config/default.go b/config/default.go new file mode 100644 index 00000000..aa9bf365 --- /dev/null +++ b/config/default.go @@ -0,0 +1,253 @@ +package config + +import ( + "bytes" + "sync" + "time" + + "github.com/micro/go-micro/config/loader" + "github.com/micro/go-micro/config/loader/memory" + "github.com/micro/go-micro/config/reader" + "github.com/micro/go-micro/config/reader/json" + "github.com/micro/go-micro/config/source" +) + +type config struct { + exit chan bool + opts Options + + sync.RWMutex + // the current snapshot + snap *loader.Snapshot + // the current values + vals reader.Values +} + +type watcher struct { + lw loader.Watcher + rd reader.Reader + path []string + value reader.Value +} + +func newConfig(opts ...Option) Config { + options := Options{ + Loader: memory.NewLoader(), + Reader: json.NewReader(), + } + + for _, o := range opts { + o(&options) + } + + options.Loader.Load(options.Source...) + snap, _ := options.Loader.Snapshot() + vals, _ := options.Reader.Values(snap.ChangeSet) + + c := &config{ + exit: make(chan bool), + opts: options, + snap: snap, + vals: vals, + } + + go c.run() + + return c +} + +func (c *config) run() { + watch := func(w loader.Watcher) error { + for { + // get changeset + snap, err := w.Next() + if err != nil { + return err + } + + c.Lock() + + // save + c.snap = snap + + // set values + c.vals, _ = c.opts.Reader.Values(snap.ChangeSet) + + c.Unlock() + } + } + + for { + w, err := c.opts.Loader.Watch() + if err != nil { + time.Sleep(time.Second) + continue + } + + done := make(chan bool) + + // the stop watch func + go func() { + select { + case <-done: + case <-c.exit: + } + w.Stop() + }() + + // block watch + if err := watch(w); err != nil { + // do something better + time.Sleep(time.Second) + } + + // close done chan + close(done) + + // if the config is closed exit + select { + case <-c.exit: + return + default: + } + } +} + +func (c *config) Map() map[string]interface{} { + c.RLock() + defer c.RUnlock() + return c.vals.Map() +} + +func (c *config) Scan(v interface{}) error { + c.RLock() + defer c.RUnlock() + return c.vals.Scan(v) +} + +// sync loads all the sources, calls the parser and updates the config +func (c *config) Sync() error { + if err := c.opts.Loader.Sync(); err != nil { + return err + } + + snap, err := c.opts.Loader.Snapshot() + if err != nil { + return err + } + + c.Lock() + defer c.Unlock() + + c.snap = snap + vals, err := c.opts.Reader.Values(snap.ChangeSet) + if err != nil { + return err + } + c.vals = vals + + return nil +} + +func (c *config) Close() error { + select { + case <-c.exit: + return nil + default: + close(c.exit) + } + return nil +} + +func (c *config) Get(path ...string) reader.Value { + c.RLock() + defer c.RUnlock() + + // did sync actually work? + if c.vals != nil { + return c.vals.Get(path...) + } + + // no value + return newValue() +} + +func (c *config) Bytes() []byte { + c.RLock() + defer c.RUnlock() + + if c.vals == nil { + return []byte{} + } + + return c.vals.Bytes() +} + +func (c *config) Load(sources ...source.Source) error { + if err := c.opts.Loader.Load(sources...); err != nil { + return err + } + + snap, err := c.opts.Loader.Snapshot() + if err != nil { + return err + } + + c.Lock() + defer c.Unlock() + + c.snap = snap + vals, err := c.opts.Reader.Values(snap.ChangeSet) + if err != nil { + return err + } + c.vals = vals + + return nil +} + +func (c *config) Watch(path ...string) (Watcher, error) { + value := c.Get(path...) + + w, err := c.opts.Loader.Watch(path...) + if err != nil { + return nil, err + } + + return &watcher{ + lw: w, + rd: c.opts.Reader, + path: path, + value: value, + }, nil +} + +func (c *config) String() string { + return "config" +} + +func (w *watcher) Next() (reader.Value, error) { + for { + s, err := w.lw.Next() + if err != nil { + return nil, err + } + + // only process changes + if bytes.Equal(w.value.Bytes(), s.ChangeSet.Data) { + continue + } + + v, err := w.rd.Values(s.ChangeSet) + if err != nil { + return nil, err + } + + w.value = v.Get() + return w.value, nil + } +} + +func (w *watcher) Stop() error { + return w.lw.Stop() +} diff --git a/config/default_test.go b/config/default_test.go new file mode 100644 index 00000000..9d1bd03e --- /dev/null +++ b/config/default_test.go @@ -0,0 +1,101 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/micro/go-micro/config/source/file" +) + +func createFileForTest(t *testing.T) *os.File { + data := []byte(`{"foo": "bar"}`) + path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) + fh, err := os.Create(path) + if err != nil { + t.Error(err) + } + _, err = fh.Write(data) + if err != nil { + t.Error(err) + } + + return fh +} + +func TestLoadWithGoodFile(t *testing.T) { + fh := createFileForTest(t) + path := fh.Name() + defer func() { + fh.Close() + os.Remove(path) + }() + + // Create new config + conf := NewConfig() + // Load file source + if err := conf.Load(file.NewSource( + file.WithPath(path), + )); err != nil { + t.Fatalf("Expected no error but got %v", err) + } +} + +func TestLoadWithInvalidFile(t *testing.T) { + fh := createFileForTest(t) + path := fh.Name() + defer func() { + fh.Close() + os.Remove(path) + }() + + // Create new config + conf := NewConfig() + // Load file source + err := conf.Load(file.NewSource( + file.WithPath(path), + file.WithPath("/i/do/not/exists.json"), + )) + + if err == nil { + t.Fatal("Expected error but none !") + } + if !strings.Contains(fmt.Sprintf("%v", err), "/i/do/not/exists.json") { + t.Fatalf("Expected error to contain the unexisting file but got %v", err) + } +} + +func TestConsul(t *testing.T) { + /*consulSource := consul.NewSource( + // optionally specify consul address; default to localhost:8500 + consul.WithAddress("131.150.38.111:8500"), + // optionally specify prefix; defaults to /micro/config + consul.WithPrefix("/project"), + // optionally strip the provided prefix from the keys, defaults to false + consul.StripPrefix(true), + consul.WithDatacenter("dc1"), + consul.WithToken("xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"), + ) + + // Create new config + conf := NewConfig() + + // Load file source + err := conf.Load(consulSource) + if err != nil { + t.Error(err) + return + } + + m := conf.Map() + t.Log("m: ", m) + + v := conf.Get("project", "dc111", "port") + + t.Log("v: ", v.Int(13))*/ + + t.Log("OK") +} diff --git a/config/encoder/encoder.go b/config/encoder/encoder.go new file mode 100644 index 00000000..0ef0654a --- /dev/null +++ b/config/encoder/encoder.go @@ -0,0 +1,8 @@ +// Package encoder handles source encoding formats +package encoder + +type Encoder interface { + Encode(interface{}) ([]byte, error) + Decode([]byte, interface{}) error + String() string +} diff --git a/config/encoder/hcl/hcl.go b/config/encoder/hcl/hcl.go new file mode 100644 index 00000000..7fa02b2c --- /dev/null +++ b/config/encoder/hcl/hcl.go @@ -0,0 +1,26 @@ +package hcl + +import ( + "encoding/json" + + "github.com/hashicorp/hcl" + "github.com/micro/go-micro/config/encoder" +) + +type hclEncoder struct{} + +func (h hclEncoder) Encode(v interface{}) ([]byte, error) { + return json.Marshal(v) +} + +func (h hclEncoder) Decode(d []byte, v interface{}) error { + return hcl.Unmarshal(d, v) +} + +func (h hclEncoder) String() string { + return "hcl" +} + +func NewEncoder() encoder.Encoder { + return hclEncoder{} +} diff --git a/config/encoder/json/json.go b/config/encoder/json/json.go new file mode 100644 index 00000000..a5b3557b --- /dev/null +++ b/config/encoder/json/json.go @@ -0,0 +1,25 @@ +package json + +import ( + "encoding/json" + + "github.com/micro/go-micro/config/encoder" +) + +type jsonEncoder struct{} + +func (j jsonEncoder) Encode(v interface{}) ([]byte, error) { + return json.Marshal(v) +} + +func (j jsonEncoder) Decode(d []byte, v interface{}) error { + return json.Unmarshal(d, v) +} + +func (j jsonEncoder) String() string { + return "json" +} + +func NewEncoder() encoder.Encoder { + return jsonEncoder{} +} diff --git a/config/encoder/toml/toml.go b/config/encoder/toml/toml.go new file mode 100644 index 00000000..f9688966 --- /dev/null +++ b/config/encoder/toml/toml.go @@ -0,0 +1,32 @@ +package toml + +import ( + "bytes" + + "github.com/BurntSushi/toml" + "github.com/micro/go-micro/config/encoder" +) + +type tomlEncoder struct{} + +func (t tomlEncoder) Encode(v interface{}) ([]byte, error) { + b := bytes.NewBuffer(nil) + defer b.Reset() + err := toml.NewEncoder(b).Encode(v) + if err != nil { + return nil, err + } + return b.Bytes(), nil +} + +func (t tomlEncoder) Decode(d []byte, v interface{}) error { + return toml.Unmarshal(d, v) +} + +func (t tomlEncoder) String() string { + return "toml" +} + +func NewEncoder() encoder.Encoder { + return tomlEncoder{} +} diff --git a/config/encoder/xml/xml.go b/config/encoder/xml/xml.go new file mode 100644 index 00000000..e970d8f1 --- /dev/null +++ b/config/encoder/xml/xml.go @@ -0,0 +1,25 @@ +package xml + +import ( + "encoding/xml" + + "github.com/micro/go-micro/config/encoder" +) + +type xmlEncoder struct{} + +func (x xmlEncoder) Encode(v interface{}) ([]byte, error) { + return xml.Marshal(v) +} + +func (x xmlEncoder) Decode(d []byte, v interface{}) error { + return xml.Unmarshal(d, v) +} + +func (x xmlEncoder) String() string { + return "xml" +} + +func NewEncoder() encoder.Encoder { + return xmlEncoder{} +} diff --git a/config/encoder/yaml/yaml.go b/config/encoder/yaml/yaml.go new file mode 100644 index 00000000..efecbf0c --- /dev/null +++ b/config/encoder/yaml/yaml.go @@ -0,0 +1,24 @@ +package yaml + +import ( + "github.com/ghodss/yaml" + "github.com/micro/go-micro/config/encoder" +) + +type yamlEncoder struct{} + +func (y yamlEncoder) Encode(v interface{}) ([]byte, error) { + return yaml.Marshal(v) +} + +func (y yamlEncoder) Decode(d []byte, v interface{}) error { + return yaml.Unmarshal(d, v) +} + +func (y yamlEncoder) String() string { + return "yaml" +} + +func NewEncoder() encoder.Encoder { + return yamlEncoder{} +} diff --git a/config/issue18_test.go b/config/issue18_test.go new file mode 100644 index 00000000..5fed22bf --- /dev/null +++ b/config/issue18_test.go @@ -0,0 +1,60 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "testing" + "time" + + "github.com/micro/go-micro/config/source/env" + "github.com/micro/go-micro/config/source/file" +) + +func createFileForIssue18(t *testing.T, content string) *os.File { + data := []byte(content) + path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) + fh, err := os.Create(path) + if err != nil { + t.Error(err) + } + _, err = fh.Write(data) + if err != nil { + t.Error(err) + } + + return fh +} + +func TestIssue18(t *testing.T) { + fh := createFileForIssue18(t, `{ + "amqp": { + "host": "rabbit.platform", + "port": 80 + }, + "handler": { + "exchange": "springCloudBus" + } +}`) + path := fh.Name() + defer func() { + fh.Close() + os.Remove(path) + }() + os.Setenv("AMQP_HOST", "rabbit.testing.com") + + conf := NewConfig() + conf.Load( + file.NewSource( + file.WithPath(path), + ), + env.NewSource(), + ) + + actualHost := conf.Get("amqp", "host").String("backup") + if actualHost != "rabbit.testing.com" { + t.Fatalf("Expected %v but got %v", + "rabbit.testing.com", + actualHost) + } +} diff --git a/config/loader/loader.go b/config/loader/loader.go new file mode 100644 index 00000000..93029243 --- /dev/null +++ b/config/loader/loader.go @@ -0,0 +1,63 @@ +// package loader manages loading from multiple sources +package loader + +import ( + "context" + + "github.com/micro/go-micro/config/reader" + "github.com/micro/go-micro/config/source" +) + +// Loader manages loading sources +type Loader interface { + // Stop the loader + Close() error + // Load the sources + Load(...source.Source) error + // A Snapshot of loaded config + Snapshot() (*Snapshot, error) + // Force sync of sources + Sync() error + // Watch for changes + Watch(...string) (Watcher, error) + // Name of loader + String() string +} + +// Watcher lets you watch sources and returns a merged ChangeSet +type Watcher interface { + // First call to next may return the current Snapshot + // If you are watching a path then only the data from + // that path is returned. + Next() (*Snapshot, error) + // Stop watching for changes + Stop() error +} + +// Snapshot is a merged ChangeSet +type Snapshot struct { + // The merged ChangeSet + ChangeSet *source.ChangeSet + // Deterministic and comparable version of the snapshot + Version string +} + +type Options struct { + Reader reader.Reader + Source []source.Source + + // for alternative data + Context context.Context +} + +type Option func(o *Options) + +// Copy snapshot +func Copy(s *Snapshot) *Snapshot { + cs := *(s.ChangeSet) + + return &Snapshot{ + ChangeSet: &cs, + Version: s.Version, + } +} diff --git a/config/loader/memory/memory.go b/config/loader/memory/memory.go new file mode 100644 index 00000000..6d5b27cb --- /dev/null +++ b/config/loader/memory/memory.go @@ -0,0 +1,415 @@ +package memory + +import ( + "bytes" + "errors" + "fmt" + "strings" + "sync" + "time" + + "github.com/micro/go-micro/config/loader" + "github.com/micro/go-micro/config/reader" + "github.com/micro/go-micro/config/reader/json" + "github.com/micro/go-micro/config/source" +) + +type memory struct { + exit chan bool + opts loader.Options + + sync.RWMutex + // the current snapshot + snap *loader.Snapshot + // the current values + vals reader.Values + // all the sets + sets []*source.ChangeSet + // all the sources + sources []source.Source + + idx int + watchers map[int]*watcher +} + +type watcher struct { + exit chan bool + path []string + value reader.Value + reader reader.Reader + updates chan reader.Value +} + +func (m *memory) watch(idx int, s source.Source) { + m.Lock() + m.sets = append(m.sets, &source.ChangeSet{Source: s.String()}) + m.Unlock() + + // watches a source for changes + watch := func(idx int, s source.Watcher) error { + for { + // get changeset + cs, err := s.Next() + if err != nil { + return err + } + + m.Lock() + + // save + m.sets[idx] = cs + + // merge sets + set, err := m.opts.Reader.Merge(m.sets...) + if err != nil { + m.Unlock() + return err + } + + // set values + m.vals, _ = m.opts.Reader.Values(set) + m.snap = &loader.Snapshot{ + ChangeSet: set, + Version: fmt.Sprintf("%d", time.Now().Unix()), + } + m.Unlock() + + // send watch updates + m.update() + } + } + + for { + // watch the source + w, err := s.Watch() + if err != nil { + time.Sleep(time.Second) + continue + } + + done := make(chan bool) + + // the stop watch func + go func() { + select { + case <-done: + case <-m.exit: + } + w.Stop() + }() + + // block watch + if err := watch(idx, w); err != nil { + // do something better + time.Sleep(time.Second) + } + + // close done chan + close(done) + + // if the config is closed exit + select { + case <-m.exit: + return + default: + } + } +} + +func (m *memory) loaded() bool { + var loaded bool + m.RLock() + if m.vals != nil { + loaded = true + } + m.RUnlock() + return loaded +} + +// reload reads the sets and creates new values +func (m *memory) reload() error { + m.Lock() + + // merge sets + set, err := m.opts.Reader.Merge(m.sets...) + if err != nil { + m.Unlock() + return err + } + + // set values + m.vals, _ = m.opts.Reader.Values(set) + m.snap = &loader.Snapshot{ + ChangeSet: set, + Version: fmt.Sprintf("%d", time.Now().Unix()), + } + + m.Unlock() + + // update watchers + m.update() + + return nil +} + +func (m *memory) update() { + var watchers []*watcher + + m.RLock() + for _, w := range m.watchers { + watchers = append(watchers, w) + } + m.RUnlock() + + for _, w := range watchers { + select { + case w.updates <- m.vals.Get(w.path...): + default: + } + } +} + +// Snapshot returns a snapshot of the current loaded config +func (m *memory) Snapshot() (*loader.Snapshot, error) { + if m.loaded() { + m.RLock() + snap := loader.Copy(m.snap) + m.RUnlock() + return snap, nil + } + + // not loaded, sync + if err := m.Sync(); err != nil { + return nil, err + } + + // make copy + m.RLock() + snap := loader.Copy(m.snap) + m.RUnlock() + + return snap, nil +} + +// Sync loads all the sources, calls the parser and updates the config +func (m *memory) Sync() error { + var sets []*source.ChangeSet + + m.Lock() + + // read the source + var gerr []string + + for _, source := range m.sources { + ch, err := source.Read() + if err != nil { + gerr = append(gerr, err.Error()) + continue + } + sets = append(sets, ch) + } + + // merge sets + set, err := m.opts.Reader.Merge(sets...) + if err != nil { + m.Unlock() + return err + } + + // set values + vals, err := m.opts.Reader.Values(set) + if err != nil { + m.Unlock() + return err + } + m.vals = vals + m.snap = &loader.Snapshot{ + ChangeSet: set, + Version: fmt.Sprintf("%d", time.Now().Unix()), + } + + m.Unlock() + + // update watchers + m.update() + + if len(gerr) > 0 { + return fmt.Errorf("source loading errors: %s", strings.Join(gerr, "\n")) + } + + return nil +} + +func (m *memory) Close() error { + select { + case <-m.exit: + return nil + default: + close(m.exit) + } + return nil +} + +func (m *memory) Get(path ...string) (reader.Value, error) { + if !m.loaded() { + if err := m.Sync(); err != nil { + return nil, err + } + } + + m.Lock() + defer m.Unlock() + + // did sync actually work? + if m.vals != nil { + return m.vals.Get(path...), nil + } + + // assuming vals is nil + // create new vals + + ch := m.snap.ChangeSet + + // we are truly screwed, trying to load in a hacked way + v, err := m.opts.Reader.Values(ch) + if err != nil { + return nil, err + } + + // lets set it just because + m.vals = v + + if m.vals != nil { + return m.vals.Get(path...), nil + } + + // ok we're going hardcore now + return nil, errors.New("no values") +} + +func (m *memory) Load(sources ...source.Source) error { + var gerrors []string + + for _, source := range sources { + set, err := source.Read() + if err != nil { + gerrors = append(gerrors, + fmt.Sprintf("error loading source %s: %v", + source, + err)) + // continue processing + continue + } + m.Lock() + m.sources = append(m.sources, source) + m.sets = append(m.sets, set) + idx := len(m.sets) - 1 + m.Unlock() + go m.watch(idx, source) + } + + if err := m.reload(); err != nil { + gerrors = append(gerrors, err.Error()) + } + + // Return errors + if len(gerrors) != 0 { + return errors.New(strings.Join(gerrors, "\n")) + } + return nil +} + +func (m *memory) Watch(path ...string) (loader.Watcher, error) { + value, err := m.Get(path...) + if err != nil { + return nil, err + } + + m.Lock() + + w := &watcher{ + exit: make(chan bool), + path: path, + value: value, + reader: m.opts.Reader, + updates: make(chan reader.Value, 1), + } + + id := m.idx + m.watchers[id] = w + m.idx++ + + m.Unlock() + + go func() { + <-w.exit + m.Lock() + delete(m.watchers, id) + m.Unlock() + }() + + return w, nil +} + +func (m *memory) String() string { + return "memory" +} + +func (w *watcher) Next() (*loader.Snapshot, error) { + for { + select { + case <-w.exit: + return nil, errors.New("watcher stopped") + case v := <-w.updates: + if bytes.Equal(w.value.Bytes(), v.Bytes()) { + continue + } + w.value = v + + cs := &source.ChangeSet{ + Data: v.Bytes(), + Format: w.reader.String(), + Source: "memory", + Timestamp: time.Now(), + } + cs.Sum() + + return &loader.Snapshot{ + ChangeSet: cs, + Version: fmt.Sprintf("%d", time.Now().Unix()), + }, nil + } + } +} + +func (w *watcher) Stop() error { + select { + case <-w.exit: + default: + close(w.exit) + } + return nil +} + +func NewLoader(opts ...loader.Option) loader.Loader { + options := loader.Options{ + Reader: json.NewReader(), + } + + for _, o := range opts { + o(&options) + } + + m := &memory{ + exit: make(chan bool), + opts: options, + watchers: make(map[int]*watcher), + sources: options.Source, + } + + for i, s := range options.Source { + go m.watch(i, s) + } + + return m +} diff --git a/config/loader/memory/options.go b/config/loader/memory/options.go new file mode 100644 index 00000000..5d778d66 --- /dev/null +++ b/config/loader/memory/options.go @@ -0,0 +1,21 @@ +package memory + +import ( + "github.com/micro/go-micro/config/loader" + "github.com/micro/go-micro/config/reader" + "github.com/micro/go-micro/config/source" +) + +// WithSource appends a source to list of sources +func WithSource(s source.Source) loader.Option { + return func(o *loader.Options) { + o.Source = append(o.Source, s) + } +} + +// WithReader sets the config reader +func WithReader(r reader.Reader) loader.Option { + return func(o *loader.Options) { + o.Reader = r + } +} diff --git a/config/options.go b/config/options.go new file mode 100644 index 00000000..a21cf945 --- /dev/null +++ b/config/options.go @@ -0,0 +1,28 @@ +package config + +import ( + "github.com/micro/go-micro/config/loader" + "github.com/micro/go-micro/config/reader" + "github.com/micro/go-micro/config/source" +) + +// WithLoader sets the loader for manager config +func WithLoader(l loader.Loader) Option { + return func(o *Options) { + o.Loader = l + } +} + +// WithSource appends a source to list of sources +func WithSource(s source.Source) Option { + return func(o *Options) { + o.Source = append(o.Source, s) + } +} + +// WithReader sets the config reader +func WithReader(r reader.Reader) Option { + return func(o *Options) { + o.Reader = r + } +} diff --git a/config/reader/json/json.go b/config/reader/json/json.go new file mode 100644 index 00000000..7f3058f8 --- /dev/null +++ b/config/reader/json/json.go @@ -0,0 +1,83 @@ +package json + +import ( + "errors" + "time" + + "github.com/imdario/mergo" + "github.com/micro/go-micro/config/encoder" + "github.com/micro/go-micro/config/encoder/json" + "github.com/micro/go-micro/config/reader" + "github.com/micro/go-micro/config/source" +) + +type jsonReader struct { + opts reader.Options + json encoder.Encoder +} + +func (j *jsonReader) Merge(changes ...*source.ChangeSet) (*source.ChangeSet, error) { + var merged map[string]interface{} + + for _, m := range changes { + if m == nil { + continue + } + + if len(m.Data) == 0 { + continue + } + + codec, ok := j.opts.Encoding[m.Format] + if !ok { + // fallback + codec = j.json + } + + var data map[string]interface{} + if err := codec.Decode(m.Data, &data); err != nil { + return nil, err + } + if err := mergo.Map(&merged, data, mergo.WithOverride); err != nil { + return nil, err + } + } + + b, err := j.json.Encode(merged) + if err != nil { + return nil, err + } + + cs := &source.ChangeSet{ + Timestamp: time.Now(), + Data: b, + Source: "json", + Format: j.json.String(), + } + cs.Checksum = cs.Sum() + + return cs, nil +} + +func (j *jsonReader) Values(ch *source.ChangeSet) (reader.Values, error) { + if ch == nil { + return nil, errors.New("changeset is nil") + } + if ch.Format != "json" { + return nil, errors.New("unsupported format") + } + return newValues(ch) +} + +func (j *jsonReader) String() string { + return "json" +} + +// NewReader creates a json reader +func NewReader(opts ...reader.Option) reader.Reader { + options := reader.NewOptions(opts...) + return &jsonReader{ + json: json.NewEncoder(), + opts: options, + } +} diff --git a/config/reader/json/json_test.go b/config/reader/json/json_test.go new file mode 100644 index 00000000..965e346d --- /dev/null +++ b/config/reader/json/json_test.go @@ -0,0 +1,43 @@ +package json + +import ( + "testing" + + "github.com/micro/go-micro/config/source" +) + +func TestReader(t *testing.T) { + data := []byte(`{"foo": "bar", "baz": {"bar": "cat"}}`) + + testData := []struct { + path []string + value string + }{ + { + []string{"foo"}, + "bar", + }, + { + []string{"baz", "bar"}, + "cat", + }, + } + + r := NewReader() + + c, err := r.Merge(&source.ChangeSet{Data: data}, &source.ChangeSet{}) + if err != nil { + t.Fatal(err) + } + + values, err := r.Values(c) + if err != nil { + t.Fatal(err) + } + + for _, test := range testData { + if v := values.Get(test.path...).String(""); v != test.value { + t.Fatalf("Expected %s got %s for path %v", test.value, v, test.path) + } + } +} diff --git a/config/reader/json/values.go b/config/reader/json/values.go new file mode 100644 index 00000000..e955e455 --- /dev/null +++ b/config/reader/json/values.go @@ -0,0 +1,208 @@ +package json + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + simple "github.com/bitly/go-simplejson" + "github.com/micro/go-micro/config/reader" + "github.com/micro/go-micro/config/source" +) + +type jsonValues struct { + ch *source.ChangeSet + sj *simple.Json +} + +type jsonValue struct { + *simple.Json +} + +func newValues(ch *source.ChangeSet) (reader.Values, error) { + sj := simple.New() + data, _ := reader.ReplaceEnvVars(ch.Data) + if err := sj.UnmarshalJSON(data); err != nil { + sj.SetPath(nil, string(ch.Data)) + } + return &jsonValues{ch, sj}, nil +} + +func newValue(s *simple.Json) reader.Value { + if s == nil { + s = simple.New() + } + return &jsonValue{s} +} + +func (j *jsonValues) Get(path ...string) reader.Value { + return &jsonValue{j.sj.GetPath(path...)} +} + +func (j *jsonValues) Del(path ...string) { + // delete the tree? + if len(path) == 0 { + j.sj = simple.New() + return + } + + if len(path) == 1 { + j.sj.Del(path[0]) + return + } + + vals := j.sj.GetPath(path[:len(path)-1]...) + vals.Del(path[len(path)-1]) + j.sj.SetPath(path[:len(path)-1], vals.Interface()) + return +} + +func (j *jsonValues) Set(val interface{}, path ...string) { + j.sj.SetPath(path, val) +} + +func (j *jsonValues) Bytes() []byte { + b, _ := j.sj.MarshalJSON() + return b +} + +func (j *jsonValues) Map() map[string]interface{} { + m, _ := j.sj.Map() + return m +} + +func (j *jsonValues) Scan(v interface{}) error { + b, err := j.sj.MarshalJSON() + if err != nil { + return err + } + return json.Unmarshal(b, v) +} + +func (j *jsonValues) String() string { + return "json" +} + +func (j *jsonValue) Bool(def bool) bool { + b, err := j.Json.Bool() + if err == nil { + return b + } + + str, ok := j.Interface().(string) + if !ok { + return def + } + + b, err = strconv.ParseBool(str) + if err != nil { + return def + } + + return b +} + +func (j *jsonValue) Int(def int) int { + i, err := j.Json.Int() + if err == nil { + return i + } + + str, ok := j.Interface().(string) + if !ok { + return def + } + + i, err = strconv.Atoi(str) + if err != nil { + return def + } + + return i +} + +func (j *jsonValue) String(def string) string { + return j.Json.MustString(def) +} + +func (j *jsonValue) Float64(def float64) float64 { + f, err := j.Json.Float64() + if err == nil { + return f + } + + str, ok := j.Interface().(string) + if !ok { + return def + } + + f, err = strconv.ParseFloat(str, 64) + if err != nil { + return def + } + + return f +} + +func (j *jsonValue) Duration(def time.Duration) time.Duration { + v, err := j.Json.String() + if err != nil { + return def + } + + value, err := time.ParseDuration(v) + if err != nil { + return def + } + + return value +} + +func (j *jsonValue) StringSlice(def []string) []string { + v, err := j.Json.String() + if err == nil { + sl := strings.Split(v, ",") + if len(sl) > 1 { + return sl + } + } + return j.Json.MustStringArray(def) +} + +func (j *jsonValue) StringMap(def map[string]string) map[string]string { + m, err := j.Json.Map() + if err != nil { + return def + } + + res := map[string]string{} + + for k, v := range m { + res[k] = fmt.Sprintf("%v", v) + } + + return res +} + +func (j *jsonValue) Scan(v interface{}) error { + b, err := j.Json.MarshalJSON() + if err != nil { + return err + } + return json.Unmarshal(b, v) +} + +func (j *jsonValue) Bytes() []byte { + b, err := j.Json.Bytes() + if err != nil { + // try return marshalled + b, err = j.Json.MarshalJSON() + if err != nil { + return []byte{} + } + return b + } + return b +} diff --git a/config/reader/json/values_test.go b/config/reader/json/values_test.go new file mode 100644 index 00000000..516199a6 --- /dev/null +++ b/config/reader/json/values_test.go @@ -0,0 +1,39 @@ +package json + +import ( + "testing" + + "github.com/micro/go-micro/config/source" +) + +func TestValues(t *testing.T) { + data := []byte(`{"foo": "bar", "baz": {"bar": "cat"}}`) + + testData := []struct { + path []string + value string + }{ + { + []string{"foo"}, + "bar", + }, + { + []string{"baz", "bar"}, + "cat", + }, + } + + values, err := newValues(&source.ChangeSet{ + Data: data, + }) + + if err != nil { + t.Fatal(err) + } + + for _, test := range testData { + if v := values.Get(test.path...).String(""); v != test.value { + t.Fatalf("Expected %s got %s for path %v", test.value, v, test.path) + } + } +} diff --git a/config/reader/options.go b/config/reader/options.go new file mode 100644 index 00000000..71b525b9 --- /dev/null +++ b/config/reader/options.go @@ -0,0 +1,42 @@ +package reader + +import ( + "github.com/micro/go-micro/config/encoder" + "github.com/micro/go-micro/config/encoder/hcl" + "github.com/micro/go-micro/config/encoder/json" + "github.com/micro/go-micro/config/encoder/toml" + "github.com/micro/go-micro/config/encoder/xml" + "github.com/micro/go-micro/config/encoder/yaml" +) + +type Options struct { + Encoding map[string]encoder.Encoder +} + +type Option func(o *Options) + +func NewOptions(opts ...Option) Options { + options := Options{ + Encoding: map[string]encoder.Encoder{ + "json": json.NewEncoder(), + "yaml": yaml.NewEncoder(), + "toml": toml.NewEncoder(), + "xml": xml.NewEncoder(), + "hcl": hcl.NewEncoder(), + "yml": yaml.NewEncoder(), + }, + } + for _, o := range opts { + o(&options) + } + return options +} + +func WithEncoder(e encoder.Encoder) Option { + return func(o *Options) { + if o.Encoding == nil { + o.Encoding = make(map[string]encoder.Encoder) + } + o.Encoding[e.String()] = e + } +} diff --git a/config/reader/preprocessor.go b/config/reader/preprocessor.go new file mode 100644 index 00000000..2895be4f --- /dev/null +++ b/config/reader/preprocessor.go @@ -0,0 +1,23 @@ +package reader + +import ( + "os" + "regexp" +) + +func ReplaceEnvVars(raw []byte) ([]byte, error) { + re := regexp.MustCompile(`\$\{([A-Za-z0-9_]+)\}`) + if re.Match(raw) { + dataS := string(raw) + res := re.ReplaceAllStringFunc(dataS, replaceEnvVars) + return []byte(res), nil + } else { + return raw, nil + } +} + +func replaceEnvVars(element string) string { + v := element[2 : len(element)-1] + el := os.Getenv(v) + return el +} diff --git a/config/reader/preprocessor_test.go b/config/reader/preprocessor_test.go new file mode 100644 index 00000000..ba5485fe --- /dev/null +++ b/config/reader/preprocessor_test.go @@ -0,0 +1,73 @@ +package reader + +import ( + "os" + "strings" + "testing" +) + +func TestReplaceEnvVars(t *testing.T) { + os.Setenv("myBar", "cat") + os.Setenv("MYBAR", "cat") + os.Setenv("my_Bar", "cat") + os.Setenv("myBar_", "cat") + + testData := []struct { + expected string + data []byte + }{ + // Right use cases + { + `{"foo": "bar", "baz": {"bar": "cat"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "${myBar}"}}`), + }, + { + `{"foo": "bar", "baz": {"bar": "cat"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "${MYBAR}"}}`), + }, + { + `{"foo": "bar", "baz": {"bar": "cat"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "${my_Bar}"}}`), + }, + { + `{"foo": "bar", "baz": {"bar": "cat"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "${myBar_}"}}`), + }, + // Wrong use cases + { + `{"foo": "bar", "baz": {"bar": "${myBar-}"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "${myBar-}"}}`), + }, + { + `{"foo": "bar", "baz": {"bar": "${}"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "${}"}}`), + }, + { + `{"foo": "bar", "baz": {"bar": "$sss}"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "$sss}"}}`), + }, + { + `{"foo": "bar", "baz": {"bar": "${sss"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "${sss"}}`), + }, + { + `{"foo": "bar", "baz": {"bar": "{something}"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "{something}"}}`), + }, + // Use cases without replace env vars + { + `{"foo": "bar", "baz": {"bar": "cat"}}`, + []byte(`{"foo": "bar", "baz": {"bar": "cat"}}`), + }, + } + + for _, test := range testData { + res, err := ReplaceEnvVars(test.data) + if err != nil { + t.Fatal(err) + } + if strings.Compare(test.expected, string(res)) != 0 { + t.Fatalf("Expected %s got %s", test.expected, res) + } + } +} diff --git a/config/reader/reader.go b/config/reader/reader.go new file mode 100644 index 00000000..eee333e3 --- /dev/null +++ b/config/reader/reader.go @@ -0,0 +1,36 @@ +// Package reader parses change sets and provides config values +package reader + +import ( + "time" + + "github.com/micro/go-micro/config/source" +) + +// Reader is an interface for merging changesets +type Reader interface { + Merge(...*source.ChangeSet) (*source.ChangeSet, error) + Values(*source.ChangeSet) (Values, error) + String() string +} + +// Values is returned by the reader +type Values interface { + Bytes() []byte + Get(path ...string) Value + Map() map[string]interface{} + Scan(v interface{}) error +} + +// Value represents a value of any type +type Value interface { + Bool(def bool) bool + Int(def int) int + String(def string) string + Float64(def float64) float64 + Duration(def time.Duration) time.Duration + StringSlice(def []string) []string + StringMap(def map[string]string) map[string]string + Scan(val interface{}) error + Bytes() []byte +} diff --git a/config/source/changeset.go b/config/source/changeset.go new file mode 100644 index 00000000..9958f61d --- /dev/null +++ b/config/source/changeset.go @@ -0,0 +1,13 @@ +package source + +import ( + "crypto/md5" + "fmt" +) + +// Sum returns the md5 checksum of the ChangeSet data +func (c *ChangeSet) Sum() string { + h := md5.New() + h.Write(c.Data) + return fmt.Sprintf("%x", h.Sum(nil)) +} diff --git a/config/source/cli/README.md b/config/source/cli/README.md new file mode 100644 index 00000000..0b482d58 --- /dev/null +++ b/config/source/cli/README.md @@ -0,0 +1,71 @@ +# cli Source + +The cli source reads config from parsed flags via a cli.Context. + +## Format + +We expect the use of the `micro/cli` package. Upper case flags will be lower cased. Dashes will be used as delimiters for nesting. + +### Example + +```go +micro.Flags( + cli.StringFlag{ + Name: "database-address", + Value: "127.0.0.1", + Usage: "the db address", + }, + cli.IntFlag{ + Name: "database-port", + Value: 3306, + Usage: "the db port", + }, +) +``` + +Becomes + +```json +{ + "database": { + "address": "127.0.0.1", + "port": 3306 + } +} +``` + +## New and Load Source + +Because a cli.Context is needed to retrieve the flags and their values, it is recommended to build your source from within a cli.Action. + +```go + +func main() { + // New Service + service := micro.NewService( + micro.Name("example"), + micro.Flags( + cli.StringFlag{ + Name: "database-address", + Value: "127.0.0.1", + Usage: "the db address", + }, + ), + ) + + var clisrc source.Source + + service.Init( + micro.Action(func(c *cli.Context) { + clisrc = cli.NewSource( + cli.Context(c), + ) + // Alternatively, just setup your config right here + }), + ) + + // ... Load and use that source ... + conf := config.NewConfig() + conf.Load(clisrc) +} +``` diff --git a/config/source/cli/cli.go b/config/source/cli/cli.go new file mode 100644 index 00000000..86b27f10 --- /dev/null +++ b/config/source/cli/cli.go @@ -0,0 +1,146 @@ +package cli + +import ( + "flag" + "io/ioutil" + "os" + "strings" + "time" + + "github.com/imdario/mergo" + "github.com/micro/cli" + "github.com/micro/go-micro/cmd" + "github.com/micro/go-micro/config/source" +) + +type cliSource struct { + opts source.Options + ctx *cli.Context +} + +func (c *cliSource) Read() (*source.ChangeSet, error) { + var changes map[string]interface{} + + for _, name := range c.ctx.GlobalFlagNames() { + tmp := toEntry(name, c.ctx.GlobalGeneric(name)) + mergo.Map(&changes, tmp) // need to sort error handling + } + + for _, name := range c.ctx.FlagNames() { + tmp := toEntry(name, c.ctx.Generic(name)) + mergo.Map(&changes, tmp) // need to sort error handling + } + + b, err := c.opts.Encoder.Encode(changes) + if err != nil { + return nil, err + } + + cs := &source.ChangeSet{ + Format: c.opts.Encoder.String(), + Data: b, + Timestamp: time.Now(), + Source: c.String(), + } + cs.Checksum = cs.Sum() + + return cs, nil +} + +func toEntry(name string, v interface{}) map[string]interface{} { + n := strings.ToLower(name) + keys := strings.FieldsFunc(n, split) + reverse(keys) + tmp := make(map[string]interface{}) + for i, k := range keys { + if i == 0 { + tmp[k] = v + continue + } + + tmp = map[string]interface{}{k: tmp} + } + return tmp +} + +func reverse(ss []string) { + for i := len(ss)/2 - 1; i >= 0; i-- { + opp := len(ss) - 1 - i + ss[i], ss[opp] = ss[opp], ss[i] + } +} + +func split(r rune) bool { + return r == '-' || r == '_' +} + +func (c *cliSource) Watch() (source.Watcher, error) { + return source.NewNoopWatcher() +} + +func (c *cliSource) String() string { + return "cli" +} + +// NewSource returns a config source for integrating parsed flags from a micro/cli.Context. +// Hyphens are delimiters for nesting, and all keys are lowercased. The assumption is that +// command line flags have already been parsed. +// +// Example: +// cli.StringFlag{Name: "db-host"}, +// +// +// { +// "database": { +// "host": "localhost" +// } +// } +func NewSource(opts ...source.Option) source.Source { + options := source.NewOptions(opts...) + + var ctx *cli.Context + + c, ok := options.Context.Value(contextKey{}).(*cli.Context) + if ok { + ctx = c + } + + // no context + if ctx == nil { + // get the default app/flags + app := cmd.App() + flags := app.Flags + + // create flagset + set := flag.NewFlagSet(app.Name, flag.ContinueOnError) + + // apply flags to set + for _, f := range flags { + f.Apply(set) + } + + // parse flags + set.SetOutput(ioutil.Discard) + set.Parse(os.Args[1:]) + + // normalise flags + normalizeFlags(app.Flags, set) + + // create context + ctx = cli.NewContext(app, set, nil) + } + + return &cliSource{ + ctx: ctx, + opts: options, + } +} + +// WithContext returns a new source with the context specified. +// The assumption is that Context is retrieved within an app.Action function. +func WithContext(ctx *cli.Context, opts ...source.Option) source.Source { + return &cliSource{ + ctx: ctx, + opts: source.NewOptions(opts...), + } +} diff --git a/config/source/cli/cli_test.go b/config/source/cli/cli_test.go new file mode 100644 index 00000000..ada1a0d6 --- /dev/null +++ b/config/source/cli/cli_test.go @@ -0,0 +1,65 @@ +package cli + +import ( + "encoding/json" + "os" + "testing" + + "github.com/micro/cli" + "github.com/micro/go-micro/cmd" + "github.com/micro/go-micro/config/source" +) + +func test(t *testing.T, withContext bool) { + var src source.Source + + // setup app + app := cmd.App() + app.Name = "testapp" + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "db-host"}, + } + + // with context + if withContext { + // set action + app.Action = func(c *cli.Context) { + src = WithContext(c) + } + + // run app + app.Run([]string{"run", "-db-host", "localhost"}) + // no context + } else { + // set args + os.Args = []string{"run", "-db-host", "localhost"} + src = NewSource() + } + + // test config + c, err := src.Read() + if err != nil { + t.Error(err) + } + + var actual map[string]interface{} + if err := json.Unmarshal(c.Data, &actual); err != nil { + t.Error(err) + } + + actualDB := actual["db"].(map[string]interface{}) + if actualDB["host"] != "localhost" { + t.Errorf("expected localhost, got %v", actualDB["name"]) + } + +} + +func TestCliSource(t *testing.T) { + // without context + test(t, false) +} + +func TestCliSourceWithContext(t *testing.T) { + // with context + test(t, true) +} diff --git a/config/source/cli/options.go b/config/source/cli/options.go new file mode 100644 index 00000000..0ee463c7 --- /dev/null +++ b/config/source/cli/options.go @@ -0,0 +1,20 @@ +package cli + +import ( + "context" + + "github.com/micro/cli" + "github.com/micro/go-micro/config/source" +) + +type contextKey struct{} + +// Context sets the cli context +func Context(c *cli.Context) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, contextKey{}, c) + } +} diff --git a/config/source/cli/util.go b/config/source/cli/util.go new file mode 100644 index 00000000..c6274068 --- /dev/null +++ b/config/source/cli/util.go @@ -0,0 +1,50 @@ +package cli + +import ( + "errors" + "flag" + "strings" + + "github.com/micro/cli" +) + +func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { + switch ff.Value.(type) { + case *cli.StringSlice: + default: + set.Set(name, ff.Value.String()) + } +} + +func normalizeFlags(flags []cli.Flag, set *flag.FlagSet) error { + visited := make(map[string]bool) + set.Visit(func(f *flag.Flag) { + visited[f.Name] = true + }) + for _, f := range flags { + parts := strings.Split(f.GetName(), ",") + if len(parts) == 1 { + continue + } + var ff *flag.Flag + for _, name := range parts { + name = strings.Trim(name, " ") + if visited[name] { + if ff != nil { + return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) + } + ff = set.Lookup(name) + } + } + if ff == nil { + continue + } + for _, name := range parts { + name = strings.Trim(name, " ") + if !visited[name] { + copyFlag(name, ff, set) + } + } + } + return nil +} diff --git a/config/source/consul/README.md b/config/source/consul/README.md new file mode 100644 index 00000000..2ba45e5b --- /dev/null +++ b/config/source/consul/README.md @@ -0,0 +1,49 @@ +# Consul Source + +The consul source reads config from consul key/values + +## Consul Format + +The consul source expects keys under the default prefix `/micro/config` + +Values are expected to be json + +``` +// set database +consul kv put micro/config/database '{"address": "10.0.0.1", "port": 3306}' +// set cache +consul kv 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 +consulSource := consul.NewSource( + // optionally specify consul address; default to localhost:8500 + consul.WithAddress("10.0.0.10:8500"), + // optionally specify prefix; defaults to /micro/config + consul.WithPrefix("/my/prefix"), + // optionally strip the provided prefix from the keys, defaults to false + consul.StripPrefix(true), +) +``` + +## Load Source + +Load the source into config + +```go +// Create new config +conf := config.NewConfig() + +// Load file source +conf.Load(consulSource) +``` diff --git a/config/source/consul/consul.go b/config/source/consul/consul.go new file mode 100644 index 00000000..16e85332 --- /dev/null +++ b/config/source/consul/consul.go @@ -0,0 +1,121 @@ +package consul + +import ( + "fmt" + "net" + "time" + + "github.com/hashicorp/consul/api" + "github.com/micro/go-micro/config/source" +) + +// Currently a single consul reader +type consul struct { + prefix string + stripPrefix string + addr string + opts source.Options + client *api.Client +} + +var ( + // DefaultPrefix is the prefix that consul keys will be assumed to have if you + // haven't specified one + DefaultPrefix = "/micro/config/" +) + +func (c *consul) Read() (*source.ChangeSet, error) { + kv, _, err := c.client.KV().List(c.prefix, nil) + if err != nil { + return nil, err + } + + if kv == nil || len(kv) == 0 { + return nil, fmt.Errorf("source not found: %s", c.prefix) + } + + data, err := makeMap(c.opts.Encoder, kv, c.stripPrefix) + if err != nil { + return nil, fmt.Errorf("error reading data: %v", err) + } + + 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(), + Format: c.opts.Encoder.String(), + Source: c.String(), + Data: b, + } + cs.Checksum = cs.Sum() + + return cs, nil +} + +func (c *consul) String() string { + return "consul" +} + +func (c *consul) Watch() (source.Watcher, error) { + w, err := newWatcher(c.prefix, c.addr, c.String(), c.stripPrefix, c.opts.Encoder) + if err != nil { + return nil, err + } + return w, nil +} + +// NewSource creates a new consul source +func NewSource(opts ...source.Option) source.Source { + options := source.NewOptions(opts...) + + // use default config + config := api.DefaultConfig() + + // check if there are any addrs + a, ok := options.Context.Value(addressKey{}).(string) + if ok { + addr, port, err := net.SplitHostPort(a) + if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { + port = "8500" + addr = a + config.Address = fmt.Sprintf("%s:%s", addr, port) + } else if err == nil { + config.Address = fmt.Sprintf("%s:%s", addr, port) + } + } + + dc, ok := options.Context.Value(dcKey{}).(string) + if ok { + config.Datacenter = dc + } + + token, ok := options.Context.Value(tokenKey{}).(string) + if ok { + config.Token = token + } + + // create the client + client, _ := api.NewClient(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 &consul{ + prefix: prefix, + stripPrefix: sp, + addr: config.Address, + opts: options, + client: client, + } +} diff --git a/config/source/consul/options.go b/config/source/consul/options.go new file mode 100644 index 00000000..9420a803 --- /dev/null +++ b/config/source/consul/options.go @@ -0,0 +1,63 @@ +package consul + +import ( + "context" + + "github.com/micro/go-micro/config/source" +) + +type addressKey struct{} +type prefixKey struct{} +type stripPrefixKey struct{} +type dcKey struct{} +type tokenKey struct{} + +// 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) + } +} + +func WithDatacenter(p string) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, dcKey{}, p) + } +} + +// WithToken sets the key token to use +func WithToken(p string) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, tokenKey{}, p) + } +} diff --git a/config/source/consul/util.go b/config/source/consul/util.go new file mode 100644 index 00000000..db6f708d --- /dev/null +++ b/config/source/consul/util.go @@ -0,0 +1,49 @@ +package consul + +import ( + "fmt" + "strings" + + "github.com/hashicorp/consul/api" + "github.com/micro/go-micro/config/encoder" +) + +func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string]interface{}, error) { + data := make(map[string]interface{}) + + // consul guarantees lexicographic order, so no need to sort + for _, v := range kv { + pathString := strings.TrimPrefix(strings.TrimPrefix(v.Key, stripPrefix), "/") + var val map[string]interface{} + + // ensure a valid value is stored at this location + if len(v.Value) > 0 { + if err := e.Decode(v.Value, &val); err != nil { + return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) + } + } + + // set target at the root + target := data + + // then descend to the target location, creating as we go, if need be + if pathString != "" { + path := strings.Split(pathString, "/") + // find (or create) the location we want to put this value at + for _, dir := range path { + if _, ok := target[dir]; !ok { + target[dir] = make(map[string]interface{}) + } + target = target[dir].(map[string]interface{}) + } + + } + + // copy over the keys from the value + for k := range val { + target[k] = val[k] + } + } + + return data, nil +} diff --git a/config/source/consul/watcher.go b/config/source/consul/watcher.go new file mode 100644 index 00000000..e6993d8b --- /dev/null +++ b/config/source/consul/watcher.go @@ -0,0 +1,96 @@ +package consul + +import ( + "errors" + "time" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/api/watch" + "github.com/micro/go-micro/config/encoder" + "github.com/micro/go-micro/config/source" +) + +type watcher struct { + e encoder.Encoder + name string + stripPrefix string + + wp *watch.Plan + ch chan *source.ChangeSet + exit chan bool +} + +func newWatcher(key, addr, name, stripPrefix string, e encoder.Encoder) (source.Watcher, error) { + w := &watcher{ + e: e, + name: name, + stripPrefix: stripPrefix, + ch: make(chan *source.ChangeSet), + exit: make(chan bool), + } + + wp, err := watch.Parse(map[string]interface{}{"type": "keyprefix", "prefix": key}) + if err != nil { + return nil, err + } + + wp.Handler = w.handle + + // wp.Run is a blocking call and will prevent newWatcher from returning + go wp.Run(addr) + + w.wp = wp + + return w, nil +} + +func (w *watcher) handle(idx uint64, data interface{}) { + if data == nil { + return + } + + kvs, ok := data.(api.KVPairs) + if !ok { + return + } + + d, err := makeMap(w.e, kvs, w.stripPrefix) + if err != nil { + return + } + + b, err := w.e.Encode(d) + if err != nil { + return + } + + cs := &source.ChangeSet{ + Timestamp: time.Now(), + Format: w.e.String(), + Source: w.name, + Data: b, + } + cs.Checksum = cs.Sum() + + w.ch <- cs +} + +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: + w.wp.Stop() + close(w.exit) + } + return nil +} diff --git a/config/source/env/README.md b/config/source/env/README.md new file mode 100644 index 00000000..25bfa07a --- /dev/null +++ b/config/source/env/README.md @@ -0,0 +1,96 @@ +# Env Source + +The env source reads config from environment variables + +## Format + +We expect environment variables to be in the standard format of FOO=bar + +Keys are converted to lowercase and split on underscore. + + +### Example + +``` +DATABASE_ADDRESS=127.0.0.1 +DATABASE_PORT=3306 +``` + +Becomes + +```json +{ + "database": { + "address": "127.0.0.1", + "port": 3306 + } +} +``` + +## Prefixes + +Environment variables can be namespaced so we only have access to a subset. Two options are available: + +``` +WithPrefix(p ...string) +WithStrippedPrefix(p ...string) +``` + +The former will preserve the prefix and make it a top level key in the config. The latter eliminates the prefix, reducing the nesting by one. + +#### Example: + +Given ENVs of: + +``` +APP_DATABASE_ADDRESS=127.0.0.1 +APP_DATABASE_PORT=3306 +VAULT_ADDR=vault:1337 +``` + +and a source initialized as follows: + +``` +src := env.NewSource( + env.WithPrefix("VAULT"), + env.WithStrippedPrefix("APP"), +) +``` + +The resulting config will be: + +``` +{ + "database": { + "address": "127.0.0.1", + "port": 3306 + }, + "vault": { + "addr": "vault:1337" + } +} +``` + + +## New Source + +Specify source with data + +```go +src := env.NewSource( + // optionally specify prefix + env.WithPrefix("MICRO"), +) +``` + +## Load Source + +Load the source into config + +```go +// Create new config +conf := config.NewConfig() + +// Load file source +conf.Load(src) +``` diff --git a/config/source/env/env.go b/config/source/env/env.go new file mode 100644 index 00000000..62dbf8b2 --- /dev/null +++ b/config/source/env/env.go @@ -0,0 +1,142 @@ +package env + +import ( + "os" + "strconv" + "strings" + "time" + + "github.com/imdario/mergo" + "github.com/micro/go-micro/config/source" +) + +var ( + DefaultPrefixes = []string{} +) + +type env struct { + prefixes []string + strippedPrefixes []string + opts source.Options +} + +func (e *env) Read() (*source.ChangeSet, error) { + var changes map[string]interface{} + + for _, env := range os.Environ() { + + if len(e.prefixes) > 0 || len(e.strippedPrefixes) > 0 { + notFound := true + + if _, ok := matchPrefix(e.prefixes, env); ok { + notFound = false + } + + if match, ok := matchPrefix(e.strippedPrefixes, env); ok { + env = strings.TrimPrefix(env, match) + notFound = false + } + + if notFound { + continue + } + } + + pair := strings.SplitN(env, "=", 2) + value := pair[1] + keys := strings.Split(strings.ToLower(pair[0]), "_") + reverse(keys) + + tmp := make(map[string]interface{}) + for i, k := range keys { + if i == 0 { + if intValue, err := strconv.Atoi(value); err == nil { + tmp[k] = intValue + } else if boolValue, err := strconv.ParseBool(value); err == nil { + tmp[k] = boolValue + } else { + tmp[k] = value + } + continue + } + + tmp = map[string]interface{}{k: tmp} + } + + if err := mergo.Map(&changes, tmp); err != nil { + return nil, err + } + } + + b, err := e.opts.Encoder.Encode(changes) + if err != nil { + return nil, err + } + + cs := &source.ChangeSet{ + Format: e.opts.Encoder.String(), + Data: b, + Timestamp: time.Now(), + Source: e.String(), + } + cs.Checksum = cs.Sum() + + return cs, nil +} + +func matchPrefix(pre []string, s string) (string, bool) { + for _, p := range pre { + if strings.HasPrefix(s, p) { + return p, true + } + } + + return "", false +} + +func reverse(ss []string) { + for i := len(ss)/2 - 1; i >= 0; i-- { + opp := len(ss) - 1 - i + ss[i], ss[opp] = ss[opp], ss[i] + } +} + +func (e *env) Watch() (source.Watcher, error) { + return newWatcher() +} + +func (e *env) String() string { + return "env" +} + +// NewSource returns a config source for parsing ENV variables. +// Underscores are delimiters for nesting, and all keys are lowercased. +// +// Example: +// "DATABASE_SERVER_HOST=localhost" will convert to +// +// { +// "database": { +// "server": { +// "host": "localhost" +// } +// } +// } +func NewSource(opts ...source.Option) source.Source { + options := source.NewOptions(opts...) + + var sp []string + var pre []string + if p, ok := options.Context.Value(strippedPrefixKey{}).([]string); ok { + sp = p + } + + if p, ok := options.Context.Value(prefixKey{}).([]string); ok { + pre = p + } + + if len(sp) > 0 || len(pre) > 0 { + pre = append(pre, DefaultPrefixes...) + } + return &env{prefixes: pre, strippedPrefixes: sp, opts: options} +} diff --git a/config/source/env/env_test.go b/config/source/env/env_test.go new file mode 100644 index 00000000..891d8d8b --- /dev/null +++ b/config/source/env/env_test.go @@ -0,0 +1,112 @@ +package env + +import ( + "encoding/json" + "os" + "testing" + "time" + + "github.com/micro/go-micro/config/source" +) + +func TestEnv_Read(t *testing.T) { + expected := map[string]map[string]string{ + "database": { + "host": "localhost", + "password": "password", + "datasource": "user:password@tcp(localhost:port)/db?charset=utf8mb4&parseTime=True&loc=Local", + }, + } + + os.Setenv("DATABASE_HOST", "localhost") + os.Setenv("DATABASE_PASSWORD", "password") + os.Setenv("DATABASE_DATASOURCE", "user:password@tcp(localhost:port)/db?charset=utf8mb4&parseTime=True&loc=Local") + + source := NewSource() + c, err := source.Read() + if err != nil { + t.Error(err) + } + + var actual map[string]interface{} + if err := json.Unmarshal(c.Data, &actual); err != nil { + t.Error(err) + } + + actualDB := actual["database"].(map[string]interface{}) + + for k, v := range expected["database"] { + a := actualDB[k] + + if a != v { + t.Errorf("expected %v got %v", v, a) + } + } +} + +func TestEnvvar_Prefixes(t *testing.T) { + os.Setenv("APP_DATABASE_HOST", "localhost") + os.Setenv("APP_DATABASE_PASSWORD", "password") + os.Setenv("VAULT_ADDR", "vault:1337") + os.Setenv("MICRO_REGISTRY", "mdns") + + var prefixtests = []struct { + prefixOpts []source.Option + expectedKeys []string + }{ + {[]source.Option{WithPrefix("APP", "MICRO")}, []string{"app", "micro"}}, + {[]source.Option{WithPrefix("MICRO"), WithStrippedPrefix("APP")}, []string{"database", "micro"}}, + {[]source.Option{WithPrefix("MICRO"), WithStrippedPrefix("APP")}, []string{"database", "micro"}}, + } + + for _, pt := range prefixtests { + source := NewSource(pt.prefixOpts...) + + c, err := source.Read() + if err != nil { + t.Error(err) + } + + var actual map[string]interface{} + if err := json.Unmarshal(c.Data, &actual); err != nil { + t.Error(err) + } + + // assert other prefixes ignored + if l := len(actual); l != len(pt.expectedKeys) { + t.Errorf("expected %v top keys, got %v", len(pt.expectedKeys), l) + } + + for _, k := range pt.expectedKeys { + if !containsKey(actual, k) { + t.Errorf("expected key %v, not found", k) + } + } + } +} + +func TestEnvvar_WatchNextNoOpsUntilStop(t *testing.T) { + source := NewSource(WithStrippedPrefix("GOMICRO_")) + w, err := source.Watch() + if err != nil { + t.Error(err) + } + + go func() { + time.Sleep(50 * time.Millisecond) + w.Stop() + }() + + if _, err := w.Next(); err.Error() != "watcher stopped" { + t.Errorf("expected watcher stopped error, got %v", err) + } +} + +func containsKey(m map[string]interface{}, s string) bool { + for k := range m { + if k == s { + return true + } + } + return false +} diff --git a/config/source/env/options.go b/config/source/env/options.go new file mode 100644 index 00000000..112a7db2 --- /dev/null +++ b/config/source/env/options.go @@ -0,0 +1,49 @@ +package env + +import ( + "context" + + "strings" + + "github.com/micro/go-micro/config/source" +) + +type strippedPrefixKey struct{} +type prefixKey struct{} + +// WithStrippedPrefix sets the environment variable prefixes to scope to. +// These prefixes will be removed from the actual config entries. +func WithStrippedPrefix(p ...string) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + + o.Context = context.WithValue(o.Context, strippedPrefixKey{}, appendUnderscore(p)) + } +} + +// WithPrefix sets the environment variable prefixes to scope to. +// These prefixes will not be removed. Each prefix will be considered a top level config entry. +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{}, appendUnderscore(p)) + } +} + +func appendUnderscore(prefixes []string) []string { + var result []string + for _, p := range prefixes { + if !strings.HasSuffix(p, "_") { + result = append(result, p+"_") + continue + } + + result = append(result, p) + } + + return result +} diff --git a/config/source/env/watcher.go b/config/source/env/watcher.go new file mode 100644 index 00000000..5dd3ef34 --- /dev/null +++ b/config/source/env/watcher.go @@ -0,0 +1,26 @@ +package env + +import ( + "errors" + + "github.com/micro/go-micro/config/source" +) + +type watcher struct { + exit chan struct{} +} + +func (w *watcher) Next() (*source.ChangeSet, error) { + <-w.exit + + return nil, errors.New("watcher stopped") +} + +func (w *watcher) Stop() error { + close(w.exit) + return nil +} + +func newWatcher() (source.Watcher, error) { + return &watcher{exit: make(chan struct{})}, nil +} diff --git a/config/source/file/README.md b/config/source/file/README.md new file mode 100644 index 00000000..89c0930c --- /dev/null +++ b/config/source/file/README.md @@ -0,0 +1,70 @@ +# File Source + +The file source reads config from a file. + +It uses the File extension to determine the Format e.g `config.yaml` has the yaml format. +It does not make use of encoders or interpet the file data. If a file extension is not present +the source Format will default to the Encoder in options. + +## Example + +A config file format in json + +```json +{ + "hosts": { + "database": { + "address": "10.0.0.1", + "port": 3306 + }, + "cache": { + "address": "10.0.0.2", + "port": 6379 + } + } +} +``` + +## New Source + +Specify file source with path to file. Path is optional and will default to `config.json` + +```go +fileSource := file.NewSource( + file.WithPath("/tmp/config.json"), +) +``` + +## File Format + +To load different file formats e.g yaml, toml, xml simply specify them with their extension + +``` +fileSource := file.NewSource( + file.WithPath("/tmp/config.yaml"), +) +``` + +If you want to specify a file without extension, ensure you set the encoder to the same format + +``` +e := toml.NewEncoder() + +fileSource := file.NewSource( + file.WithPath("/tmp/config"), + source.WithEncoder(e), +) +``` + +## Load Source + +Load the source into config + +```go +// Create new config +conf := config.NewConfig() + +// Load file source +conf.Load(fileSource) +``` + diff --git a/config/source/file/file.go b/config/source/file/file.go new file mode 100644 index 00000000..8a4b720d --- /dev/null +++ b/config/source/file/file.go @@ -0,0 +1,65 @@ +// Package file is a file source. Expected format is json +package file + +import ( + "io/ioutil" + "os" + + "github.com/micro/go-micro/config/source" +) + +type file struct { + path string + opts source.Options +} + +var ( + DefaultPath = "config.json" +) + +func (f *file) Read() (*source.ChangeSet, error) { + fh, err := os.Open(f.path) + if err != nil { + return nil, err + } + defer fh.Close() + b, err := ioutil.ReadAll(fh) + if err != nil { + return nil, err + } + info, err := fh.Stat() + if err != nil { + return nil, err + } + + cs := &source.ChangeSet{ + Format: format(f.path, f.opts.Encoder), + Source: f.String(), + Timestamp: info.ModTime(), + Data: b, + } + cs.Checksum = cs.Sum() + + return cs, nil +} + +func (f *file) String() string { + return "file" +} + +func (f *file) Watch() (source.Watcher, error) { + if _, err := os.Stat(f.path); err != nil { + return nil, err + } + return newWatcher(f) +} + +func NewSource(opts ...source.Option) source.Source { + options := source.NewOptions(opts...) + path := DefaultPath + f, ok := options.Context.Value(filePathKey{}).(string) + if ok { + path = f + } + return &file{opts: options, path: path} +} diff --git a/config/source/file/file_test.go b/config/source/file/file_test.go new file mode 100644 index 00000000..f144a387 --- /dev/null +++ b/config/source/file/file_test.go @@ -0,0 +1,37 @@ +package file + +import ( + "fmt" + "os" + "path/filepath" + "testing" + "time" +) + +func TestFile(t *testing.T) { + data := []byte(`{"foo": "bar"}`) + path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) + fh, err := os.Create(path) + if err != nil { + t.Error(err) + } + defer func() { + fh.Close() + os.Remove(path) + }() + + _, err = fh.Write(data) + if err != nil { + t.Error(err) + } + + f := NewSource(WithPath(path)) + c, err := f.Read() + if err != nil { + t.Error(err) + } + t.Logf("%+v", c) + if string(c.Data) != string(data) { + t.Error("data from file does not match") + } +} diff --git a/config/source/file/format.go b/config/source/file/format.go new file mode 100644 index 00000000..63f51bd9 --- /dev/null +++ b/config/source/file/format.go @@ -0,0 +1,15 @@ +package file + +import ( + "strings" + + "github.com/micro/go-micro/config/encoder" +) + +func format(p string, e encoder.Encoder) string { + parts := strings.Split(p, ".") + if len(parts) > 1 { + return parts[len(parts)-1] + } + return e.String() +} diff --git a/config/source/file/format_test.go b/config/source/file/format_test.go new file mode 100644 index 00000000..47f09836 --- /dev/null +++ b/config/source/file/format_test.go @@ -0,0 +1,31 @@ +package file + +import ( + "testing" + + "github.com/micro/go-micro/config/source" +) + +func TestFormat(t *testing.T) { + opts := source.NewOptions() + e := opts.Encoder + + testCases := []struct { + p string + f string + }{ + {"/foo/bar.json", "json"}, + {"/foo/bar.yaml", "yaml"}, + {"/foo/bar.xml", "xml"}, + {"/foo/bar.conf.ini", "ini"}, + {"conf", e.String()}, + } + + for _, d := range testCases { + f := format(d.p, e) + if f != d.f { + t.Fatalf("%s: expected %s got %s", d.p, d.f, f) + } + } + +} diff --git a/config/source/file/options.go b/config/source/file/options.go new file mode 100644 index 00000000..e9b16e90 --- /dev/null +++ b/config/source/file/options.go @@ -0,0 +1,19 @@ +package file + +import ( + "context" + + "github.com/micro/go-micro/config/source" +) + +type filePathKey struct{} + +// WithPath sets the path to file +func WithPath(p string) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, filePathKey{}, p) + } +} diff --git a/config/source/file/watcher.go b/config/source/file/watcher.go new file mode 100644 index 00000000..de28b07b --- /dev/null +++ b/config/source/file/watcher.go @@ -0,0 +1,66 @@ +package file + +import ( + "errors" + "os" + + "github.com/fsnotify/fsnotify" + "github.com/micro/go-micro/config/source" +) + +type watcher struct { + f *file + + fw *fsnotify.Watcher + exit chan bool +} + +func newWatcher(f *file) (source.Watcher, error) { + fw, err := fsnotify.NewWatcher() + if err != nil { + return nil, err + } + + fw.Add(f.path) + + return &watcher{ + f: f, + fw: fw, + exit: make(chan bool), + }, nil +} + +func (w *watcher) Next() (*source.ChangeSet, error) { + // is it closed? + select { + case <-w.exit: + return nil, errors.New("watcher stopped") + default: + } + + // try get the event + select { + case event, _ := <-w.fw.Events: + if event.Op == fsnotify.Rename { + // check existence of file, and add watch again + _, err := os.Stat(event.Name) + if err == nil || os.IsExist(err) { + w.fw.Add(event.Name) + } + } + + c, err := w.f.Read() + if err != nil { + return nil, err + } + return c, nil + case err := <-w.fw.Errors: + return nil, err + case <-w.exit: + return nil, errors.New("watcher stopped") + } +} + +func (w *watcher) Stop() error { + return w.fw.Close() +} diff --git a/config/source/flag/README.md b/config/source/flag/README.md new file mode 100644 index 00000000..fb78bae2 --- /dev/null +++ b/config/source/flag/README.md @@ -0,0 +1,47 @@ +# Flag Source + +The flag source reads config from flags + +## Format + +We expect the use of the `flag` package. Upper case flags will be lower cased. Dashes will be used as delimiters. + +### Example + +``` +dbAddress := flag.String("database_address", "127.0.0.1", "the db address") +dbPort := flag.Int("database_port", 3306, "the db port) +``` + +Becomes + +```json +{ + "database": { + "address": "127.0.0.1", + "port": 3306 + } +} +``` + +## New Source + +```go +flagSource := flag.NewSource( + // optionally enable reading of unset flags and their default + // values into config, defaults to false + IncludeUnset(true) +) +``` + +## Load Source + +Load the source into config + +```go +// Create new config +conf := config.NewConfig() + +// Load file source +conf.Load(flagSource) +``` diff --git a/config/source/flag/flag.go b/config/source/flag/flag.go new file mode 100644 index 00000000..04483d5b --- /dev/null +++ b/config/source/flag/flag.go @@ -0,0 +1,97 @@ +package flag + +import ( + "errors" + "flag" + "github.com/imdario/mergo" + "github.com/micro/go-micro/config/source" + "strings" + "time" +) + +type flagsrc struct { + opts source.Options +} + +func (fs *flagsrc) Read() (*source.ChangeSet, error) { + if !flag.Parsed() { + return nil, errors.New("flags not parsed") + } + + var changes map[string]interface{} + + visitFn := func(f *flag.Flag) { + n := strings.ToLower(f.Name) + keys := strings.FieldsFunc(n, split) + reverse(keys) + + tmp := make(map[string]interface{}) + for i, k := range keys { + if i == 0 { + tmp[k] = f.Value + continue + } + + tmp = map[string]interface{}{k: tmp} + } + + mergo.Map(&changes, tmp) // need to sort error handling + return + } + + unset, ok := fs.opts.Context.Value(includeUnsetKey{}).(bool) + if ok && unset { + flag.VisitAll(visitFn) + } else { + flag.Visit(visitFn) + } + + b, err := fs.opts.Encoder.Encode(changes) + if err != nil { + return nil, err + } + + cs := &source.ChangeSet{ + Format: fs.opts.Encoder.String(), + Data: b, + Timestamp: time.Now(), + Source: fs.String(), + } + cs.Checksum = cs.Sum() + + return cs, nil +} + +func split(r rune) bool { + return r == '-' || r == '_' +} + +func reverse(ss []string) { + for i := len(ss)/2 - 1; i >= 0; i-- { + opp := len(ss) - 1 - i + ss[i], ss[opp] = ss[opp], ss[i] + } +} + +func (fs *flagsrc) Watch() (source.Watcher, error) { + return source.NewNoopWatcher() +} + +func (fs *flagsrc) String() string { + return "flag" +} + +// NewSource returns a config source for integrating parsed flags. +// Hyphens are delimiters for nesting, and all keys are lowercased. +// +// Example: +// dbhost := flag.String("database-host", "localhost", "the db host name") +// +// { +// "database": { +// "host": "localhost" +// } +// } +func NewSource(opts ...source.Option) source.Source { + return &flagsrc{opts: source.NewOptions(opts...)} +} diff --git a/config/source/flag/flag_test.go b/config/source/flag/flag_test.go new file mode 100644 index 00000000..1b07ac81 --- /dev/null +++ b/config/source/flag/flag_test.go @@ -0,0 +1,66 @@ +package flag + +import ( + "encoding/json" + "flag" + "testing" +) + +var ( + dbuser = flag.String("database-user", "default", "db user") + dbhost = flag.String("database-host", "", "db host") + dbpw = flag.String("database-password", "", "db pw") +) + +func init() { + flag.Set("database-host", "localhost") + flag.Set("database-password", "some-password") + flag.Parse() +} + +func TestFlagsrc_Read(t *testing.T) { + source := NewSource() + c, err := source.Read() + if err != nil { + t.Error(err) + } + + var actual map[string]interface{} + if err := json.Unmarshal(c.Data, &actual); err != nil { + t.Error(err) + } + + actualDB := actual["database"].(map[string]interface{}) + if actualDB["host"] != *dbhost { + t.Errorf("expected %v got %v", *dbhost, actualDB["host"]) + } + + if actualDB["password"] != *dbpw { + t.Errorf("expected %v got %v", *dbpw, actualDB["password"]) + } + + // unset flags should not be loaded + if actualDB["user"] != nil { + t.Errorf("expected %v got %v", nil, actualDB["user"]) + } +} + +func TestFlagsrc_ReadAll(t *testing.T) { + source := NewSource(IncludeUnset(true)) + c, err := source.Read() + if err != nil { + t.Error(err) + } + + var actual map[string]interface{} + if err := json.Unmarshal(c.Data, &actual); err != nil { + t.Error(err) + } + + actualDB := actual["database"].(map[string]interface{}) + + // unset flag defaults should be loaded + if actualDB["user"] != *dbuser { + t.Errorf("expected %v got %v", *dbuser, actualDB["user"]) + } +} diff --git a/config/source/flag/options.go b/config/source/flag/options.go new file mode 100644 index 00000000..369cccb6 --- /dev/null +++ b/config/source/flag/options.go @@ -0,0 +1,20 @@ +package flag + +import ( + "context" + + "github.com/micro/go-micro/config/source" +) + +type includeUnsetKey struct{} + +// IncludeUnset toggles the loading of unset flags and their respective default values. +// Default behavior is to ignore any unset flags. +func IncludeUnset(b bool) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, includeUnsetKey{}, true) + } +} diff --git a/config/source/memory/README.md b/config/source/memory/README.md new file mode 100644 index 00000000..2c8038d8 --- /dev/null +++ b/config/source/memory/README.md @@ -0,0 +1,44 @@ +# Memory Source + +The memory source provides in-memory data as a source + +## Memory Format + +The expected data format is json + +```json +data := []byte(`{ + "hosts": { + "database": { + "address": "10.0.0.1", + "port": 3306 + }, + "cache": { + "address": "10.0.0.2", + "port": 6379 + } + } +}`) +``` + +## New Source + +Specify source with data + +```go +memorySource := memory.NewSource( + memory.WithData(data), +) +``` + +## Load Source + +Load the source into config + +```go +// Create new config +conf := config.NewConfig() + +// Load file source +conf.Load(memorySource) +``` diff --git a/config/source/memory/memory.go b/config/source/memory/memory.go new file mode 100644 index 00000000..50a509fd --- /dev/null +++ b/config/source/memory/memory.go @@ -0,0 +1,93 @@ +// Package memory is a memory source +package memory + +import ( + "sync" + "time" + + "github.com/micro/go-micro/config/source" + "github.com/pborman/uuid" +) + +type memory struct { + sync.RWMutex + ChangeSet *source.ChangeSet + Watchers map[string]*watcher +} + +func (s *memory) Read() (*source.ChangeSet, error) { + s.RLock() + cs := &source.ChangeSet{ + Timestamp: s.ChangeSet.Timestamp, + Data: s.ChangeSet.Data, + Checksum: s.ChangeSet.Checksum, + Source: s.ChangeSet.Source, + } + s.RUnlock() + return cs, nil +} + +func (s *memory) Watch() (source.Watcher, error) { + w := &watcher{ + Id: uuid.NewUUID().String(), + Updates: make(chan *source.ChangeSet, 100), + Source: s, + } + + s.Lock() + s.Watchers[w.Id] = w + s.Unlock() + return w, nil +} + +// Update allows manual updates of the config data. +func (s *memory) Update(c *source.ChangeSet) { + // don't process nil + if c == nil { + return + } + + // hash the file + s.Lock() + // update changeset + s.ChangeSet = &source.ChangeSet{ + Data: c.Data, + Format: c.Format, + Source: "memory", + Timestamp: time.Now(), + } + s.ChangeSet.Checksum = s.ChangeSet.Sum() + + // update watchers + for _, w := range s.Watchers { + select { + case w.Updates <- s.ChangeSet: + default: + } + } + s.Unlock() +} + +func (s *memory) String() string { + return "memory" +} + +func NewSource(opts ...source.Option) source.Source { + var options source.Options + for _, o := range opts { + o(&options) + } + + s := &memory{ + Watchers: make(map[string]*watcher), + } + + if options.Context != nil { + c, ok := options.Context.Value(changeSetKey{}).(*source.ChangeSet) + if ok { + s.Update(c) + } + } + + return s +} diff --git a/config/source/memory/options.go b/config/source/memory/options.go new file mode 100644 index 00000000..5b1e6c57 --- /dev/null +++ b/config/source/memory/options.go @@ -0,0 +1,32 @@ +package memory + +import ( + "context" + + "github.com/micro/go-micro/config/source" +) + +type changeSetKey struct{} + +// WithChangeSet allows a changeset to be set +func WithChangeSet(cs *source.ChangeSet) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, changeSetKey{}, cs) + } +} + +// WithData allows the source data to be set +func WithData(d []byte) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, changeSetKey{}, &source.ChangeSet{ + Data: d, + Format: "json", + }) + } +} diff --git a/config/source/memory/watcher.go b/config/source/memory/watcher.go new file mode 100644 index 00000000..4cdc09e1 --- /dev/null +++ b/config/source/memory/watcher.go @@ -0,0 +1,23 @@ +package memory + +import ( + "github.com/micro/go-micro/config/source" +) + +type watcher struct { + Id string + Updates chan *source.ChangeSet + Source *memory +} + +func (w *watcher) Next() (*source.ChangeSet, error) { + cs := <-w.Updates + return cs, nil +} + +func (w *watcher) Stop() error { + w.Source.Lock() + delete(w.Source.Watchers, w.Id) + w.Source.Unlock() + return nil +} diff --git a/config/source/noop.go b/config/source/noop.go new file mode 100644 index 00000000..fc444411 --- /dev/null +++ b/config/source/noop.go @@ -0,0 +1,25 @@ +package source + +import ( + "errors" +) + +type noopWatcher struct { + exit chan struct{} +} + +func (w *noopWatcher) Next() (*ChangeSet, error) { + <-w.exit + + return nil, errors.New("noopWatcher stopped") +} + +func (w *noopWatcher) Stop() error { + close(w.exit) + return nil +} + +// NewNoopWatcher returns a watcher that blocks on Next() until Stop() is called. +func NewNoopWatcher() (Watcher, error) { + return &noopWatcher{exit: make(chan struct{})}, nil +} diff --git a/config/source/options.go b/config/source/options.go new file mode 100644 index 00000000..0f8f7943 --- /dev/null +++ b/config/source/options.go @@ -0,0 +1,38 @@ +package source + +import ( + "context" + + "github.com/micro/go-micro/config/encoder" + "github.com/micro/go-micro/config/encoder/json" +) + +type Options struct { + // Encoder + Encoder encoder.Encoder + + // for alternative data + Context context.Context +} + +type Option func(o *Options) + +func NewOptions(opts ...Option) Options { + options := Options{ + Encoder: json.NewEncoder(), + Context: context.Background(), + } + + for _, o := range opts { + o(&options) + } + + return options +} + +// WithEncoder sets the source encoder +func WithEncoder(e encoder.Encoder) Option { + return func(o *Options) { + o.Encoder = e + } +} diff --git a/config/source/source.go b/config/source/source.go new file mode 100644 index 00000000..828c8ad2 --- /dev/null +++ b/config/source/source.go @@ -0,0 +1,28 @@ +// Package source is the interface for sources +package source + +import ( + "time" +) + +// Source is the source from which config is loaded +type Source interface { + Read() (*ChangeSet, error) + Watch() (Watcher, error) + String() string +} + +// ChangeSet represents a set of changes from a source +type ChangeSet struct { + Data []byte + Checksum string + Format string + Source string + Timestamp time.Time +} + +// Watcher watches a source for changes +type Watcher interface { + Next() (*ChangeSet, error) + Stop() error +} diff --git a/config/value.go b/config/value.go new file mode 100644 index 00000000..929d671b --- /dev/null +++ b/config/value.go @@ -0,0 +1,49 @@ +package config + +import ( + "time" + + "github.com/micro/go-micro/config/reader" +) + +type value struct{} + +func newValue() reader.Value { + return new(value) +} + +func (v *value) Bool(def bool) bool { + return false +} + +func (v *value) Int(def int) int { + return 0 +} + +func (v *value) String(def string) string { + return "" +} + +func (v *value) Float64(def float64) float64 { + return 0.0 +} + +func (v *value) Duration(def time.Duration) time.Duration { + return time.Duration(0) +} + +func (v *value) StringSlice(def []string) []string { + return nil +} + +func (v *value) StringMap(def map[string]string) map[string]string { + return map[string]string{} +} + +func (v *value) Scan(val interface{}) error { + return nil +} + +func (v *value) Bytes() []byte { + return nil +} From 8618183508511ef09e17282a14e1adbed4401443 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 30 May 2019 23:20:20 +0100 Subject: [PATCH 02/18] bump go.mod --- go.mod | 71 ++++++++++++++++++++++++++++++++-------------------------- go.sum | 55 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 5a0adffb..45392aef 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module github.com/micro/go-micro require ( cloud.google.com/go v0.39.0 // indirect contrib.go.opencensus.io/exporter/ocagent v0.5.0 // indirect - github.com/Azure/azure-sdk-for-go v29.0.0+incompatible // indirect + github.com/Azure/azure-sdk-for-go v30.0.0+incompatible // indirect github.com/Azure/go-autorest v12.1.0+incompatible // indirect + github.com/BurntSushi/toml v0.3.1 github.com/DataDog/dd-trace-go v1.14.0 // indirect github.com/DataDog/zstd v1.4.0 // indirect github.com/Jeffail/gabs v1.4.0 // indirect @@ -14,13 +15,13 @@ require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/SAP/go-hdb v0.14.1 // indirect github.com/Shopify/sarama v1.22.1 // indirect - github.com/StackExchange/wmi v0.0.0-20181212234831-e0a55b97c705 // indirect - github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190522081930-582d16a078d0 // indirect - github.com/aliyun/aliyun-oss-go-sdk v1.9.6 // indirect + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect + github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190530073359-dfac1ef71ffa // indirect + github.com/aliyun/aliyun-oss-go-sdk v1.9.8 // indirect github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61 // indirect - github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect - github.com/aws/aws-sdk-go v1.19.35 // indirect + github.com/aws/aws-sdk-go v1.19.41 // indirect + github.com/bitly/go-simplejson v0.5.0 github.com/boombuler/barcode v1.0.0 // indirect github.com/chrismalek/oktasdk-go v0.0.0-20181212195951-3430665dfaa0 // indirect github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect @@ -34,7 +35,7 @@ require ( github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b // indirect github.com/digitalocean/godo v1.15.0 // indirect github.com/dnaeon/go-vcr v1.0.1 // indirect - github.com/dnstap/golang-dnstap v0.0.0-20190521061535-1a0dab85b926 // indirect + github.com/dnstap/golang-dnstap v0.1.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect @@ -44,9 +45,12 @@ require ( github.com/envoyproxy/go-control-plane v0.8.0 // indirect github.com/evanphx/json-patch v4.2.0+incompatible // indirect github.com/farsightsec/golang-framestream v0.0.0-20190425193708-fa4b164d59b8 // indirect + github.com/fsnotify/fsnotify v1.4.7 github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa // indirect github.com/gammazero/workerpool v0.0.0-20190521015540-3b91a70bc0a1 // indirect github.com/garyburd/redigo v1.6.0 // indirect + github.com/ghodss/yaml v1.0.0 + github.com/go-acme/lego v2.6.0+incompatible // indirect github.com/go-ldap/ldap v3.0.3+incompatible // indirect github.com/go-log/log v0.1.0 github.com/go-ole/go-ole v1.2.4 // indirect @@ -56,7 +60,7 @@ require ( github.com/go-openapi/swag v0.19.0 // indirect github.com/go-sql-driver/mysql v1.4.1 // indirect github.com/go-stomp/stomp v2.0.3+incompatible // indirect - github.com/gocql/gocql v0.0.0-20190423091413-b99afaf3b163 // indirect + github.com/gocql/gocql v0.0.0-20190523124812-0680bfb96414 // indirect github.com/gogo/googleapis v1.2.0 // indirect github.com/golang/mock v1.3.1 // indirect github.com/golang/protobuf v1.3.1 @@ -64,22 +68,22 @@ require ( github.com/google/gofuzz v1.0.0 // indirect github.com/google/pprof v0.0.0-20190515194954-54271f7e092f // indirect github.com/google/uuid v1.1.1 - github.com/gophercloud/gophercloud v0.0.0-20190520235722-e87e5f90e7e6 // indirect + github.com/gophercloud/gophercloud v0.1.0 // indirect github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect github.com/gorilla/mux v1.7.2 // indirect github.com/grpc-ecosystem/grpc-gateway v1.9.0 // indirect - github.com/hashicorp/consul v1.5.0 + github.com/hashicorp/consul v1.5.1 github.com/hashicorp/consul/api v1.1.0 github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-discover v0.0.0-20190522154730-8aba54d36e17 // indirect github.com/hashicorp/go-hclog v0.9.2 // indirect - github.com/hashicorp/go-memdb v1.0.2 // indirect - github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-memdb v1.0.3 // indirect github.com/hashicorp/go-version v1.2.0 // indirect + github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93 // indirect github.com/hashicorp/memberlist v0.1.4 - github.com/hashicorp/nomad/api v0.0.0-20190522160243-df84e07c1a46 // indirect - github.com/hashicorp/raft v1.0.1 // indirect + github.com/hashicorp/nomad/api v0.0.0-20190529164939-86a6569933bd // indirect + github.com/hashicorp/raft v1.1.0 // indirect github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea // indirect github.com/hashicorp/serf v0.8.3 // indirect github.com/hashicorp/vault v1.1.2 // indirect @@ -96,6 +100,7 @@ require ( github.com/hashicorp/vault-plugin-secrets-kv v0.5.1 // indirect github.com/hashicorp/vault/api v1.0.2 // indirect github.com/hashicorp/vault/sdk v0.1.11 // indirect + github.com/imdario/mergo v0.3.7 github.com/influxdata/influxdb v1.7.6 // indirect github.com/jarcoal/httpmock v1.0.4 // indirect github.com/jefferai/jsonx v1.0.0 // indirect @@ -107,33 +112,33 @@ require ( github.com/kr/pty v1.1.4 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lib/pq v1.1.1 // indirect - github.com/linode/linodego v0.8.1 // indirect + github.com/linode/linodego v0.9.0 // indirect github.com/lucas-clemente/quic-go v0.11.1 // indirect github.com/lyft/protoc-gen-validate v0.0.14 // indirect github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983 // indirect github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b // indirect - github.com/mattn/go-isatty v0.0.8 // indirect + github.com/mattn/go-colorable v0.1.2 // indirect github.com/mholt/caddy v1.0.0 // indirect github.com/mholt/certmagic v0.5.1 // indirect github.com/michaelklishin/rabbit-hole v1.5.0 // indirect - github.com/micro/cli v0.1.0 + github.com/micro/cli v0.2.0 github.com/micro/go-log v0.1.0 github.com/micro/go-rcache v0.3.0 github.com/micro/mdns v0.1.0 github.com/micro/util v0.2.0 - github.com/miekg/dns v1.1.12 // indirect + github.com/miekg/dns v1.1.13 // indirect github.com/mitchellh/hashstructure v1.0.0 github.com/mitchellh/pointerstructure v0.0.0-20190430161007-f252a8fd71c8 // indirect github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30 // indirect github.com/opentracing/opentracing-go v1.1.0 // indirect github.com/openzipkin/zipkin-go-opentracing v0.3.5 // indirect github.com/ory-am/common v0.4.0 // indirect - github.com/pborman/uuid v1.2.0 // indirect + github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.8.1 github.com/pquerna/otp v1.1.0 // indirect github.com/prometheus/client_golang v0.9.3 // indirect github.com/prometheus/common v0.4.1 // indirect - github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1 // indirect + github.com/prometheus/procfs v0.0.1 // indirect github.com/prometheus/tsdb v0.8.0 // indirect github.com/rogpeppe/fastuuid v1.1.0 // indirect github.com/russross/blackfriday v2.0.0+incompatible // indirect @@ -145,32 +150,34 @@ require ( github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94 // indirect github.com/stretchr/objx v0.2.0 // indirect - github.com/ugorji/go v1.1.4 // indirect + github.com/ugorji/go v1.1.5-pre // indirect github.com/vmware/govmomi v0.20.1 // indirect + go.opencensus.io v0.22.0 // indirect go.uber.org/atomic v1.4.0 // indirect go.uber.org/zap v1.10.0 // indirect - golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f // indirect + golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 // indirect golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522 // indirect - golang.org/x/image v0.0.0-20190516052701-61b8692d9a5c // indirect + golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff // indirect golang.org/x/lint v0.0.0-20190409202823-959b441ac422 // indirect golang.org/x/mobile v0.0.0-20190509164839-32b2708ab171 // indirect golang.org/x/net v0.0.0-20190522155817-f3200d17e092 - golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07 // indirect - golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5 // indirect - golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd // indirect + golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0 // indirect + golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 // indirect + golang.org/x/tools v0.0.0-20190530215528-75312fb06703 // indirect google.golang.org/appengine v1.6.0 // indirect - google.golang.org/genproto v0.0.0-20190516172635-bb713bdc0e52 // indirect + google.golang.org/genproto v0.0.0-20190530194941-fb225487d101 // indirect + google.golang.org/grpc v1.21.0 // indirect gopkg.in/gorethink/gorethink.v4 v4.1.0 // indirect gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect gopkg.in/ory-am/dockertest.v2 v2.2.3 // indirect - honnef.co/go/tools v0.0.0-20190522022531-bad1bd262ba8 // indirect - k8s.io/api v0.0.0-20190515023547-db5a9d1c40eb // indirect + honnef.co/go/tools v0.0.0-20190530170028-a1efa522b896 // indirect + k8s.io/api v0.0.0-20190528154508-67ef80593b24 // indirect k8s.io/client-go v11.0.0+incompatible // indirect k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a // indirect - k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22 // indirect - k8s.io/utils v0.0.0-20190520173318-324c5df7d3f0 // indirect + k8s.io/klog v0.3.2 // indirect + k8s.io/kube-openapi v0.0.0-20190530181030-b52b5b0f5a7c // indirect + k8s.io/utils v0.0.0-20190529001817-6999998975a7 // indirect layeh.com/radius v0.0.0-20190322222518-890bc1058917 // indirect - sigs.k8s.io/structured-merge-diff v0.0.0-20190521201008-1c46bef2e9c8 // indirect ) replace github.com/golang/lint => github.com/golang/lint v0.0.0-20190227174305-8f45f776aaf1 diff --git a/go.sum b/go.sum index 19443b70..7e47ccd2 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,7 @@ github.com/Azure/azure-sdk-for-go v27.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo github.com/Azure/azure-sdk-for-go v27.3.0+incompatible h1:i+ROfG3CsZUPoVAnhK06T3R6PmBzKB9ds+lHBpN7Mzo= github.com/Azure/azure-sdk-for-go v27.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v30.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v10.7.0+incompatible h1:dB+dKSLGdJLEhU/FoZTSNSPMZuE5H4M5p5zgSct7qwM= @@ -27,6 +28,7 @@ github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSW github.com/Azure/go-autorest v12.0.0+incompatible h1:N+VqClcomLGD/sHb3smbSYYtNMgKpVV3Cd5r5i8z6bQ= github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v12.1.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v0.0.0-20160329135253-cc2f4770f4d6/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -70,6 +72,7 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/StackExchange/wmi v0.0.0-20181212234831-e0a55b97c705 h1:UUppSQnhf4Yc6xGxSkoQpPhb7RVzuv5Nb1mwJ5VId9s= github.com/StackExchange/wmi v0.0.0-20181212234831-e0a55b97c705/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -79,8 +82,10 @@ github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190412020505-60e2075261b6/go.mod github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190423023524-6ff5e74c25e8 h1:n3yJ9NAD5JfC5aTyO6yoJm5wbQ8LozPHrj2qJnAAHlI= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190423023524-6ff5e74c25e8/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA= github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190522081930-582d16a078d0/go.mod h1:0nPXeXAsIm3YH7imFCamfa0u+PueDefehKCQ8dicxmc= +github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190530073359-dfac1ef71ffa/go.mod h1:0nPXeXAsIm3YH7imFCamfa0u+PueDefehKCQ8dicxmc= github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v1.9.6/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/aliyun/aliyun-oss-go-sdk v1.9.8/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61 h1:Xz25cuW4REGC5W5UtpMU3QItMIImag615HiQcRbxqKQ= github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61/go.mod h1:ikc1XA58M+Rx7SEbf0bLJCfBkwayZ8T5jBo5FXK8Uz8= @@ -104,6 +109,7 @@ github.com/aws/aws-sdk-go v1.15.24/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZo github.com/aws/aws-sdk-go v1.19.15 h1:Ov8zxPunHxZFxrXBarqzkZBSZugJRzPgb4mfq/SyVgA= github.com/aws/aws-sdk-go v1.19.15/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.19.35/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.19.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -115,6 +121,8 @@ github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3 github.com/bifurcation/mint v0.0.0-20190129141059-83ba9bc2ead9/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= @@ -198,6 +206,7 @@ github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnstap/golang-dnstap v0.0.0-20170829151710-2cf77a2b5e11/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U= github.com/dnstap/golang-dnstap v0.0.0-20190521061535-1a0dab85b926/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U= +github.com/dnstap/golang-dnstap v0.1.0/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U= github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= @@ -255,6 +264,7 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= +github.com/go-acme/lego v2.6.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-ini/ini v1.25.4 h1:Mujh4R/dH6YL8bxuISne3xX2+qcQ9p0IxKAP6ExWoUo= @@ -298,6 +308,7 @@ github.com/gocql/gocql v0.0.0-20180617115710-e06f8c1bcd78/go.mod h1:4Fw1eo5iaEhD github.com/gocql/gocql v0.0.0-20190418090649-59a610c947c5 h1:ja4omKSx9OiML8GnnDG13qOX58UAcSJfOmce21YXALk= github.com/gocql/gocql v0.0.0-20190418090649-59a610c947c5/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= github.com/gocql/gocql v0.0.0-20190423091413-b99afaf3b163/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= +github.com/gocql/gocql v0.0.0-20190523124812-0680bfb96414/go.mod h1:Q7Sru5153KG8D9zwueuQJB3ccJf9/bIwF/x8b3oKgT8= github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/googleapis v1.2.0 h1:Z0v3OJDotX9ZBpdz2V+AI7F4fITSZhVE5mg6GQppwMM= @@ -348,6 +359,7 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -366,6 +378,7 @@ github.com/gophercloud/gophercloud v0.0.0-20190307220656-fe1ba5ce12dd/go.mod h1: github.com/gophercloud/gophercloud v0.0.0-20190422143055-fe6299556848 h1:3C19GoTlj2BtSe+APK65YeFikcZVacnXncVEPGuqOQU= github.com/gophercloud/gophercloud v0.0.0-20190422143055-fe6299556848/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.0.0-20190520235722-e87e5f90e7e6/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw= github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -404,6 +417,8 @@ github.com/hashicorp/consul v1.4.4 h1:DR1+5EGgnPsd/LIsK3c9RDvajcsV5GOkGQBSNd3dpn github.com/hashicorp/consul v1.4.4/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= github.com/hashicorp/consul v1.5.0 h1:GPtcwUGw5kjoSIF7NpDHmwHEM17ufGn1ezKQSutBMhI= github.com/hashicorp/consul v1.5.0/go.mod h1:7rvUESOLul7V9uCo5TNZ64jzf9W5Fcy/xf/TxtOT0xQ= +github.com/hashicorp/consul v1.5.1 h1:p7tRmQ4m3ZMYkGQkuyjLXKbdU1weeumgZFqZOvw7o4c= +github.com/hashicorp/consul v1.5.1/go.mod h1:QsmgXh2YA9Njv6y3/FHXqHYhsMye++3oBoAZ6SR8R8I= github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -426,13 +441,17 @@ github.com/hashicorp/go-hclog v0.0.0-20180402200405-69ff559dc25f/go.mod h1:9bjs9 github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.8.0 h1:z3ollgGRg8RjfJH6UVBaG54R70GFd++QOkvnJH3VSBY= github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= +github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v0.0.0-20180223233045-1289e7fffe71/go.mod h1:kbfItVoBJwCfKXDXN4YoAXjxcFVZ7MRrJzyTX6H4giE= github.com/hashicorp/go-memdb v1.0.1 h1:QR2h3O60I0DSvCsogh77kZUPzZBkbDSfeUjzhrK8p04= github.com/hashicorp/go-memdb v1.0.1/go.mod h1:I6dKdmYhZqU0RJSheVEWgTNWdVQH5QvTgIUQ0t/t32M= github.com/hashicorp/go-memdb v1.0.2/go.mod h1:I6dKdmYhZqU0RJSheVEWgTNWdVQH5QvTgIUQ0t/t32M= +github.com/hashicorp/go-memdb v1.0.3/go.mod h1:LWQ8R70vPrS4OEY9k28D2z8/Zzyu34NVzeRibGAzHO0= github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.4 h1:SFT72YqIkOcLdWJUYcriVX7hbrZpwc/f7h8aW2NUqrA= @@ -493,9 +512,11 @@ github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mo github.com/hashicorp/nomad/api v0.0.0-20190422193122-09c998a4a160 h1:3a/eASHSEdXV9ghYxoZj8DJ52/9Wp22Ers70lxB/vnU= github.com/hashicorp/nomad/api v0.0.0-20190422193122-09c998a4a160/go.mod h1:BDngVi1f4UA6aJq9WYTgxhfWSE1+42xshvstLU2fRGk= github.com/hashicorp/nomad/api v0.0.0-20190522160243-df84e07c1a46/go.mod h1:BDngVi1f4UA6aJq9WYTgxhfWSE1+42xshvstLU2fRGk= +github.com/hashicorp/nomad/api v0.0.0-20190529164939-86a6569933bd/go.mod h1:BDngVi1f4UA6aJq9WYTgxhfWSE1+42xshvstLU2fRGk= github.com/hashicorp/raft v1.0.1-0.20190409200437-d9fe23f7d472/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= github.com/hashicorp/raft v1.0.1 h1:94uRdS11oEneUkxmXq6Vg9shNhBILh2UTb9crQjJWl0= github.com/hashicorp/raft v1.0.1/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= +github.com/hashicorp/raft v1.1.0/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= github.com/hashicorp/raft-boltdb v0.0.0-20150201200839-d1e82c1ec3f1/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea h1:xykPFhrBAS2J0VBzVa5e80b5ZtYuNQtgXjN40qBZlD4= github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= @@ -614,6 +635,7 @@ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/linode/linodego v0.7.1 h1:4WZmMpSA2NRwlPZcc0+4Gyn7rr99Evk9bnr0B3gXRKE= github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= github.com/linode/linodego v0.8.1/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= +github.com/linode/linodego v0.9.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04= github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk= github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao= @@ -632,6 +654,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= @@ -650,6 +673,8 @@ github.com/michaelklishin/rabbit-hole v1.5.0/go.mod h1:vvI1uOitYZi0O5HEGXhaWC1XT github.com/micro/cli v0.0.0-20181223203424-1b0c9793c300/go.mod h1:x9x6qy+tXv17jzYWQup462+j3SIUgDa6vVTzU4IXy/w= github.com/micro/cli v0.1.0 h1:5DT+QdbAPPQvB3gYTgwze7tFO1m+7DU1sz9XfQczbsc= github.com/micro/cli v0.1.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= +github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= +github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= github.com/micro/go-log v0.1.0 h1:szYSR+yyTsomZM2jyinJC5562DlqffSjHmTZFaeZ2vY= github.com/micro/go-log v0.1.0/go.mod h1:qaFBF6d6Jk01Gz4cbMkCA2vVuLk3FSaLLjmEGrMCreA= github.com/micro/go-micro v0.23.0/go.mod h1:3z3lfMkNU9Sr1L/CxL++8pVJmQapRo0N6kNjwYDtOVs= @@ -681,6 +706,8 @@ github.com/miekg/dns v1.1.8 h1:1QYRAKU3lN5cRfLCkPU08hwvLJFhvjP6MqNMmQz6ZVI= github.com/miekg/dns v1.1.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12 h1:WMhc1ik4LNkTg8U9l3hI1LvxKmIL+f1+WV/SZtCbDDA= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.13 h1:x7DQtkU0cedzeS8TD36tT/w1Hm4rDtfCaYYAHE7TTBI= +github.com/miekg/dns v1.1.13/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v0.0.0-20160804032330-cdac8253d00f/go.mod h1:eOsF2yLPlBBJPvD+nhl5QMTBSOBbOph6N7j/IDUw7PY= @@ -826,6 +853,7 @@ github.com/prometheus/procfs v0.0.0-20190416084830-8368d24ba045 h1:Raos9GP+3BlCB github.com/prometheus/procfs v0.0.0-20190416084830-8368d24ba045/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.8.0/go.mod h1:fSI0j+IUQrDd7+ZtR9WKIGtoYAYAJUKcKhYLG25tN4g= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -833,6 +861,7 @@ github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOe github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= @@ -906,8 +935,10 @@ github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqri github.com/ugorji/go v1.1.2 h1:JON3E2/GPW2iDNGoSAusl1KDf5TRQ8k8q7Tp097pZGs= github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go/codec v0.0.0-20190309163734-c4a1c341dc93 h1:JnDJ9gMf6CfErtoOXnghtY5hhMuDtW4tUBaWSBrqvKs= github.com/ugorji/go/codec v0.0.0-20190309163734-c4a1c341dc93/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= +github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/vmware/govmomi v0.20.0 h1:+1IyhvoVb5JET2Wvgw9J3ZDv6CK4sxzUunpH8LhQqm4= @@ -926,6 +957,7 @@ go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2 h1:NAfh7zF0/3/HqtMvJNZ/RFrSlCE6ZTlHmKfhL/Dm1Jk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -950,13 +982,17 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd h1:sMHc2rZHuzQmrbVoSpt9HgerkXPyIeCSO6k0zUMGfFk= golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190516052701-61b8692d9a5c/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -966,6 +1002,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190509164839-32b2708ab171/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -990,6 +1027,7 @@ golang.org/x/net v0.0.0-20190403144856-b630fd6fe46b/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190420063019-afa5a82059c6 h1:HdqqaWmYAUI7/dmByKKEw+yxDksGSo+9GjkUc9Zp34E= golang.org/x/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -1003,6 +1041,7 @@ golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1039,9 +1078,12 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5 h1:f005F/Jl5JLP036x7QIvUVhNTqxvSYwFIiyOh2q12iU= golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 h1:R4dVlxdmKenVdMRS/tTspEpSTRWINYrHD8ySIU9yCIU= +golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1069,6 +1111,7 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190530215528-75312fb06703/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= google.golang.org/api v0.0.0-20180829000535-087779f1d2c9 h1:z1TeLUmxf9ws9KLICfmX+KGXTs+rjm+aGWzfsv7MZ9w= google.golang.org/api v0.0.0-20180829000535-087779f1d2c9/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= @@ -1098,8 +1141,10 @@ google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQN google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190516172635-bb713bdc0e52/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/grpc v0.0.0-20180920234847-8997b5fa0873/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= @@ -1110,6 +1155,7 @@ google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/DataDog/dd-trace-go.v0 v0.6.1/go.mod h1:uxRvUTC61u1w+PTfyHNOzLPTCHYt6CJyGZvZSAzGvZA= gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= @@ -1119,6 +1165,7 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUy gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg= gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -1161,6 +1208,7 @@ honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190522022531-bad1bd262ba8/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190530170028-a1efa522b896/go.mod h1:wtc9q0E9zm8PjdRMh29DPlTlCCHVzKDwnkT4GskQVzg= istio.io/gogo-genproto v0.0.0-20190124151557-6d926a6e6feb/go.mod h1:eIDJ6jNk/IeJz6ODSksHl5Aiczy5JUq6vFhJWI5OtiI= k8s.io/api v0.0.0-20180806132203-61b11ee65332 h1:+ED/2NBbOoeWB9QrGTHxZI7UnE7rnHPKKumOl0WXphs= k8s.io/api v0.0.0-20180806132203-61b11ee65332/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= @@ -1172,6 +1220,7 @@ k8s.io/api v0.0.0-20190409092523-d687e77c8ae9/go.mod h1:FQEUn50aaytlU65qqBn/w+5u k8s.io/api v0.0.0-20190419092548-c5cad27821f6 h1:S/8tIFYavaVbM3nFX0yqkw4X0BooJqRO+TrDANFX1Uo= k8s.io/api v0.0.0-20190419092548-c5cad27821f6/go.mod h1:B0cvvXrD9UkqARVdlFhdZB9SNL0TzJ13UB/p410skE4= k8s.io/api v0.0.0-20190515023547-db5a9d1c40eb/go.mod h1:fbdFiGtx7GQ3+vkBAYto3QsSImiYIJdpH3YfaclST/U= +k8s.io/api v0.0.0-20190528154508-67ef80593b24/go.mod h1:aCWu6byTIKt+TeO2ZJ48xnOrYgDq0jqxbxmzfjXbNqw= k8s.io/apimachinery v0.0.0-20180821005732-488889b0007f h1:V0PkbgaYp5JqCmzLyRmssDtzim0NShXM8gYi4fcX230= k8s.io/apimachinery v0.0.0-20180821005732-488889b0007f/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 h1:tT6oQBi0qwLbbZSfDkdIsb23EwaLY85hoAV4SpXfdao= @@ -1183,6 +1232,7 @@ k8s.io/apimachinery v0.0.0-20190418212431-b3683fe6b520/go.mod h1:tXkZEnPhecLuffc k8s.io/apimachinery v0.0.0-20190419212445-b874eabb9a4e h1:h2UL1ppdZDnaCKNvEFzbRIscOymKZznckYlXgZ3iQME= k8s.io/apimachinery v0.0.0-20190419212445-b874eabb9a4e/go.mod h1:tXkZEnPhecLuffcJcEuO/iNpM8w0n42dM5fNrr9OVVE= k8s.io/apimachinery v0.0.0-20190515023456-b74e4c97951f/go.mod h1:Ew3b/24/JSgJdn4RsnrLskv3LvMZDlZ1Fl1xopsJftY= +k8s.io/apimachinery v0.0.0-20190528154326-e59c2fb0a8e5/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA= k8s.io/client-go v8.0.0+incompatible h1:tTI4hRmb1DRMl4fG6Vclfdi6nTM82oIrTT7HfitmxC4= k8s.io/client-go v8.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34= @@ -1198,15 +1248,20 @@ k8s.io/klog v0.0.0-20190306015804-8e90cee79f82 h1:SHucoAy7lRb+w5oC/hbXyZg+zX+Wft k8s.io/klog v0.0.0-20190306015804-8e90cee79f82/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.2/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190306001800-15615b16d372/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22/go.mod h1:iU+ZGYsNlvU9XKUSso6SQfKTCCw7lFduMZy26Mgr2Fw= +k8s.io/kube-openapi v0.0.0-20190530181030-b52b5b0f5a7c/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7 h1:8r+l4bNWjRlsFYlQJnKJ2p7s1YQPj4XyXiJVqDHRx7c= k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= k8s.io/utils v0.0.0-20190520173318-324c5df7d3f0/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20190529001817-6999998975a7/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= layeh.com/radius v0.0.0-20190322222518-890bc1058917 h1:BDXFaFzUt5EIqe/4wrTc4AcYZWP6iC6Ult+jQWLh5eU= layeh.com/radius v0.0.0-20190322222518-890bc1058917/go.mod h1:fywZKyu//X7iRzaxLgPWsvc0L26IUpVvE/aeIL2JtIQ= sigs.k8s.io/structured-merge-diff v0.0.0-20190426204423-ea680f03cc65/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190521201008-1c46bef2e9c8/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= From b4874806df8587dc1862b34e90ca3153470c22e1 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Thu, 30 May 2019 23:52:10 +0100 Subject: [PATCH 03/18] Add util --- broker/http_broker.go | 6 +- server/rpc_server.go | 3 +- transport/http_transport.go | 6 +- util/addr/addr.go | 126 ++++++++++++++++++++++++++++++++++++ util/addr/addr_test.go | 38 +++++++++++ util/backoff/backoff.go | 14 ++++ util/ctx/ctx.go | 18 ++++++ util/ctx/ctx_test.go | 41 ++++++++++++ util/file/file.go | 15 +++++ util/file/file_test.go | 17 +++++ util/grpc/grpc.go | 40 ++++++++++++ util/grpc/grpc_test.go | 46 +++++++++++++ util/http/http.go | 23 +++++++ util/http/http_test.go | 87 +++++++++++++++++++++++++ util/http/options.go | 17 +++++ util/http/roundtripper.go | 40 ++++++++++++ util/net/net.go | 63 ++++++++++++++++++ util/net/net_test.go | 21 ++++++ util/tls/tls.go | 74 +++++++++++++++++++++ 19 files changed, 687 insertions(+), 8 deletions(-) create mode 100644 util/addr/addr.go create mode 100644 util/addr/addr_test.go create mode 100644 util/backoff/backoff.go create mode 100644 util/ctx/ctx.go create mode 100644 util/ctx/ctx_test.go create mode 100644 util/file/file.go create mode 100644 util/file/file_test.go create mode 100644 util/grpc/grpc.go create mode 100644 util/grpc/grpc_test.go create mode 100644 util/http/http.go create mode 100644 util/http/http_test.go create mode 100644 util/http/options.go create mode 100644 util/http/roundtripper.go create mode 100644 util/net/net.go create mode 100644 util/net/net_test.go create mode 100644 util/tls/tls.go diff --git a/broker/http_broker.go b/broker/http_broker.go index fefeed4d..a7f6243d 100644 --- a/broker/http_broker.go +++ b/broker/http_broker.go @@ -22,10 +22,10 @@ import ( "github.com/micro/go-micro/codec/json" merr "github.com/micro/go-micro/errors" "github.com/micro/go-micro/registry" + maddr "github.com/micro/go-micro/util/addr" + mnet "github.com/micro/go-micro/util/net" + mls "github.com/micro/go-micro/util/tls" "github.com/micro/go-rcache" - maddr "github.com/micro/util/go/lib/addr" - mnet "github.com/micro/util/go/lib/net" - mls "github.com/micro/util/go/lib/tls" "golang.org/x/net/http2" ) diff --git a/server/rpc_server.go b/server/rpc_server.go index 69f880b3..6838d65e 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -16,8 +16,7 @@ import ( "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/transport" - - "github.com/micro/util/go/lib/addr" + "github.com/micro/go-micro/util/addr" ) type rpcServer struct { diff --git a/transport/http_transport.go b/transport/http_transport.go index f72ed8cd..ec098ca2 100644 --- a/transport/http_transport.go +++ b/transport/http_transport.go @@ -13,9 +13,9 @@ import ( "sync" "time" - maddr "github.com/micro/util/go/lib/addr" - mnet "github.com/micro/util/go/lib/net" - mls "github.com/micro/util/go/lib/tls" + maddr "github.com/micro/go-micro/util/addr" + mnet "github.com/micro/go-micro/util/net" + mls "github.com/micro/go-micro/util/tls" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" ) diff --git a/util/addr/addr.go b/util/addr/addr.go new file mode 100644 index 00000000..ab3acca1 --- /dev/null +++ b/util/addr/addr.go @@ -0,0 +1,126 @@ +package addr + +import ( + "fmt" + "net" +) + +var ( + privateBlocks []*net.IPNet +) + +func init() { + for _, b := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "100.64.0.0/10", "fd00::/8"} { + if _, block, err := net.ParseCIDR(b); err == nil { + privateBlocks = append(privateBlocks, block) + } + } +} + +func isPrivateIP(ipAddr string) bool { + ip := net.ParseIP(ipAddr) + for _, priv := range privateBlocks { + if priv.Contains(ip) { + return true + } + } + return false +} + +// Extract returns a real ip +func Extract(addr string) (string, error) { + // if addr specified then its returned + if len(addr) > 0 && (addr != "0.0.0.0" && addr != "[::]") { + return addr, nil + } + + ifaces, err := net.Interfaces() + if err != nil { + return "", fmt.Errorf("Failed to get interfaces! Err: %v", err) + } + + var addrs []net.Addr + for _, iface := range ifaces { + ifaceAddrs, err := iface.Addrs() + if err != nil { + // ignore error, interface can dissapear from system + continue + } + addrs = append(addrs, ifaceAddrs...) + } + + var ipAddr []byte + var publicIP []byte + + for _, rawAddr := range addrs { + var ip net.IP + switch addr := rawAddr.(type) { + case *net.IPAddr: + ip = addr.IP + case *net.IPNet: + ip = addr.IP + default: + continue + } + + if !isPrivateIP(ip.String()) { + publicIP = ip + continue + } + + ipAddr = ip + break + } + + // return private ip + if ipAddr != nil { + return net.IP(ipAddr).String(), nil + } + + // return public or virtual ip + if publicIP != nil { + return net.IP(publicIP).String(), nil + } + + return "", fmt.Errorf("No IP address found, and explicit IP not provided") +} + +// IPs returns all known ips +func IPs() []string { + ifaces, err := net.Interfaces() + if err != nil { + return nil + } + + var ipAddrs []string + + for _, i := range ifaces { + addrs, err := i.Addrs() + if err != nil { + continue + } + + for _, addr := range addrs { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + + if ip == nil { + continue + } + + ip = ip.To4() + if ip == nil { + continue + } + + ipAddrs = append(ipAddrs, ip.String()) + } + } + + return ipAddrs +} diff --git a/util/addr/addr_test.go b/util/addr/addr_test.go new file mode 100644 index 00000000..ad23b128 --- /dev/null +++ b/util/addr/addr_test.go @@ -0,0 +1,38 @@ +package addr + +import ( + "net" + "testing" +) + +func TestExtractor(t *testing.T) { + testData := []struct { + addr string + expect string + parse bool + }{ + {"127.0.0.1", "127.0.0.1", false}, + {"10.0.0.1", "10.0.0.1", false}, + {"", "", true}, + {"0.0.0.0", "", true}, + {"[::]", "", true}, + } + + for _, d := range testData { + addr, err := Extract(d.addr) + if err != nil { + t.Errorf("Unexpected error %v", err) + } + + if d.parse { + ip := net.ParseIP(addr) + if ip == nil { + t.Error("Unexpected nil IP") + } + + } else if addr != d.expect { + t.Errorf("Expected %s got %s", d.expect, addr) + } + } + +} diff --git a/util/backoff/backoff.go b/util/backoff/backoff.go new file mode 100644 index 00000000..013d5291 --- /dev/null +++ b/util/backoff/backoff.go @@ -0,0 +1,14 @@ +// Package backoff provides backoff functionality +package backoff + +import ( + "math" + "time" +) + +func Do(attempts int) time.Duration { + if attempts == 0 { + return time.Duration(0) + } + return time.Duration(math.Pow(10, float64(attempts))) * time.Millisecond +} diff --git a/util/ctx/ctx.go b/util/ctx/ctx.go new file mode 100644 index 00000000..2fb69a43 --- /dev/null +++ b/util/ctx/ctx.go @@ -0,0 +1,18 @@ +package ctx + +import ( + "context" + "net/http" + "strings" + + "github.com/micro/go-micro/metadata" +) + +func FromRequest(r *http.Request) context.Context { + ctx := context.Background() + md := make(metadata.Metadata) + for k, v := range r.Header { + md[k] = strings.Join(v, ",") + } + return metadata.NewContext(ctx, md) +} diff --git a/util/ctx/ctx_test.go b/util/ctx/ctx_test.go new file mode 100644 index 00000000..440baea1 --- /dev/null +++ b/util/ctx/ctx_test.go @@ -0,0 +1,41 @@ +package ctx + +import ( + "net/http" + "testing" + + "github.com/micro/go-micro/metadata" +) + +func TestRequestToContext(t *testing.T) { + testData := []struct { + request *http.Request + expect metadata.Metadata + }{ + { + &http.Request{ + Header: http.Header{ + "foo1": []string{"bar"}, + "foo2": []string{"bar", "baz"}, + }, + }, + metadata.Metadata{ + "foo1": "bar", + "foo2": "bar,baz", + }, + }, + } + + for _, d := range testData { + ctx := FromRequest(d.request) + md, ok := metadata.FromContext(ctx) + if !ok { + t.Fatalf("Expected metadata for request %+v", d.request) + } + for k, v := range d.expect { + if val := md[k]; val != v { + t.Fatalf("Expected %s for key %s for expected md %+v, got md %+v", v, k, d.expect, md) + } + } + } +} diff --git a/util/file/file.go b/util/file/file.go new file mode 100644 index 00000000..3e61d3f3 --- /dev/null +++ b/util/file/file.go @@ -0,0 +1,15 @@ +package file + +import "os" + +// Exists returns true if the path is existing +func Exists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return true, err +} diff --git a/util/file/file_test.go b/util/file/file_test.go new file mode 100644 index 00000000..4ee3fabc --- /dev/null +++ b/util/file/file_test.go @@ -0,0 +1,17 @@ +package file + +import ( + "testing" +) + +func TestExists(t *testing.T) { + ok, err := Exists("/") + + if ok { + return + } + + if !ok || err != nil { + t.Fatalf("Test Exists fail, %s", err) + } +} diff --git a/util/grpc/grpc.go b/util/grpc/grpc.go new file mode 100644 index 00000000..b06a0673 --- /dev/null +++ b/util/grpc/grpc.go @@ -0,0 +1,40 @@ +package grpc + +import ( + "fmt" + "strings" +) + +// ServiceMethod converts a gRPC method to a Go method +// Input: +// Foo.Bar, /Foo/Bar, /package.Foo/Bar, /a.package.Foo/Bar +// Output: +// [Foo, Bar] +func ServiceMethod(m string) (string, string, error) { + if len(m) == 0 { + return "", "", fmt.Errorf("malformed method name: %q", m) + } + + // grpc method + if m[0] == '/' { + // [ , Foo, Bar] + // [ , package.Foo, Bar] + // [ , a.package.Foo, Bar] + parts := strings.Split(m, "/") + if len(parts) != 3 || len(parts[1]) == 0 || len(parts[2]) == 0 { + return "", "", fmt.Errorf("malformed method name: %q", m) + } + service := strings.Split(parts[1], ".") + return service[len(service)-1], parts[2], nil + } + + // non grpc method + parts := strings.Split(m, ".") + + // expect [Foo, Bar] + if len(parts) != 2 { + return "", "", fmt.Errorf("malformed method name: %q", m) + } + + return parts[0], parts[1], nil +} diff --git a/util/grpc/grpc_test.go b/util/grpc/grpc_test.go new file mode 100644 index 00000000..c7f30cc1 --- /dev/null +++ b/util/grpc/grpc_test.go @@ -0,0 +1,46 @@ +package grpc + +import ( + "testing" +) + +func TestServiceMethod(t *testing.T) { + type testCase struct { + input string + service string + method string + err bool + } + + methods := []testCase{ + {"Foo.Bar", "Foo", "Bar", false}, + {"/Foo/Bar", "Foo", "Bar", false}, + {"/package.Foo/Bar", "Foo", "Bar", false}, + {"/a.package.Foo/Bar", "Foo", "Bar", false}, + {"a.package.Foo/Bar", "", "", true}, + {"/Foo/Bar/Baz", "", "", true}, + {"Foo.Bar.Baz", "", "", true}, + } + for _, test := range methods { + service, method, err := ServiceMethod(test.input) + if err != nil && test.err == true { + continue + } + // unexpected error + if err != nil && test.err == false { + t.Fatalf("unexpected err %v for %+v", err, test) + } + // expecter error + if test.err == true && err == nil { + t.Fatalf("expected error for %+v: got service: %s method: %s", test, service, method) + } + + if service != test.service { + t.Fatalf("wrong service for %+v: got service: %s method: %s", test, service, method) + } + + if method != test.method { + t.Fatalf("wrong method for %+v: got service: %s method: %s", test, service, method) + } + } +} diff --git a/util/http/http.go b/util/http/http.go new file mode 100644 index 00000000..06bff69f --- /dev/null +++ b/util/http/http.go @@ -0,0 +1,23 @@ +package http + +import ( + "net/http" + + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/selector" +) + +func NewRoundTripper(opts ...Option) http.RoundTripper { + options := Options{ + Registry: registry.DefaultRegistry, + } + for _, o := range opts { + o(&options) + } + + return &roundTripper{ + rt: http.DefaultTransport, + st: selector.Random, + opts: options, + } +} diff --git a/util/http/http_test.go b/util/http/http_test.go new file mode 100644 index 00000000..b7bfe370 --- /dev/null +++ b/util/http/http_test.go @@ -0,0 +1,87 @@ +package http + +import ( + "io/ioutil" + "net" + "net/http" + "strconv" + "testing" + + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/registry/memory" +) + +func TestRoundTripper(t *testing.T) { + m := memory.NewRegistry() + + rt := NewRoundTripper( + WithRegistry(m), + ) + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(`hello world`)) + }) + + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + defer l.Close() + + go http.Serve(l, nil) + + host, p, _ := net.SplitHostPort(l.Addr().String()) + port, _ := strconv.Atoi(p) + + m.Register(®istry.Service{ + Name: "example.com", + Nodes: []*registry.Node{ + { + Id: "1", + Address: host, + Port: port, + }, + }, + }) + + req, err := http.NewRequest("GET", "http://example.com", nil) + if err != nil { + t.Fatal(err) + } + + w, err := rt.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + + b, err := ioutil.ReadAll(w.Body) + if err != nil { + t.Fatal(err) + } + w.Body.Close() + + if string(b) != "hello world" { + t.Fatal("response is", string(b)) + } + + // test http request + c := &http.Client{ + Transport: rt, + } + + rsp, err := c.Get("http://example.com") + if err != nil { + t.Fatal(err) + } + + b, err = ioutil.ReadAll(rsp.Body) + if err != nil { + t.Fatal(err) + } + rsp.Body.Close() + + if string(b) != "hello world" { + t.Fatal("response is", string(b)) + } + +} diff --git a/util/http/options.go b/util/http/options.go new file mode 100644 index 00000000..a248e422 --- /dev/null +++ b/util/http/options.go @@ -0,0 +1,17 @@ +package http + +import ( + "github.com/micro/go-micro/registry" +) + +type Options struct { + Registry registry.Registry +} + +type Option func(*Options) + +func WithRegistry(r registry.Registry) Option { + return func(o *Options) { + o.Registry = r + } +} diff --git a/util/http/roundtripper.go b/util/http/roundtripper.go new file mode 100644 index 00000000..f90ef34f --- /dev/null +++ b/util/http/roundtripper.go @@ -0,0 +1,40 @@ +package http + +import ( + "errors" + "fmt" + "net/http" + + "github.com/micro/go-micro/selector" +) + +type roundTripper struct { + rt http.RoundTripper + st selector.Strategy + opts Options +} + +func (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + s, err := r.opts.Registry.GetService(req.URL.Host) + if err != nil { + return nil, err + } + + next := r.st(s) + + // rudimentary retry 3 times + for i := 0; i < 3; i++ { + n, err := next() + if err != nil { + continue + } + req.URL.Host = fmt.Sprintf("%s:%d", n.Address, n.Port) + w, err := r.rt.RoundTrip(req) + if err != nil { + continue + } + return w, nil + } + + return nil, errors.New("failed request") +} diff --git a/util/net/net.go b/util/net/net.go new file mode 100644 index 00000000..b092068f --- /dev/null +++ b/util/net/net.go @@ -0,0 +1,63 @@ +package net + +import ( + "errors" + "fmt" + "net" + "strconv" + "strings" +) + +// Listen takes addr:portmin-portmax and binds to the first available port +// Example: Listen("localhost:5000-6000", fn) +func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, error) { + // host:port || host:min-max + parts := strings.Split(addr, ":") + + // + if len(parts) < 2 { + return fn(addr) + } + + // try to extract port range + ports := strings.Split(parts[len(parts)-1], "-") + + // single port + if len(ports) < 2 { + return fn(addr) + } + + // we have a port range + + // extract min port + min, err := strconv.Atoi(ports[0]) + if err != nil { + return nil, errors.New("unable to extract port range") + } + + // extract max port + max, err := strconv.Atoi(ports[1]) + if err != nil { + return nil, errors.New("unable to extract port range") + } + + // set host + host := parts[:len(parts)-1] + + // range the ports + for port := min; port <= max; port++ { + // try bind to host:port + ln, err := fn(fmt.Sprintf("%s:%d", host, port)) + if err == nil { + return ln, nil + } + + // hit max port + if port == max { + return nil, err + } + } + + // why are we here? + return nil, fmt.Errorf("unable to bind to %s", addr) +} diff --git a/util/net/net_test.go b/util/net/net_test.go new file mode 100644 index 00000000..a9fca743 --- /dev/null +++ b/util/net/net_test.go @@ -0,0 +1,21 @@ +package net + +import ( + "net" + "testing" +) + +func TestListen(t *testing.T) { + fn := func(addr string) (net.Listener, error) { + return net.Listen("tcp", addr) + } + + // try to create a number of listeners + for i := 0; i < 10; i++ { + l, err := Listen("localhost:10000-11000", fn) + if err != nil { + t.Fatal(err) + } + defer l.Close() + } +} diff --git a/util/tls/tls.go b/util/tls/tls.go new file mode 100644 index 00000000..6df2c6e4 --- /dev/null +++ b/util/tls/tls.go @@ -0,0 +1,74 @@ +package tls + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "net" + "time" +) + +func Certificate(host ...string) (tls.Certificate, error) { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return tls.Certificate{}, err + } + + notBefore := time.Now() + notAfter := notBefore.Add(time.Hour * 24 * 365) + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return tls.Certificate{}, err + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Acme Co"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + for _, h := range host { + if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } + + template.IsCA = true + template.KeyUsage |= x509.KeyUsageCertSign + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + return tls.Certificate{}, err + } + + // create public key + certOut := bytes.NewBuffer(nil) + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + + // create private key + keyOut := bytes.NewBuffer(nil) + b, err := x509.MarshalECPrivateKey(priv) + if err != nil { + return tls.Certificate{}, err + } + pem.Encode(keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}) + + return tls.X509KeyPair(certOut.Bytes(), keyOut.Bytes()) +} From 7faab93f9e6a1f8d5c8ab5b8c80ae6d8fa86d03a Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 00:18:41 +0100 Subject: [PATCH 04/18] Add agent => bot --- agent/.travis.yml | 7 ++ agent/README.md | 197 +++++++++++++++++++++++++++++ agent/agent.go | 2 + agent/command/command.go | 54 ++++++++ agent/command/command_test.go | 65 ++++++++++ agent/input/discord/README.md | 22 ++++ agent/input/discord/conn.go | 94 ++++++++++++++ agent/input/discord/discord.go | 153 ++++++++++++++++++++++ agent/input/input.go | 55 ++++++++ agent/input/slack/conn.go | 160 +++++++++++++++++++++++ agent/input/slack/slack.go | 147 ++++++++++++++++++++++ agent/input/telegram/README.md | 18 +++ agent/input/telegram/conn.go | 115 +++++++++++++++++ agent/input/telegram/telegram.go | 101 +++++++++++++++ agent/proto/bot.micro.go | 118 +++++++++++++++++ agent/proto/bot.pb.go | 210 +++++++++++++++++++++++++++++++ agent/proto/bot.proto | 25 ++++ 17 files changed, 1543 insertions(+) create mode 100644 agent/.travis.yml create mode 100644 agent/README.md create mode 100644 agent/agent.go create mode 100644 agent/command/command.go create mode 100644 agent/command/command_test.go create mode 100644 agent/input/discord/README.md create mode 100644 agent/input/discord/conn.go create mode 100644 agent/input/discord/discord.go create mode 100644 agent/input/input.go create mode 100644 agent/input/slack/conn.go create mode 100644 agent/input/slack/slack.go create mode 100644 agent/input/telegram/README.md create mode 100644 agent/input/telegram/conn.go create mode 100644 agent/input/telegram/telegram.go create mode 100644 agent/proto/bot.micro.go create mode 100644 agent/proto/bot.pb.go create mode 100644 agent/proto/bot.proto diff --git a/agent/.travis.yml b/agent/.travis.yml new file mode 100644 index 00000000..60a31c5f --- /dev/null +++ b/agent/.travis.yml @@ -0,0 +1,7 @@ +language: go +go: +- 1.10.x +- 1.11.x +notifications: + slack: + secure: j+1gw9+LEu6GNisO18UoYOT8x9SGGoy57xJTmSQcWLGmhlcRwdvRzBJTdnZQ/sItokJSufW4K4cVZy4749fq7EaHqMtcuFkwju/i5EVOHliOlTqvo6bZaCThvuSfknBmHK0oU3u0DZBDAqR7BGTRztB+8A4gUNTVYumkP1sVWqoF8lvkM276Il1oprWeRyAdCpBNDuiUlMC0SpJmfUKrqpE64xe1iOCedPTPj7cbgnl35NBll0poXPIp/XNYn4ZsNP100vb5LSyvGHO5Z5XB3LZJit3wNWB3zI9y5Dr4d2EAV/c1VWqalbbT0/CLvSEnP++ubZhnK7sTMhgYxIlMtNTT/81MplVTeKcS+UFBw/aeTzrjhx6g5FNQiN2cnurs/O0Xwoq0Oh01l4uTIU4xUGQFtba/WFPDAO7cEWk8T1Z/fjkD22bDvkm3C2XXsA5nXeIjLhODKRV2fc5/Slxi2p5znhVRFukxnvPh0vVWh8yeukyjYjQXQ2n7Cl+UDBlggWGtRAYOnNo1uhLPShVoJwc/NjnRX5vJPbnjkASkEutqWAw/Rmwh+wx5+WNiYjo/VE8ZJPKyRK+0dQqhOrP73HWJxO9sMFucymeFVcxa4z3B7Nn7TBo1BhCyAdohT9V19gqfRO+TA8kifz8BF8jWBYUBOSQZrg92bYGkia3ROMs= diff --git a/agent/README.md b/agent/README.md new file mode 100644 index 00000000..bb6cba7c --- /dev/null +++ b/agent/README.md @@ -0,0 +1,197 @@ +# Agent + +Agent is a library used to create commands, inputs and robot services + +## Getting Started + +- [Commands](#commands) - Commands are functions executed by the bot based on text based pattern matching. +- [Inputs](#inputs) - Inputs are plugins for communication e.g Slack, Telegram, IRC, etc. +- [Services](#services) - Write bots as micro services + +## Commands + +Commands are functions executed by the bot based on text based pattern matching. + +### Write a Command + +```go +import "github.com/micro/go-bot/command" + +func Ping() command.Command { + usage := "ping" + description := "Returns pong" + + return command.NewCommand("ping", usage, desc, func(args ...string) ([]byte, error) { + return []byte("pong"), nil + }) +} +``` + +### Register the command + +Add the command to the Commands map with a pattern key that can be matched by golang/regexp.Match + +```go +import "github.com/micro/go-bot/command" + +func init() { + command.Commands["^ping$"] = Ping() +} +``` + +### Rebuild Micro + +Build binary +```shell +cd github.com/micro/micro + +// For local use +go build -i -o micro ./main.go + +// For docker image +CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -i -o micro ./main.go +``` + +## Inputs + +Inputs are plugins for communication e.g Slack, HipChat, XMPP, IRC, SMTP, etc, etc. + +New inputs can be added in the following way. + +### Write an Input + +Write an input that satisfies the Input interface. + +```go +type Input interface { + // Provide cli flags + Flags() []cli.Flag + // Initialise input using cli context + Init(*cli.Context) error + // Stream events from the input + Stream() (Conn, error) + // Start the input + Start() error + // Stop the input + Stop() error + // name of the input + String() string +} +``` + +### Register the input + +Add the input to the Inputs map. + +```go +import "github.com/micro/micro/bot/input" + +func init() { + input.Inputs["name"] = MyInput +} +``` + +### Rebuild Micro + +Build binary +```shell +cd github.com/micro/micro + +// For local use +go build -i -o micro ./main.go + +// For docker image +CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -i -o micro ./main.go +``` + +## Services + +The micro bot supports the ability to create commands as micro services. + +### How does it work? + +The bot watches the service registry for services with it's namespace. The default namespace is `go.micro.bot`. +Any service within this namespace will automatically be added to the list of available commands. When a command +is executed, the bot will call the service with method `Command.Exec`. It also expects the method `Command.Help` +to exist for usage info. + + +The service interface is as follows and can be found at [go-bot/proto](https://github.com/micro/go-bot/blob/master/proto/bot.proto) + +``` +syntax = "proto3"; + +package go.micro.bot; + +service Command { + rpc Help(HelpRequest) returns (HelpResponse) {}; + rpc Exec(ExecRequest) returns (ExecResponse) {}; +} + +message HelpRequest { +} + +message HelpResponse { + string usage = 1; + string description = 2; +} + +message ExecRequest { + repeated string args = 1; +} + +message ExecResponse { + bytes result = 1; + string error = 2; +} +``` + +### Example + +Here's an example echo command as a microservice + +```go +package main + +import ( + "fmt" + "strings" + + "github.com/micro/go-micro" + "golang.org/x/net/context" + + proto "github.com/micro/go-bot/proto" +) + +type Command struct{} + +// Help returns the command usage +func (c *Command) Help(ctx context.Context, req *proto.HelpRequest, rsp *proto.HelpResponse) error { + // Usage should include the name of the command + rsp.Usage = "echo" + rsp.Description = "This is an example bot command as a micro service which echos the message" + return nil +} + +// Exec executes the command +func (c *Command) Exec(ctx context.Context, req *proto.ExecRequest, rsp *proto.ExecResponse) error { + rsp.Result = []byte(strings.Join(req.Args, " ")) + // rsp.Error could be set to return an error instead + // the function error would only be used for service level issues + return nil +} + +func main() { + service := micro.NewService( + micro.Name("go.micro.bot.echo"), + ) + + service.Init() + + proto.RegisterCommandHandler(service.Server(), new(Command)) + + if err := service.Run(); err != nil { + fmt.Println(err) + } +} +``` diff --git a/agent/agent.go b/agent/agent.go new file mode 100644 index 00000000..359e8f71 --- /dev/null +++ b/agent/agent.go @@ -0,0 +1,2 @@ +// Package agent provides an interface for building robots +package agent diff --git a/agent/command/command.go b/agent/command/command.go new file mode 100644 index 00000000..92d670c8 --- /dev/null +++ b/agent/command/command.go @@ -0,0 +1,54 @@ +// Package command is an interface for defining bot commands +package command + +var ( + // Commmands keyed by golang/regexp patterns + // regexp.Match(key, input) is used to match + Commands = map[string]Command{} +) + +// Command is the interface for specific named +// commands executed via plugins or the bot. +type Command interface { + // Executes the command with args passed in + Exec(args ...string) ([]byte, error) + // Usage of the command + Usage() string + // Description of the command + Description() string + // Name of the command + String() string +} + +type cmd struct { + name string + usage string + description string + exec func(args ...string) ([]byte, error) +} + +func (c *cmd) Description() string { + return c.description +} + +func (c *cmd) Exec(args ...string) ([]byte, error) { + return c.exec(args...) +} + +func (c *cmd) Usage() string { + return c.usage +} + +func (c *cmd) String() string { + return c.name +} + +// NewCommand helps quickly create a new command +func NewCommand(name, usage, description string, exec func(args ...string) ([]byte, error)) Command { + return &cmd{ + name: name, + usage: usage, + description: description, + exec: exec, + } +} diff --git a/agent/command/command_test.go b/agent/command/command_test.go new file mode 100644 index 00000000..5f8c7cdc --- /dev/null +++ b/agent/command/command_test.go @@ -0,0 +1,65 @@ +package command + +import ( + "testing" +) + +func TestCommand(t *testing.T) { + c := &cmd{ + name: "test", + usage: "test usage", + description: "test description", + exec: func(args ...string) ([]byte, error) { + return []byte("test"), nil + }, + } + + if c.String() != c.name { + t.Fatalf("expected name %s got %s", c.name, c.String()) + } + + if c.Usage() != c.usage { + t.Fatalf("expected usage %s got %s", c.usage, c.Usage()) + } + + if c.Description() != c.description { + t.Fatalf("expected description %s got %s", c.description, c.Description()) + } + + if r, err := c.Exec(); err != nil { + t.Fatal(err) + } else if string(r) != "test" { + t.Fatalf("expected exec result test got %s", string(r)) + } +} + +func TestNewCommand(t *testing.T) { + c := &cmd{ + name: "test", + usage: "test usage", + description: "test description", + exec: func(args ...string) ([]byte, error) { + return []byte("test"), nil + }, + } + + nc := NewCommand(c.name, c.usage, c.description, c.exec) + + if nc.String() != c.name { + t.Fatalf("expected name %s got %s", c.name, nc.String()) + } + + if nc.Usage() != c.usage { + t.Fatalf("expected usage %s got %s", c.usage, nc.Usage()) + } + + if nc.Description() != c.description { + t.Fatalf("expected description %s got %s", c.description, nc.Description()) + } + + if r, err := nc.Exec(); err != nil { + t.Fatal(err) + } else if string(r) != "test" { + t.Fatalf("expected exec result test got %s", string(r)) + } +} diff --git a/agent/input/discord/README.md b/agent/input/discord/README.md new file mode 100644 index 00000000..7031f529 --- /dev/null +++ b/agent/input/discord/README.md @@ -0,0 +1,22 @@ +# Discord input for micro-bot +[Discord](https://discordapp.com) support for micro bot based on [discordgo](github.com/bwmarrin/discordgo). + +This was originally written by Aleksandr Tihomirov (@zet4) and can be found at https://github.com/zet4/micro-misc/. + +## Options +### discord_token + +You have to supply an application token via `--discord_token`. + +Head over to Discord's [developer introduction](https://discordapp.com/developers/docs/intro) +to learn how to create applications and how the API works. + +### discord_prefix + +Set a command prefix with `--discord_prefix`. The default prefix is `Micro `. +You can mention the bot or use the prefix to run a command. + +### discord_whitelist + +Pass a list of comma-separated user IDs with `--discord_whitelist`. Only allow +these users to use the bot. diff --git a/agent/input/discord/conn.go b/agent/input/discord/conn.go new file mode 100644 index 00000000..20a35af9 --- /dev/null +++ b/agent/input/discord/conn.go @@ -0,0 +1,94 @@ +package discord + +import ( + "errors" + "strings" + "sync" + + "github.com/bwmarrin/discordgo" + "github.com/micro/go-micro/agent/input" + "github.com/micro/go-log" +) + +type discordConn struct { + master *discordInput + exit chan struct{} + recv chan *discordgo.Message + + sync.Mutex +} + +func newConn(master *discordInput) *discordConn { + conn := &discordConn{ + master: master, + exit: make(chan struct{}), + recv: make(chan *discordgo.Message), + } + + conn.master.session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Author.ID == master.botID { + return + } + + whitelisted := false + for _, ID := range conn.master.whitelist { + if m.Author.ID == ID { + whitelisted = true + break + } + } + + if len(master.whitelist) > 0 && !whitelisted { + return + } + + var valid bool + m.Message.Content, valid = conn.master.prefixfn(m.Message.Content) + if !valid { + return + } + + conn.recv <- m.Message + }) + + return conn +} + +func (dc *discordConn) Recv(event *input.Event) error { + for { + select { + case <-dc.exit: + return errors.New("connection closed") + case msg := <-dc.recv: + + event.From = msg.ChannelID + ":" + msg.Author.ID + event.To = dc.master.botID + event.Type = input.TextEvent + event.Data = []byte(msg.Content) + return nil + } + } +} + +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) + } + return nil +} + +func (dc *discordConn) Close() error { + if err := dc.master.session.Close(); err != nil { + return err + } + + select { + case <-dc.exit: + return nil + default: + close(dc.exit) + } + return nil +} diff --git a/agent/input/discord/discord.go b/agent/input/discord/discord.go new file mode 100644 index 00000000..05eb816a --- /dev/null +++ b/agent/input/discord/discord.go @@ -0,0 +1,153 @@ +package discord + +import ( + "fmt" + "sync" + + "errors" + "strings" + + "github.com/bwmarrin/discordgo" + "github.com/micro/cli" + "github.com/micro/go-micro/agent/input" +) + +func init() { + input.Inputs["discord"] = newInput() +} + +func newInput() *discordInput { + return &discordInput{} +} + +type discordInput struct { + token string + whitelist []string + prefix string + prefixfn func(string) (string, bool) + botID string + + session *discordgo.Session + + sync.Mutex + running bool + exit chan struct{} +} + +func (d *discordInput) Flags() []cli.Flag { + return []cli.Flag{ + cli.StringFlag{ + Name: "discord_token", + EnvVar: "MICRO_DISCORD_TOKEN", + Usage: "Discord token (prefix with Bot if it's for bot account)", + }, + cli.StringFlag{ + Name: "discord_whitelist", + EnvVar: "MICRO_DISCORD_WHITELIST", + Usage: "Discord Whitelist (seperated by ,)", + }, + cli.StringFlag{ + Name: "discord_prefix", + Usage: "Discord Prefix", + EnvVar: "MICRO_DISCORD_PREFIX", + Value: "Micro ", + }, + } +} + +func (d *discordInput) Init(ctx *cli.Context) error { + token := ctx.String("discord_token") + whitelist := ctx.String("discord_whitelist") + prefix := ctx.String("discord_prefix") + + if len(token) == 0 { + return errors.New("require token") + } + + d.token = token + d.prefix = prefix + + if len(whitelist) > 0 { + d.whitelist = strings.Split(whitelist, ",") + } + + return nil +} + +func (d *discordInput) Start() error { + if len(d.token) == 0 { + return errors.New("missing discord configuration") + } + + d.Lock() + defer d.Unlock() + + if d.running { + return nil + } + + var err error + d.session, err = discordgo.New(d.token) + if err != nil { + return err + } + + u, err := d.session.User("@me") + if err != nil { + return err + } + + d.botID = u.ID + d.prefixfn = CheckPrefixFactory(fmt.Sprintf("<@%s> ", d.botID), fmt.Sprintf("<@!%s> ", d.botID), d.prefix) + + d.exit = make(chan struct{}) + d.running = true + + return nil +} + +func (d *discordInput) Stream() (input.Conn, error) { + d.Lock() + defer d.Unlock() + if !d.running { + return nil, errors.New("not running") + } + + //Fire-n-forget close just in case... + d.session.Close() + + conn := newConn(d) + if err := d.session.Open(); err != nil { + return nil, err + } + return conn, nil +} + +func (d *discordInput) Stop() error { + d.Lock() + defer d.Unlock() + + if !d.running { + return nil + } + + close(d.exit) + d.running = false + return nil +} + +func (d *discordInput) String() string { + return "discord" +} + +// CheckPrefixFactory Creates a prefix checking function and stuff. +func CheckPrefixFactory(prefixes ...string) func(string) (string, bool) { + return func(content string) (string, bool) { + for _, prefix := range prefixes { + if strings.HasPrefix(content, prefix) { + return strings.TrimPrefix(content, prefix), true + } + } + return "", false + } +} diff --git a/agent/input/input.go b/agent/input/input.go new file mode 100644 index 00000000..2b1d9aab --- /dev/null +++ b/agent/input/input.go @@ -0,0 +1,55 @@ +// Package input is an interface for bot inputs +package input + +import ( + "github.com/micro/cli" +) + +type EventType string + +const ( + TextEvent EventType = "text" +) + +var ( + // Inputs keyed by name + // Example slack or hipchat + Inputs = map[string]Input{} +) + +// Event is the unit sent and received +type Event struct { + Type EventType + From string + To string + Data []byte + Meta map[string]interface{} +} + +// Input is an interface for sources which +// provide a way to communicate with the bot. +// Slack, HipChat, XMPP, etc. +type Input interface { + // Provide cli flags + Flags() []cli.Flag + // Initialise input using cli context + Init(*cli.Context) error + // Stream events from the input + Stream() (Conn, error) + // Start the input + Start() error + // Stop the input + Stop() error + // name of the input + String() string +} + +// Conn interface provides a way to +// send and receive events. Send and +// Recv both block until succeeding +// or failing. +type Conn interface { + Close() error + Recv(*Event) error + Send(*Event) error +} diff --git a/agent/input/slack/conn.go b/agent/input/slack/conn.go new file mode 100644 index 00000000..ee640922 --- /dev/null +++ b/agent/input/slack/conn.go @@ -0,0 +1,160 @@ +package slack + +import ( + "errors" + "fmt" + "strings" + "sync" + "time" + + "github.com/micro/go-micro/agent/input" + "github.com/nlopes/slack" +) + +// Satisfies the input.Conn interface +type slackConn struct { + auth *slack.AuthTestResponse + rtm *slack.RTM + exit chan bool + + sync.Mutex + names map[string]string +} + +func (s *slackConn) run() { + // func retrieves user names and maps to IDs + setNames := func() { + names := make(map[string]string) + users, err := s.rtm.Client.GetUsers() + if err != nil { + return + } + + for _, user := range users { + names[user.ID] = user.Name + } + + s.Lock() + s.names = names + s.Unlock() + } + + setNames() + + t := time.NewTicker(time.Minute) + defer t.Stop() + + for { + select { + case <-s.exit: + return + case <-t.C: + setNames() + } + } +} + +func (s *slackConn) getName(id string) string { + s.Lock() + name := s.names[id] + s.Unlock() + return name +} + +func (s *slackConn) Close() error { + select { + case <-s.exit: + return nil + default: + close(s.exit) + } + return nil +} + +func (s *slackConn) Recv(event *input.Event) error { + if event == nil { + return errors.New("event cannot be nil") + } + + for { + select { + case <-s.exit: + return errors.New("connection closed") + case e := <-s.rtm.IncomingEvents: + switch ev := e.Data.(type) { + case *slack.MessageEvent: + // only accept type message + if ev.Type != "message" { + continue + } + + // only accept DMs or messages to me + switch { + case strings.HasPrefix(ev.Channel, "D"): + case strings.HasPrefix(ev.Text, s.auth.User): + case strings.HasPrefix(ev.Text, fmt.Sprintf("<@%s>", s.auth.UserID)): + default: + continue + } + + // Strip username from text + switch { + case strings.HasPrefix(ev.Text, s.auth.User): + args := strings.Split(ev.Text, " ")[1:] + ev.Text = strings.Join(args, " ") + event.To = s.auth.User + case strings.HasPrefix(ev.Text, fmt.Sprintf("<@%s>", s.auth.UserID)): + args := strings.Split(ev.Text, " ")[1:] + ev.Text = strings.Join(args, " ") + event.To = s.auth.UserID + } + + if event.Meta == nil { + event.Meta = make(map[string]interface{}) + } + + // fill in the blanks + event.From = ev.Channel + ":" + ev.User + event.Type = input.TextEvent + event.Data = []byte(ev.Text) + event.Meta["reply"] = ev + return nil + case *slack.InvalidAuthEvent: + return errors.New("invalid credentials") + } + } + } +} + +func (s *slackConn) Send(event *input.Event) error { + var channel, message, name string + + if len(event.To) == 0 { + return errors.New("require Event.To") + } + + parts := strings.Split(event.To, ":") + + if len(parts) == 2 { + channel = parts[0] + name = s.getName(parts[1]) + // try using reply meta + } else if ev, ok := event.Meta["reply"]; ok { + channel = ev.(*slack.MessageEvent).Channel + name = s.getName(ev.(*slack.MessageEvent).User) + } + + // don't know where to send the message + if len(channel) == 0 { + return errors.New("could not determine who message is to") + } + + if len(name) == 0 || strings.HasPrefix(channel, "D") { + message = string(event.Data) + } else { + message = fmt.Sprintf("@%s: %s", name, string(event.Data)) + } + + s.rtm.SendMessage(s.rtm.NewOutgoingMessage(message, channel)) + return nil +} diff --git a/agent/input/slack/slack.go b/agent/input/slack/slack.go new file mode 100644 index 00000000..9e67b2ed --- /dev/null +++ b/agent/input/slack/slack.go @@ -0,0 +1,147 @@ +package slack + +import ( + "errors" + "sync" + + "github.com/micro/cli" + "github.com/micro/go-micro/agent/input" + "github.com/nlopes/slack" +) + +type slackInput struct { + debug bool + token string + + sync.Mutex + running bool + exit chan bool + + api *slack.Client +} + +func init() { + input.Inputs["slack"] = NewInput() +} + +func (p *slackInput) Flags() []cli.Flag { + return []cli.Flag{ + cli.BoolFlag{ + Name: "slack_debug", + Usage: "Slack debug output", + EnvVar: "MICRO_SLACK_DEBUG", + }, + cli.StringFlag{ + Name: "slack_token", + Usage: "Slack token", + EnvVar: "MICRO_SLACK_TOKEN", + }, + } +} + +func (p *slackInput) Init(ctx *cli.Context) error { + debug := ctx.Bool("slack_debug") + token := ctx.String("slack_token") + + if len(token) == 0 { + return errors.New("missing slack token") + } + + p.debug = debug + p.token = token + + return nil +} + +func (p *slackInput) Stream() (input.Conn, error) { + p.Lock() + defer p.Unlock() + + if !p.running { + return nil, errors.New("not running") + } + + // test auth + auth, err := p.api.AuthTest() + if err != nil { + return nil, err + } + + rtm := p.api.NewRTM() + exit := make(chan bool) + + go rtm.ManageConnection() + + go func() { + select { + case <-p.exit: + select { + case <-exit: + return + default: + close(exit) + } + case <-exit: + } + + rtm.Disconnect() + }() + + conn := &slackConn{ + auth: auth, + rtm: rtm, + exit: exit, + names: make(map[string]string), + } + + go conn.run() + + return conn, nil +} + +func (p *slackInput) Start() error { + if len(p.token) == 0 { + return errors.New("missing slack token") + } + + p.Lock() + defer p.Unlock() + + if p.running { + return nil + } + + api := slack.New(p.token, slack.OptionDebug(p.debug)) + + // test auth + _, err := api.AuthTest() + if err != nil { + return err + } + + p.api = api + p.exit = make(chan bool) + p.running = true + return nil +} + +func (p *slackInput) Stop() error { + p.Lock() + defer p.Unlock() + + if !p.running { + return nil + } + + close(p.exit) + p.running = false + return nil +} + +func (p *slackInput) String() string { + return "slack" +} + +func NewInput() input.Input { + return &slackInput{} +} diff --git a/agent/input/telegram/README.md b/agent/input/telegram/README.md new file mode 100644 index 00000000..c68cdeca --- /dev/null +++ b/agent/input/telegram/README.md @@ -0,0 +1,18 @@ +# Telegram Messenger input for micro bot +[Telegram](https://telegram.org) support for micro bot based on [telegram-bot-api](https://github.com/go-telegram-bot-api/telegram-bot-api). + +## Options +### --telegram_token (required) + +Sets bot's token for interacting with API. + +Head over to Telegram's [API documentation](https://core.telegram.org/bots/api) +to learn how to create bots and how the API works. + +### --telegram_debug + +Sets the debug flag to make the bot's output verbose. + +### --telegram_whitelist + +Sets a list of comma-separated nicknames (without @ symbol in the beginning) for interacting with bot. Only these users can use the bot. diff --git a/agent/input/telegram/conn.go b/agent/input/telegram/conn.go new file mode 100644 index 00000000..99311f4c --- /dev/null +++ b/agent/input/telegram/conn.go @@ -0,0 +1,115 @@ +package telegram + +import ( + "errors" + "strings" + "sync" + + "github.com/forestgiant/sliceutil" + "github.com/micro/go-micro/agent/input" + "github.com/micro/go-log" + "gopkg.in/telegram-bot-api.v4" +) + +type telegramConn struct { + input *telegramInput + + recv <-chan tgbotapi.Update + exit chan bool + + syncCond *sync.Cond + mutex sync.Mutex +} + +func newConn(input *telegramInput) (*telegramConn, error) { + conn := &telegramConn{ + input: input, + } + + conn.syncCond = sync.NewCond(&conn.mutex) + + go conn.run() + + return conn, nil +} + +func (tc *telegramConn) run() { + u := tgbotapi.NewUpdate(0) + u.Timeout = 60 + updates, err := tc.input.api.GetUpdatesChan(u) + if err != nil { + return + } + + tc.recv = updates + tc.syncCond.Signal() + + for { + select { + case <-tc.exit: + return + } + } +} + +func (tc *telegramConn) Close() error { + return nil +} + +func (tc *telegramConn) Recv(event *input.Event) error { + if event == nil { + return errors.New("event cannot be nil") + } + + for { + if tc.recv == nil { + tc.mutex.Lock() + tc.syncCond.Wait() + } + + update := <-tc.recv + + if update.Message == nil || (len(tc.input.whitelist) > 0 && !sliceutil.Contains(tc.input.whitelist, update.Message.From.UserName)) { + continue + } + + if event.Meta == nil { + event.Meta = make(map[string]interface{}) + } + + event.Type = input.TextEvent + event.From = update.Message.From.UserName + event.To = tc.input.api.Self.UserName + event.Data = []byte(update.Message.Text) + event.Meta["chatId"] = update.Message.Chat.ID + event.Meta["chatType"] = update.Message.Chat.Type + event.Meta["messageId"] = update.Message.MessageID + + return nil + } +} + +func (tc *telegramConn) Send(event *input.Event) error { + messageText := strings.TrimSpace(string(event.Data)) + + chatId := event.Meta["chatId"].(int64) + chatType := ChatType(event.Meta["chatType"].(string)) + + msgConfig := tgbotapi.NewMessage(chatId, messageText) + msgConfig.ParseMode = tgbotapi.ModeHTML + + if sliceutil.Contains([]ChatType{Group, Supergroup}, chatType) { + msgConfig.ReplyToMessageID = event.Meta["messageId"].(int) + } + + _, err := tc.input.api.Send(msgConfig) + + if err != nil { + // probably it could be because of nested HTML tags -- telegram doesn't allow nested tags + log.Log("[telegram][Send] error:", err) + msgConfig.Text = "This bot couldn't send the response (Internal error)" + tc.input.api.Send(msgConfig) + } + + return nil +} diff --git a/agent/input/telegram/telegram.go b/agent/input/telegram/telegram.go new file mode 100644 index 00000000..87566e4e --- /dev/null +++ b/agent/input/telegram/telegram.go @@ -0,0 +1,101 @@ +package telegram + +import ( + "errors" + "strings" + "sync" + + "github.com/micro/cli" + "github.com/micro/go-micro/agent/input" + "gopkg.in/telegram-bot-api.v4" +) + +type telegramInput struct { + sync.Mutex + + debug bool + token string + whitelist []string + + api *tgbotapi.BotAPI +} + +type ChatType string + +const ( + Private ChatType = "private" + Group ChatType = "group" + Supergroup ChatType = "supergroup" +) + +func init() { + input.Inputs["telegram"] = &telegramInput{} +} + +func (ti *telegramInput) Flags() []cli.Flag { + return []cli.Flag{ + cli.BoolFlag{ + Name: "telegram_debug", + EnvVar: "MICRO_TELEGRAM_DEBUG", + Usage: "Telegram debug output", + }, + cli.StringFlag{ + Name: "telegram_token", + EnvVar: "MICRO_TELEGRAM_TOKEN", + Usage: "Telegram token", + }, + cli.StringFlag{ + Name: "telegram_whitelist", + EnvVar: "MICRO_TELEGRAM_WHITELIST", + Usage: "Telegram bot's users (comma-separated values)", + }, + } +} + +func (ti *telegramInput) Init(ctx *cli.Context) error { + ti.debug = ctx.Bool("telegram_debug") + ti.token = ctx.String("telegram_token") + + whitelist := ctx.String("telegram_whitelist") + + if whitelist != "" { + ti.whitelist = strings.Split(whitelist, ",") + } + + if len(ti.token) == 0 { + return errors.New("missing telegram token") + } + + return nil +} + +func (ti *telegramInput) Stream() (input.Conn, error) { + ti.Lock() + defer ti.Unlock() + + return newConn(ti) +} + +func (ti *telegramInput) Start() error { + ti.Lock() + defer ti.Unlock() + + api, err := tgbotapi.NewBotAPI(ti.token) + if err != nil { + return err + } + + ti.api = api + + api.Debug = ti.debug + + return nil +} + +func (ti *telegramInput) Stop() error { + return nil +} + +func (p *telegramInput) String() string { + return "telegram" +} diff --git a/agent/proto/bot.micro.go b/agent/proto/bot.micro.go new file mode 100644 index 00000000..2bac4842 --- /dev/null +++ b/agent/proto/bot.micro.go @@ -0,0 +1,118 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: github.com/micro/go-bot/proto/bot.proto + +/* +Package go_micro_bot is a generated protocol buffer package. + +It is generated from these files: + github.com/micro/go-bot/proto/bot.proto + +It has these top-level messages: + HelpRequest + HelpResponse + ExecRequest + ExecResponse +*/ +package go_micro_bot + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + client "github.com/micro/go-micro/client" + server "github.com/micro/go-micro/server" + context "context" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ client.Option +var _ server.Option + +// Client API for Command service + +type CommandService interface { + Help(ctx context.Context, in *HelpRequest, opts ...client.CallOption) (*HelpResponse, error) + Exec(ctx context.Context, in *ExecRequest, opts ...client.CallOption) (*ExecResponse, error) +} + +type commandService struct { + c client.Client + name string +} + +func NewCommandService(name string, c client.Client) CommandService { + if c == nil { + c = client.NewClient() + } + if len(name) == 0 { + name = "go.micro.bot" + } + return &commandService{ + c: c, + name: name, + } +} + +func (c *commandService) Help(ctx context.Context, in *HelpRequest, opts ...client.CallOption) (*HelpResponse, error) { + req := c.c.NewRequest(c.name, "Command.Help", in) + out := new(HelpResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *commandService) Exec(ctx context.Context, in *ExecRequest, opts ...client.CallOption) (*ExecResponse, error) { + req := c.c.NewRequest(c.name, "Command.Exec", in) + out := new(ExecResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Command service + +type CommandHandler interface { + Help(context.Context, *HelpRequest, *HelpResponse) error + Exec(context.Context, *ExecRequest, *ExecResponse) error +} + +func RegisterCommandHandler(s server.Server, hdlr CommandHandler, opts ...server.HandlerOption) error { + type _command interface { + Help(ctx context.Context, in *HelpRequest, out *HelpResponse) error + Exec(ctx context.Context, in *ExecRequest, out *ExecResponse) error + } + type Command struct { + _command + } + h := &commandHandler{hdlr} + return s.Handle(s.NewHandler(&Command{h}, opts...)) +} + +type commandHandler struct { + CommandHandler +} + +func (h *commandHandler) Help(ctx context.Context, in *HelpRequest, out *HelpResponse) error { + return h.CommandHandler.Help(ctx, in, out) +} + +func (h *commandHandler) Exec(ctx context.Context, in *ExecRequest, out *ExecResponse) error { + return h.CommandHandler.Exec(ctx, in, out) +} diff --git a/agent/proto/bot.pb.go b/agent/proto/bot.pb.go new file mode 100644 index 00000000..f36d9f4a --- /dev/null +++ b/agent/proto/bot.pb.go @@ -0,0 +1,210 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: github.com/micro/go-bot/proto/bot.proto + +package go_micro_bot + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type HelpRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HelpRequest) Reset() { *m = HelpRequest{} } +func (m *HelpRequest) String() string { return proto.CompactTextString(m) } +func (*HelpRequest) ProtoMessage() {} +func (*HelpRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_bot_654832eab83ed4b5, []int{0} +} +func (m *HelpRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HelpRequest.Unmarshal(m, b) +} +func (m *HelpRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HelpRequest.Marshal(b, m, deterministic) +} +func (dst *HelpRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_HelpRequest.Merge(dst, src) +} +func (m *HelpRequest) XXX_Size() int { + return xxx_messageInfo_HelpRequest.Size(m) +} +func (m *HelpRequest) XXX_DiscardUnknown() { + xxx_messageInfo_HelpRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_HelpRequest proto.InternalMessageInfo + +type HelpResponse struct { + Usage string `protobuf:"bytes,1,opt,name=usage,proto3" json:"usage,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HelpResponse) Reset() { *m = HelpResponse{} } +func (m *HelpResponse) String() string { return proto.CompactTextString(m) } +func (*HelpResponse) ProtoMessage() {} +func (*HelpResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bot_654832eab83ed4b5, []int{1} +} +func (m *HelpResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HelpResponse.Unmarshal(m, b) +} +func (m *HelpResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HelpResponse.Marshal(b, m, deterministic) +} +func (dst *HelpResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_HelpResponse.Merge(dst, src) +} +func (m *HelpResponse) XXX_Size() int { + return xxx_messageInfo_HelpResponse.Size(m) +} +func (m *HelpResponse) XXX_DiscardUnknown() { + xxx_messageInfo_HelpResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_HelpResponse proto.InternalMessageInfo + +func (m *HelpResponse) GetUsage() string { + if m != nil { + return m.Usage + } + return "" +} + +func (m *HelpResponse) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +type ExecRequest struct { + Args []string `protobuf:"bytes,1,rep,name=args,proto3" json:"args,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecRequest) Reset() { *m = ExecRequest{} } +func (m *ExecRequest) String() string { return proto.CompactTextString(m) } +func (*ExecRequest) ProtoMessage() {} +func (*ExecRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_bot_654832eab83ed4b5, []int{2} +} +func (m *ExecRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ExecRequest.Unmarshal(m, b) +} +func (m *ExecRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ExecRequest.Marshal(b, m, deterministic) +} +func (dst *ExecRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecRequest.Merge(dst, src) +} +func (m *ExecRequest) XXX_Size() int { + return xxx_messageInfo_ExecRequest.Size(m) +} +func (m *ExecRequest) XXX_DiscardUnknown() { + xxx_messageInfo_ExecRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_ExecRequest proto.InternalMessageInfo + +func (m *ExecRequest) GetArgs() []string { + if m != nil { + return m.Args + } + return nil +} + +type ExecResponse struct { + Result []byte `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExecResponse) Reset() { *m = ExecResponse{} } +func (m *ExecResponse) String() string { return proto.CompactTextString(m) } +func (*ExecResponse) ProtoMessage() {} +func (*ExecResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bot_654832eab83ed4b5, []int{3} +} +func (m *ExecResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ExecResponse.Unmarshal(m, b) +} +func (m *ExecResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ExecResponse.Marshal(b, m, deterministic) +} +func (dst *ExecResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecResponse.Merge(dst, src) +} +func (m *ExecResponse) XXX_Size() int { + return xxx_messageInfo_ExecResponse.Size(m) +} +func (m *ExecResponse) XXX_DiscardUnknown() { + xxx_messageInfo_ExecResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_ExecResponse proto.InternalMessageInfo + +func (m *ExecResponse) GetResult() []byte { + if m != nil { + return m.Result + } + return nil +} + +func (m *ExecResponse) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +func init() { + proto.RegisterType((*HelpRequest)(nil), "go.micro.bot.HelpRequest") + proto.RegisterType((*HelpResponse)(nil), "go.micro.bot.HelpResponse") + proto.RegisterType((*ExecRequest)(nil), "go.micro.bot.ExecRequest") + proto.RegisterType((*ExecResponse)(nil), "go.micro.bot.ExecResponse") +} + +func init() { + proto.RegisterFile("github.com/micro/go-bot/proto/bot.proto", fileDescriptor_bot_654832eab83ed4b5) +} + +var fileDescriptor_bot_654832eab83ed4b5 = []byte{ + // 246 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0x41, 0x4b, 0xc4, 0x30, + 0x10, 0x85, 0xb7, 0xba, 0xae, 0xec, 0xb4, 0x5e, 0x82, 0x48, 0xdd, 0x53, 0xcd, 0xc5, 0xbd, 0x98, + 0x82, 0x5e, 0x05, 0x0f, 0xa2, 0x78, 0xee, 0x3f, 0x68, 0xba, 0x43, 0x2c, 0x6c, 0x3b, 0x35, 0x99, + 0x82, 0xff, 0xc1, 0x3f, 0x2d, 0x4d, 0x72, 0x08, 0xcb, 0xde, 0xe6, 0x65, 0x86, 0xf7, 0xbe, 0x17, + 0x78, 0x34, 0x3d, 0x7f, 0xcf, 0x5a, 0x75, 0x34, 0xd4, 0x43, 0xdf, 0x59, 0xaa, 0x0d, 0x3d, 0x69, + 0xe2, 0x7a, 0xb2, 0xc4, 0x54, 0x6b, 0x62, 0xe5, 0x27, 0x51, 0x18, 0x52, 0xfe, 0x40, 0x69, 0x62, + 0x79, 0x03, 0xf9, 0x17, 0x1e, 0xa7, 0x06, 0x7f, 0x66, 0x74, 0x2c, 0x3f, 0xa1, 0x08, 0xd2, 0x4d, + 0x34, 0x3a, 0x14, 0xb7, 0x70, 0x35, 0xbb, 0xd6, 0x60, 0x99, 0x55, 0xd9, 0x7e, 0xdb, 0x04, 0x21, + 0x2a, 0xc8, 0x0f, 0xe8, 0x3a, 0xdb, 0x4f, 0xdc, 0xd3, 0x58, 0x5e, 0xf8, 0x5d, 0xfa, 0x24, 0x1f, + 0x20, 0xff, 0xf8, 0xc5, 0x2e, 0xda, 0x0a, 0x01, 0xeb, 0xd6, 0x1a, 0x57, 0x66, 0xd5, 0xe5, 0x7e, + 0xdb, 0xf8, 0x59, 0xbe, 0x42, 0x11, 0x4e, 0x62, 0xd4, 0x1d, 0x6c, 0x2c, 0xba, 0xf9, 0xc8, 0x3e, + 0xab, 0x68, 0xa2, 0x5a, 0x10, 0xd0, 0x5a, 0xb2, 0x31, 0x26, 0x88, 0xe7, 0xbf, 0x0c, 0xae, 0xdf, + 0x69, 0x18, 0xda, 0xf1, 0x20, 0xde, 0x60, 0xbd, 0x40, 0x8b, 0x7b, 0x95, 0x56, 0x53, 0x49, 0xaf, + 0xdd, 0xee, 0xdc, 0x2a, 0x04, 0xcb, 0xd5, 0x62, 0xb0, 0xa0, 0x9c, 0x1a, 0x24, 0x0d, 0x4e, 0x0d, + 0x52, 0x72, 0xb9, 0xd2, 0x1b, 0xff, 0xb5, 0x2f, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x77, + 0xdf, 0x28, 0x85, 0x01, 0x00, 0x00, +} diff --git a/agent/proto/bot.proto b/agent/proto/bot.proto new file mode 100644 index 00000000..0f808615 --- /dev/null +++ b/agent/proto/bot.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package go.micro.bot; + +service Command { + rpc Help(HelpRequest) returns (HelpResponse) {}; + rpc Exec(ExecRequest) returns (ExecResponse) {}; +} + +message HelpRequest { +} + +message HelpResponse { + string usage = 1; + string description = 2; +} + +message ExecRequest { + repeated string args = 1; +} + +message ExecResponse { + bytes result = 1; + string error = 2; +} From ddd08377e6e4c0dbaca908c5cdf017e8de4b47f0 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 00:19:05 +0100 Subject: [PATCH 05/18] remove travis file from agent --- agent/.travis.yml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 agent/.travis.yml diff --git a/agent/.travis.yml b/agent/.travis.yml deleted file mode 100644 index 60a31c5f..00000000 --- a/agent/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go -go: -- 1.10.x -- 1.11.x -notifications: - slack: - secure: j+1gw9+LEu6GNisO18UoYOT8x9SGGoy57xJTmSQcWLGmhlcRwdvRzBJTdnZQ/sItokJSufW4K4cVZy4749fq7EaHqMtcuFkwju/i5EVOHliOlTqvo6bZaCThvuSfknBmHK0oU3u0DZBDAqR7BGTRztB+8A4gUNTVYumkP1sVWqoF8lvkM276Il1oprWeRyAdCpBNDuiUlMC0SpJmfUKrqpE64xe1iOCedPTPj7cbgnl35NBll0poXPIp/XNYn4ZsNP100vb5LSyvGHO5Z5XB3LZJit3wNWB3zI9y5Dr4d2EAV/c1VWqalbbT0/CLvSEnP++ubZhnK7sTMhgYxIlMtNTT/81MplVTeKcS+UFBw/aeTzrjhx6g5FNQiN2cnurs/O0Xwoq0Oh01l4uTIU4xUGQFtba/WFPDAO7cEWk8T1Z/fjkD22bDvkm3C2XXsA5nXeIjLhODKRV2fc5/Slxi2p5znhVRFukxnvPh0vVWh8yeukyjYjQXQ2n7Cl+UDBlggWGtRAYOnNo1uhLPShVoJwc/NjnRX5vJPbnjkASkEutqWAw/Rmwh+wx5+WNiYjo/VE8ZJPKyRK+0dQqhOrP73HWJxO9sMFucymeFVcxa4z3B7Nn7TBo1BhCyAdohT9V19gqfRO+TA8kifz8BF8jWBYUBOSQZrg92bYGkia3ROMs= From a353c83f4710d80184f172b3f3c2332cb5c46829 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 00:22:43 +0100 Subject: [PATCH 06/18] Add rcache => cache --- registry/cache/README.md | 31 +++ registry/cache/options.go | 12 ++ registry/cache/rcache.go | 429 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 472 insertions(+) create mode 100644 registry/cache/README.md create mode 100644 registry/cache/options.go create mode 100644 registry/cache/rcache.go diff --git a/registry/cache/README.md b/registry/cache/README.md new file mode 100644 index 00000000..1c2d6e90 --- /dev/null +++ b/registry/cache/README.md @@ -0,0 +1,31 @@ +# Registry Cache + +Cache is a library that provides a caching layer for the go-micro [registry](https://godoc.org/github.com/micro/go-micro/registry#Registry). + +If you're looking for caching in your microservices use the [selector](https://micro.mu/docs/fault-tolerance.html#caching-discovery). + +## Interface + +``` +// Cache is the registry cache interface +type Cache interface { + // embed the registry interface + registry.Registry + // stop the cache watcher + Stop() +} +``` + +## Usage + +``` +import ( + "github.com/micro/go-micro/registry" + "github.com/micro/go-micro/registry/cache" +) + +r := registry.NewRegistry() +cache := cache.New(r) + +services, _ := cache.GetService("my.service") +``` diff --git a/registry/cache/options.go b/registry/cache/options.go new file mode 100644 index 00000000..284721a9 --- /dev/null +++ b/registry/cache/options.go @@ -0,0 +1,12 @@ +package cache + +import ( + "time" +) + +// WithTTL sets the cache TTL +func WithTTL(t time.Duration) Option { + return func(o *Options) { + o.TTL = t + } +} diff --git a/registry/cache/rcache.go b/registry/cache/rcache.go new file mode 100644 index 00000000..53b11576 --- /dev/null +++ b/registry/cache/rcache.go @@ -0,0 +1,429 @@ +// Package cache provides a registry cache +package cache + +import ( + "math" + "math/rand" + "sync" + "time" + + log "github.com/micro/go-log" + "github.com/micro/go-micro/registry" +) + +// Cache is the registry cache interface +type Cache interface { + // embed the registry interface + registry.Registry + // stop the cache watcher + Stop() +} + +type Options struct { + // TTL is the cache TTL + TTL time.Duration +} + +type Option func(o *Options) + +type cache struct { + registry.Registry + opts Options + + // registry cache + sync.RWMutex + cache map[string][]*registry.Service + ttls map[string]time.Time + watched map[string]bool + + exit chan bool +} + +var ( + DefaultTTL = time.Minute +) + +func backoff(attempts int) time.Duration { + if attempts == 0 { + return time.Duration(0) + } + return time.Duration(math.Pow(10, float64(attempts))) * time.Millisecond +} + +// isValid checks if the service is valid +func (c *cache) isValid(services []*registry.Service, ttl time.Time) bool { + // no services exist + if len(services) == 0 { + return false + } + + // ttl is invalid + if ttl.IsZero() { + return false + } + + // time since ttl is longer than timeout + if time.Since(ttl) > c.opts.TTL { + return false + } + + // ok + return true +} + +func (c *cache) quit() bool { + select { + case <-c.exit: + return true + default: + return false + } +} + +// cp copies a service. Because we're caching handing back pointers would +// create a race condition, so we do this instead its fast enough +func (c *cache) cp(current []*registry.Service) []*registry.Service { + var services []*registry.Service + + for _, service := range current { + // copy service + s := new(registry.Service) + *s = *service + + // copy nodes + var nodes []*registry.Node + for _, node := range service.Nodes { + n := new(registry.Node) + *n = *node + nodes = append(nodes, n) + } + s.Nodes = nodes + + // copy endpoints + var eps []*registry.Endpoint + for _, ep := range service.Endpoints { + e := new(registry.Endpoint) + *e = *ep + eps = append(eps, e) + } + s.Endpoints = eps + + // append service + services = append(services, s) + } + + return services +} + +func (c *cache) del(service string) { + delete(c.cache, service) + delete(c.ttls, service) +} + +func (c *cache) get(service string) ([]*registry.Service, error) { + // read lock + c.RLock() + + // check the cache first + services := c.cache[service] + // get cache ttl + ttl := c.ttls[service] + + // got services && within ttl so return cache + if c.isValid(services, ttl) { + // make a copy + cp := c.cp(services) + // unlock the read + c.RUnlock() + // return servics + return cp, nil + } + + // get does the actual request for a service and cache it + get := func(service string) ([]*registry.Service, error) { + // ask the registry + services, err := c.Registry.GetService(service) + if err != nil { + return nil, err + } + + // cache results + c.Lock() + c.set(service, c.cp(services)) + c.Unlock() + + return services, nil + } + + // watch service if not watched + if _, ok := c.watched[service]; !ok { + go c.run(service) + } + + // unlock the read lock + c.RUnlock() + + // get and return services + return get(service) +} + +func (c *cache) set(service string, services []*registry.Service) { + c.cache[service] = services + c.ttls[service] = time.Now().Add(c.opts.TTL) +} + +func (c *cache) update(res *registry.Result) { + if res == nil || res.Service == nil { + return + } + + c.Lock() + defer c.Unlock() + + services, ok := c.cache[res.Service.Name] + if !ok { + // we're not going to cache anything + // unless there was already a lookup + return + } + + if len(res.Service.Nodes) == 0 { + switch res.Action { + case "delete": + c.del(res.Service.Name) + } + return + } + + // existing service found + var service *registry.Service + var index int + for i, s := range services { + if s.Version == res.Service.Version { + service = s + index = i + } + } + + switch res.Action { + case "create", "update": + if service == nil { + c.set(res.Service.Name, append(services, res.Service)) + return + } + + // append old nodes to new service + for _, cur := range service.Nodes { + var seen bool + for _, node := range res.Service.Nodes { + if cur.Id == node.Id { + seen = true + break + } + } + if !seen { + res.Service.Nodes = append(res.Service.Nodes, cur) + } + } + + services[index] = res.Service + c.set(res.Service.Name, services) + case "delete": + if service == nil { + return + } + + var nodes []*registry.Node + + // filter cur nodes to remove the dead one + for _, cur := range service.Nodes { + var seen bool + for _, del := range res.Service.Nodes { + if del.Id == cur.Id { + seen = true + break + } + } + if !seen { + nodes = append(nodes, cur) + } + } + + // still got nodes, save and return + if len(nodes) > 0 { + service.Nodes = nodes + services[index] = service + c.set(service.Name, services) + return + } + + // zero nodes left + + // only have one thing to delete + // nuke the thing + if len(services) == 1 { + c.del(service.Name) + return + } + + // still have more than 1 service + // check the version and keep what we know + var srvs []*registry.Service + for _, s := range services { + if s.Version != service.Version { + srvs = append(srvs, s) + } + } + + // save + c.set(service.Name, srvs) + } +} + +// run starts the cache watcher loop +// it creates a new watcher if there's a problem +func (c *cache) run(service string) { + // set watcher + c.Lock() + c.watched[service] = true + c.Unlock() + + // delete watcher on exit + defer func() { + c.Lock() + delete(c.watched, service) + c.Unlock() + }() + + var a, b int + + for { + // exit early if already dead + if c.quit() { + return + } + + // jitter before starting + j := rand.Int63n(100) + time.Sleep(time.Duration(j) * time.Millisecond) + + // create new watcher + w, err := c.Registry.Watch( + registry.WatchService(service), + ) + + if err != nil { + if c.quit() { + return + } + + d := backoff(a) + + if a > 3 { + log.Log("rcache: ", err, " backing off ", d) + a = 0 + } + + time.Sleep(d) + a++ + + continue + } + + // reset a + a = 0 + + // watch for events + if err := c.watch(w); err != nil { + if c.quit() { + return + } + + d := backoff(b) + + if b > 3 { + log.Log("rcache: ", err, " backing off ", d) + b = 0 + } + + time.Sleep(d) + b++ + + continue + } + + // reset b + b = 0 + } +} + +// watch loops the next event and calls update +// it returns if there's an error +func (c *cache) watch(w registry.Watcher) error { + defer w.Stop() + + // manage this loop + go func() { + // wait for exit + <-c.exit + w.Stop() + }() + + for { + res, err := w.Next() + if err != nil { + return err + } + c.update(res) + } +} + +func (c *cache) GetService(service string) ([]*registry.Service, error) { + // get the service + services, err := c.get(service) + if err != nil { + return nil, err + } + + // if there's nothing return err + if len(services) == 0 { + return nil, registry.ErrNotFound + } + + // return services + return services, nil +} + +func (c *cache) Stop() { + select { + case <-c.exit: + return + default: + close(c.exit) + } +} + +func (c *cache) String() string { + return "rcache" +} + +// New returns a new cache +func New(r registry.Registry, opts ...Option) Cache { + rand.Seed(time.Now().UnixNano()) + options := Options{ + TTL: DefaultTTL, + } + + for _, o := range opts { + o(&options) + } + + return &cache{ + Registry: r, + opts: options, + watched: make(map[string]bool), + cache: make(map[string][]*registry.Service), + ttls: make(map[string]time.Time), + exit: make(chan bool), + } +} From c567d1ceb31f3129cc958b2887cf231acc680742 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 00:26:34 +0100 Subject: [PATCH 07/18] Add runtime => run --- runtime/.travis.yml | 7 +++ runtime/README.md | 28 ++++++++++ runtime/package/docker/docker.go | 93 ++++++++++++++++++++++++++++++++ runtime/package/go/golang.go | 70 ++++++++++++++++++++++++ runtime/package/options.go | 15 ++++++ runtime/package/package.go | 34 ++++++++++++ runtime/process/options.go | 5 ++ runtime/process/os/os.go | 86 +++++++++++++++++++++++++++++ runtime/process/process.go | 37 +++++++++++++ runtime/source/git/git.go | 87 ++++++++++++++++++++++++++++++ runtime/source/go/golang.go | 93 ++++++++++++++++++++++++++++++++ runtime/source/options.go | 15 ++++++ runtime/source/source.go | 22 ++++++++ 13 files changed, 592 insertions(+) create mode 100644 runtime/.travis.yml create mode 100644 runtime/README.md create mode 100644 runtime/package/docker/docker.go create mode 100644 runtime/package/go/golang.go create mode 100644 runtime/package/options.go create mode 100644 runtime/package/package.go create mode 100644 runtime/process/options.go create mode 100644 runtime/process/os/os.go create mode 100644 runtime/process/process.go create mode 100644 runtime/source/git/git.go create mode 100644 runtime/source/go/golang.go create mode 100644 runtime/source/options.go create mode 100644 runtime/source/source.go diff --git a/runtime/.travis.yml b/runtime/.travis.yml new file mode 100644 index 00000000..1dbeee0b --- /dev/null +++ b/runtime/.travis.yml @@ -0,0 +1,7 @@ +language: go +go: +- 1.9.4 +- 1.10.x +notifications: + slack: + secure: fQJsxnChA2JDbdNti8cLiBlVj/ws38vaLyDJzkM+jhrU8NmdPbnjYu99lauDak0Yy9qdLNYUUO1KP6Kn8gl5VcbdC0++T3jPNCgIkJpvm/DJZKKtWlDXCavCDZ3EtCv8IhviD2dguHGtcX08/G6zc9V44GQu3sPWDdGdYnplh7OBIvicJZ5v8o6TR/WZ/4waGCLxeR84fIamXcZTlHGk3hJMKqCsb6urJX42rOlfSgjourb1yu8Tyg8uTXsO3Z7fgiZ73mYvZ1iD1v5thHB8T6bfB4g3U3KE53IjV9oV9bL6iDoiHbPWTIHD6yaZKXDbMxyw/sZ70GgxXH795pJeVBAWv9X6nH+aemwR72kgszvDLq64jxeAqJAmK5OqRs0YSQMKmvceSCIbEptCnpdl0KhhDZg/ojsfJOHyJb/SrEcntuvvig7O3Qyp9OtJdXJa5JnXi7Z2tPDXy+QnL/WSXUHU7JnDfQeQJC6QawxVGllxECcStIVb2/FrT0wnEinS66uhQhW48zLFcbJIFYNVsTlCMkTjXBkSvbjn3qSQr9IaMvpmDXhp9EC99Y5DgkPFP0S7aGjPCxfgrMHxqyxeEwmJQ+vYO6sZxnZbOzUMYVgPdAptQJ30QjovoF3lcQoBnZjvoKdunKE4qvSFYsMlxDV0SJhS5bc+eIXNIN5jYE8= diff --git a/runtime/README.md b/runtime/README.md new file mode 100644 index 00000000..600bdceb --- /dev/null +++ b/runtime/README.md @@ -0,0 +1,28 @@ +# Runtime + +A runtime for self governing services. + +## Overview + +In recent years we've started to develop complex architectures for the pipeline between writing code and running it. This +philosophy of build, run, manage or however many variations, has created a number of layers of abstraction that make it +all the more difficult to run code. + +Runtime manages the lifecycle of a service from source to running process. If the source is the *source of truth* then +everything in between running is wasted breath. Applications should be self governing and self sustaining. +To enable that we need libraries which make it possible. + +Runtime will fetch source code, build a binary and execute it. Any Go program that uses this library should be able +to run dependencies or itself with ease, with the ability to update itself as the source is updated. + +## Features + +- **Source** - Fetches source whether it be git, go, docker, etc +- **Package** - Compiles the source into a binary which can be executed +- **Process** - Executes a binary and creates a running process + +## Usage + +TODO + + diff --git a/runtime/package/docker/docker.go b/runtime/package/docker/docker.go new file mode 100644 index 00000000..e53010e5 --- /dev/null +++ b/runtime/package/docker/docker.go @@ -0,0 +1,93 @@ +// Package docker builds docker images +package docker + +import ( + "archive/tar" + "bytes" + "io/ioutil" + "os" + "path/filepath" + + "github.com/fsouza/go-dockerclient" + "github.com/micro/go-log" + "github.com/micro/go-run/package" +) + +type Packager struct { + Options packager.Options + Client *docker.Client +} + +func (d *Packager) Compile(s *packager.Source) (*packager.Binary, error) { + image := filepath.Join(s.Repository.Path, s.Repository.Name) + + buf := new(bytes.Buffer) + tw := tar.NewWriter(buf) + defer tw.Close() + + dockerFile := "Dockerfile" + + // open docker file + f, err := os.Open(filepath.Join(s.Repository.Path, s.Repository.Name, dockerFile)) + if err != nil { + return nil, err + } + // read docker file + by, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + + tarHeader := &tar.Header{ + Name: dockerFile, + Size: int64(len(by)), + } + err = tw.WriteHeader(tarHeader) + if err != nil { + return nil, err + } + _, err = tw.Write(by) + if err != nil { + return nil, err + } + tr := bytes.NewReader(buf.Bytes()) + + err = d.Client.BuildImage(docker.BuildImageOptions{ + Name: image, + Dockerfile: dockerFile, + InputStream: tr, + OutputStream: ioutil.Discard, + RmTmpContainer: true, + SuppressOutput: true, + }) + if err != nil { + return nil, err + } + return &packager.Binary{ + Name: image, + Path: image, + Type: "docker", + Source: s, + }, nil +} + +func (d *Packager) Delete(b *packager.Binary) error { + image := filepath.Join(b.Path, b.Name) + return d.Client.RemoveImage(image) +} + +func NewPackager(opts ...packager.Option) packager.Packager { + options := packager.Options{} + for _, o := range opts { + o(&options) + } + endpoint := "unix:///var/run/docker.sock" + client, err := docker.NewClient(endpoint) + if err != nil { + log.Fatal(err) + } + return &Packager{ + Options: options, + Client: client, + } +} diff --git a/runtime/package/go/golang.go b/runtime/package/go/golang.go new file mode 100644 index 00000000..63572451 --- /dev/null +++ b/runtime/package/go/golang.go @@ -0,0 +1,70 @@ +// Package golang is a go package manager +package golang + +import ( + "os" + "os/exec" + "path/filepath" + + "github.com/micro/go-run/package" +) + +type Packager struct { + Options packager.Options + Cmd string + Path string +} + +// whichGo locates the go command +func whichGo() string { + // check GOROOT + if gr := os.Getenv("GOROOT"); len(gr) > 0 { + return filepath.Join(gr, "bin", "go") + } + + // check path + for _, p := range filepath.SplitList(os.Getenv("PATH")) { + bin := filepath.Join(p, "go") + if _, err := os.Stat(bin); err == nil { + return bin + } + } + + // best effort + return "go" +} + +func (g *Packager) Compile(s *packager.Source) (*packager.Binary, error) { + binary := filepath.Join(g.Path, s.Repository.Name) + source := filepath.Join(s.Repository.Path, s.Repository.Name) + + cmd := exec.Command(g.Cmd, "build", "-o", binary, source) + if err := cmd.Run(); err != nil { + return nil, err + } + return &packager.Binary{ + Name: s.Repository.Name, + Path: binary, + Type: "go", + Source: s, + }, nil +} + +func (g *Packager) Delete(b *packager.Binary) error { + binary := filepath.Join(b.Path, b.Name) + return os.Remove(binary) +} + +func NewPackager(opts ...packager.Option) packager.Packager { + options := packager.Options{ + Path: os.TempDir(), + } + for _, o := range opts { + o(&options) + } + return &Packager{ + Options: options, + Cmd: whichGo(), + Path: options.Path, + } +} diff --git a/runtime/package/options.go b/runtime/package/options.go new file mode 100644 index 00000000..a308c737 --- /dev/null +++ b/runtime/package/options.go @@ -0,0 +1,15 @@ +package packager + +type Options struct { + // local path to download source + Path string +} + +type Option func(o *Options) + +// Local path for repository +func Path(p string) Option { + return func(o *Options) { + o.Path = p + } +} diff --git a/runtime/package/package.go b/runtime/package/package.go new file mode 100644 index 00000000..39545544 --- /dev/null +++ b/runtime/package/package.go @@ -0,0 +1,34 @@ +// Package packager creates a binary image. Due to package being a reserved keyword we use packager. +package packager + +import ( + "github.com/micro/go-run/source" +) + +// Package builds binaries +type Packager interface { + // Compile builds a binary + Compile(*Source) (*Binary, error) + // Deletes the binary + Delete(*Binary) error +} + +// Source is the source of a build +type Source struct { + // Language is the language of code + Language string + // Location of the source + Repository *source.Repository +} + +// Binary is the representation of a binary +type Binary struct { + // Name of the binary + Name string + // Location of the binary + Path string + // Type of binary + Type string + // Source of the binary + Source *Source +} diff --git a/runtime/process/options.go b/runtime/process/options.go new file mode 100644 index 00000000..0dcc6882 --- /dev/null +++ b/runtime/process/options.go @@ -0,0 +1,5 @@ +package process + +type Options struct{} + +type Option func(o *Options) diff --git a/runtime/process/os/os.go b/runtime/process/os/os.go new file mode 100644 index 00000000..7f946e8c --- /dev/null +++ b/runtime/process/os/os.go @@ -0,0 +1,86 @@ +// Package os runs processes locally +package os + +import ( + "fmt" + "os" + "os/exec" + "strconv" + + "github.com/micro/go-run/process" +) + +type Process struct { +} + +func (p *Process) Exec(exe *process.Executable) error { + cmd := exec.Command(exe.Binary.Path) + return cmd.Run() +} + +func (p *Process) Fork(exe *process.Executable) (*process.PID, error) { + cmd := exec.Command(exe.Binary.Path) + if err := cmd.Start(); err != nil { + return nil, err + } + in, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + out, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + er, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + + return &process.PID{ + ID: fmt.Sprintf("%d", cmd.Process.Pid), + Input: in, + Output: out, + Error: er, + }, nil +} + +func (p *Process) Kill(pid *process.PID) error { + id, err := strconv.Atoi(pid.ID) + if err != nil { + return err + } + + pr, err := os.FindProcess(id) + if err != nil { + return err + } + + return pr.Kill() +} + +func (p *Process) Wait(pid *process.PID) error { + id, err := strconv.Atoi(pid.ID) + if err != nil { + return err + } + + pr, err := os.FindProcess(id) + if err != nil { + return err + } + + ps, err := pr.Wait() + if err != nil { + return err + } + + if ps.Success() { + return nil + } + + return fmt.Errorf(ps.String()) +} + +func NewProcess(opts ...process.Option) process.Process { + return &Process{} +} diff --git a/runtime/process/process.go b/runtime/process/process.go new file mode 100644 index 00000000..5306c79c --- /dev/null +++ b/runtime/process/process.go @@ -0,0 +1,37 @@ +// Package process executes a binary +package process + +import ( + "io" + + "github.com/micro/go-run/package" +) + +// Process manages a running process +type Process interface { + // Executes a process to completion + Exec(*Executable) error + // Creates a new process + Fork(*Executable) (*PID, error) + // Kills the process + Kill(*PID) error + // Waits for a process to exit + Wait(*PID) error +} + +type Executable struct { + // The executable binary + Binary *packager.Binary +} + +// PID is the running process +type PID struct { + // ID of the process + ID string + // Stdin + Input io.Writer + // Stdout + Output io.Reader + // Stderr + Error io.Reader +} diff --git a/runtime/source/git/git.go b/runtime/source/git/git.go new file mode 100644 index 00000000..a2590ec7 --- /dev/null +++ b/runtime/source/git/git.go @@ -0,0 +1,87 @@ +// Package git provides a git source +package git + +import ( + "os" + "path/filepath" + "strings" + + "github.com/micro/go-run/source" + "gopkg.in/src-d/go-git.v4" +) + +// Source retrieves source code +// An empty struct can be used +type Source struct { + Options source.Options +} + +func (g *Source) Fetch(url string) (*source.Repository, error) { + purl := url + + if parts := strings.Split(url, "://"); len(parts) > 1 { + purl = parts[len(parts)-1] + } + + name := filepath.Base(url) + path := filepath.Join(g.Options.Path, purl) + + _, err := git.PlainClone(path, false, &git.CloneOptions{ + URL: url, + }) + if err == nil { + return &source.Repository{ + Name: name, + Path: path, + URL: url, + }, nil + } + + // repo already exists + if err != git.ErrRepositoryAlreadyExists { + return nil, err + } + + // open repo + re, err := git.PlainOpen(path) + if err != nil { + return nil, err + } + + // update it + if err := re.Fetch(nil); err != nil { + return nil, err + } + + return &source.Repository{ + Name: name, + Path: path, + URL: url, + }, nil +} + +func (g *Source) Commit(r *source.Repository) error { + repo := filepath.Join(r.Path) + re, err := git.PlainOpen(repo) + if err != nil { + return err + } + return re.Push(nil) +} + +func (g *Source) String() string { + return "git" +} + +func NewSource(opts ...source.Option) *Source { + options := source.Options{ + Path: os.TempDir(), + } + for _, o := range opts { + o(&options) + } + + return &Source{ + Options: options, + } +} diff --git a/runtime/source/go/golang.go b/runtime/source/go/golang.go new file mode 100644 index 00000000..cbf42a9e --- /dev/null +++ b/runtime/source/go/golang.go @@ -0,0 +1,93 @@ +// Package golang is a source for Go +package golang + +import ( + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/micro/go-run/source" +) + +type Source struct { + Options source.Options + // Go Command + Cmd string + Path string +} + +func (g *Source) Fetch(url string) (*source.Repository, error) { + purl := url + + if parts := strings.Split(url, "://"); len(parts) > 1 { + purl = parts[len(parts)-1] + } + + // name of repo + name := filepath.Base(url) + // local path of repo + path := filepath.Join(g.Path, purl) + args := []string{"get", "-d", url, path} + + cmd := exec.Command(g.Cmd, args...) + if err := cmd.Run(); err != nil { + return nil, err + } + return &source.Repository{ + Name: name, + Path: path, + URL: url, + }, nil +} + +// Commit is not yet supported +func (g *Source) Commit(r *source.Repository) error { + return nil +} + +func (g *Source) String() string { + return "golang" +} + +// whichGo locates the go command +func whichGo() string { + // check GOROOT + if gr := os.Getenv("GOROOT"); len(gr) > 0 { + return filepath.Join(gr, "bin", "go") + } + + // check path + for _, p := range filepath.SplitList(os.Getenv("PATH")) { + bin := filepath.Join(p, "go") + if _, err := os.Stat(bin); err == nil { + return bin + } + } + + // best effort + return "go" +} + +func NewSource(opts ...source.Option) source.Source { + options := source.Options{ + Path: os.TempDir(), + } + for _, o := range opts { + o(&options) + } + + cmd := whichGo() + path := options.Path + + // point of no return + if len(cmd) == 0 { + panic("Could not find Go executable") + } + + return &Source{ + Options: options, + Cmd: cmd, + Path: path, + } +} diff --git a/runtime/source/options.go b/runtime/source/options.go new file mode 100644 index 00000000..2e842f33 --- /dev/null +++ b/runtime/source/options.go @@ -0,0 +1,15 @@ +package source + +type Options struct { + // local path to download source + Path string +} + +type Option func(o *Options) + +// Local path for repository +func Path(p string) Option { + return func(o *Options) { + o.Path = p + } +} diff --git a/runtime/source/source.go b/runtime/source/source.go new file mode 100644 index 00000000..2afa92e3 --- /dev/null +++ b/runtime/source/source.go @@ -0,0 +1,22 @@ +// Package source retrieves source code +package source + +// Source retrieves source code +type Source interface { + // Fetch repo from a url + Fetch(url string) (*Repository, error) + // Commit and upload repo + Commit(*Repository) error + // The sourcerer + String() string +} + +// Repository is the source repository +type Repository struct { + // Name or repo + Name string + // Local path where repo is stored + Path string + // URL from which repo was retrieved + URL string +} From c90d0eff0a0d7bc0cf58cad12e21490081eb32ad Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 00:27:41 +0100 Subject: [PATCH 08/18] update links --- runtime/package/docker/docker.go | 2 +- runtime/package/go/golang.go | 2 +- runtime/package/package.go | 2 +- runtime/process/os/os.go | 2 +- runtime/process/process.go | 2 +- runtime/source/git/git.go | 2 +- runtime/source/go/golang.go | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/runtime/package/docker/docker.go b/runtime/package/docker/docker.go index e53010e5..4a420060 100644 --- a/runtime/package/docker/docker.go +++ b/runtime/package/docker/docker.go @@ -10,7 +10,7 @@ import ( "github.com/fsouza/go-dockerclient" "github.com/micro/go-log" - "github.com/micro/go-run/package" + "github.com/micro/go-micro/runtime/package" ) type Packager struct { diff --git a/runtime/package/go/golang.go b/runtime/package/go/golang.go index 63572451..a9a591ab 100644 --- a/runtime/package/go/golang.go +++ b/runtime/package/go/golang.go @@ -6,7 +6,7 @@ import ( "os/exec" "path/filepath" - "github.com/micro/go-run/package" + "github.com/micro/go-micro/runtime/package" ) type Packager struct { diff --git a/runtime/package/package.go b/runtime/package/package.go index 39545544..078c8a59 100644 --- a/runtime/package/package.go +++ b/runtime/package/package.go @@ -2,7 +2,7 @@ package packager import ( - "github.com/micro/go-run/source" + "github.com/micro/go-micro/runtime/source" ) // Package builds binaries diff --git a/runtime/process/os/os.go b/runtime/process/os/os.go index 7f946e8c..30d69680 100644 --- a/runtime/process/os/os.go +++ b/runtime/process/os/os.go @@ -7,7 +7,7 @@ import ( "os/exec" "strconv" - "github.com/micro/go-run/process" + "github.com/micro/go-micro/runtime/process" ) type Process struct { diff --git a/runtime/process/process.go b/runtime/process/process.go index 5306c79c..0e47e88d 100644 --- a/runtime/process/process.go +++ b/runtime/process/process.go @@ -4,7 +4,7 @@ package process import ( "io" - "github.com/micro/go-run/package" + "github.com/micro/go-micro/runtime/package" ) // Process manages a running process diff --git a/runtime/source/git/git.go b/runtime/source/git/git.go index a2590ec7..f8d8000b 100644 --- a/runtime/source/git/git.go +++ b/runtime/source/git/git.go @@ -6,7 +6,7 @@ import ( "path/filepath" "strings" - "github.com/micro/go-run/source" + "github.com/micro/go-micro/runtime/source" "gopkg.in/src-d/go-git.v4" ) diff --git a/runtime/source/go/golang.go b/runtime/source/go/golang.go index cbf42a9e..6265cfc1 100644 --- a/runtime/source/go/golang.go +++ b/runtime/source/go/golang.go @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "github.com/micro/go-run/source" + "github.com/micro/go-micro/runtime/source" ) type Source struct { From 5595a8e0e4bf928fde0af9e67325167bc1a11289 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 00:35:04 +0100 Subject: [PATCH 09/18] Add log => go-log --- util/log/README.md | 17 +++++++++++++++++ util/log/log.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 util/log/README.md create mode 100644 util/log/log.go diff --git a/util/log/README.md b/util/log/README.md new file mode 100644 index 00000000..2ae61058 --- /dev/null +++ b/util/log/README.md @@ -0,0 +1,17 @@ +# Log + +This is the global logger for all micro based libraries which makes use of [github.com/go-log/log](https://github.com/go-log/log). + +It defaults the logger to the stdlib log implementation. + +## Set Logger + +Set the logger for micro libraries + +```go +// import micro/go-log +import "github.com/micro/go-micro/util/log" + +// SetLogger expects github.com/go-log/log.Logger interface +log.SetLogger(mylogger) +``` diff --git a/util/log/log.go b/util/log/log.go new file mode 100644 index 00000000..86208c06 --- /dev/null +++ b/util/log/log.go @@ -0,0 +1,41 @@ +// Package log is a global internal logger +package log + +import ( + "os" + + "github.com/go-log/log" + golog "github.com/go-log/log/log" +) + +var ( + // the local logger + logger log.Logger = golog.New() +) + +// Log makes use of github.com/go-log/log.Log +func Log(v ...interface{}) { + logger.Log(v...) +} + +// Logf makes use of github.com/go-log/log.Logf +func Logf(format string, v ...interface{}) { + logger.Logf(format, v...) +} + +// Fatal logs with Log and then exits with os.Exit(1) +func Fatal(v ...interface{}) { + Log(v...) + os.Exit(1) +} + +// Fatalf logs with Logf and then exits with os.Exit(1) +func Fatalf(format string, v ...interface{}) { + Logf(format, v...) + os.Exit(1) +} + +// SetLogger sets the local logger +func SetLogger(l log.Logger) { + logger = l +} From 4035ab5c7b0c926211d154abc3ff20b31787bfa8 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 00:38:05 +0100 Subject: [PATCH 10/18] Change go-log links --- agent/input/discord/conn.go | 2 +- agent/input/telegram/conn.go | 2 +- agent/proto/bot.micro.go | 2 +- broker/http_broker_test.go | 2 +- cmd/cmd.go | 2 +- codec/text/text.go | 75 ++++++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- registry/cache/rcache.go | 2 +- registry/gossip/gossip.go | 2 +- runtime/package/docker/docker.go | 2 +- server/rpc_router.go | 2 +- server/rpc_server.go | 2 +- server/server.go | 2 +- service_test.go | 2 +- util/log/README.md | 2 +- 16 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 codec/text/text.go diff --git a/agent/input/discord/conn.go b/agent/input/discord/conn.go index 20a35af9..cadc69d0 100644 --- a/agent/input/discord/conn.go +++ b/agent/input/discord/conn.go @@ -7,7 +7,7 @@ import ( "github.com/bwmarrin/discordgo" "github.com/micro/go-micro/agent/input" - "github.com/micro/go-log" + "github.com/micro/go-micro/util/log" ) type discordConn struct { diff --git a/agent/input/telegram/conn.go b/agent/input/telegram/conn.go index 99311f4c..44d1ada1 100644 --- a/agent/input/telegram/conn.go +++ b/agent/input/telegram/conn.go @@ -7,7 +7,7 @@ import ( "github.com/forestgiant/sliceutil" "github.com/micro/go-micro/agent/input" - "github.com/micro/go-log" + "github.com/micro/go-micro/util/log" "gopkg.in/telegram-bot-api.v4" ) diff --git a/agent/proto/bot.micro.go b/agent/proto/bot.micro.go index 2bac4842..0a027a82 100644 --- a/agent/proto/bot.micro.go +++ b/agent/proto/bot.micro.go @@ -20,9 +20,9 @@ import fmt "fmt" import math "math" import ( + context "context" client "github.com/micro/go-micro/client" server "github.com/micro/go-micro/server" - context "context" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/broker/http_broker_test.go b/broker/http_broker_test.go index a2aabdd5..69bad10e 100644 --- a/broker/http_broker_test.go +++ b/broker/http_broker_test.go @@ -7,8 +7,8 @@ import ( glog "github.com/go-log/log" "github.com/google/uuid" - "github.com/micro/go-log" "github.com/micro/go-micro/registry/memory" + "github.com/micro/go-micro/util/log" ) func newTestRegistry() *memory.Registry { diff --git a/cmd/cmd.go b/cmd/cmd.go index c4987dbf..9a9a34ef 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -10,9 +10,9 @@ import ( "time" "github.com/micro/cli" - "github.com/micro/go-log" "github.com/micro/go-micro/client" "github.com/micro/go-micro/server" + "github.com/micro/go-micro/util/log" // brokers "github.com/micro/go-micro/broker" diff --git a/codec/text/text.go b/codec/text/text.go new file mode 100644 index 00000000..f6f28859 --- /dev/null +++ b/codec/text/text.go @@ -0,0 +1,75 @@ +// Package text reads any text/* content-type +package text + +import ( + "fmt" + "io" + "io/ioutil" + + "github.com/micro/go-micro/codec" +) + +type Codec struct { + Conn io.ReadWriteCloser +} + +// Frame gives us the ability to define raw data to send over the pipes +type Frame struct { + Data []byte +} + +func (c *Codec) ReadHeader(m *codec.Message, t codec.MessageType) error { + return nil +} + +func (c *Codec) ReadBody(b interface{}) error { + // read bytes + buf, err := ioutil.ReadAll(c.Conn) + if err != nil { + return err + } + + switch b.(type) { + case *[]byte: + v := b.(*[]byte) + *v = buf + case *Frame: + v := b.(*Frame) + v.Data = buf + default: + return fmt.Errorf("failed to read body: %v is not type of *[]byte", b) + } + + return nil +} + +func (c *Codec) Write(m *codec.Message, b interface{}) error { + var v []byte + switch b.(type) { + case *Frame: + v = b.(*Frame).Data + case *[]byte: + ve := b.(*[]byte) + v = *ve + case []byte: + v = b.([]byte) + default: + return fmt.Errorf("failed to write: %v is not type of *[]byte or []byte", b) + } + _, err := c.Conn.Write(v) + return err +} + +func (c *Codec) Close() error { + return c.Conn.Close() +} + +func (c *Codec) String() string { + return "bytes" +} + +func NewCodec(c io.ReadWriteCloser) codec.Codec { + return &Codec{ + Conn: c, + } +} diff --git a/go.mod b/go.mod index 45392aef..56a83819 100644 --- a/go.mod +++ b/go.mod @@ -122,7 +122,7 @@ require ( github.com/mholt/certmagic v0.5.1 // indirect github.com/michaelklishin/rabbit-hole v1.5.0 // indirect github.com/micro/cli v0.2.0 - github.com/micro/go-log v0.1.0 + github.com/micro/go-micro/util/log v0.1.0 github.com/micro/go-rcache v0.3.0 github.com/micro/mdns v0.1.0 github.com/micro/util v0.2.0 diff --git a/go.sum b/go.sum index 7e47ccd2..90b692dd 100644 --- a/go.sum +++ b/go.sum @@ -675,8 +675,8 @@ github.com/micro/cli v0.1.0 h1:5DT+QdbAPPQvB3gYTgwze7tFO1m+7DU1sz9XfQczbsc= github.com/micro/cli v0.1.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= -github.com/micro/go-log v0.1.0 h1:szYSR+yyTsomZM2jyinJC5562DlqffSjHmTZFaeZ2vY= -github.com/micro/go-log v0.1.0/go.mod h1:qaFBF6d6Jk01Gz4cbMkCA2vVuLk3FSaLLjmEGrMCreA= +github.com/micro/go-micro/util/log v0.1.0 h1:szYSR+yyTsomZM2jyinJC5562DlqffSjHmTZFaeZ2vY= +github.com/micro/go-micro/util/log v0.1.0/go.mod h1:qaFBF6d6Jk01Gz4cbMkCA2vVuLk3FSaLLjmEGrMCreA= github.com/micro/go-micro v0.23.0/go.mod h1:3z3lfMkNU9Sr1L/CxL++8pVJmQapRo0N6kNjwYDtOVs= github.com/micro/go-micro v0.26.0/go.mod h1:CweCFO/pq8dCSIOdzVZ4ooIpUrKlyJ0AcFB269M7PgU= github.com/micro/go-micro v0.26.1/go.mod h1:Jgc5gPEmDiG1TWE5Qnzzx5qyXnU9VTXKT1FkXkfvt8g= diff --git a/registry/cache/rcache.go b/registry/cache/rcache.go index 53b11576..09ff3c48 100644 --- a/registry/cache/rcache.go +++ b/registry/cache/rcache.go @@ -7,8 +7,8 @@ import ( "sync" "time" - log "github.com/micro/go-log" "github.com/micro/go-micro/registry" + log "github.com/micro/go-micro/util/log" ) // Cache is the registry cache interface diff --git a/registry/gossip/gossip.go b/registry/gossip/gossip.go index ca654568..c8ea457a 100644 --- a/registry/gossip/gossip.go +++ b/registry/gossip/gossip.go @@ -16,9 +16,9 @@ import ( "github.com/golang/protobuf/proto" "github.com/google/uuid" "github.com/hashicorp/memberlist" - log "github.com/micro/go-log" "github.com/micro/go-micro/registry" pb "github.com/micro/go-micro/registry/gossip/proto" + log "github.com/micro/go-micro/util/log" "github.com/mitchellh/hashstructure" ) diff --git a/runtime/package/docker/docker.go b/runtime/package/docker/docker.go index 4a420060..2f0c46c0 100644 --- a/runtime/package/docker/docker.go +++ b/runtime/package/docker/docker.go @@ -9,8 +9,8 @@ import ( "path/filepath" "github.com/fsouza/go-dockerclient" - "github.com/micro/go-log" "github.com/micro/go-micro/runtime/package" + "github.com/micro/go-micro/util/log" ) type Packager struct { diff --git a/server/rpc_router.go b/server/rpc_router.go index 5d23d5b8..af29d4b8 100644 --- a/server/rpc_router.go +++ b/server/rpc_router.go @@ -16,8 +16,8 @@ import ( "unicode" "unicode/utf8" - "github.com/micro/go-log" "github.com/micro/go-micro/codec" + "github.com/micro/go-micro/util/log" ) var ( diff --git a/server/rpc_server.go b/server/rpc_server.go index 6838d65e..bd95a312 100644 --- a/server/rpc_server.go +++ b/server/rpc_server.go @@ -10,13 +10,13 @@ import ( "sync" "time" - log "github.com/micro/go-log" "github.com/micro/go-micro/broker" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/metadata" "github.com/micro/go-micro/registry" "github.com/micro/go-micro/transport" "github.com/micro/go-micro/util/addr" + log "github.com/micro/go-micro/util/log" ) type rpcServer struct { diff --git a/server/server.go b/server/server.go index 706e6b7e..2e742f95 100644 --- a/server/server.go +++ b/server/server.go @@ -8,9 +8,9 @@ import ( "syscall" "github.com/google/uuid" - log "github.com/micro/go-log" "github.com/micro/go-micro/codec" "github.com/micro/go-micro/registry" + log "github.com/micro/go-micro/util/log" ) // Server is a simple micro server abstraction diff --git a/service_test.go b/service_test.go index 5c2dba3f..6d4cbbc0 100644 --- a/service_test.go +++ b/service_test.go @@ -7,10 +7,10 @@ import ( "testing" glog "github.com/go-log/log" - "github.com/micro/go-log" "github.com/micro/go-micro/client" "github.com/micro/go-micro/registry/memory" proto "github.com/micro/go-micro/server/debug/proto" + "github.com/micro/go-micro/util/log" ) func testShutdown(wg *sync.WaitGroup, cancel func()) { diff --git a/util/log/README.md b/util/log/README.md index 2ae61058..6e26ad79 100644 --- a/util/log/README.md +++ b/util/log/README.md @@ -9,7 +9,7 @@ It defaults the logger to the stdlib log implementation. Set the logger for micro libraries ```go -// import micro/go-log +// import go-micro/util/log import "github.com/micro/go-micro/util/log" // SetLogger expects github.com/go-log/log.Logger interface From 95d134b57eb22baa7a12446b11035c9c726ba706 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 00:43:23 +0100 Subject: [PATCH 11/18] Add sync => go-sync --- sync/README.md | 141 ++++++++++++++++++++ sync/cron.go | 93 +++++++++++++ sync/data/consul/consul.go | 93 +++++++++++++ sync/data/data.go | 32 +++++ sync/data/etcd/etcd.go | 93 +++++++++++++ sync/data/memcached/memcached.go | 178 +++++++++++++++++++++++++ sync/data/options.go | 19 +++ sync/data/redis/redis.go | 82 ++++++++++++ sync/db.go | 157 ++++++++++++++++++++++ sync/event/event.go | 27 ++++ sync/leader/consul/consul.go | 158 ++++++++++++++++++++++ sync/leader/etcd/etcd.go | 145 ++++++++++++++++++++ sync/leader/leader.go | 25 ++++ sync/leader/options.go | 22 ++++ sync/lock/consul/consul.go | 104 +++++++++++++++ sync/lock/etcd/etcd.go | 115 ++++++++++++++++ sync/lock/lock.go | 27 ++++ sync/lock/options.go | 33 +++++ sync/lock/redis/pool.go | 29 ++++ sync/lock/redis/redis.go | 94 +++++++++++++ sync/options.go | 36 +++++ sync/sync.go | 41 ++++++ sync/task/broker/broker.go | 219 +++++++++++++++++++++++++++++++ sync/task/local/local.go | 59 +++++++++ sync/task/task.go | 83 ++++++++++++ sync/time/local/local.go | 18 +++ sync/time/ntp/ntp.go | 51 +++++++ sync/time/time.go | 18 +++ 28 files changed, 2192 insertions(+) create mode 100644 sync/README.md create mode 100644 sync/cron.go create mode 100644 sync/data/consul/consul.go create mode 100644 sync/data/data.go create mode 100644 sync/data/etcd/etcd.go create mode 100644 sync/data/memcached/memcached.go create mode 100644 sync/data/options.go create mode 100644 sync/data/redis/redis.go create mode 100644 sync/db.go create mode 100644 sync/event/event.go create mode 100644 sync/leader/consul/consul.go create mode 100644 sync/leader/etcd/etcd.go create mode 100644 sync/leader/leader.go create mode 100644 sync/leader/options.go create mode 100644 sync/lock/consul/consul.go create mode 100644 sync/lock/etcd/etcd.go create mode 100644 sync/lock/lock.go create mode 100644 sync/lock/options.go create mode 100644 sync/lock/redis/pool.go create mode 100644 sync/lock/redis/redis.go create mode 100644 sync/options.go create mode 100644 sync/sync.go create mode 100644 sync/task/broker/broker.go create mode 100644 sync/task/local/local.go create mode 100644 sync/task/task.go create mode 100644 sync/time/local/local.go create mode 100644 sync/time/ntp/ntp.go create mode 100644 sync/time/time.go diff --git a/sync/README.md b/sync/README.md new file mode 100644 index 00000000..94349374 --- /dev/null +++ b/sync/README.md @@ -0,0 +1,141 @@ +# Sync + +Sync is a synchronization library for distributed systems. + +## Overview + +Distributed systems by their very nature are decoupled and independent. In most cases they must honour 2 out of 3 letters of the CAP theorem +e.g Availability and Partitional tolerance but sacrificing consistency. In the case of microservices we often offload this concern to +an external database or eventing system. Go Sync provides a framework for synchronization which can be used in the application by the developer. + +## Getting Started + +- [Data](#data) - simple distributed data storage +- [Leader](#leader) - leadership election for group coordination +- [Lock](#lock) - distributed locking for exclusive resource access +- [Task](#task) - distributed job execution +- [Time](#time) - provides synchronized time + +## Lock + +The Lock interface provides distributed locking. Multiple instances attempting to lock the same id will block until available. + +```go +import "github.com/micro/go-micro/sync/lock/consul" + +lock := consul.NewLock() + +// acquire lock +err := lock.Acquire("id") +// handle err + +// release lock +err = lock.Release("id") +// handle err +``` + +## Leader + +Leader provides leadership election. Useful where one node needs to coordinate some action. + +```go +import ( + "github.com/micro/go-micro/sync/leader" + "github.com/micro/go-micro/sync/leader/consul" +) + +l := consul.NewLeader( + leader.Group("name"), +) + +// elect leader +e, err := l.Elect("id") +// handle err + + +// operate while leader +revoked := e.Revoked() + +for { + select { + case <-revoked: + // re-elect + e.Elect("id") + default: + // leader operation + } +} + +// resign leadership +e.Resign() +``` + +## Data + +Data provides a simple interface for distributed data storage. + +```go +import ( + "github.com/micro/go-micro/sync/data" + "github.com/micro/go-micro/sync/data/consul" +) + +keyval := consul.NewData() + +err := keyval.Write(&data.Record{ + Key: "foo", + Value: []byte(`bar`), +}) +// handle err + +v, err := keyval.Read("foo") +// handle err + +err = keyval.Delete("foo") +``` + +## Task + +Task provides distributed job execution. It's a simple way to distribute work across a coordinated pool of workers. + +```go +import ( + "github.com/micro/go-micro/sync/task" + "github.com/micro/go-micro/sync/task/local" +) + +t := local.NewTask( + task.WithPool(10), +) + +err := t.Run(task.Command{ + Name: "atask", + Func: func() error { + // exec some work + return nil + }, +}) + +if err != nil { + // do something +} +``` + +## Time + +Time provides synchronized time. Local machines may have clock skew and time cannot be guaranteed to be the same everywhere. +Synchronized Time allows you to decide how time is defined for your applications. + +```go +import ( + "github.com/micro/go-micro/sync/time/ntp" +) + + +t := ntp.NewTime() +time, err := t.Now() +``` + +## TODO + +- Event package - strongly consistent event stream e.g kafka diff --git a/sync/cron.go b/sync/cron.go new file mode 100644 index 00000000..52ef20d5 --- /dev/null +++ b/sync/cron.go @@ -0,0 +1,93 @@ +package sync + +import ( + "fmt" + "math" + "time" + + "github.com/micro/go-log" + "github.com/micro/go-micro/sync/leader/consul" + "github.com/micro/go-micro/sync/task" + "github.com/micro/go-micro/sync/task/local" +) + +type syncCron struct { + opts Options +} + +func backoff(attempts int) time.Duration { + if attempts == 0 { + return time.Duration(0) + } + return time.Duration(math.Pow(10, float64(attempts))) * time.Millisecond +} + +func (c *syncCron) Schedule(s task.Schedule, t task.Command) error { + id := fmt.Sprintf("%s-%s", s.String(), t.String()) + + go func() { + // run the scheduler + tc := s.Run() + + var i int + + for { + // leader election + e, err := c.opts.Leader.Elect(id) + if err != nil { + log.Logf("[cron] leader election error: %v", err) + time.Sleep(backoff(i)) + i++ + continue + } + + i = 0 + r := e.Revoked() + + // execute the task + Tick: + for { + select { + // schedule tick + case _, ok := <-tc: + // ticked once + if !ok { + break Tick + } + + log.Logf("[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) + } + // leader revoked + case <-r: + break Tick + } + } + + // resign + e.Resign() + } + }() + + return nil +} + +func NewCron(opts ...Option) Cron { + var options Options + for _, o := range opts { + o(&options) + } + + if options.Leader == nil { + options.Leader = consul.NewLeader() + } + + if options.Task == nil { + options.Task = local.NewTask() + } + + return &syncCron{ + opts: options, + } +} diff --git a/sync/data/consul/consul.go b/sync/data/consul/consul.go new file mode 100644 index 00000000..9d2c7a93 --- /dev/null +++ b/sync/data/consul/consul.go @@ -0,0 +1,93 @@ +// Package consul is a consul implementation of kv +package consul + +import ( + "fmt" + "net" + + "github.com/hashicorp/consul/api" + "github.com/micro/go-micro/sync/data" +) + +type ckv struct { + client *api.Client +} + +func (c *ckv) Read(key string) (*data.Record, error) { + keyval, _, err := c.client.KV().Get(key, nil) + if err != nil { + return nil, err + } + + if keyval == nil { + return nil, data.ErrNotFound + } + + return &data.Record{ + Key: keyval.Key, + Value: keyval.Value, + }, nil +} + +func (c *ckv) Delete(key string) error { + _, err := c.client.KV().Delete(key, nil) + return err +} + +func (c *ckv) Write(record *data.Record) error { + _, err := c.client.KV().Put(&api.KVPair{ + Key: record.Key, + Value: record.Value, + }, nil) + return err +} + +func (c *ckv) Dump() ([]*data.Record, error) { + keyval, _, err := c.client.KV().List("/", nil) + if err != nil { + return nil, err + } + if keyval == nil { + return nil, data.ErrNotFound + } + var vals []*data.Record + for _, keyv := range keyval { + vals = append(vals, &data.Record{ + Key: keyv.Key, + Value: keyv.Value, + }) + } + return vals, nil +} + +func (c *ckv) String() string { + return "consul" +} + +func NewData(opts ...data.Option) data.Data { + var options data.Options + for _, o := range opts { + o(&options) + } + + config := api.DefaultConfig() + + // set host + // config.Host something + // check if there are any addrs + if len(options.Nodes) > 0 { + addr, port, err := net.SplitHostPort(options.Nodes[0]) + if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { + port = "8500" + config.Address = fmt.Sprintf("%s:%s", options.Nodes[0], port) + } else if err == nil { + config.Address = fmt.Sprintf("%s:%s", addr, port) + } + } + + client, _ := api.NewClient(config) + + return &ckv{ + client: client, + } +} diff --git a/sync/data/data.go b/sync/data/data.go new file mode 100644 index 00000000..20e4a4c8 --- /dev/null +++ b/sync/data/data.go @@ -0,0 +1,32 @@ +// Package data is an interface for key-value storage. +package data + +import ( + "errors" + "time" +) + +var ( + ErrNotFound = errors.New("not found") +) + +// Data is a data storage interface +type Data interface { + // Dump the known records + Dump() ([]*Record, error) + // Read a record with key + Read(key string) (*Record, error) + // Write a record + Write(r *Record) error + // Delete a record with key + Delete(key string) error +} + +// Record represents a data record +type Record struct { + Key string + Value []byte + Expiration time.Duration +} + +type Option func(o *Options) diff --git a/sync/data/etcd/etcd.go b/sync/data/etcd/etcd.go new file mode 100644 index 00000000..fa0db751 --- /dev/null +++ b/sync/data/etcd/etcd.go @@ -0,0 +1,93 @@ +// Package etcd is an etcd v3 implementation of kv +package etcd + +import ( + "context" + "log" + + "github.com/micro/go-micro/sync/data" + client "go.etcd.io/etcd/clientv3" +) + +type ekv struct { + kv client.KV +} + +func (e *ekv) Read(key string) (*data.Record, error) { + keyval, err := e.kv.Get(context.Background(), key) + if err != nil { + return nil, err + } + + if keyval == nil || len(keyval.Kvs) == 0 { + return nil, data.ErrNotFound + } + + return &data.Record{ + Key: string(keyval.Kvs[0].Key), + Value: keyval.Kvs[0].Value, + }, nil +} + +func (e *ekv) Delete(key string) error { + _, err := e.kv.Delete(context.Background(), key) + return err +} + +func (e *ekv) Write(record *data.Record) error { + _, err := e.kv.Put(context.Background(), record.Key, string(record.Value)) + return err +} + +func (e *ekv) Dump() ([]*data.Record, error) { + keyval, err := e.kv.Get(context.Background(), "/", client.WithPrefix()) + if err != nil { + return nil, err + } + var vals []*data.Record + if keyval == nil || len(keyval.Kvs) == 0 { + return vals, nil + } + for _, keyv := range keyval.Kvs { + vals = append(vals, &data.Record{ + Key: string(keyv.Key), + Value: keyv.Value, + }) + } + return vals, nil +} + +func (e *ekv) String() string { + return "etcd" +} + +func NewData(opts ...data.Option) data.Data { + var options data.Options + for _, o := range opts { + o(&options) + } + + var endpoints []string + + for _, addr := range options.Nodes { + if len(addr) > 0 { + endpoints = append(endpoints, addr) + } + } + + if len(endpoints) == 0 { + endpoints = []string{"http://127.0.0.1:2379"} + } + + // TODO: parse addresses + c, err := client.New(client.Config{ + Endpoints: endpoints, + }) + if err != nil { + log.Fatal(err) + } + + return &ekv{ + kv: client.NewKV(c), + } +} diff --git a/sync/data/memcached/memcached.go b/sync/data/memcached/memcached.go new file mode 100644 index 00000000..69cdd19b --- /dev/null +++ b/sync/data/memcached/memcached.go @@ -0,0 +1,178 @@ +package memcached + +import ( + "bufio" + "bytes" + "fmt" + "io" + "net" + "strings" + "time" + + mc "github.com/bradfitz/gomemcache/memcache" + "github.com/micro/go-micro/sync/data" +) + +type mkv struct { + Server *mc.ServerList + Client *mc.Client +} + +func (m *mkv) Read(key string) (*data.Record, error) { + keyval, err := m.Client.Get(key) + if err != nil && err == mc.ErrCacheMiss { + return nil, data.ErrNotFound + } else if err != nil { + return nil, err + } + + if keyval == nil { + return nil, data.ErrNotFound + } + + return &data.Record{ + Key: keyval.Key, + Value: keyval.Value, + Expiration: time.Second * time.Duration(keyval.Expiration), + }, nil +} + +func (m *mkv) Delete(key string) error { + return m.Client.Delete(key) +} + +func (m *mkv) Write(record *data.Record) error { + return m.Client.Set(&mc.Item{ + Key: record.Key, + Value: record.Value, + Expiration: int32(record.Expiration.Seconds()), + }) +} + +func (m *mkv) Dump() ([]*data.Record, error) { + // stats + // cachedump + // get keys + + var keys []string + + //data := make(map[string]string) + if err := m.Server.Each(func(c net.Addr) error { + cc, err := net.Dial("tcp", c.String()) + if err != nil { + return err + } + defer cc.Close() + + b := bufio.NewReadWriter(bufio.NewReader(cc), bufio.NewWriter(cc)) + + // get records + if _, err := fmt.Fprintf(b, "stats records\r\n"); err != nil { + return err + } + + b.Flush() + + v, err := b.ReadSlice('\n') + if err != nil { + return err + } + + parts := bytes.Split(v, []byte("\n")) + if len(parts) < 1 { + return nil + } + vals := strings.Split(string(parts[0]), ":") + records := vals[1] + + // drain + for { + buf, err := b.ReadSlice('\n') + if err == io.EOF { + break + } + if err != nil { + return err + } + if strings.HasPrefix(string(buf), "END") { + break + } + } + + b.Writer.Reset(cc) + b.Reader.Reset(cc) + + if _, err := fmt.Fprintf(b, "lru_crawler metadump %s\r\n", records); err != nil { + return err + } + b.Flush() + + for { + v, err := b.ReadString('\n') + if err == io.EOF { + break + } + if err != nil { + return err + } + if strings.HasPrefix(v, "END") { + break + } + key := strings.Split(v, " ")[0] + keys = append(keys, strings.TrimPrefix(key, "key=")) + } + + return nil + }); err != nil { + return nil, err + } + + var vals []*data.Record + + // concurrent op + ch := make(chan *data.Record, len(keys)) + + for _, k := range keys { + go func(key string) { + i, _ := m.Read(key) + ch <- i + }(k) + } + + for i := 0; i < len(keys); i++ { + record := <-ch + + if record == nil { + continue + } + + vals = append(vals, record) + } + + close(ch) + + return vals, nil +} + +func (m *mkv) String() string { + return "memcached" +} + +func NewData(opts ...data.Option) data.Data { + var options data.Options + for _, o := range opts { + o(&options) + } + + if len(options.Nodes) == 0 { + options.Nodes = []string{"127.0.0.1:11211"} + } + + ss := new(mc.ServerList) + ss.SetServers(options.Nodes...) + + return &mkv{ + Server: ss, + Client: mc.New(options.Nodes...), + } +} diff --git a/sync/data/options.go b/sync/data/options.go new file mode 100644 index 00000000..1d85aca3 --- /dev/null +++ b/sync/data/options.go @@ -0,0 +1,19 @@ +package data + +type Options struct { + Nodes []string + Prefix string +} + +func Nodes(a ...string) Option { + return func(o *Options) { + o.Nodes = a + } +} + +// Prefix sets a prefix to any lock ids used +func Prefix(p string) Option { + return func(o *Options) { + o.Prefix = p + } +} diff --git a/sync/data/redis/redis.go b/sync/data/redis/redis.go new file mode 100644 index 00000000..05f05529 --- /dev/null +++ b/sync/data/redis/redis.go @@ -0,0 +1,82 @@ +package redis + +import ( + "github.com/micro/go-micro/sync/data" + redis "gopkg.in/redis.v3" +) + +type rkv struct { + Client *redis.Client +} + +func (r *rkv) Read(key string) (*data.Record, error) { + val, err := r.Client.Get(key).Bytes() + + if err != nil && err == redis.Nil { + return nil, data.ErrNotFound + } else if err != nil { + return nil, err + } + + if val == nil { + return nil, data.ErrNotFound + } + + d, err := r.Client.TTL(key).Result() + if err != nil { + return nil, err + } + + return &data.Record{ + Key: key, + Value: val, + Expiration: d, + }, nil +} + +func (r *rkv) Delete(key string) error { + return r.Client.Del(key).Err() +} + +func (r *rkv) Write(record *data.Record) error { + return r.Client.Set(record.Key, record.Value, record.Expiration).Err() +} + +func (r *rkv) Dump() ([]*data.Record, error) { + keys, err := r.Client.Keys("*").Result() + if err != nil { + return nil, err + } + var vals []*data.Record + for _, k := range keys { + i, err := r.Read(k) + if err != nil { + return nil, err + } + vals = append(vals, i) + } + return vals, nil +} + +func (r *rkv) String() string { + return "redis" +} + +func NewData(opts ...data.Option) data.Data { + var options data.Options + for _, o := range opts { + o(&options) + } + + if len(options.Nodes) == 0 { + options.Nodes = []string{"127.0.0.1:6379"} + } + + return &rkv{ + Client: redis.NewClient(&redis.Options{ + Addr: options.Nodes[0], + Password: "", // no password set + DB: 0, // use default DB + }), + } +} diff --git a/sync/db.go b/sync/db.go new file mode 100644 index 00000000..a16af598 --- /dev/null +++ b/sync/db.go @@ -0,0 +1,157 @@ +package sync + +import ( + "bytes" + "encoding/base64" + "encoding/json" + "fmt" + + "github.com/micro/go-micro/sync/data" + ckv "github.com/micro/go-micro/sync/data/consul" + lock "github.com/micro/go-micro/sync/lock/consul" +) + +type syncDB struct { + opts Options +} + +func ekey(k interface{}) string { + b, _ := json.Marshal(k) + return base64.StdEncoding.EncodeToString(b) +} + +func (m *syncDB) Read(key, val interface{}) error { + if key == nil { + return fmt.Errorf("key is nil") + } + + kstr := ekey(key) + + // lock + if err := m.opts.Lock.Acquire(kstr); err != nil { + return err + } + defer m.opts.Lock.Release(kstr) + + // get key + kval, err := m.opts.Data.Read(kstr) + if err != nil { + return err + } + + // decode value + return json.Unmarshal(kval.Value, val) +} + +func (m *syncDB) Write(key, val interface{}) error { + if key == nil { + return fmt.Errorf("key is nil") + } + + kstr := ekey(key) + + // lock + if err := m.opts.Lock.Acquire(kstr); err != nil { + return err + } + defer m.opts.Lock.Release(kstr) + + // encode value + b, err := json.Marshal(val) + if err != nil { + return err + } + + // set key + return m.opts.Data.Write(&data.Record{ + Key: kstr, + Value: b, + }) +} + +func (m *syncDB) Delete(key interface{}) error { + if key == nil { + return fmt.Errorf("key is nil") + } + + kstr := ekey(key) + + // lock + if err := m.opts.Lock.Acquire(kstr); err != nil { + return err + } + defer m.opts.Lock.Release(kstr) + return m.opts.Data.Delete(kstr) +} + +func (m *syncDB) Iterate(fn func(key, val interface{}) error) error { + keyvals, err := m.opts.Data.Dump() + if err != nil { + return err + } + + for _, keyval := range keyvals { + // lock + if err := m.opts.Lock.Acquire(keyval.Key); err != nil { + return err + } + // unlock + defer m.opts.Lock.Release(keyval.Key) + + // unmarshal value + var val interface{} + + if len(keyval.Value) > 0 && keyval.Value[0] == '{' { + if err := json.Unmarshal(keyval.Value, &val); err != nil { + return err + } + } else { + val = keyval.Value + } + + // exec func + if err := fn(keyval.Key, val); err != nil { + return err + } + + // save val + b, err := json.Marshal(val) + if err != nil { + return err + } + + // no save + if i := bytes.Compare(keyval.Value, b); i == 0 { + return nil + } + + // set key + if err := m.opts.Data.Write(&data.Record{ + Key: keyval.Key, + Value: b, + }); err != nil { + return err + } + } + + return nil +} + +func NewDB(opts ...Option) DB { + var options Options + for _, o := range opts { + o(&options) + } + + if options.Lock == nil { + options.Lock = lock.NewLock() + } + + if options.Data == nil { + options.Data = ckv.NewData() + } + + return &syncDB{ + opts: options, + } +} diff --git a/sync/event/event.go b/sync/event/event.go new file mode 100644 index 00000000..bd85d16c --- /dev/null +++ b/sync/event/event.go @@ -0,0 +1,27 @@ +// Package event provides a distributed log interface +package event + +// Event provides a distributed log interface +type Event interface { + // Log retrieves the log with an id/name + Log(id string) (Log, error) +} + +// Log is an individual event log +type Log interface { + // Close the log handle + Close() error + // Log ID + Id() string + // Read will read the next record + Read() (*Record, error) + // Go to an offset + Seek(offset int64) error + // Write an event to the log + Write(*Record) error +} + +type Record struct { + Metadata map[string]interface{} + Data []byte +} diff --git a/sync/leader/consul/consul.go b/sync/leader/consul/consul.go new file mode 100644 index 00000000..b5b344c6 --- /dev/null +++ b/sync/leader/consul/consul.go @@ -0,0 +1,158 @@ +package consul + +import ( + "fmt" + "log" + "net" + "os" + "path" + "sync" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/api/watch" + "github.com/micro/go-micro/sync/leader" +) + +type consulLeader struct { + opts leader.Options + c *api.Client +} + +type consulElected struct { + c *api.Client + l *api.Lock + id string + key string + opts leader.ElectOptions + + mtx sync.RWMutex + rv <-chan struct{} +} + +func (c *consulLeader) Elect(id string, opts ...leader.ElectOption) (leader.Elected, error) { + var options leader.ElectOptions + for _, o := range opts { + o(&options) + } + + key := path.Join("micro/leader", c.opts.Group) + + lc, err := c.c.LockOpts(&api.LockOptions{ + Key: key, + Value: []byte(id), + }) + if err != nil { + return nil, err + } + + rv, err := lc.Lock(nil) + if err != nil { + return nil, err + } + + return &consulElected{ + c: c.c, + key: key, + rv: rv, + id: id, + l: lc, + opts: options, + }, nil +} + +func (c *consulLeader) Follow() chan string { + ch := make(chan string, 1) + + key := path.Join("/micro/leader", c.opts.Group) + + p, err := watch.Parse(map[string]interface{}{ + "type": "key", + "key": key, + }) + if err != nil { + return ch + } + p.Handler = func(idx uint64, raw interface{}) { + if raw == nil { + return // ignore + } + v, ok := raw.(*api.KVPair) + if !ok || v == nil { + return // ignore + } + ch <- string(v.Value) + } + + go p.RunWithClientAndLogger(c.c, log.New(os.Stdout, "consul: ", log.Lshortfile)) + return ch +} + +func (c *consulLeader) String() string { + return "consul" +} + +func (c *consulElected) Id() string { + return c.id +} + +func (c *consulElected) Reelect() error { + rv, err := c.l.Lock(nil) + if err != nil { + return err + } + + c.mtx.Lock() + c.rv = rv + c.mtx.Unlock() + return nil +} + +func (c *consulElected) Revoked() chan bool { + ch := make(chan bool, 1) + c.mtx.RLock() + rv := c.rv + c.mtx.RUnlock() + + go func() { + <-rv + ch <- true + close(ch) + }() + + return ch +} + +func (c *consulElected) Resign() error { + return c.l.Unlock() +} + +func NewLeader(opts ...leader.Option) leader.Leader { + options := leader.Options{ + Group: "default", + } + for _, o := range opts { + o(&options) + } + + config := api.DefaultConfig() + + // set host + // config.Host something + // check if there are any addrs + if len(options.Nodes) > 0 { + addr, port, err := net.SplitHostPort(options.Nodes[0]) + if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { + port = "8500" + config.Address = fmt.Sprintf("%s:%s", addr, port) + } else if err == nil { + config.Address = fmt.Sprintf("%s:%s", addr, port) + } + } + + client, _ := api.NewClient(config) + + return &consulLeader{ + opts: options, + c: client, + } +} diff --git a/sync/leader/etcd/etcd.go b/sync/leader/etcd/etcd.go new file mode 100644 index 00000000..603c698f --- /dev/null +++ b/sync/leader/etcd/etcd.go @@ -0,0 +1,145 @@ +package etcd + +import ( + "context" + "log" + "path" + "strings" + + "github.com/micro/go-micro/sync/leader" + client "go.etcd.io/etcd/clientv3" + cc "go.etcd.io/etcd/clientv3/concurrency" +) + +type etcdLeader struct { + opts leader.Options + path string + client *client.Client +} + +type etcdElected struct { + s *cc.Session + e *cc.Election + id string +} + +func (e *etcdLeader) Elect(id string, opts ...leader.ElectOption) (leader.Elected, error) { + var options leader.ElectOptions + for _, o := range opts { + o(&options) + } + + // make path + path := path.Join(e.path, strings.Replace(id, "/", "-", -1)) + + s, err := cc.NewSession(e.client) + if err != nil { + return nil, err + } + + l := cc.NewElection(s, path) + + ctx, _ := context.WithCancel(context.Background()) + + if err := l.Campaign(ctx, id); err != nil { + return nil, err + } + + return &etcdElected{ + e: l, + id: id, + }, nil +} + +func (e *etcdLeader) Follow() chan string { + ch := make(chan string) + + s, err := cc.NewSession(e.client) + if err != nil { + return ch + } + + l := cc.NewElection(s, e.path) + ech := l.Observe(context.Background()) + + go func() { + for { + select { + case r, ok := <-ech: + if !ok { + return + } + ch <- string(r.Kvs[0].Value) + } + } + }() + + return ch +} + +func (e *etcdLeader) String() string { + return "etcd" +} + +func (e *etcdElected) Reelect() error { + ctx, _ := context.WithCancel(context.Background()) + return e.e.Campaign(ctx, e.id) +} + +func (e *etcdElected) Revoked() chan bool { + ch := make(chan bool, 1) + ech := e.e.Observe(context.Background()) + + go func() { + for r := range ech { + if string(r.Kvs[0].Value) != e.id { + ch <- true + close(ch) + return + } + } + }() + + return ch +} + +func (e *etcdElected) Resign() error { + return e.e.Resign(context.Background()) +} + +func (e *etcdElected) Id() string { + return e.id +} + +func NewLeader(opts ...leader.Option) leader.Leader { + var options leader.Options + for _, o := range opts { + o(&options) + } + + var endpoints []string + + for _, addr := range options.Nodes { + if len(addr) > 0 { + endpoints = append(endpoints, addr) + } + } + + if len(endpoints) == 0 { + endpoints = []string{"http://127.0.0.1:2379"} + } + + // TODO: parse addresses + c, err := client.New(client.Config{ + Endpoints: endpoints, + }) + if err != nil { + log.Fatal(err) + } + + return &etcdLeader{ + path: "/micro/leader", + client: c, + opts: options, + } +} diff --git a/sync/leader/leader.go b/sync/leader/leader.go new file mode 100644 index 00000000..a4ac53f3 --- /dev/null +++ b/sync/leader/leader.go @@ -0,0 +1,25 @@ +// Package leader provides leader election +package leader + +// Leader provides leadership election +type Leader interface { + // elect leader + Elect(id string, opts ...ElectOption) (Elected, error) + // follow the leader + Follow() chan string +} + +type Elected interface { + // id of leader + Id() string + // seek re-election + Reelect() error + // resign leadership + Resign() error + // observe leadership revocation + Revoked() chan bool +} + +type Option func(o *Options) + +type ElectOption func(o *ElectOptions) diff --git a/sync/leader/options.go b/sync/leader/options.go new file mode 100644 index 00000000..05e92e91 --- /dev/null +++ b/sync/leader/options.go @@ -0,0 +1,22 @@ +package leader + +type Options struct { + Nodes []string + Group string +} + +type ElectOptions struct{} + +// Nodes sets the addresses of the underlying systems +func Nodes(a ...string) Option { + return func(o *Options) { + o.Nodes = a + } +} + +// Group sets the group name for coordinating leadership +func Group(g string) Option { + return func(o *Options) { + o.Group = g + } +} diff --git a/sync/lock/consul/consul.go b/sync/lock/consul/consul.go new file mode 100644 index 00000000..ef0f2dd4 --- /dev/null +++ b/sync/lock/consul/consul.go @@ -0,0 +1,104 @@ +// Package consul is a consul implemenation of lock +package consul + +import ( + "errors" + "fmt" + "net" + "sync" + "time" + + "github.com/hashicorp/consul/api" + lock "github.com/micro/go-micro/sync/lock" +) + +type consulLock struct { + sync.Mutex + + locks map[string]*api.Lock + opts lock.Options + c *api.Client +} + +func (c *consulLock) Acquire(id string, opts ...lock.AcquireOption) error { + var options lock.AcquireOptions + for _, o := range opts { + o(&options) + } + + if options.Wait <= time.Duration(0) { + options.Wait = api.DefaultLockWaitTime + } + + ttl := fmt.Sprintf("%v", options.TTL) + if options.TTL <= time.Duration(0) { + ttl = api.DefaultLockSessionTTL + } + + l, err := c.c.LockOpts(&api.LockOptions{ + Key: c.opts.Prefix + id, + LockWaitTime: options.Wait, + SessionTTL: ttl, + }) + + if err != nil { + return err + } + + _, err = l.Lock(nil) + if err != nil { + return err + } + + c.Lock() + c.locks[id] = l + c.Unlock() + + return nil +} + +func (c *consulLock) Release(id string) error { + c.Lock() + defer c.Unlock() + l, ok := c.locks[id] + if !ok { + return errors.New("lock not found") + } + err := l.Unlock() + delete(c.locks, id) + return err +} + +func (c *consulLock) String() string { + return "consul" +} + +func NewLock(opts ...lock.Option) lock.Lock { + var options lock.Options + for _, o := range opts { + o(&options) + } + + config := api.DefaultConfig() + + // set host + // config.Host something + // check if there are any addrs + if len(options.Nodes) > 0 { + addr, port, err := net.SplitHostPort(options.Nodes[0]) + if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { + port = "8500" + config.Address = fmt.Sprintf("%s:%s", options.Nodes[0], port) + } else if err == nil { + config.Address = fmt.Sprintf("%s:%s", addr, port) + } + } + + client, _ := api.NewClient(config) + + return &consulLock{ + locks: make(map[string]*api.Lock), + opts: options, + c: client, + } +} diff --git a/sync/lock/etcd/etcd.go b/sync/lock/etcd/etcd.go new file mode 100644 index 00000000..d506e7b5 --- /dev/null +++ b/sync/lock/etcd/etcd.go @@ -0,0 +1,115 @@ +// Package etcd is an etcd implementation of lock +package etcd + +import ( + "context" + "errors" + "log" + "path" + "strings" + "sync" + + "github.com/micro/go-micro/sync/lock" + client "go.etcd.io/etcd/clientv3" + cc "go.etcd.io/etcd/clientv3/concurrency" +) + +type etcdLock struct { + opts lock.Options + path string + client *client.Client + + sync.Mutex + locks map[string]*elock +} + +type elock struct { + s *cc.Session + m *cc.Mutex +} + +func (e *etcdLock) Acquire(id string, opts ...lock.AcquireOption) error { + var options lock.AcquireOptions + for _, o := range opts { + o(&options) + } + + // make path + path := path.Join(e.path, strings.Replace(e.opts.Prefix+id, "/", "-", -1)) + + var sopts []cc.SessionOption + if options.TTL > 0 { + sopts = append(sopts, cc.WithTTL(int(options.TTL.Seconds()))) + } + + s, err := cc.NewSession(e.client, sopts...) + if err != nil { + return err + } + + m := cc.NewMutex(s, path) + + ctx, _ := context.WithCancel(context.Background()) + + if err := m.Lock(ctx); err != nil { + return err + } + + e.Lock() + e.locks[id] = &elock{ + s: s, + m: m, + } + e.Unlock() + return nil +} + +func (e *etcdLock) Release(id string) error { + e.Lock() + defer e.Unlock() + v, ok := e.locks[id] + if !ok { + return errors.New("lock not found") + } + err := v.m.Unlock(context.Background()) + delete(e.locks, id) + return err +} + +func (e *etcdLock) String() string { + return "etcd" +} + +func NewLock(opts ...lock.Option) lock.Lock { + var options lock.Options + for _, o := range opts { + o(&options) + } + + var endpoints []string + + for _, addr := range options.Nodes { + if len(addr) > 0 { + endpoints = append(endpoints, addr) + } + } + + if len(endpoints) == 0 { + endpoints = []string{"http://127.0.0.1:2379"} + } + + // TODO: parse addresses + c, err := client.New(client.Config{ + Endpoints: endpoints, + }) + if err != nil { + log.Fatal(err) + } + + return &etcdLock{ + path: "/micro/lock", + client: c, + opts: options, + locks: make(map[string]*elock), + } +} diff --git a/sync/lock/lock.go b/sync/lock/lock.go new file mode 100644 index 00000000..8be6629f --- /dev/null +++ b/sync/lock/lock.go @@ -0,0 +1,27 @@ +// Package lock provides distributed locking +package lock + +import ( + "time" +) + +// Lock is a distributed locking interface +type Lock interface { + // Acquire a lock with given id + Acquire(id string, opts ...AcquireOption) error + // Release the lock with given id + Release(id string) error +} + +type Options struct { + Nodes []string + Prefix string +} + +type AcquireOptions struct { + TTL time.Duration + Wait time.Duration +} + +type Option func(o *Options) +type AcquireOption func(o *AcquireOptions) diff --git a/sync/lock/options.go b/sync/lock/options.go new file mode 100644 index 00000000..4804ff9c --- /dev/null +++ b/sync/lock/options.go @@ -0,0 +1,33 @@ +package lock + +import ( + "time" +) + +// Nodes sets the addresses the underlying lock implementation +func Nodes(a ...string) Option { + return func(o *Options) { + o.Nodes = a + } +} + +// Prefix sets a prefix to any lock ids used +func Prefix(p string) Option { + return func(o *Options) { + o.Prefix = p + } +} + +// TTL sets the lock ttl +func TTL(t time.Duration) AcquireOption { + return func(o *AcquireOptions) { + o.TTL = t + } +} + +// Wait sets the wait time +func Wait(t time.Duration) AcquireOption { + return func(o *AcquireOptions) { + o.Wait = t + } +} diff --git a/sync/lock/redis/pool.go b/sync/lock/redis/pool.go new file mode 100644 index 00000000..bc80a0b9 --- /dev/null +++ b/sync/lock/redis/pool.go @@ -0,0 +1,29 @@ +package redis + +import ( + "sync" + + "github.com/gomodule/redigo/redis" +) + +type pool struct { + sync.Mutex + i int + addrs []string +} + +func (p *pool) Get() redis.Conn { + for i := 0; i < 3; i++ { + p.Lock() + addr := p.addrs[p.i%len(p.addrs)] + p.i++ + p.Unlock() + + c, err := redis.Dial("tcp", addr) + if err != nil { + continue + } + return c + } + return nil +} diff --git a/sync/lock/redis/redis.go b/sync/lock/redis/redis.go new file mode 100644 index 00000000..2ea4a676 --- /dev/null +++ b/sync/lock/redis/redis.go @@ -0,0 +1,94 @@ +// Package redis is a redis implemenation of lock +package redis + +import ( + "errors" + "sync" + "time" + + "github.com/go-redsync/redsync" + "github.com/micro/go-micro/sync/lock" +) + +type redisLock struct { + sync.Mutex + + locks map[string]*redsync.Mutex + opts lock.Options + c *redsync.Redsync +} + +func (r *redisLock) Acquire(id string, opts ...lock.AcquireOption) error { + var options lock.AcquireOptions + for _, o := range opts { + o(&options) + } + + var ropts []redsync.Option + + if options.Wait > time.Duration(0) { + ropts = append(ropts, redsync.SetRetryDelay(options.Wait)) + ropts = append(ropts, redsync.SetTries(1)) + } + + if options.TTL > time.Duration(0) { + ropts = append(ropts, redsync.SetExpiry(options.TTL)) + } + + m := r.c.NewMutex(r.opts.Prefix+id, ropts...) + err := m.Lock() + if err != nil { + return err + } + + r.Lock() + r.locks[id] = m + r.Unlock() + + return nil +} + +func (r *redisLock) Release(id string) error { + r.Lock() + defer r.Unlock() + m, ok := r.locks[id] + if !ok { + return errors.New("lock not found") + } + + unlocked := m.Unlock() + delete(r.locks, id) + + if !unlocked { + return errors.New("lock not unlocked") + } + + return nil +} + +func (r *redisLock) String() string { + return "redis" +} + +func NewLock(opts ...lock.Option) lock.Lock { + var options lock.Options + for _, o := range opts { + o(&options) + } + + nodes := options.Nodes + + if len(nodes) == 0 { + nodes = []string{"127.0.0.1:6379"} + } + + rpool := redsync.New([]redsync.Pool{&pool{ + addrs: nodes, + }}) + + return &redisLock{ + locks: make(map[string]*redsync.Mutex), + opts: options, + c: rpool, + } +} diff --git a/sync/options.go b/sync/options.go new file mode 100644 index 00000000..8b46acf0 --- /dev/null +++ b/sync/options.go @@ -0,0 +1,36 @@ +package sync + +import ( + "github.com/micro/go-micro/sync/data" + "github.com/micro/go-micro/sync/leader" + "github.com/micro/go-micro/sync/lock" + "github.com/micro/go-micro/sync/time" +) + +// WithLeader sets the leader election implementation opton +func WithLeader(l leader.Leader) Option { + return func(o *Options) { + o.Leader = l + } +} + +// WithLock sets the locking implementation option +func WithLock(l lock.Lock) Option { + return func(o *Options) { + o.Lock = l + } +} + +// WithData sets the data implementation option +func WithData(s data.Data) Option { + return func(o *Options) { + o.Data = s + } +} + +// WithTime sets the time implementation option +func WithTime(t time.Time) Option { + return func(o *Options) { + o.Time = t + } +} diff --git a/sync/sync.go b/sync/sync.go new file mode 100644 index 00000000..7cb63c51 --- /dev/null +++ b/sync/sync.go @@ -0,0 +1,41 @@ +// Package sync is a distributed synchronization framework +package sync + +import ( + "github.com/micro/go-micro/sync/data" + "github.com/micro/go-micro/sync/leader" + "github.com/micro/go-micro/sync/lock" + "github.com/micro/go-micro/sync/task" + "github.com/micro/go-micro/sync/time" +) + +// DB provides synchronized access to key-value storage. +// It uses the data interface and lock interface to +// provide a consistent storage mechanism. +type DB interface { + // Read value with given key + Read(key, val interface{}) error + // Write value with given key + Write(key, val interface{}) error + // Delete value with given key + Delete(key interface{}) error + // Iterate over all key/vals. Value changes are saved + Iterate(func(key, val interface{}) error) error +} + +// Cron is a distributed scheduler using leader election +// and distributed task runners. It uses the leader and +// task interfaces. +type Cron interface { + Schedule(task.Schedule, task.Command) error +} + +type Options struct { + Leader leader.Leader + Lock lock.Lock + Data data.Data + Task task.Task + Time time.Time +} + +type Option func(o *Options) diff --git a/sync/task/broker/broker.go b/sync/task/broker/broker.go new file mode 100644 index 00000000..af0ee673 --- /dev/null +++ b/sync/task/broker/broker.go @@ -0,0 +1,219 @@ +// Package broker provides a distributed task manager built on the micro broker +package broker + +import ( + "context" + "errors" + "fmt" + "math/rand" + "strings" + "sync" + "time" + + "github.com/google/uuid" + "github.com/micro/go-micro/broker" + "github.com/micro/go-micro/sync/task" +) + +type brokerKey struct{} + +// Task is a broker task +type Task struct { + // a micro broker + Broker broker.Broker + // Options + Options task.Options + + mtx sync.RWMutex + status string +} + +func returnError(err error, ch chan error) { + select { + case ch <- err: + default: + } +} + +func (t *Task) Run(c task.Command) error { + // connect + t.Broker.Connect() + // unique id for this runner + id := uuid.New().String() + // topic of the command + topic := fmt.Sprintf("task.%s", c.Name) + + // global error + errCh := make(chan error, t.Options.Pool) + + // subscribe for distributed work + workFn := func(p broker.Publication) error { + msg := p.Message() + + // get command name + command := msg.Header["Command"] + + // check the command is what we expect + if command != c.Name { + returnError(errors.New("received unknown command: "+command), errCh) + return nil + } + + // new task created + switch msg.Header["Status"] { + case "start": + // artificially delay start of processing + time.Sleep(time.Millisecond * time.Duration(10+rand.Intn(100))) + + // execute the function + err := c.Func() + + status := "done" + errors := "" + + if err != nil { + status = "error" + errors = err.Error() + } + + // create response + msg := &broker.Message{ + Header: map[string]string{ + "Command": c.Name, + "Error": errors, + "Id": id, + "Status": status, + "Timestamp": fmt.Sprintf("%d", time.Now().Unix()), + }, + // Body is nil, may be used in future + } + + // publish end of task + if err := t.Broker.Publish(topic, msg); err != nil { + returnError(err, errCh) + } + } + + return nil + } + + // subscribe for the pool size + for i := 0; i < t.Options.Pool; i++ { + // subscribe to work + subWork, err := t.Broker.Subscribe(topic, workFn, broker.Queue(fmt.Sprintf("work.%d", i))) + if err != nil { + return err + } + + // unsubscribe on completion + defer subWork.Unsubscribe() + } + + // subscribe to all status messages + subStatus, err := t.Broker.Subscribe(topic, func(p broker.Publication) error { + msg := p.Message() + + // get command name + command := msg.Header["Command"] + + // check the command is what we expect + if command != c.Name { + return nil + } + + // check task status + switch msg.Header["Status"] { + // task is complete + case "done": + errCh <- nil + // someone failed + case "error": + returnError(errors.New(msg.Header["Error"]), errCh) + } + + return nil + }) + if err != nil { + return err + } + defer subStatus.Unsubscribe() + + // a new task + msg := &broker.Message{ + Header: map[string]string{ + "Command": c.Name, + "Id": id, + "Status": "start", + "Timestamp": fmt.Sprintf("%d", time.Now().Unix()), + }, + } + + // artificially delay the start of the task + time.Sleep(time.Millisecond * time.Duration(10+rand.Intn(100))) + + // publish the task + if err := t.Broker.Publish(topic, msg); err != nil { + return err + } + + var gerrors []string + + // wait for all responses + for i := 0; i < t.Options.Pool; i++ { + // check errors + err := <-errCh + + // append to errors + if err != nil { + gerrors = append(gerrors, err.Error()) + } + } + + // return the errors + if len(gerrors) > 0 { + return errors.New("errors: " + strings.Join(gerrors, "\n")) + } + + return nil +} + +func (t *Task) Status() string { + t.mtx.RLock() + defer t.mtx.RUnlock() + return t.status +} + +// Broker sets the micro broker +func WithBroker(b broker.Broker) task.Option { + return func(o *task.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, brokerKey{}, b) + } +} + +// NewTask returns a new broker task +func NewTask(opts ...task.Option) task.Task { + options := task.Options{ + Context: context.Background(), + } + + for _, o := range opts { + o(&options) + } + + if options.Pool == 0 { + options.Pool = 1 + } + + b, ok := options.Context.Value(brokerKey{}).(broker.Broker) + if !ok { + b = broker.DefaultBroker + } + + return &Task{ + Broker: b, + Options: options, + } +} diff --git a/sync/task/local/local.go b/sync/task/local/local.go new file mode 100644 index 00000000..94aa7707 --- /dev/null +++ b/sync/task/local/local.go @@ -0,0 +1,59 @@ +// Package local provides a local task runner +package local + +import ( + "fmt" + "sync" + + "github.com/micro/go-micro/sync/task" +) + +type localTask struct { + opts task.Options + mtx sync.RWMutex + status string +} + +func (l *localTask) Run(t task.Command) error { + ch := make(chan error, l.opts.Pool) + + for i := 0; i < l.opts.Pool; i++ { + go func() { + ch <- t.Execute() + }() + } + + var err error + + for i := 0; i < l.opts.Pool; i++ { + er := <-ch + if err != nil { + err = er + l.mtx.Lock() + l.status = fmt.Sprintf("command [%s] status: %s", t.Name, err.Error()) + l.mtx.Unlock() + } + } + + close(ch) + return err +} + +func (l *localTask) Status() string { + l.mtx.RLock() + defer l.mtx.RUnlock() + return l.status +} + +func NewTask(opts ...task.Option) task.Task { + var options task.Options + for _, o := range opts { + o(&options) + } + if options.Pool == 0 { + options.Pool = 1 + } + return &localTask{ + opts: options, + } +} diff --git a/sync/task/task.go b/sync/task/task.go new file mode 100644 index 00000000..031355ca --- /dev/null +++ b/sync/task/task.go @@ -0,0 +1,83 @@ +// Package task provides an interface for distributed jobs +package task + +import ( + "context" + "fmt" + "time" +) + +// Task represents a distributed task +type Task interface { + // Run runs a command immediately until completion + Run(Command) error + // Status provides status of last execution + Status() string +} + +// Command to be executed +type Command struct { + Name string + Func func() error +} + +// Schedule represents a time or interval at which a task should run +type Schedule struct { + // When to start the schedule. Zero time means immediately + Time time.Time + // Non zero interval dictates an ongoing schedule + Interval time.Duration +} + +type Options struct { + // Pool size for workers + Pool int + // Alternative options + Context context.Context +} + +type Option func(o *Options) + +func (c Command) Execute() error { + return c.Func() +} + +func (c Command) String() string { + return c.Name +} + +func (s Schedule) Run() <-chan time.Time { + d := s.Time.Sub(time.Now()) + + ch := make(chan time.Time, 1) + + go func() { + // wait for start time + <-time.After(d) + + // zero interval + if s.Interval == time.Duration(0) { + ch <- time.Now() + close(ch) + return + } + + // start ticker + for t := range time.Tick(s.Interval) { + ch <- t + } + }() + + return ch +} + +func (s Schedule) String() string { + return fmt.Sprintf("%d-%d", s.Time.Unix(), s.Interval) +} + +// WithPool sets the pool size for concurrent work +func WithPool(i int) Option { + return func(o *Options) { + o.Pool = i + } +} diff --git a/sync/time/local/local.go b/sync/time/local/local.go new file mode 100644 index 00000000..a3d899c1 --- /dev/null +++ b/sync/time/local/local.go @@ -0,0 +1,18 @@ +// Package local provides a local clock +package local + +import ( + gotime "time" + + "github.com/micro/go-micro/sync/time" +) + +type Time struct{} + +func (t *Time) Now() (gotime.Time, error) { + return gotime.Now(), nil +} + +func NewTime(opts ...time.Option) time.Time { + return new(Time) +} diff --git a/sync/time/ntp/ntp.go b/sync/time/ntp/ntp.go new file mode 100644 index 00000000..2de6a852 --- /dev/null +++ b/sync/time/ntp/ntp.go @@ -0,0 +1,51 @@ +// Package ntp provides ntp synchronized time +package ntp + +import ( + "context" + gotime "time" + + "github.com/beevik/ntp" + "github.com/micro/go-micro/sync/time" +) + +type ntpTime struct { + server string +} + +type ntpServerKey struct{} + +func (n *ntpTime) Now() (gotime.Time, error) { + return ntp.Time(n.server) +} + +// NewTime returns ntp time +func NewTime(opts ...time.Option) time.Time { + options := time.Options{ + Context: context.Background(), + } + + for _, o := range opts { + o(&options) + } + + server := "time.google.com" + + if k, ok := options.Context.Value(ntpServerKey{}).(string); ok { + server = k + } + + return &ntpTime{ + server: server, + } +} + +// WithServer sets the ntp server +func WithServer(s string) time.Option { + return func(o *time.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, ntpServerKey{}, s) + } +} diff --git a/sync/time/time.go b/sync/time/time.go new file mode 100644 index 00000000..7c11a751 --- /dev/null +++ b/sync/time/time.go @@ -0,0 +1,18 @@ +// Package time provides clock synchronization +package time + +import ( + "context" + "time" +) + +// Time returns synchronized time +type Time interface { + Now() (time.Time, error) +} + +type Options struct { + Context context.Context +} + +type Option func(o *Options) From f2139e2a162354c61803b5c9a3cdd4ad32f7ee9b Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 01:22:19 +0100 Subject: [PATCH 12/18] Add debug => go-debug --- debug/README.md | 17 + debug/handler/handler.go | 2 + debug/handler/http/http.go | 17 + debug/handler/rpc/proto/debug.micro.go | 157 +++++++ debug/handler/rpc/proto/debug.pb.go | 561 +++++++++++++++++++++++++ debug/handler/rpc/proto/debug.proto | 36 ++ debug/handler/rpc/rpc.go | 27 ++ debug/health/health.go | 28 ++ debug/log/log.go | 36 ++ debug/stats/stats.go | 24 ++ debug/store/buffer/buffer.go | 62 +++ debug/store/store.go | 27 ++ debug/trace/trace.go | 29 ++ 13 files changed, 1023 insertions(+) create mode 100644 debug/README.md create mode 100644 debug/handler/handler.go create mode 100644 debug/handler/http/http.go create mode 100644 debug/handler/rpc/proto/debug.micro.go create mode 100644 debug/handler/rpc/proto/debug.pb.go create mode 100644 debug/handler/rpc/proto/debug.proto create mode 100644 debug/handler/rpc/rpc.go create mode 100644 debug/health/health.go create mode 100644 debug/log/log.go create mode 100644 debug/stats/stats.go create mode 100644 debug/store/buffer/buffer.go create mode 100644 debug/store/store.go create mode 100644 debug/trace/trace.go diff --git a/debug/README.md b/debug/README.md new file mode 100644 index 00000000..7c70e92f --- /dev/null +++ b/debug/README.md @@ -0,0 +1,17 @@ +# Debug + +Debug is a debugging library for microservices + +## Overview + +Debug is a pluggable library for debugging. It includes base level requirements for logging, tracing and metrics. +Our goal is to provide a simple experience for understanding what's happening in a running system with zero dependencies +by default or by plugging into robust systems like ELK, zipkin, etc. + +## Features + +- Health (Checks) +- Log (Logging) +- Stats (Metrics) +- Trace (Requests) + diff --git a/debug/handler/handler.go b/debug/handler/handler.go new file mode 100644 index 00000000..8715044f --- /dev/null +++ b/debug/handler/handler.go @@ -0,0 +1,2 @@ +// Package handler provides handlers +package handler diff --git a/debug/handler/http/http.go b/debug/handler/http/http.go new file mode 100644 index 00000000..41b4ec23 --- /dev/null +++ b/debug/handler/http/http.go @@ -0,0 +1,17 @@ +// Package http provides http handlers +package http + +import ( + "net/http" +) + +type Handler struct{} + +func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/debug/health": + case "/debug/log": + case "/debug/stats": + case "/debug/trace": + } +} diff --git a/debug/handler/rpc/proto/debug.micro.go b/debug/handler/rpc/proto/debug.micro.go new file mode 100644 index 00000000..dd3ec138 --- /dev/null +++ b/debug/handler/rpc/proto/debug.micro.go @@ -0,0 +1,157 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: go-debug/handler/rpc/proto/debug.proto + +/* +Package go_micro_debug is a generated protocol buffer package. + +It is generated from these files: + go-debug/handler/rpc/proto/debug.proto + +It has these top-level messages: + Check + Log + Stats + Trace + Request + HealthResponse + LogResponse + StatsResponse + TraceResponse +*/ +package go_micro_debug + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "context" + client "github.com/micro/go-micro/client" + server "github.com/micro/go-micro/server" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ client.Option +var _ server.Option + +// Client API for Debug service + +type DebugService interface { + Health(ctx context.Context, in *Request, opts ...client.CallOption) (*HealthResponse, error) + Log(ctx context.Context, in *Request, opts ...client.CallOption) (*LogResponse, error) + Stats(ctx context.Context, in *Request, opts ...client.CallOption) (*StatsResponse, error) + Trace(ctx context.Context, in *Request, opts ...client.CallOption) (*TraceResponse, error) +} + +type debugService struct { + c client.Client + name string +} + +func NewDebugService(name string, c client.Client) DebugService { + if c == nil { + c = client.NewClient() + } + if len(name) == 0 { + name = "go.micro.debug" + } + return &debugService{ + c: c, + name: name, + } +} + +func (c *debugService) Health(ctx context.Context, in *Request, opts ...client.CallOption) (*HealthResponse, error) { + req := c.c.NewRequest(c.name, "Debug.Health", in) + out := new(HealthResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugService) Log(ctx context.Context, in *Request, opts ...client.CallOption) (*LogResponse, error) { + req := c.c.NewRequest(c.name, "Debug.Log", in) + out := new(LogResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugService) Stats(ctx context.Context, in *Request, opts ...client.CallOption) (*StatsResponse, error) { + req := c.c.NewRequest(c.name, "Debug.Stats", in) + out := new(StatsResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugService) Trace(ctx context.Context, in *Request, opts ...client.CallOption) (*TraceResponse, error) { + req := c.c.NewRequest(c.name, "Debug.Trace", in) + out := new(TraceResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Debug service + +type DebugHandler interface { + Health(context.Context, *Request, *HealthResponse) error + Log(context.Context, *Request, *LogResponse) error + Stats(context.Context, *Request, *StatsResponse) error + Trace(context.Context, *Request, *TraceResponse) error +} + +func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.HandlerOption) error { + type debug interface { + Health(ctx context.Context, in *Request, out *HealthResponse) error + Log(ctx context.Context, in *Request, out *LogResponse) error + Stats(ctx context.Context, in *Request, out *StatsResponse) error + Trace(ctx context.Context, in *Request, out *TraceResponse) error + } + type Debug struct { + debug + } + h := &debugHandler{hdlr} + return s.Handle(s.NewHandler(&Debug{h}, opts...)) +} + +type debugHandler struct { + DebugHandler +} + +func (h *debugHandler) Health(ctx context.Context, in *Request, out *HealthResponse) error { + return h.DebugHandler.Health(ctx, in, out) +} + +func (h *debugHandler) Log(ctx context.Context, in *Request, out *LogResponse) error { + return h.DebugHandler.Log(ctx, in, out) +} + +func (h *debugHandler) Stats(ctx context.Context, in *Request, out *StatsResponse) error { + return h.DebugHandler.Stats(ctx, in, out) +} + +func (h *debugHandler) Trace(ctx context.Context, in *Request, out *TraceResponse) error { + return h.DebugHandler.Trace(ctx, in, out) +} diff --git a/debug/handler/rpc/proto/debug.pb.go b/debug/handler/rpc/proto/debug.pb.go new file mode 100644 index 00000000..1f4f6771 --- /dev/null +++ b/debug/handler/rpc/proto/debug.pb.go @@ -0,0 +1,561 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: go-debug/handler/rpc/proto/debug.proto + +package go_micro_debug + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Check struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Check) Reset() { *m = Check{} } +func (m *Check) String() string { return proto.CompactTextString(m) } +func (*Check) ProtoMessage() {} +func (*Check) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{0} +} + +func (m *Check) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Check.Unmarshal(m, b) +} +func (m *Check) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Check.Marshal(b, m, deterministic) +} +func (m *Check) XXX_Merge(src proto.Message) { + xxx_messageInfo_Check.Merge(m, src) +} +func (m *Check) XXX_Size() int { + return xxx_messageInfo_Check.Size(m) +} +func (m *Check) XXX_DiscardUnknown() { + xxx_messageInfo_Check.DiscardUnknown(m) +} + +var xxx_messageInfo_Check proto.InternalMessageInfo + +type Log struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Log) Reset() { *m = Log{} } +func (m *Log) String() string { return proto.CompactTextString(m) } +func (*Log) ProtoMessage() {} +func (*Log) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{1} +} + +func (m *Log) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Log.Unmarshal(m, b) +} +func (m *Log) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Log.Marshal(b, m, deterministic) +} +func (m *Log) XXX_Merge(src proto.Message) { + xxx_messageInfo_Log.Merge(m, src) +} +func (m *Log) XXX_Size() int { + return xxx_messageInfo_Log.Size(m) +} +func (m *Log) XXX_DiscardUnknown() { + xxx_messageInfo_Log.DiscardUnknown(m) +} + +var xxx_messageInfo_Log proto.InternalMessageInfo + +type Stats struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Stats) Reset() { *m = Stats{} } +func (m *Stats) String() string { return proto.CompactTextString(m) } +func (*Stats) ProtoMessage() {} +func (*Stats) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{2} +} + +func (m *Stats) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Stats.Unmarshal(m, b) +} +func (m *Stats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Stats.Marshal(b, m, deterministic) +} +func (m *Stats) XXX_Merge(src proto.Message) { + xxx_messageInfo_Stats.Merge(m, src) +} +func (m *Stats) XXX_Size() int { + return xxx_messageInfo_Stats.Size(m) +} +func (m *Stats) XXX_DiscardUnknown() { + xxx_messageInfo_Stats.DiscardUnknown(m) +} + +var xxx_messageInfo_Stats proto.InternalMessageInfo + +type Trace struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Trace) Reset() { *m = Trace{} } +func (m *Trace) String() string { return proto.CompactTextString(m) } +func (*Trace) ProtoMessage() {} +func (*Trace) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{3} +} + +func (m *Trace) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Trace.Unmarshal(m, b) +} +func (m *Trace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Trace.Marshal(b, m, deterministic) +} +func (m *Trace) XXX_Merge(src proto.Message) { + xxx_messageInfo_Trace.Merge(m, src) +} +func (m *Trace) XXX_Size() int { + return xxx_messageInfo_Trace.Size(m) +} +func (m *Trace) XXX_DiscardUnknown() { + xxx_messageInfo_Trace.DiscardUnknown(m) +} + +var xxx_messageInfo_Trace proto.InternalMessageInfo + +type Request struct { + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Request) Reset() { *m = Request{} } +func (m *Request) String() string { return proto.CompactTextString(m) } +func (*Request) ProtoMessage() {} +func (*Request) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{4} +} + +func (m *Request) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Request.Unmarshal(m, b) +} +func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Request.Marshal(b, m, deterministic) +} +func (m *Request) XXX_Merge(src proto.Message) { + xxx_messageInfo_Request.Merge(m, src) +} +func (m *Request) XXX_Size() int { + return xxx_messageInfo_Request.Size(m) +} +func (m *Request) XXX_DiscardUnknown() { + xxx_messageInfo_Request.DiscardUnknown(m) +} + +var xxx_messageInfo_Request proto.InternalMessageInfo + +func (m *Request) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +type HealthResponse struct { + Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` + Checks []*Check `protobuf:"bytes,2,rep,name=checks,proto3" json:"checks,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HealthResponse) Reset() { *m = HealthResponse{} } +func (m *HealthResponse) String() string { return proto.CompactTextString(m) } +func (*HealthResponse) ProtoMessage() {} +func (*HealthResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{5} +} + +func (m *HealthResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HealthResponse.Unmarshal(m, b) +} +func (m *HealthResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HealthResponse.Marshal(b, m, deterministic) +} +func (m *HealthResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_HealthResponse.Merge(m, src) +} +func (m *HealthResponse) XXX_Size() int { + return xxx_messageInfo_HealthResponse.Size(m) +} +func (m *HealthResponse) XXX_DiscardUnknown() { + xxx_messageInfo_HealthResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_HealthResponse proto.InternalMessageInfo + +func (m *HealthResponse) GetStatus() string { + if m != nil { + return m.Status + } + return "" +} + +func (m *HealthResponse) GetChecks() []*Check { + if m != nil { + return m.Checks + } + return nil +} + +type LogResponse struct { + Logs []*Log `protobuf:"bytes,1,rep,name=logs,proto3" json:"logs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *LogResponse) Reset() { *m = LogResponse{} } +func (m *LogResponse) String() string { return proto.CompactTextString(m) } +func (*LogResponse) ProtoMessage() {} +func (*LogResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{6} +} + +func (m *LogResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_LogResponse.Unmarshal(m, b) +} +func (m *LogResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_LogResponse.Marshal(b, m, deterministic) +} +func (m *LogResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_LogResponse.Merge(m, src) +} +func (m *LogResponse) XXX_Size() int { + return xxx_messageInfo_LogResponse.Size(m) +} +func (m *LogResponse) XXX_DiscardUnknown() { + xxx_messageInfo_LogResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_LogResponse proto.InternalMessageInfo + +func (m *LogResponse) GetLogs() []*Log { + if m != nil { + return m.Logs + } + return nil +} + +type StatsResponse struct { + Stats []*Stats `protobuf:"bytes,1,rep,name=stats,proto3" json:"stats,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StatsResponse) Reset() { *m = StatsResponse{} } +func (m *StatsResponse) String() string { return proto.CompactTextString(m) } +func (*StatsResponse) ProtoMessage() {} +func (*StatsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{7} +} + +func (m *StatsResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StatsResponse.Unmarshal(m, b) +} +func (m *StatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StatsResponse.Marshal(b, m, deterministic) +} +func (m *StatsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StatsResponse.Merge(m, src) +} +func (m *StatsResponse) XXX_Size() int { + return xxx_messageInfo_StatsResponse.Size(m) +} +func (m *StatsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StatsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StatsResponse proto.InternalMessageInfo + +func (m *StatsResponse) GetStats() []*Stats { + if m != nil { + return m.Stats + } + return nil +} + +type TraceResponse struct { + Traces []*Trace `protobuf:"bytes,1,rep,name=traces,proto3" json:"traces,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TraceResponse) Reset() { *m = TraceResponse{} } +func (m *TraceResponse) String() string { return proto.CompactTextString(m) } +func (*TraceResponse) ProtoMessage() {} +func (*TraceResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a796f9dd3ce1270e, []int{8} +} + +func (m *TraceResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TraceResponse.Unmarshal(m, b) +} +func (m *TraceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TraceResponse.Marshal(b, m, deterministic) +} +func (m *TraceResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_TraceResponse.Merge(m, src) +} +func (m *TraceResponse) XXX_Size() int { + return xxx_messageInfo_TraceResponse.Size(m) +} +func (m *TraceResponse) XXX_DiscardUnknown() { + xxx_messageInfo_TraceResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_TraceResponse proto.InternalMessageInfo + +func (m *TraceResponse) GetTraces() []*Trace { + if m != nil { + return m.Traces + } + return nil +} + +func init() { + proto.RegisterType((*Check)(nil), "go.micro.debug.Check") + proto.RegisterType((*Log)(nil), "go.micro.debug.Log") + proto.RegisterType((*Stats)(nil), "go.micro.debug.Stats") + proto.RegisterType((*Trace)(nil), "go.micro.debug.Trace") + proto.RegisterType((*Request)(nil), "go.micro.debug.Request") + proto.RegisterType((*HealthResponse)(nil), "go.micro.debug.HealthResponse") + proto.RegisterType((*LogResponse)(nil), "go.micro.debug.LogResponse") + proto.RegisterType((*StatsResponse)(nil), "go.micro.debug.StatsResponse") + proto.RegisterType((*TraceResponse)(nil), "go.micro.debug.TraceResponse") +} + +func init() { + proto.RegisterFile("go-debug/handler/rpc/proto/debug.proto", fileDescriptor_a796f9dd3ce1270e) +} + +var fileDescriptor_a796f9dd3ce1270e = []byte{ + // 312 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0x4f, 0x83, 0x30, + 0x18, 0xc5, 0x37, 0x26, 0x2c, 0x7e, 0xcb, 0x38, 0xd4, 0xa8, 0x53, 0xa3, 0x59, 0x7a, 0xd0, 0x25, + 0x06, 0x48, 0x66, 0xe2, 0x49, 0x4d, 0xcc, 0x3c, 0x78, 0xd8, 0x09, 0x4d, 0x3c, 0x33, 0x68, 0x80, + 0x88, 0x2b, 0xb6, 0xe5, 0x0f, 0xf1, 0x3f, 0x36, 0xfd, 0xa8, 0x18, 0x70, 0x1c, 0xbc, 0xb5, 0x1f, + 0xef, 0xf7, 0xfa, 0xfa, 0x0a, 0x5c, 0xa6, 0xdc, 0x4b, 0xd8, 0xa6, 0x4a, 0x83, 0x2c, 0xda, 0x26, + 0x05, 0x13, 0x81, 0x28, 0xe3, 0xa0, 0x14, 0x5c, 0xf1, 0x00, 0xe7, 0x3e, 0xae, 0x89, 0x9b, 0x72, + 0xff, 0x23, 0x8f, 0x05, 0xf7, 0x71, 0x4a, 0xc7, 0x60, 0xaf, 0x32, 0x16, 0xbf, 0x53, 0x1b, 0x46, + 0x6b, 0x8e, 0xfb, 0x17, 0x15, 0x29, 0xa9, 0x17, 0xaf, 0x22, 0x8a, 0x19, 0x3d, 0x81, 0x71, 0xc8, + 0x3e, 0x2b, 0x26, 0x15, 0x71, 0xc1, 0xca, 0x93, 0xd9, 0x70, 0x3e, 0x5c, 0xec, 0x87, 0x56, 0x9e, + 0xd0, 0x37, 0x70, 0x9f, 0x59, 0x54, 0xa8, 0x2c, 0x64, 0xb2, 0xe4, 0x5b, 0xc9, 0xc8, 0x11, 0x38, + 0x52, 0x45, 0xaa, 0x92, 0x46, 0x65, 0x76, 0xc4, 0x03, 0x27, 0xd6, 0xc7, 0xc8, 0x99, 0x35, 0x1f, + 0x2d, 0x26, 0xcb, 0x43, 0xbf, 0x9d, 0xc3, 0xc7, 0x10, 0xa1, 0x11, 0xd1, 0x5b, 0x98, 0xac, 0x79, + 0xda, 0xb8, 0x5e, 0xc1, 0x5e, 0xc1, 0x53, 0xed, 0xa9, 0xd9, 0x83, 0x2e, 0xab, 0xa5, 0x28, 0xa0, + 0x77, 0x30, 0xc5, 0xf4, 0x0d, 0x79, 0x0d, 0xb6, 0x4e, 0xf0, 0x83, 0xfe, 0x39, 0xb6, 0x56, 0xd7, + 0x1a, 0xfa, 0x00, 0x53, 0xbc, 0x72, 0x43, 0x7b, 0xe0, 0x28, 0x3d, 0xe8, 0xc5, 0x6b, 0xb9, 0x11, + 0x2d, 0xbf, 0x2c, 0xb0, 0x9f, 0xf4, 0x9c, 0xac, 0xc0, 0xa9, 0x8b, 0x21, 0xc7, 0x5d, 0xc4, 0x74, + 0x79, 0x7a, 0xd1, 0xfd, 0xd0, 0x6e, 0x92, 0x0e, 0xc8, 0x3d, 0xbe, 0x48, 0xbf, 0xc3, 0xd9, 0xae, + 0x1e, 0x7e, 0xf1, 0x47, 0xf3, 0x92, 0xfd, 0x06, 0xe7, 0xbb, 0xdb, 0x68, 0x59, 0xe0, 0x0d, 0xff, + 0x61, 0xd1, 0x2a, 0x90, 0x0e, 0x36, 0x0e, 0xfe, 0x76, 0x37, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, + 0x76, 0x9d, 0x79, 0xec, 0xa0, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// DebugClient is the client API for Debug service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DebugClient interface { + Health(ctx context.Context, in *Request, opts ...grpc.CallOption) (*HealthResponse, error) + Log(ctx context.Context, in *Request, opts ...grpc.CallOption) (*LogResponse, error) + Stats(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatsResponse, error) + Trace(ctx context.Context, in *Request, opts ...grpc.CallOption) (*TraceResponse, error) +} + +type debugClient struct { + cc *grpc.ClientConn +} + +func NewDebugClient(cc *grpc.ClientConn) DebugClient { + return &debugClient{cc} +} + +func (c *debugClient) Health(ctx context.Context, in *Request, opts ...grpc.CallOption) (*HealthResponse, error) { + out := new(HealthResponse) + err := c.cc.Invoke(ctx, "/go.micro.debug.Debug/Health", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugClient) Log(ctx context.Context, in *Request, opts ...grpc.CallOption) (*LogResponse, error) { + out := new(LogResponse) + err := c.cc.Invoke(ctx, "/go.micro.debug.Debug/Log", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugClient) Stats(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatsResponse, error) { + out := new(StatsResponse) + err := c.cc.Invoke(ctx, "/go.micro.debug.Debug/Stats", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugClient) Trace(ctx context.Context, in *Request, opts ...grpc.CallOption) (*TraceResponse, error) { + out := new(TraceResponse) + err := c.cc.Invoke(ctx, "/go.micro.debug.Debug/Trace", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DebugServer is the server API for Debug service. +type DebugServer interface { + Health(context.Context, *Request) (*HealthResponse, error) + Log(context.Context, *Request) (*LogResponse, error) + Stats(context.Context, *Request) (*StatsResponse, error) + Trace(context.Context, *Request) (*TraceResponse, error) +} + +func RegisterDebugServer(s *grpc.Server, srv DebugServer) { + s.RegisterService(&_Debug_serviceDesc, srv) +} + +func _Debug_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServer).Health(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.debug.Debug/Health", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServer).Health(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Debug_Log_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServer).Log(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.debug.Debug/Log", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServer).Log(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Debug_Stats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServer).Stats(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.debug.Debug/Stats", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServer).Stats(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _Debug_Trace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServer).Trace(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/go.micro.debug.Debug/Trace", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServer).Trace(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _Debug_serviceDesc = grpc.ServiceDesc{ + ServiceName: "go.micro.debug.Debug", + HandlerType: (*DebugServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Health", + Handler: _Debug_Health_Handler, + }, + { + MethodName: "Log", + Handler: _Debug_Log_Handler, + }, + { + MethodName: "Stats", + Handler: _Debug_Stats_Handler, + }, + { + MethodName: "Trace", + Handler: _Debug_Trace_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "go-debug/handler/rpc/proto/debug.proto", +} diff --git a/debug/handler/rpc/proto/debug.proto b/debug/handler/rpc/proto/debug.proto new file mode 100644 index 00000000..119f69c9 --- /dev/null +++ b/debug/handler/rpc/proto/debug.proto @@ -0,0 +1,36 @@ +syntax = "proto3"; + +package go.micro.debug; + +service Debug { + rpc Health(Request) returns (HealthResponse) {}; + rpc Log(Request) returns (LogResponse) {}; + rpc Stats(Request) returns (StatsResponse) {}; + rpc Trace(Request) returns (TraceResponse) {}; +} + +message Check {} +message Log {} +message Stats {} +message Trace {} + +message Request { + string id = 1; +} + +message HealthResponse { + string status = 1; + repeated Check checks = 2; +} + +message LogResponse { + repeated Log logs = 1; +} + +message StatsResponse { + repeated Stats stats = 1; +} + +message TraceResponse { + repeated Trace traces = 1; +} diff --git a/debug/handler/rpc/rpc.go b/debug/handler/rpc/rpc.go new file mode 100644 index 00000000..f43fd51a --- /dev/null +++ b/debug/handler/rpc/rpc.go @@ -0,0 +1,27 @@ +// Package rpc provides an rpc handler +package rpc + +import ( + "context" + + proto "github.com/micro/go-micro/debug/handler/rpc/proto" +) + +type Debug struct { +} + +func (d *Debug) Health(ctx context.Context, req *proto.Request, rsp *proto.HealthResponse) error { + return nil +} + +func (d *Debug) Log(ctx context.Context, req *proto.Request, rsp *proto.LogResponse) error { + return nil +} + +func (d *Debug) Stats(ctx context.Context, req *proto.Request, rsp *proto.StatsResponse) error { + return nil +} + +func (d *Debug) Trace(ctx context.Context, req *proto.Request, rsp *proto.TraceResponse) error { + return nil +} diff --git a/debug/health/health.go b/debug/health/health.go new file mode 100644 index 00000000..3e0a14ee --- /dev/null +++ b/debug/health/health.go @@ -0,0 +1,28 @@ +// Package health is for user defined health checks +package health + +type Health interface { + Register([]*Check) error + Read(...ReadOption) ([]*Check, error) + Check(...CheckOption) ([]*Status, error) + String() string +} + +type Check struct { + Id string + Metadata map[string]string + Exec func() (*Status, error) +} + +type Status struct { + Code int + Detail string +} + +type CheckOptions struct{} + +type CheckOption func(o *CheckOptions) + +type ReadOptions struct{} + +type ReadOption func(o *ReadOptions) diff --git a/debug/log/log.go b/debug/log/log.go new file mode 100644 index 00000000..a64e7b6c --- /dev/null +++ b/debug/log/log.go @@ -0,0 +1,36 @@ +// Package log provides a logging interface +package log + +import ( + "time" +) + +// Log provides access to logs +type Log interface { + Read(...ReadOption) ([]*Entry, error) + Write([]*Entry, ...WriteOption) error + String() string +} + +// A single log entry +type Entry struct { + Id string + Time time.Time + Message []byte + Metadata map[string]string +} + +type ReadOption func(o *ReadOptions) + +type WriteOption func(o *WriteOptions) + +type ReadOptions struct { + // read the given id + Id string + // Number of entries to read + Entries int + // Filter function + Filter func(*Entry) bool +} + +type WriteOptions struct{} diff --git a/debug/stats/stats.go b/debug/stats/stats.go new file mode 100644 index 00000000..873ea4a5 --- /dev/null +++ b/debug/stats/stats.go @@ -0,0 +1,24 @@ +// Package stats provides process statistics +package stats + +// Stats provides metrics recording and retrieval +type Stats interface { + Read(...ReadOption) []*Metrics + Record(*Metrics) error + String() string +} + +type Metrics struct { + // Unique id of metric + Id string + // Metadata + Metadata map[string]string + // Floating values + Values map[string]float64 + // Counters + Counters map[string]int64 +} + +type ReadOptions struct{} + +type ReadOption func(o *ReadOptions) diff --git a/debug/store/buffer/buffer.go b/debug/store/buffer/buffer.go new file mode 100644 index 00000000..75c84b07 --- /dev/null +++ b/debug/store/buffer/buffer.go @@ -0,0 +1,62 @@ +// Package buffer provides a simple ring buffer +package buffer + +import ( + "sync" + + "github.com/micro/go-micro/debug/store" +) + +type Buffer struct { + sync.RWMutex + index map[string]int + records []*store.Record +} + +func (b *Buffer) Read(opts ...store.ReadOption) ([]*store.Record, error) { + var options store.ReadOptions + for _, o := range opts { + o(&options) + } + + b.RLock() + defer b.RUnlock() + + if len(options.Id) > 0 { + idx, ok := b.index[options.Id] + if !ok || len(b.records) < idx { + return nil, store.ErrNotFound + } + return []*store.Record{b.records[idx]}, nil + } + + return b.records, nil +} + +func (b *Buffer) Write(records []*store.Record) error { + b.Lock() + defer b.Unlock() + + if b.index == nil { + b.index = make(map[string]int) + } + + i := len(b.records) + + for _, r := range records { + b.index[r.Id] = i + i++ + b.records = append(b.records, r) + } + + return nil +} + +func (b *Buffer) String() string { + return "buffer" +} + +type Record struct { + Id string + Value interface{} +} diff --git a/debug/store/store.go b/debug/store/store.go new file mode 100644 index 00000000..233a5508 --- /dev/null +++ b/debug/store/store.go @@ -0,0 +1,27 @@ +// Package store stores the various pieces of data +package store + +import ( + "errors" +) + +type Store interface { + Read(...ReadOption) ([]*Record, error) + Write([]*Record) error + String() string +} + +type Record struct { + Id string + Value interface{} +} + +type ReadOptions struct { + Id string +} + +type ReadOption func(o *ReadOptions) + +var ( + ErrNotFound = errors.New("not found") +) diff --git a/debug/trace/trace.go b/debug/trace/trace.go new file mode 100644 index 00000000..4f7da863 --- /dev/null +++ b/debug/trace/trace.go @@ -0,0 +1,29 @@ +// Package trace provides a tracing interface +package trace + +import ( + "time" +) + +// Trace is for request tracing +type Trace interface { + // Read the traces + Read(...ReadOption) ([]*Span, error) + // Collect traces + Collect([]*Span) error + // Name of tracer + String() string +} + +type Span struct { + Id string + Name string + Trace string + Metadata map[string]string + Start time.Time + Finish time.Time +} + +type ReadOptions struct{} + +type ReadOption func(o *ReadOptions) From 02d580600d5c2e2e309004c08a826585d1beab4f Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 11:52:43 +0100 Subject: [PATCH 13/18] remove debug for now --- debug/README.md | 17 - debug/handler/handler.go | 2 - debug/handler/http/http.go | 17 - debug/handler/rpc/proto/debug.micro.go | 157 ------- debug/handler/rpc/proto/debug.pb.go | 561 ------------------------- debug/handler/rpc/proto/debug.proto | 36 -- debug/handler/rpc/rpc.go | 27 -- debug/health/health.go | 28 -- debug/log/log.go | 36 -- debug/stats/stats.go | 24 -- debug/store/buffer/buffer.go | 62 --- debug/store/store.go | 27 -- debug/trace/trace.go | 29 -- 13 files changed, 1023 deletions(-) delete mode 100644 debug/README.md delete mode 100644 debug/handler/handler.go delete mode 100644 debug/handler/http/http.go delete mode 100644 debug/handler/rpc/proto/debug.micro.go delete mode 100644 debug/handler/rpc/proto/debug.pb.go delete mode 100644 debug/handler/rpc/proto/debug.proto delete mode 100644 debug/handler/rpc/rpc.go delete mode 100644 debug/health/health.go delete mode 100644 debug/log/log.go delete mode 100644 debug/stats/stats.go delete mode 100644 debug/store/buffer/buffer.go delete mode 100644 debug/store/store.go delete mode 100644 debug/trace/trace.go diff --git a/debug/README.md b/debug/README.md deleted file mode 100644 index 7c70e92f..00000000 --- a/debug/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Debug - -Debug is a debugging library for microservices - -## Overview - -Debug is a pluggable library for debugging. It includes base level requirements for logging, tracing and metrics. -Our goal is to provide a simple experience for understanding what's happening in a running system with zero dependencies -by default or by plugging into robust systems like ELK, zipkin, etc. - -## Features - -- Health (Checks) -- Log (Logging) -- Stats (Metrics) -- Trace (Requests) - diff --git a/debug/handler/handler.go b/debug/handler/handler.go deleted file mode 100644 index 8715044f..00000000 --- a/debug/handler/handler.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package handler provides handlers -package handler diff --git a/debug/handler/http/http.go b/debug/handler/http/http.go deleted file mode 100644 index 41b4ec23..00000000 --- a/debug/handler/http/http.go +++ /dev/null @@ -1,17 +0,0 @@ -// Package http provides http handlers -package http - -import ( - "net/http" -) - -type Handler struct{} - -func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - switch r.URL.Path { - case "/debug/health": - case "/debug/log": - case "/debug/stats": - case "/debug/trace": - } -} diff --git a/debug/handler/rpc/proto/debug.micro.go b/debug/handler/rpc/proto/debug.micro.go deleted file mode 100644 index dd3ec138..00000000 --- a/debug/handler/rpc/proto/debug.micro.go +++ /dev/null @@ -1,157 +0,0 @@ -// Code generated by protoc-gen-micro. DO NOT EDIT. -// source: go-debug/handler/rpc/proto/debug.proto - -/* -Package go_micro_debug is a generated protocol buffer package. - -It is generated from these files: - go-debug/handler/rpc/proto/debug.proto - -It has these top-level messages: - Check - Log - Stats - Trace - Request - HealthResponse - LogResponse - StatsResponse - TraceResponse -*/ -package go_micro_debug - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - -import ( - context "context" - client "github.com/micro/go-micro/client" - server "github.com/micro/go-micro/server" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ client.Option -var _ server.Option - -// Client API for Debug service - -type DebugService interface { - Health(ctx context.Context, in *Request, opts ...client.CallOption) (*HealthResponse, error) - Log(ctx context.Context, in *Request, opts ...client.CallOption) (*LogResponse, error) - Stats(ctx context.Context, in *Request, opts ...client.CallOption) (*StatsResponse, error) - Trace(ctx context.Context, in *Request, opts ...client.CallOption) (*TraceResponse, error) -} - -type debugService struct { - c client.Client - name string -} - -func NewDebugService(name string, c client.Client) DebugService { - if c == nil { - c = client.NewClient() - } - if len(name) == 0 { - name = "go.micro.debug" - } - return &debugService{ - c: c, - name: name, - } -} - -func (c *debugService) Health(ctx context.Context, in *Request, opts ...client.CallOption) (*HealthResponse, error) { - req := c.c.NewRequest(c.name, "Debug.Health", in) - out := new(HealthResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *debugService) Log(ctx context.Context, in *Request, opts ...client.CallOption) (*LogResponse, error) { - req := c.c.NewRequest(c.name, "Debug.Log", in) - out := new(LogResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *debugService) Stats(ctx context.Context, in *Request, opts ...client.CallOption) (*StatsResponse, error) { - req := c.c.NewRequest(c.name, "Debug.Stats", in) - out := new(StatsResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *debugService) Trace(ctx context.Context, in *Request, opts ...client.CallOption) (*TraceResponse, error) { - req := c.c.NewRequest(c.name, "Debug.Trace", in) - out := new(TraceResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// Server API for Debug service - -type DebugHandler interface { - Health(context.Context, *Request, *HealthResponse) error - Log(context.Context, *Request, *LogResponse) error - Stats(context.Context, *Request, *StatsResponse) error - Trace(context.Context, *Request, *TraceResponse) error -} - -func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.HandlerOption) error { - type debug interface { - Health(ctx context.Context, in *Request, out *HealthResponse) error - Log(ctx context.Context, in *Request, out *LogResponse) error - Stats(ctx context.Context, in *Request, out *StatsResponse) error - Trace(ctx context.Context, in *Request, out *TraceResponse) error - } - type Debug struct { - debug - } - h := &debugHandler{hdlr} - return s.Handle(s.NewHandler(&Debug{h}, opts...)) -} - -type debugHandler struct { - DebugHandler -} - -func (h *debugHandler) Health(ctx context.Context, in *Request, out *HealthResponse) error { - return h.DebugHandler.Health(ctx, in, out) -} - -func (h *debugHandler) Log(ctx context.Context, in *Request, out *LogResponse) error { - return h.DebugHandler.Log(ctx, in, out) -} - -func (h *debugHandler) Stats(ctx context.Context, in *Request, out *StatsResponse) error { - return h.DebugHandler.Stats(ctx, in, out) -} - -func (h *debugHandler) Trace(ctx context.Context, in *Request, out *TraceResponse) error { - return h.DebugHandler.Trace(ctx, in, out) -} diff --git a/debug/handler/rpc/proto/debug.pb.go b/debug/handler/rpc/proto/debug.pb.go deleted file mode 100644 index 1f4f6771..00000000 --- a/debug/handler/rpc/proto/debug.pb.go +++ /dev/null @@ -1,561 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: go-debug/handler/rpc/proto/debug.proto - -package go_micro_debug - -import ( - context "context" - fmt "fmt" - proto "github.com/golang/protobuf/proto" - grpc "google.golang.org/grpc" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type Check struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Check) Reset() { *m = Check{} } -func (m *Check) String() string { return proto.CompactTextString(m) } -func (*Check) ProtoMessage() {} -func (*Check) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{0} -} - -func (m *Check) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Check.Unmarshal(m, b) -} -func (m *Check) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Check.Marshal(b, m, deterministic) -} -func (m *Check) XXX_Merge(src proto.Message) { - xxx_messageInfo_Check.Merge(m, src) -} -func (m *Check) XXX_Size() int { - return xxx_messageInfo_Check.Size(m) -} -func (m *Check) XXX_DiscardUnknown() { - xxx_messageInfo_Check.DiscardUnknown(m) -} - -var xxx_messageInfo_Check proto.InternalMessageInfo - -type Log struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Log) Reset() { *m = Log{} } -func (m *Log) String() string { return proto.CompactTextString(m) } -func (*Log) ProtoMessage() {} -func (*Log) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{1} -} - -func (m *Log) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Log.Unmarshal(m, b) -} -func (m *Log) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Log.Marshal(b, m, deterministic) -} -func (m *Log) XXX_Merge(src proto.Message) { - xxx_messageInfo_Log.Merge(m, src) -} -func (m *Log) XXX_Size() int { - return xxx_messageInfo_Log.Size(m) -} -func (m *Log) XXX_DiscardUnknown() { - xxx_messageInfo_Log.DiscardUnknown(m) -} - -var xxx_messageInfo_Log proto.InternalMessageInfo - -type Stats struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Stats) Reset() { *m = Stats{} } -func (m *Stats) String() string { return proto.CompactTextString(m) } -func (*Stats) ProtoMessage() {} -func (*Stats) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{2} -} - -func (m *Stats) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Stats.Unmarshal(m, b) -} -func (m *Stats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Stats.Marshal(b, m, deterministic) -} -func (m *Stats) XXX_Merge(src proto.Message) { - xxx_messageInfo_Stats.Merge(m, src) -} -func (m *Stats) XXX_Size() int { - return xxx_messageInfo_Stats.Size(m) -} -func (m *Stats) XXX_DiscardUnknown() { - xxx_messageInfo_Stats.DiscardUnknown(m) -} - -var xxx_messageInfo_Stats proto.InternalMessageInfo - -type Trace struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Trace) Reset() { *m = Trace{} } -func (m *Trace) String() string { return proto.CompactTextString(m) } -func (*Trace) ProtoMessage() {} -func (*Trace) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{3} -} - -func (m *Trace) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Trace.Unmarshal(m, b) -} -func (m *Trace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Trace.Marshal(b, m, deterministic) -} -func (m *Trace) XXX_Merge(src proto.Message) { - xxx_messageInfo_Trace.Merge(m, src) -} -func (m *Trace) XXX_Size() int { - return xxx_messageInfo_Trace.Size(m) -} -func (m *Trace) XXX_DiscardUnknown() { - xxx_messageInfo_Trace.DiscardUnknown(m) -} - -var xxx_messageInfo_Trace proto.InternalMessageInfo - -type Request struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Request) Reset() { *m = Request{} } -func (m *Request) String() string { return proto.CompactTextString(m) } -func (*Request) ProtoMessage() {} -func (*Request) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{4} -} - -func (m *Request) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Request.Unmarshal(m, b) -} -func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Request.Marshal(b, m, deterministic) -} -func (m *Request) XXX_Merge(src proto.Message) { - xxx_messageInfo_Request.Merge(m, src) -} -func (m *Request) XXX_Size() int { - return xxx_messageInfo_Request.Size(m) -} -func (m *Request) XXX_DiscardUnknown() { - xxx_messageInfo_Request.DiscardUnknown(m) -} - -var xxx_messageInfo_Request proto.InternalMessageInfo - -func (m *Request) GetId() string { - if m != nil { - return m.Id - } - return "" -} - -type HealthResponse struct { - Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` - Checks []*Check `protobuf:"bytes,2,rep,name=checks,proto3" json:"checks,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *HealthResponse) Reset() { *m = HealthResponse{} } -func (m *HealthResponse) String() string { return proto.CompactTextString(m) } -func (*HealthResponse) ProtoMessage() {} -func (*HealthResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{5} -} - -func (m *HealthResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_HealthResponse.Unmarshal(m, b) -} -func (m *HealthResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_HealthResponse.Marshal(b, m, deterministic) -} -func (m *HealthResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_HealthResponse.Merge(m, src) -} -func (m *HealthResponse) XXX_Size() int { - return xxx_messageInfo_HealthResponse.Size(m) -} -func (m *HealthResponse) XXX_DiscardUnknown() { - xxx_messageInfo_HealthResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_HealthResponse proto.InternalMessageInfo - -func (m *HealthResponse) GetStatus() string { - if m != nil { - return m.Status - } - return "" -} - -func (m *HealthResponse) GetChecks() []*Check { - if m != nil { - return m.Checks - } - return nil -} - -type LogResponse struct { - Logs []*Log `protobuf:"bytes,1,rep,name=logs,proto3" json:"logs,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *LogResponse) Reset() { *m = LogResponse{} } -func (m *LogResponse) String() string { return proto.CompactTextString(m) } -func (*LogResponse) ProtoMessage() {} -func (*LogResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{6} -} - -func (m *LogResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_LogResponse.Unmarshal(m, b) -} -func (m *LogResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_LogResponse.Marshal(b, m, deterministic) -} -func (m *LogResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_LogResponse.Merge(m, src) -} -func (m *LogResponse) XXX_Size() int { - return xxx_messageInfo_LogResponse.Size(m) -} -func (m *LogResponse) XXX_DiscardUnknown() { - xxx_messageInfo_LogResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_LogResponse proto.InternalMessageInfo - -func (m *LogResponse) GetLogs() []*Log { - if m != nil { - return m.Logs - } - return nil -} - -type StatsResponse struct { - Stats []*Stats `protobuf:"bytes,1,rep,name=stats,proto3" json:"stats,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *StatsResponse) Reset() { *m = StatsResponse{} } -func (m *StatsResponse) String() string { return proto.CompactTextString(m) } -func (*StatsResponse) ProtoMessage() {} -func (*StatsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{7} -} - -func (m *StatsResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StatsResponse.Unmarshal(m, b) -} -func (m *StatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StatsResponse.Marshal(b, m, deterministic) -} -func (m *StatsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_StatsResponse.Merge(m, src) -} -func (m *StatsResponse) XXX_Size() int { - return xxx_messageInfo_StatsResponse.Size(m) -} -func (m *StatsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_StatsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_StatsResponse proto.InternalMessageInfo - -func (m *StatsResponse) GetStats() []*Stats { - if m != nil { - return m.Stats - } - return nil -} - -type TraceResponse struct { - Traces []*Trace `protobuf:"bytes,1,rep,name=traces,proto3" json:"traces,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *TraceResponse) Reset() { *m = TraceResponse{} } -func (m *TraceResponse) String() string { return proto.CompactTextString(m) } -func (*TraceResponse) ProtoMessage() {} -func (*TraceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_a796f9dd3ce1270e, []int{8} -} - -func (m *TraceResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_TraceResponse.Unmarshal(m, b) -} -func (m *TraceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_TraceResponse.Marshal(b, m, deterministic) -} -func (m *TraceResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_TraceResponse.Merge(m, src) -} -func (m *TraceResponse) XXX_Size() int { - return xxx_messageInfo_TraceResponse.Size(m) -} -func (m *TraceResponse) XXX_DiscardUnknown() { - xxx_messageInfo_TraceResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_TraceResponse proto.InternalMessageInfo - -func (m *TraceResponse) GetTraces() []*Trace { - if m != nil { - return m.Traces - } - return nil -} - -func init() { - proto.RegisterType((*Check)(nil), "go.micro.debug.Check") - proto.RegisterType((*Log)(nil), "go.micro.debug.Log") - proto.RegisterType((*Stats)(nil), "go.micro.debug.Stats") - proto.RegisterType((*Trace)(nil), "go.micro.debug.Trace") - proto.RegisterType((*Request)(nil), "go.micro.debug.Request") - proto.RegisterType((*HealthResponse)(nil), "go.micro.debug.HealthResponse") - proto.RegisterType((*LogResponse)(nil), "go.micro.debug.LogResponse") - proto.RegisterType((*StatsResponse)(nil), "go.micro.debug.StatsResponse") - proto.RegisterType((*TraceResponse)(nil), "go.micro.debug.TraceResponse") -} - -func init() { - proto.RegisterFile("go-debug/handler/rpc/proto/debug.proto", fileDescriptor_a796f9dd3ce1270e) -} - -var fileDescriptor_a796f9dd3ce1270e = []byte{ - // 312 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0x4f, 0x83, 0x30, - 0x18, 0xc5, 0x37, 0x26, 0x2c, 0x7e, 0xcb, 0x38, 0xd4, 0xa8, 0x53, 0xa3, 0x59, 0x7a, 0xd0, 0x25, - 0x06, 0x48, 0x66, 0xe2, 0x49, 0x4d, 0xcc, 0x3c, 0x78, 0xd8, 0x09, 0x4d, 0x3c, 0x33, 0x68, 0x80, - 0x88, 0x2b, 0xb6, 0xe5, 0x0f, 0xf1, 0x3f, 0x36, 0xfd, 0xa8, 0x18, 0x70, 0x1c, 0xbc, 0xb5, 0x1f, - 0xef, 0xf7, 0xfa, 0xfa, 0x0a, 0x5c, 0xa6, 0xdc, 0x4b, 0xd8, 0xa6, 0x4a, 0x83, 0x2c, 0xda, 0x26, - 0x05, 0x13, 0x81, 0x28, 0xe3, 0xa0, 0x14, 0x5c, 0xf1, 0x00, 0xe7, 0x3e, 0xae, 0x89, 0x9b, 0x72, - 0xff, 0x23, 0x8f, 0x05, 0xf7, 0x71, 0x4a, 0xc7, 0x60, 0xaf, 0x32, 0x16, 0xbf, 0x53, 0x1b, 0x46, - 0x6b, 0x8e, 0xfb, 0x17, 0x15, 0x29, 0xa9, 0x17, 0xaf, 0x22, 0x8a, 0x19, 0x3d, 0x81, 0x71, 0xc8, - 0x3e, 0x2b, 0x26, 0x15, 0x71, 0xc1, 0xca, 0x93, 0xd9, 0x70, 0x3e, 0x5c, 0xec, 0x87, 0x56, 0x9e, - 0xd0, 0x37, 0x70, 0x9f, 0x59, 0x54, 0xa8, 0x2c, 0x64, 0xb2, 0xe4, 0x5b, 0xc9, 0xc8, 0x11, 0x38, - 0x52, 0x45, 0xaa, 0x92, 0x46, 0x65, 0x76, 0xc4, 0x03, 0x27, 0xd6, 0xc7, 0xc8, 0x99, 0x35, 0x1f, - 0x2d, 0x26, 0xcb, 0x43, 0xbf, 0x9d, 0xc3, 0xc7, 0x10, 0xa1, 0x11, 0xd1, 0x5b, 0x98, 0xac, 0x79, - 0xda, 0xb8, 0x5e, 0xc1, 0x5e, 0xc1, 0x53, 0xed, 0xa9, 0xd9, 0x83, 0x2e, 0xab, 0xa5, 0x28, 0xa0, - 0x77, 0x30, 0xc5, 0xf4, 0x0d, 0x79, 0x0d, 0xb6, 0x4e, 0xf0, 0x83, 0xfe, 0x39, 0xb6, 0x56, 0xd7, - 0x1a, 0xfa, 0x00, 0x53, 0xbc, 0x72, 0x43, 0x7b, 0xe0, 0x28, 0x3d, 0xe8, 0xc5, 0x6b, 0xb9, 0x11, - 0x2d, 0xbf, 0x2c, 0xb0, 0x9f, 0xf4, 0x9c, 0xac, 0xc0, 0xa9, 0x8b, 0x21, 0xc7, 0x5d, 0xc4, 0x74, - 0x79, 0x7a, 0xd1, 0xfd, 0xd0, 0x6e, 0x92, 0x0e, 0xc8, 0x3d, 0xbe, 0x48, 0xbf, 0xc3, 0xd9, 0xae, - 0x1e, 0x7e, 0xf1, 0x47, 0xf3, 0x92, 0xfd, 0x06, 0xe7, 0xbb, 0xdb, 0x68, 0x59, 0xe0, 0x0d, 0xff, - 0x61, 0xd1, 0x2a, 0x90, 0x0e, 0x36, 0x0e, 0xfe, 0x76, 0x37, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, - 0x76, 0x9d, 0x79, 0xec, 0xa0, 0x02, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// DebugClient is the client API for Debug service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type DebugClient interface { - Health(ctx context.Context, in *Request, opts ...grpc.CallOption) (*HealthResponse, error) - Log(ctx context.Context, in *Request, opts ...grpc.CallOption) (*LogResponse, error) - Stats(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatsResponse, error) - Trace(ctx context.Context, in *Request, opts ...grpc.CallOption) (*TraceResponse, error) -} - -type debugClient struct { - cc *grpc.ClientConn -} - -func NewDebugClient(cc *grpc.ClientConn) DebugClient { - return &debugClient{cc} -} - -func (c *debugClient) Health(ctx context.Context, in *Request, opts ...grpc.CallOption) (*HealthResponse, error) { - out := new(HealthResponse) - err := c.cc.Invoke(ctx, "/go.micro.debug.Debug/Health", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *debugClient) Log(ctx context.Context, in *Request, opts ...grpc.CallOption) (*LogResponse, error) { - out := new(LogResponse) - err := c.cc.Invoke(ctx, "/go.micro.debug.Debug/Log", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *debugClient) Stats(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatsResponse, error) { - out := new(StatsResponse) - err := c.cc.Invoke(ctx, "/go.micro.debug.Debug/Stats", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *debugClient) Trace(ctx context.Context, in *Request, opts ...grpc.CallOption) (*TraceResponse, error) { - out := new(TraceResponse) - err := c.cc.Invoke(ctx, "/go.micro.debug.Debug/Trace", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// DebugServer is the server API for Debug service. -type DebugServer interface { - Health(context.Context, *Request) (*HealthResponse, error) - Log(context.Context, *Request) (*LogResponse, error) - Stats(context.Context, *Request) (*StatsResponse, error) - Trace(context.Context, *Request) (*TraceResponse, error) -} - -func RegisterDebugServer(s *grpc.Server, srv DebugServer) { - s.RegisterService(&_Debug_serviceDesc, srv) -} - -func _Debug_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Request) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DebugServer).Health(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/go.micro.debug.Debug/Health", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DebugServer).Health(ctx, req.(*Request)) - } - return interceptor(ctx, in, info, handler) -} - -func _Debug_Log_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Request) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DebugServer).Log(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/go.micro.debug.Debug/Log", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DebugServer).Log(ctx, req.(*Request)) - } - return interceptor(ctx, in, info, handler) -} - -func _Debug_Stats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Request) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DebugServer).Stats(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/go.micro.debug.Debug/Stats", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DebugServer).Stats(ctx, req.(*Request)) - } - return interceptor(ctx, in, info, handler) -} - -func _Debug_Trace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(Request) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(DebugServer).Trace(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/go.micro.debug.Debug/Trace", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(DebugServer).Trace(ctx, req.(*Request)) - } - return interceptor(ctx, in, info, handler) -} - -var _Debug_serviceDesc = grpc.ServiceDesc{ - ServiceName: "go.micro.debug.Debug", - HandlerType: (*DebugServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "Health", - Handler: _Debug_Health_Handler, - }, - { - MethodName: "Log", - Handler: _Debug_Log_Handler, - }, - { - MethodName: "Stats", - Handler: _Debug_Stats_Handler, - }, - { - MethodName: "Trace", - Handler: _Debug_Trace_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "go-debug/handler/rpc/proto/debug.proto", -} diff --git a/debug/handler/rpc/proto/debug.proto b/debug/handler/rpc/proto/debug.proto deleted file mode 100644 index 119f69c9..00000000 --- a/debug/handler/rpc/proto/debug.proto +++ /dev/null @@ -1,36 +0,0 @@ -syntax = "proto3"; - -package go.micro.debug; - -service Debug { - rpc Health(Request) returns (HealthResponse) {}; - rpc Log(Request) returns (LogResponse) {}; - rpc Stats(Request) returns (StatsResponse) {}; - rpc Trace(Request) returns (TraceResponse) {}; -} - -message Check {} -message Log {} -message Stats {} -message Trace {} - -message Request { - string id = 1; -} - -message HealthResponse { - string status = 1; - repeated Check checks = 2; -} - -message LogResponse { - repeated Log logs = 1; -} - -message StatsResponse { - repeated Stats stats = 1; -} - -message TraceResponse { - repeated Trace traces = 1; -} diff --git a/debug/handler/rpc/rpc.go b/debug/handler/rpc/rpc.go deleted file mode 100644 index f43fd51a..00000000 --- a/debug/handler/rpc/rpc.go +++ /dev/null @@ -1,27 +0,0 @@ -// Package rpc provides an rpc handler -package rpc - -import ( - "context" - - proto "github.com/micro/go-micro/debug/handler/rpc/proto" -) - -type Debug struct { -} - -func (d *Debug) Health(ctx context.Context, req *proto.Request, rsp *proto.HealthResponse) error { - return nil -} - -func (d *Debug) Log(ctx context.Context, req *proto.Request, rsp *proto.LogResponse) error { - return nil -} - -func (d *Debug) Stats(ctx context.Context, req *proto.Request, rsp *proto.StatsResponse) error { - return nil -} - -func (d *Debug) Trace(ctx context.Context, req *proto.Request, rsp *proto.TraceResponse) error { - return nil -} diff --git a/debug/health/health.go b/debug/health/health.go deleted file mode 100644 index 3e0a14ee..00000000 --- a/debug/health/health.go +++ /dev/null @@ -1,28 +0,0 @@ -// Package health is for user defined health checks -package health - -type Health interface { - Register([]*Check) error - Read(...ReadOption) ([]*Check, error) - Check(...CheckOption) ([]*Status, error) - String() string -} - -type Check struct { - Id string - Metadata map[string]string - Exec func() (*Status, error) -} - -type Status struct { - Code int - Detail string -} - -type CheckOptions struct{} - -type CheckOption func(o *CheckOptions) - -type ReadOptions struct{} - -type ReadOption func(o *ReadOptions) diff --git a/debug/log/log.go b/debug/log/log.go deleted file mode 100644 index a64e7b6c..00000000 --- a/debug/log/log.go +++ /dev/null @@ -1,36 +0,0 @@ -// Package log provides a logging interface -package log - -import ( - "time" -) - -// Log provides access to logs -type Log interface { - Read(...ReadOption) ([]*Entry, error) - Write([]*Entry, ...WriteOption) error - String() string -} - -// A single log entry -type Entry struct { - Id string - Time time.Time - Message []byte - Metadata map[string]string -} - -type ReadOption func(o *ReadOptions) - -type WriteOption func(o *WriteOptions) - -type ReadOptions struct { - // read the given id - Id string - // Number of entries to read - Entries int - // Filter function - Filter func(*Entry) bool -} - -type WriteOptions struct{} diff --git a/debug/stats/stats.go b/debug/stats/stats.go deleted file mode 100644 index 873ea4a5..00000000 --- a/debug/stats/stats.go +++ /dev/null @@ -1,24 +0,0 @@ -// Package stats provides process statistics -package stats - -// Stats provides metrics recording and retrieval -type Stats interface { - Read(...ReadOption) []*Metrics - Record(*Metrics) error - String() string -} - -type Metrics struct { - // Unique id of metric - Id string - // Metadata - Metadata map[string]string - // Floating values - Values map[string]float64 - // Counters - Counters map[string]int64 -} - -type ReadOptions struct{} - -type ReadOption func(o *ReadOptions) diff --git a/debug/store/buffer/buffer.go b/debug/store/buffer/buffer.go deleted file mode 100644 index 75c84b07..00000000 --- a/debug/store/buffer/buffer.go +++ /dev/null @@ -1,62 +0,0 @@ -// Package buffer provides a simple ring buffer -package buffer - -import ( - "sync" - - "github.com/micro/go-micro/debug/store" -) - -type Buffer struct { - sync.RWMutex - index map[string]int - records []*store.Record -} - -func (b *Buffer) Read(opts ...store.ReadOption) ([]*store.Record, error) { - var options store.ReadOptions - for _, o := range opts { - o(&options) - } - - b.RLock() - defer b.RUnlock() - - if len(options.Id) > 0 { - idx, ok := b.index[options.Id] - if !ok || len(b.records) < idx { - return nil, store.ErrNotFound - } - return []*store.Record{b.records[idx]}, nil - } - - return b.records, nil -} - -func (b *Buffer) Write(records []*store.Record) error { - b.Lock() - defer b.Unlock() - - if b.index == nil { - b.index = make(map[string]int) - } - - i := len(b.records) - - for _, r := range records { - b.index[r.Id] = i - i++ - b.records = append(b.records, r) - } - - return nil -} - -func (b *Buffer) String() string { - return "buffer" -} - -type Record struct { - Id string - Value interface{} -} diff --git a/debug/store/store.go b/debug/store/store.go deleted file mode 100644 index 233a5508..00000000 --- a/debug/store/store.go +++ /dev/null @@ -1,27 +0,0 @@ -// Package store stores the various pieces of data -package store - -import ( - "errors" -) - -type Store interface { - Read(...ReadOption) ([]*Record, error) - Write([]*Record) error - String() string -} - -type Record struct { - Id string - Value interface{} -} - -type ReadOptions struct { - Id string -} - -type ReadOption func(o *ReadOptions) - -var ( - ErrNotFound = errors.New("not found") -) diff --git a/debug/trace/trace.go b/debug/trace/trace.go deleted file mode 100644 index 4f7da863..00000000 --- a/debug/trace/trace.go +++ /dev/null @@ -1,29 +0,0 @@ -// Package trace provides a tracing interface -package trace - -import ( - "time" -) - -// Trace is for request tracing -type Trace interface { - // Read the traces - Read(...ReadOption) ([]*Span, error) - // Collect traces - Collect([]*Span) error - // Name of tracer - String() string -} - -type Span struct { - Id string - Name string - Trace string - Metadata map[string]string - Start time.Time - Finish time.Time -} - -type ReadOptions struct{} - -type ReadOption func(o *ReadOptions) From e41a461c8b3e2a53b6c430d0adc00ff2fb1d31a4 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 12:10:41 +0100 Subject: [PATCH 14/18] update agent readme --- agent/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/agent/README.md b/agent/README.md index bb6cba7c..76e6dc23 100644 --- a/agent/README.md +++ b/agent/README.md @@ -15,7 +15,7 @@ Commands are functions executed by the bot based on text based pattern matching. ### Write a Command ```go -import "github.com/micro/go-bot/command" +import "github.com/micro/go-micro/agent/command" func Ping() command.Command { usage := "ping" @@ -32,7 +32,7 @@ func Ping() command.Command { Add the command to the Commands map with a pattern key that can be matched by golang/regexp.Match ```go -import "github.com/micro/go-bot/command" +import "github.com/micro/go-micro/agent/command" func init() { command.Commands["^ping$"] = Ping() @@ -116,7 +116,7 @@ is executed, the bot will call the service with method `Command.Exec`. It also e to exist for usage info. -The service interface is as follows and can be found at [go-bot/proto](https://github.com/micro/go-bot/blob/master/proto/bot.proto) +The service interface is as follows and can be found at [go-micro/agent/proto](https://github.com/micro/go-micro/agent/blob/master/proto/bot.proto) ``` syntax = "proto3"; @@ -160,7 +160,7 @@ import ( "github.com/micro/go-micro" "golang.org/x/net/context" - proto "github.com/micro/go-bot/proto" + proto "github.com/micro/go-micro/agent/proto" ) type Command struct{} From 0f47569714f194efd40914c0b6ed9ba8ddcfbeac Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 12:35:43 +0100 Subject: [PATCH 15/18] update go.mod --- go.mod | 169 ++++--------- go.sum | 505 ++++++++------------------------------- sync/leader/etcd/etcd.go | 4 +- sync/lock/etcd/etcd.go | 4 +- 4 files changed, 156 insertions(+), 526 deletions(-) diff --git a/go.mod b/go.mod index 56a83819..99f36a71 100644 --- a/go.mod +++ b/go.mod @@ -2,158 +2,90 @@ module github.com/micro/go-micro require ( cloud.google.com/go v0.39.0 // indirect - contrib.go.opencensus.io/exporter/ocagent v0.5.0 // indirect - github.com/Azure/azure-sdk-for-go v30.0.0+incompatible // indirect - github.com/Azure/go-autorest v12.1.0+incompatible // indirect github.com/BurntSushi/toml v0.3.1 - github.com/DataDog/dd-trace-go v1.14.0 // indirect - github.com/DataDog/zstd v1.4.0 // indirect - github.com/Jeffail/gabs v1.4.0 // indirect - github.com/Microsoft/go-winio v0.4.12 // indirect - github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/OneOfOne/xxhash v1.2.5 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/SAP/go-hdb v0.14.1 // indirect - github.com/Shopify/sarama v1.22.1 // indirect - github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect - github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190530073359-dfac1ef71ffa // indirect - github.com/aliyun/aliyun-oss-go-sdk v1.9.8 // indirect - github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61 // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect - github.com/aws/aws-sdk-go v1.19.41 // indirect + github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect + github.com/beevik/ntp v0.2.0 github.com/bitly/go-simplejson v0.5.0 - github.com/boombuler/barcode v1.0.0 // indirect - github.com/chrismalek/oktasdk-go v0.0.0-20181212195951-3430665dfaa0 // indirect + github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect + github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 + github.com/bwmarrin/discordgo v0.19.0 github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect - github.com/coredns/coredns v1.5.0 // indirect - github.com/coreos/etcd v3.3.13+incompatible // indirect + github.com/coreos/bbolt v1.3.2 // indirect + github.com/coreos/etcd v3.3.13+incompatible github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e // indirect - github.com/dancannon/gorethink v4.0.0+incompatible // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 // indirect - github.com/denverdino/aliyungo v0.0.0-20190410085603-611ead8a6fed // indirect + github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b // indirect - github.com/digitalocean/godo v1.15.0 // indirect - github.com/dnaeon/go-vcr v1.0.1 // indirect - github.com/dnstap/golang-dnstap v0.1.0 // indirect - github.com/docker/go-connections v0.4.0 // indirect - github.com/docker/go-units v0.4.0 // indirect - github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect - github.com/elazarl/go-bindata-assetfs v1.0.0 // indirect - github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f // indirect - github.com/emicklei/go-restful v2.9.5+incompatible // indirect - github.com/envoyproxy/go-control-plane v0.8.0 // indirect - github.com/evanphx/json-patch v4.2.0+incompatible // indirect - github.com/farsightsec/golang-framestream v0.0.0-20190425193708-fa4b164d59b8 // indirect + github.com/emirpasic/gods v1.12.0 // indirect + github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c github.com/fsnotify/fsnotify v1.4.7 - github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa // indirect - github.com/gammazero/workerpool v0.0.0-20190521015540-3b91a70bc0a1 // indirect + github.com/fsouza/go-dockerclient v1.4.1 github.com/garyburd/redigo v1.6.0 // indirect github.com/ghodss/yaml v1.0.0 - github.com/go-acme/lego v2.6.0+incompatible // indirect - github.com/go-ldap/ldap v3.0.3+incompatible // indirect + github.com/gliderlabs/ssh v0.1.4 // indirect github.com/go-log/log v0.1.0 - github.com/go-ole/go-ole v1.2.4 // indirect - github.com/go-openapi/jsonpointer v0.19.0 // indirect - github.com/go-openapi/jsonreference v0.19.0 // indirect - github.com/go-openapi/spec v0.19.0 // indirect - github.com/go-openapi/swag v0.19.0 // indirect - github.com/go-sql-driver/mysql v1.4.1 // indirect - github.com/go-stomp/stomp v2.0.3+incompatible // indirect - github.com/gocql/gocql v0.0.0-20190523124812-0680bfb96414 // indirect - github.com/gogo/googleapis v1.2.0 // indirect + github.com/go-redsync/redsync v1.2.0 + github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect + github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect github.com/golang/mock v1.3.1 // indirect github.com/golang/protobuf v1.3.1 + github.com/gomodule/redigo v2.0.0+incompatible github.com/google/btree v1.0.0 // indirect - github.com/google/gofuzz v1.0.0 // indirect github.com/google/pprof v0.0.0-20190515194954-54271f7e092f // indirect github.com/google/uuid v1.1.1 - github.com/gophercloud/gophercloud v0.1.0 // indirect - github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect - github.com/gorilla/mux v1.7.2 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.9.0 // indirect - github.com/hashicorp/consul v1.5.1 github.com/hashicorp/consul/api v1.1.0 - github.com/hashicorp/go-checkpoint v0.5.0 // indirect - github.com/hashicorp/go-discover v0.0.0-20190522154730-8aba54d36e17 // indirect - github.com/hashicorp/go-hclog v0.9.2 // indirect - github.com/hashicorp/go-memdb v1.0.3 // indirect - github.com/hashicorp/go-version v1.2.0 // indirect + github.com/hashicorp/go-immutable-radix v1.1.0 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 - github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93 // indirect + github.com/hashicorp/mdns v1.0.1 // indirect github.com/hashicorp/memberlist v0.1.4 - github.com/hashicorp/nomad/api v0.0.0-20190529164939-86a6569933bd // indirect - github.com/hashicorp/raft v1.1.0 // indirect - github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea // indirect github.com/hashicorp/serf v0.8.3 // indirect - github.com/hashicorp/vault v1.1.2 // indirect - github.com/hashicorp/vault-plugin-auth-alicloud v0.5.1 // indirect - github.com/hashicorp/vault-plugin-auth-azure v0.5.1 // indirect - github.com/hashicorp/vault-plugin-auth-centrify v0.5.1 // indirect - github.com/hashicorp/vault-plugin-auth-jwt v0.5.1 // indirect - github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1 // indirect - github.com/hashicorp/vault-plugin-secrets-ad v0.5.1 // indirect - github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.1 // indirect - github.com/hashicorp/vault-plugin-secrets-azure v0.5.1 // indirect - github.com/hashicorp/vault-plugin-secrets-gcp v0.5.2 // indirect - github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.1 // indirect - github.com/hashicorp/vault-plugin-secrets-kv v0.5.1 // indirect - github.com/hashicorp/vault/api v1.0.2 // indirect - github.com/hashicorp/vault/sdk v0.1.11 // indirect github.com/imdario/mergo v0.3.7 - github.com/influxdata/influxdb v1.7.6 // indirect - github.com/jarcoal/httpmock v1.0.4 // indirect - github.com/jefferai/jsonx v1.0.0 // indirect - github.com/joyent/triton-go v0.0.0-20190112182421-51ffac552869 // indirect - github.com/keybase/go-crypto v0.0.0-20190416182011-b785b22cc757 // indirect + github.com/jonboulle/clockwork v0.1.0 // indirect + github.com/json-iterator/go v1.1.6 // indirect github.com/kisielk/errcheck v1.2.0 // indirect - github.com/klauspost/cpuid v1.2.1 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/kr/pty v1.1.4 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect - github.com/lib/pq v1.1.1 // indirect - github.com/linode/linodego v0.9.0 // indirect - github.com/lucas-clemente/quic-go v0.11.1 // indirect - github.com/lyft/protoc-gen-validate v0.0.14 // indirect - github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983 // indirect - github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b // indirect + github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect + github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018 // indirect github.com/mattn/go-colorable v0.1.2 // indirect - github.com/mholt/caddy v1.0.0 // indirect - github.com/mholt/certmagic v0.5.1 // indirect - github.com/michaelklishin/rabbit-hole v1.5.0 // indirect github.com/micro/cli v0.2.0 - github.com/micro/go-micro/util/log v0.1.0 + github.com/micro/go-log v0.1.0 github.com/micro/go-rcache v0.3.0 github.com/micro/mdns v0.1.0 - github.com/micro/util v0.2.0 github.com/miekg/dns v1.1.13 // indirect github.com/mitchellh/hashstructure v1.0.0 - github.com/mitchellh/pointerstructure v0.0.0-20190430161007-f252a8fd71c8 // indirect - github.com/munnerz/goautoneg v0.0.0-20190414153302-2ae31c8b6b30 // indirect - github.com/opentracing/opentracing-go v1.1.0 // indirect - github.com/openzipkin/zipkin-go-opentracing v0.3.5 // indirect - github.com/ory-am/common v0.4.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/nlopes/slack v0.5.0 + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.8.1 - github.com/pquerna/otp v1.1.0 // indirect github.com/prometheus/client_golang v0.9.3 // indirect github.com/prometheus/common v0.4.1 // indirect github.com/prometheus/procfs v0.0.1 // indirect github.com/prometheus/tsdb v0.8.0 // indirect github.com/rogpeppe/fastuuid v1.1.0 // indirect - github.com/russross/blackfriday v2.0.0+incompatible // indirect - github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec // indirect - github.com/shirou/gopsutil v2.18.12+incompatible // indirect github.com/sirupsen/logrus v1.4.2 // indirect - github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 // indirect - github.com/softlayer/softlayer-go v0.0.0-20190508182157-7c592eb2559c // indirect + github.com/soheilhy/cmux v0.1.4 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94 // indirect github.com/stretchr/objx v0.2.0 // indirect - github.com/ugorji/go v1.1.5-pre // indirect - github.com/vmware/govmomi v0.20.1 // indirect + github.com/technoweenie/multipartstreamer v1.0.1 // indirect + github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect + github.com/xanzy/ssh-agent v0.2.1 // indirect + github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect + go.etcd.io/bbolt v1.3.2 // indirect + go.etcd.io/etcd v3.3.13+incompatible go.opencensus.io v0.22.0 // indirect go.uber.org/atomic v1.4.0 // indirect + go.uber.org/multierr v1.1.0 // indirect go.uber.org/zap v1.10.0 // indirect golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 // indirect golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522 // indirect @@ -162,22 +94,19 @@ require ( golang.org/x/mobile v0.0.0-20190509164839-32b2708ab171 // indirect golang.org/x/net v0.0.0-20190522155817-f3200d17e092 golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0 // indirect - golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 // indirect + golang.org/x/sys v0.0.0-20190531073156-46560c3f3c0a // indirect + golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect golang.org/x/tools v0.0.0-20190530215528-75312fb06703 // indirect google.golang.org/appengine v1.6.0 // indirect google.golang.org/genproto v0.0.0-20190530194941-fb225487d101 // indirect google.golang.org/grpc v1.21.0 // indirect - gopkg.in/gorethink/gorethink.v4 v4.1.0 // indirect - gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect - gopkg.in/ory-am/dockertest.v2 v2.2.3 // indirect + gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a // indirect + gopkg.in/redis.v3 v3.6.4 + gopkg.in/src-d/go-billy.v4 v4.3.0 // indirect + gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 // indirect + gopkg.in/src-d/go-git.v4 v4.11.0 + gopkg.in/telegram-bot-api.v4 v4.6.4 honnef.co/go/tools v0.0.0-20190530170028-a1efa522b896 // indirect - k8s.io/api v0.0.0-20190528154508-67ef80593b24 // indirect - k8s.io/client-go v11.0.0+incompatible // indirect - k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a // indirect - k8s.io/klog v0.3.2 // indirect - k8s.io/kube-openapi v0.0.0-20190530181030-b52b5b0f5a7c // indirect - k8s.io/utils v0.0.0-20190529001817-6999998975a7 // indirect - layeh.com/radius v0.0.0-20190322222518-890bc1058917 // indirect ) replace github.com/golang/lint => github.com/golang/lint v0.0.0-20190227174305-8f45f776aaf1 diff --git a/go.sum b/go.sum index 90b692dd..d2e9f0c3 100644 --- a/go.sum +++ b/go.sum @@ -1,32 +1,15 @@ cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.28.0 h1:KZ/88LWSw8NxMkjdQyX7LQSGR9PkHr4PaVuNm8zgFq0= cloud.google.com/go v0.28.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= -contrib.go.opencensus.io/exporter/ocagent v0.4.12 h1:jGFvw3l57ViIVEPKKEUXPcLYIXJmQxLUh6ey1eJhwyc= -contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= -contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= -git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/Azure/azure-sdk-for-go v16.0.0+incompatible h1:gr1qKY/Ll72VjFTZmaBwRK1yQHAxCnV25ekOKroc9ws= github.com/Azure/azure-sdk-for-go v16.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v27.1.0+incompatible h1:/aGULErVaJsMdtew1p9OhEo8FeBzfRKRzJbc8NWJv/w= -github.com/Azure/azure-sdk-for-go v27.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v27.3.0+incompatible h1:i+ROfG3CsZUPoVAnhK06T3R6PmBzKB9ds+lHBpN7Mzo= -github.com/Azure/azure-sdk-for-go v27.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v30.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest v10.7.0+incompatible h1:dB+dKSLGdJLEhU/FoZTSNSPMZuE5H4M5p5zgSct7qwM= github.com/Azure/go-autorest v10.7.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v10.15.3+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v11.7.1+incompatible h1:M2YZIajBBVekV86x0rr1443Lc1F/Ylxb9w+5EtSyX3Q= -github.com/Azure/go-autorest v11.7.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest v12.0.0+incompatible h1:N+VqClcomLGD/sHb3smbSYYtNMgKpVV3Cd5r5i8z6bQ= -github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v12.1.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -40,19 +23,14 @@ github.com/DataDog/zstd v1.3.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Jeffail/gabs v1.1.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E= github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Jeffail/gabs v1.2.0 h1:uFhoIVTtsX7hV2RxNgWad8gMU+8OJdzFbOathJdhD3o= -github.com/Jeffail/gabs v1.2.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Microsoft/go-winio v0.4.3/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc= github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= @@ -62,7 +40,6 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/SAP/go-hdb v0.12.0/go.mod h1:etBT+FAi1t5k3K3tf5vQTnosgYmhDkRi8jEnQqCnxF0= -github.com/SAP/go-hdb v0.14.1 h1:hkw4ozGZ/i4eak7ZuGkY5e0hxiXFdNUBNhr4AvZVNFE= github.com/SAP/go-hdb v0.14.1/go.mod h1:7fdQLVC2lER3urZLjZCm0AuMQfApof92n3aylBPEkMo= github.com/SermoDigital/jose v0.0.0-20180104203859-803625baeddc/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= @@ -70,25 +47,15 @@ github.com/Shopify/sarama v1.21.0/go.mod h1:yuqtN/pe8cXRWG5zPaO7hCfNJp5MwmkoJEoL github.com/Shopify/sarama v1.22.1/go.mod h1:FRzlvRpMFO/639zY1SDxUxkqH97Y0ndM5CbGj6oG3As= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/StackExchange/wmi v0.0.0-20181212234831-e0a55b97c705 h1:UUppSQnhf4Yc6xGxSkoQpPhb7RVzuv5Nb1mwJ5VId9s= -github.com/StackExchange/wmi v0.0.0-20181212234831-e0a55b97c705/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190412020505-60e2075261b6 h1:5RwdKFlGKokYBbq4M2ZZ0LzfxdK4e1L4rwQH+76wPkE= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190412020505-60e2075261b6/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190423023524-6ff5e74c25e8 h1:n3yJ9NAD5JfC5aTyO6yoJm5wbQ8LozPHrj2qJnAAHlI= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190423023524-6ff5e74c25e8/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190522081930-582d16a078d0/go.mod h1:0nPXeXAsIm3YH7imFCamfa0u+PueDefehKCQ8dicxmc= -github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190530073359-dfac1ef71ffa/go.mod h1:0nPXeXAsIm3YH7imFCamfa0u+PueDefehKCQ8dicxmc= -github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/aliyun/aliyun-oss-go-sdk v1.9.6/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= -github.com/aliyun/aliyun-oss-go-sdk v1.9.8/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61 h1:Xz25cuW4REGC5W5UtpMU3QItMIImag615HiQcRbxqKQ= -github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61/go.mod h1:ikc1XA58M+Rx7SEbf0bLJCfBkwayZ8T5jBo5FXK8Uz8= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs= github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -100,17 +67,12 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20180319081651-7d2e70ef918f/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.14.17/go.mod h1:ZRmQr0FajVIyZ4ZzBYKG5P3ZqPz9IHG41ZoMu1ADI3k= -github.com/aws/aws-sdk-go v1.15.24 h1:xLAdTA/ore6xdPAljzZRed7IGqQgC+nY+ERS5vaj4Ro= github.com/aws/aws-sdk-go v1.15.24/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.19.15 h1:Ov8zxPunHxZFxrXBarqzkZBSZugJRzPgb4mfq/SyVgA= -github.com/aws/aws-sdk-go v1.19.15/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.19.35/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.19.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= +github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= +github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= @@ -119,30 +81,20 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= github.com/bifurcation/mint v0.0.0-20190129141059-83ba9bc2ead9/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU= -github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/briankassouf/jose v0.9.2-0.20180619214549-d2569464773f h1:ZMEzE7R0WNqgbHplzSBaYJhJi5AZWTCK9baU0ebzG6g= -github.com/briankassouf/jose v0.9.2-0.20180619214549-d2569464773f/go.mod h1:HQhVmdUf7dBNwIIdBTivnCDxcf6IZY3/zrb+uKSJz6Y= -github.com/cenkalti/backoff v2.0.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= +github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/bwmarrin/discordgo v0.19.0 h1:kMED/DB0NR1QhRcalb85w0Cu3Ep2OrGAqZH1R5awQiY= +github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4= -github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/centrify/cloud-golang-sdk v0.0.0-20190214225812-119110094d0f h1:gJzxrodnNd/CtPXjO3WYiakyNzHg3rtAi7rO74ejHYU= -github.com/centrify/cloud-golang-sdk v0.0.0-20190214225812-119110094d0f/go.mod h1:C0rtzmGXgN78pYR0tGJFhtHgkbAs0lIbHwkB81VxDQE= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/chrismalek/oktasdk-go v0.0.0-20181212195951-3430665dfaa0 h1:CWU8piLyqoi9qXEUwzOh5KFKGgmSU5ZhktJyYcq6ryQ= -github.com/chrismalek/oktasdk-go v0.0.0-20181212195951-3430665dfaa0/go.mod h1:5d8DqS60xkj9k3aXfL3+mXBH0DPYO0FQjcKosxl+b/Q= github.com/circonus-labs/circonus-gometrics v0.0.0-20161109192337-d17a8420c36e/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= @@ -152,89 +104,69 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp 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/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8= github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/coredns/coredns v1.1.2/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0= -github.com/coredns/coredns v1.5.0 h1:SJ0xqULsNLGNSBE+G678tM/v1cJ5o5s/FcTC1qPTQkI= github.com/coredns/coredns v1.5.0/go.mod h1:He0NCGwdo32s+0TFFuiB9ccnFZRAsjdrW5Q3Vv5Ne6g= github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.11+incompatible h1:0gCnqKsq7XxMi69JsnbmMc1o+RJH3XH64sV9aiTTYko= github.com/coreos/etcd v3.3.11+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.12+incompatible h1:pAWNwdf7QiT1zfaWyqCtNZQWCLByQyA3JrSQyuYAqnQ= -github.com/coreos/etcd v3.3.12+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +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/coreos/go-oidc v2.0.0+incompatible h1:+RStIopZ8wooMx+Vs5Bt8zMXxV1ABl5LbakNExNmZIg= -github.com/coreos/go-oidc v2.0.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190212144455-93d5ec2c7f76 h1:FE783w8WFh+Rvg+7bZ5g8p7gP4SeVS4AoNwkvazlsBg= github.com/coreos/go-systemd v0.0.0-20190212144455-93d5ec2c7f76/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/dancannon/gorethink v4.0.0+incompatible h1:KFV7Gha3AuqT+gr0B/eKvGhbjmUv0qGF43aKCIKVE9A= -github.com/dancannon/gorethink v4.0.0+incompatible/go.mod h1:BLvkat9KmZc1efyYwhz3WnybhRZtgF1K929FD8z1avU= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20180620032804-94c9c97e8c9f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= -github.com/denisenkom/go-mssqldb v0.0.0-20190418034912-35416408c946 h1:xn+jBHAqNYs6CnHhJwfWZQspPHMEL+LzUk0vpqWj6eo= -github.com/denisenkom/go-mssqldb v0.0.0-20190418034912-35416408c946/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661 h1:lrWnAyy/F72MbxIxFUzKmcMCdt9Oi8RzpAxzTNQHD7o= github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= -github.com/denverdino/aliyungo v0.0.0-20190410085603-611ead8a6fed h1:WtFFp2kd7j/ATD3dT5tdjyoXuynxHu6D0AJVG9Be1q4= github.com/denverdino/aliyungo v0.0.0-20190410085603-611ead8a6fed/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.1.1 h1:v0A7yF3xmKLjjdJGIeBbINfMufcrrRhqZsxuVQMoT+U= github.com/digitalocean/godo v1.1.1/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= -github.com/digitalocean/godo v1.13.0 h1:+0rQUl0AkTmhKDeqP8Y1Z60cJzhC/1jPI6jWpWnLUr8= -github.com/digitalocean/godo v1.13.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/digitalocean/godo v1.15.0/go.mod h1:AAPQ+tiM4st79QHlEBTg8LM7JQNre4SAQCbn56wEyKY= -github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4= -github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnstap/golang-dnstap v0.0.0-20170829151710-2cf77a2b5e11/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U= -github.com/dnstap/golang-dnstap v0.0.0-20190521061535-1a0dab85b926/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U= github.com/dnstap/golang-dnstap v0.1.0/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U= +github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc= +github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74 h1:2MIhn2R6oXQbgW5yHfS+d6YqyMfXiu2L55rFZC4UD/M= github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= -github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20190421051319-9d40249d3c2f/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo= +github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.0.0-20180919002855-2137d9196328/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= -github.com/envoyproxy/go-control-plane v0.6.9 h1:deEH9W8ZAUGNbCdX+9iNzBOGrAOrnpJGoy0PcTqk/tE= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= -github.com/envoyproxy/go-control-plane v0.7.1 h1:CwDZ3n/znIaqNalgauCWLZ6Wl7NCe6v9yjiY4kslaMk= -github.com/envoyproxy/go-control-plane v0.7.1/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.8.0/go.mod h1:GSSbY9P1neVhdY7G4wu+IK1rk/dqhiCC/4ExuWJZVuk= -github.com/envoyproxy/protoc-gen-validate v0.0.14 h1:YBW6/cKy9prEGRYLnaGa4IDhzxZhRCtKsax8srGKDnM= github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/estesp/manifest-tool v0.9.0/go.mod h1:w/oandYlJC/m8nkP8UaJVxsm/LwjurJQHXR27njws74= github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -245,43 +177,35 @@ github.com/farsightsec/golang-framestream v0.0.0-20190425193708-fa4b164d59b8/go. github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/structs v0.0.0-20180123065059-ebf56d35bba7/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c h1:pBgVXWDXju1m8W4lnEeIqTHPOzhTUO81a7yknM/xQR4= +github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c/go.mod h1:pFdJbAhRf7rh6YYMUdIQGyzne6zYL1tCUW8QV2B3UfY= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU= -github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= -github.com/gammazero/deque v0.0.0-20190130191400-2afb3858e9c7 h1:D2LrfOPgGHQprIxmsTpxtzhpmF66HoM6rXSmcqaX7h8= -github.com/gammazero/deque v0.0.0-20190130191400-2afb3858e9c7/go.mod h1:GeIq9qoE43YdGnDXURnmKTnGg15pQz4mYkXSTChbneI= -github.com/gammazero/deque v0.0.0-20190521012701-46e4ffb7a622/go.mod h1:D90+MBHVc9Sk1lJAbEVgws0eYEurY4mv2TDso3Nxh3w= -github.com/gammazero/workerpool v0.0.0-20190406235159-88d534f22b56 h1:VzbudKn/nvxYKOdzgkEBS6SSreRjAgoJ+ZeS4wPFkgc= -github.com/gammazero/workerpool v0.0.0-20190406235159-88d534f22b56/go.mod h1:w9RqFVO2BM3xwWEcAB8Fwp0OviTBBEiRmSBDfbXnd3w= -github.com/gammazero/workerpool v0.0.0-20190521015540-3b91a70bc0a1/go.mod h1:avlwxCMavNtjwf7NrfnzdIGU3OZYI5D1NFQ2Rn3nHKg= +github.com/fsouza/go-dockerclient v1.4.1 h1:W7wuJ3IB48WYZv/UBk9dCTIb9oX805+L9KIm65HcUYs= +github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs= github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1 h1:j3L6gSLQalDETeEg/Jg0mGY0/y/N6zI2xX1978P0Uqw= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/gliderlabs/ssh v0.1.4/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= github.com/go-acme/lego v2.6.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-ini/ini v1.25.4 h1:Mujh4R/dH6YL8bxuISne3xX2+qcQ9p0IxKAP6ExWoUo= github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-ini/ini v1.42.0 h1:TWr1wGj35+UiWHlBA8er89seFXxzwFn11spilrrj+38= github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-ldap/ldap v3.0.2+incompatible h1:kD5HQcAzlQ7yrhfn+h+MSABeAy/jAJhvIJ/QDllP44g= github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= -github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk= github.com/go-ldap/ldap v3.0.3+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U= github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= -github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= @@ -294,37 +218,29 @@ github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-redsync/redsync v1.2.0 h1:a4y3xKQUOA5092Grjps3F5vaRbjA9uoUB59RVwOMttA= +github.com/go-redsync/redsync v1.2.0/go.mod h1:QClK/s99KRhfKdpxLTMsI5mSu43iLp0NfOneLPie+78= github.com/go-sql-driver/mysql v0.0.0-20180618115901-749ddf1598b4/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stomp/stomp v2.0.2+incompatible h1:0yPknMJh32lE2xiCFGW5t/KgamhUC4OgCv10wIjx5aw= -github.com/go-stomp/stomp v2.0.2+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c= -github.com/go-stomp/stomp v2.0.3+incompatible/go.mod h1:VqCtqNZv1226A1/79yh+rMiFUcfY3R109np+7ke4n0c= -github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gocql/gocql v0.0.0-20180617115710-e06f8c1bcd78/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= -github.com/gocql/gocql v0.0.0-20190418090649-59a610c947c5 h1:ja4omKSx9OiML8GnnDG13qOX58UAcSJfOmce21YXALk= -github.com/gocql/gocql v0.0.0-20190418090649-59a610c947c5/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= -github.com/gocql/gocql v0.0.0-20190423091413-b99afaf3b163/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= github.com/gocql/gocql v0.0.0-20190523124812-0680bfb96414/go.mod h1:Q7Sru5153KG8D9zwueuQJB3ccJf9/bIwF/x8b3oKgT8= -github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/googleapis v1.2.0 h1:Z0v3OJDotX9ZBpdz2V+AI7F4fITSZhVE5mg6GQppwMM= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/lint v0.0.0-20190227174305-8f45f776aaf1/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -332,29 +248,27 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -365,62 +279,39 @@ github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s= github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gophercloud/gophercloud v0.0.0-20180828235145-f29afc2cceca h1:wobTb8SE189AuxzEKClyYxiI4nUGWlpVtl13eLiFlOE= github.com/gophercloud/gophercloud v0.0.0-20180828235145-f29afc2cceca/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4= -github.com/gophercloud/gophercloud v0.0.0-20190307220656-fe1ba5ce12dd h1:tkA3C/XTk8iACLOlTez37pL+0iGSYkkRGKdXgJ6ZylM= github.com/gophercloud/gophercloud v0.0.0-20190307220656-fe1ba5ce12dd/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v0.0.0-20190422143055-fe6299556848 h1:3C19GoTlj2BtSe+APK65YeFikcZVacnXncVEPGuqOQU= -github.com/gophercloud/gophercloud v0.0.0-20190422143055-fe6299556848/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gophercloud/gophercloud v0.0.0-20190520235722-e87e5f90e7e6/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c h1:16eHWuMGvCjSfgRJKqIzapE78onvvTbdi1rMkU00lZw= github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e h1:XWcjeEtTFTOVA9Fs1w7n2XBftk5ib4oZrhzWk0B+3eA= -github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 h1:f0n1xnMSmBLzVfsMMvriDyA75NB/oBgILX2GcHXIQzY= -github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q= github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.8.3/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE= -github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= -github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul v1.4.2 h1:D9iJoJb8Ehe/Zmr+UEE3U3FjOLZ4LUxqFMl4O43BM1U= github.com/hashicorp/consul v1.4.2/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= -github.com/hashicorp/consul v1.4.4 h1:DR1+5EGgnPsd/LIsK3c9RDvajcsV5GOkGQBSNd3dpn8= -github.com/hashicorp/consul v1.4.4/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI= -github.com/hashicorp/consul v1.5.0 h1:GPtcwUGw5kjoSIF7NpDHmwHEM17ufGn1ezKQSutBMhI= -github.com/hashicorp/consul v1.5.0/go.mod h1:7rvUESOLul7V9uCo5TNZ64jzf9W5Fcy/xf/TxtOT0xQ= -github.com/hashicorp/consul v1.5.1 h1:p7tRmQ4m3ZMYkGQkuyjLXKbdU1weeumgZFqZOvw7o4c= github.com/hashicorp/consul v1.5.1/go.mod h1:QsmgXh2YA9Njv6y3/FHXqHYhsMye++3oBoAZ6SR8R8I= github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1 h1:LnuDWGNsoajlhGyHJvuWW6FVqRl8JOTPqS6CPTsYjhY= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -432,14 +323,9 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-discover v0.0.0-20190403160810-22221edb15cd/go.mod h1:ueUgD9BeIocT7QNuvxSyJyPAM9dfifBcaWmeybb67OY= -github.com/hashicorp/go-discover v0.0.0-20190408185603-6ccdb67f9b84 h1:ImeFWg0F3G8xtba0MrlDXgw8lmR4dDgwqZrrWOowelY= -github.com/hashicorp/go-discover v0.0.0-20190408185603-6ccdb67f9b84/go.mod h1:FTV98wIi2RF5iDl1iLR/cB+no+B//ODP6133EcC9djw= github.com/hashicorp/go-discover v0.0.0-20190522154730-8aba54d36e17/go.mod h1:FTV98wIi2RF5iDl1iLR/cB+no+B//ODP6133EcC9djw= -github.com/hashicorp/go-gcp-common v0.5.0 h1:kkIQTjNTopn4eXQ1+lCiHYZXUtgIZvbc6YtAQkMnTos= -github.com/hashicorp/go-gcp-common v0.5.0/go.mod h1:IDGUI2N/OS3PiU4qZcXJeWKPI6O/9Y8hOrbSiMcqyYw= github.com/hashicorp/go-hclog v0.0.0-20180402200405-69ff559dc25f/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= -github.com/hashicorp/go-hclog v0.8.0 h1:z3ollgGRg8RjfJH6UVBaG54R70GFd++QOkvnJH3VSBY= github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= @@ -448,20 +334,15 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v0.0.0-20180223233045-1289e7fffe71/go.mod h1:kbfItVoBJwCfKXDXN4YoAXjxcFVZ7MRrJzyTX6H4giE= -github.com/hashicorp/go-memdb v1.0.1 h1:QR2h3O60I0DSvCsogh77kZUPzZBkbDSfeUjzhrK8p04= -github.com/hashicorp/go-memdb v1.0.1/go.mod h1:I6dKdmYhZqU0RJSheVEWgTNWdVQH5QvTgIUQ0t/t32M= -github.com/hashicorp/go-memdb v1.0.2/go.mod h1:I6dKdmYhZqU0RJSheVEWgTNWdVQH5QvTgIUQ0t/t32M= github.com/hashicorp/go-memdb v1.0.3/go.mod h1:LWQ8R70vPrS4OEY9k28D2z8/Zzyu34NVzeRibGAzHO0= github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-msgpack v0.5.4 h1:SFT72YqIkOcLdWJUYcriVX7hbrZpwc/f7h8aW2NUqrA= github.com/hashicorp/go-msgpack v0.5.4/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v0.0.0-20180331002553-e8d22c780116/go.mod h1:JSqWYsict+jzcj0+xElxyrBQRPNoiWQuddnxArJ7XHQ= -github.com/hashicorp/go-plugin v1.0.0 h1:/gQ1sNR8/LHpoxKRQq4PmLBuacfZb4tC93e9B30o/7c= github.com/hashicorp/go-plugin v1.0.0/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.0.0-20180531211321-3b087ef2d313/go.mod h1:fXcdFsQoipQa7mwORhKad5jmDCeSy/RCGzWA08PO0lM= github.com/hashicorp/go-retryablehttp v0.5.3 h1:QlWt0KvWT0lq8MFppF9tsJGF+ynG7ztc2KIPhzRGk7s= @@ -480,9 +361,7 @@ github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1 github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v0.0.0-20170202080759-03c5bf6be031/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= @@ -495,120 +374,69 @@ github.com/hashicorp/hcl v0.0.0-20180906183839-65a6292f0157/go.mod h1:E5yfLk+7sw github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hil v0.0.0-20160711231837-1e86c6b523c5/go.mod h1:KHvg/R2/dPtaePb16oW4qIyzkMxXOL38xjRN64adsts= -github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93 h1:T1Q6ag9tCwun16AW+XK3tAql24P4uTGUMIn1/92WsQQ= github.com/hashicorp/hil v0.0.0-20190212132231-97b3a9cdfa93/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0 h1:WhIgCr5a7AaVH6jPUwjtRuuE7/RDufnUvzIr48smyxs= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.1 h1:XFSOubp8KWB+Jd2PDyaX5xUd5bhSP/+pTDZVDMzZJM8= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.4 h1:gkyML/r71w3FL8gUi74Vk76avkj/9lYAY9lvg0OcoGs= github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69 h1:lc3c72qGlIMDqQpQH82Y4vaglRMMFdJbziYWriR4UcE= github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q= -github.com/hashicorp/nomad/api v0.0.0-20190422193122-09c998a4a160 h1:3a/eASHSEdXV9ghYxoZj8DJ52/9Wp22Ers70lxB/vnU= -github.com/hashicorp/nomad/api v0.0.0-20190422193122-09c998a4a160/go.mod h1:BDngVi1f4UA6aJq9WYTgxhfWSE1+42xshvstLU2fRGk= -github.com/hashicorp/nomad/api v0.0.0-20190522160243-df84e07c1a46/go.mod h1:BDngVi1f4UA6aJq9WYTgxhfWSE1+42xshvstLU2fRGk= -github.com/hashicorp/nomad/api v0.0.0-20190529164939-86a6569933bd/go.mod h1:BDngVi1f4UA6aJq9WYTgxhfWSE1+42xshvstLU2fRGk= github.com/hashicorp/raft v1.0.1-0.20190409200437-d9fe23f7d472/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= -github.com/hashicorp/raft v1.0.1 h1:94uRdS11oEneUkxmXq6Vg9shNhBILh2UTb9crQjJWl0= -github.com/hashicorp/raft v1.0.1/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= github.com/hashicorp/raft v1.1.0/go.mod h1:4Ak7FSPnuvmb0GV6vgIAJ4vYT4bek9bb6Q+7HVbyzqM= github.com/hashicorp/raft-boltdb v0.0.0-20150201200839-d1e82c1ec3f1/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= -github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea h1:xykPFhrBAS2J0VBzVa5e80b5ZtYuNQtgXjN40qBZlD4= github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk= github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k= github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hashicorp/vault v0.10.3/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= -github.com/hashicorp/vault v1.1.2 h1:NDaWEwrTwjg3VKrKQmQykuiq4UqMUlbqloRvIX5fhns= github.com/hashicorp/vault v1.1.2/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0= -github.com/hashicorp/vault-plugin-auth-alicloud v0.5.1 h1:CldlLfMGlcXy+5CvnNsOWJjE9/C1i+Nho4ClSJe+63k= -github.com/hashicorp/vault-plugin-auth-alicloud v0.5.1/go.mod h1:v0d6/ft2ESFHG/PB2pqcwDPlvtAWWfOmfsY0nfbIMy0= -github.com/hashicorp/vault-plugin-auth-azure v0.5.1 h1:1CTmC68zYhp/cKuHW8K0QbnWEetFK7UUu5jaWhmzbHw= -github.com/hashicorp/vault-plugin-auth-azure v0.5.1/go.mod h1:D/slkpcqcZMqslj1X9jfU9aIOrC41LVkfDQ9lFhYg0o= -github.com/hashicorp/vault-plugin-auth-centrify v0.5.1 h1:kHWphxtASUJVYgqvfr6KjCN74qWLJeLhSRE5kBQ4iiQ= -github.com/hashicorp/vault-plugin-auth-centrify v0.5.1/go.mod h1:GHplZPj7NfPWdeCkgTRnNzbjVP5IW5MNm7+MMsjobpQ= -github.com/hashicorp/vault-plugin-auth-gcp v0.5.1 h1:8DR00s+Wmc21i3sfzvsqW88VMdf6NI2ue+onGoHshww= -github.com/hashicorp/vault-plugin-auth-gcp v0.5.1/go.mod h1:eLj92eX8MPI4vY1jaazVLF2sVbSAJ3LRHLRhF/pUmlI= -github.com/hashicorp/vault-plugin-auth-jwt v0.5.1 h1:d9WLI7oF6VMtwBZwS5bbChc4kW+UwNZUKIGXH6wnnTc= -github.com/hashicorp/vault-plugin-auth-jwt v0.5.1/go.mod h1:5VU7gc6/BEEFQW/viqMs3LBxI1D1cxJmKqKQEP3JUP4= -github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1 h1:q6DGb12Vw/CpZ9xDWAmpzxVRKeClFqRFgbIZ3fZcvuY= -github.com/hashicorp/vault-plugin-auth-kubernetes v0.5.1/go.mod h1:qCDsm0njdfUrnN5sFKMLjxGjZKjQf2qB6dReQ4gr4YI= -github.com/hashicorp/vault-plugin-secrets-ad v0.5.1 h1:BdiASUZLOvOUs317EnaUNjGxTSw0PYGQA7zJZhDKLC4= -github.com/hashicorp/vault-plugin-secrets-ad v0.5.1/go.mod h1:EH9CI8+0aWRBz8eIgGth0QjttmHWlGvn+8ZmX/ZUetE= -github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.1 h1:72K91p4uLhT/jgtBq2zV5Wn8ocvny4sAN56XOcTxK1w= -github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.1/go.mod h1:MspbyD2pPrYgBnYIawkBsFinaDb9lx9PA6uBYOG+d8I= -github.com/hashicorp/vault-plugin-secrets-azure v0.5.1 h1:6XFAkvpQl4zrXpZLSW9TCfF2z0mb2vwbrNmX2nzn480= -github.com/hashicorp/vault-plugin-secrets-azure v0.5.1/go.mod h1:9D3lbhWkN7kTCIrQl8yxMU4IkisAY3SYZaRvseih6ZE= -github.com/hashicorp/vault-plugin-secrets-gcp v0.5.2 h1:oH5EVMJCOHb81Ib9E7/ps1WrN3zkS6SnkbCW4tlk6Ro= -github.com/hashicorp/vault-plugin-secrets-gcp v0.5.2/go.mod h1:2VjVlKHTwqvcVCkZBhYks+HASDzQ4/bIsJoOpO2YJFY= -github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.1 h1:v25YWb7eMPe9DjGsUexRRuWwPlFNh+lbEGOeNrZalf8= -github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.1/go.mod h1:seBkt6x33ZT20koMcUwV/viMomnXDipsLgK5KUKz2ik= github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20190318174639-195e0e9d07f1/go.mod h1:VJHHT2SC1tAPrfENQeBhLlb5FbZoKZM+oC/ROmEftz0= -github.com/hashicorp/vault-plugin-secrets-kv v0.5.1 h1:awaZ/UoeiDD0j3xF1E0kmXWJvAZw8ULayQu46mB6Un4= github.com/hashicorp/vault-plugin-secrets-kv v0.5.1/go.mod h1:PIjaafaRr2QlkGl2SNhIywxlejeW0iMUtmx8u9u/a6c= -github.com/hashicorp/vault/api v1.0.1 h1:YQI4SgOlkmbEKZI8ZClo6fm9oXlBHJUlrbEtFiRPrng= github.com/hashicorp/vault/api v1.0.1/go.mod h1:AV/+M5VPDpB90arloVX0rVDUIHkONiwz5Uza9HRtpUE= github.com/hashicorp/vault/api v1.0.2/go.mod h1:AV/+M5VPDpB90arloVX0rVDUIHkONiwz5Uza9HRtpUE= -github.com/hashicorp/vault/sdk v0.1.8 h1:pfF3KwA1yPlfpmcumNsFM4uo91WMasX5gTuIkItu9r0= github.com/hashicorp/vault/sdk v0.1.8/go.mod h1:tHZfc6St71twLizWNHvnnbiGFo1aq0eD2jGPLtP8kAU= -github.com/hashicorp/vault/sdk v0.1.9 h1:GkHLrt3ZU8j/ATmbLqW5P/frBCxPhCRC6nLD0kDP/yc= -github.com/hashicorp/vault/sdk v0.1.9/go.mod h1:tHZfc6St71twLizWNHvnnbiGFo1aq0eD2jGPLtP8kAU= github.com/hashicorp/vault/sdk v0.1.11/go.mod h1:XF2Bod+ahPWGARnyFq5LfkOZwWwvveR5ptYwJLqK0ZI= -github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 h1:O/pT5C1Q3mVXMyuqg7yuAWUg/jMZR1/0QTzTRdNR6Uw= github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd h1:anPrsicrIi2ColgWTVPk+TrN42hJIWlfPHSBP9S0ZkM= +github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/influxdata/influxdb v1.7.6 h1:8mQ7A/V+3noMGCt/P9pD09ISaiz9XvgCk303UYA3gcs= -github.com/influxdata/influxdb v1.7.6/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= -github.com/jarcoal/httpmock v1.0.3 h1:Qgv39cyHvgEguAofjb5GomnBCm10Dq71K+k1Aq0h7/o= -github.com/jarcoal/httpmock v1.0.3/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.0.4/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= -github.com/jeffchao/backoff v0.0.0-20140404060208-9d7fd7aa17f2 h1:mex1izRBCD+7WjieGgRdy7e651vD/lvB1bD9vNE/3K4= -github.com/jeffchao/backoff v0.0.0-20140404060208-9d7fd7aa17f2/go.mod h1:xkfESuHriIekR+4RoV+fu91j/CfnYM29Zi2tMFw5iD4= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee/go.mod h1:N0t2vlmpe8nyZB5ouIbJQPDSR+mH6oe7xHB9VZHSUzM= -github.com/jefferai/jsonx v1.0.0 h1:Xoz0ZbmkpBvED5W9W1B5B/zc3Oiq7oXqiW7iRV3B6EI= github.com/jefferai/jsonx v1.0.0/go.mod h1:OGmqmi2tTeI/PS+qQfBDToLHHJIy/RMp24fPo8vFvoQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= -github.com/jmespath/go-jmespath v0.0.0-20151117175822-3433f3ea46d9/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62 h1:JHCT6xuyPUrbbgAPE/3dqlvUKzRHMNuTBKKUb6OeR/k= github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= -github.com/joyent/triton-go v0.0.0-20190112182421-51ffac552869 h1:BvV6PYcRz0yGnWXNZrd5wginNT1GfFfPvvWpPbjfFL8= github.com/joyent/triton-go v0.0.0-20190112182421-51ffac552869/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= +github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-crypto v0.0.0-20180614160407-5114a9a81e1b/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= -github.com/keybase/go-crypto v0.0.0-20190416182011-b785b22cc757 h1:rHXu79NFmin5AvIe4JsnfCBGb1qAIlMTX0vnpVnDn7s= github.com/keybase/go-crypto v0.0.0-20190416182011-b785b22cc757/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -629,27 +457,24 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v0.0.0-20180523175426-90697d60dd84/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0 h1:/5u4a+KGJptBRqGzPvYQL9p0d/tPR4S31+Tnzj9lEO4= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/linode/linodego v0.7.1 h1:4WZmMpSA2NRwlPZcc0+4Gyn7rr99Evk9bnr0B3gXRKE= github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= -github.com/linode/linodego v0.8.1/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= github.com/linode/linodego v0.9.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04= github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk= github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao= -github.com/lucas-clemente/quic-go v0.11.1/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= +github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58= +github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 h1:AsEBgzv3DhuYHI/GiQh2HxvTP71HCCE9E/tzGUzGdtU= +github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= +github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018 h1:MNApn+Z+fIT4NPZopPfCc1obT6aY3SVM6DOctz1A9ZU= +github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= github.com/lyft/protoc-gen-validate v0.0.0-20180911180927-64fcb82c878e/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/lyft/protoc-gen-validate v0.0.14/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= -github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b h1:v29yPGHhOqw7VHEnTeQFAth3SsBrmwc8JfuhNY0G34k= -github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b/go.mod h1:5MWrJXKRQyhQdUCF+vu6U5c4nQpg70vW3eHaU0/AYbU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= @@ -659,8 +484,6 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 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= @@ -668,15 +491,13 @@ github.com/mholt/caddy v0.11.5/go.mod h1:Wb1PlT4DAYSqOEd03MsqkdkXnTxA8v9pKjdpxbq github.com/mholt/caddy v1.0.0/go.mod h1:PzUpQ3yGCTuEuy0KSxEeB4TZOi3zBZ8BR/zY0RBP414= github.com/mholt/certmagic v0.5.0/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY= github.com/mholt/certmagic v0.5.1/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY= -github.com/michaelklishin/rabbit-hole v1.5.0 h1:Bex27BiFDsijCM9D0ezSHqyy0kehpYHuNKaPqq/a4RM= -github.com/michaelklishin/rabbit-hole v1.5.0/go.mod h1:vvI1uOitYZi0O5HEGXhaWC1XT80Gy+HvFheJ+5Krlhk= github.com/micro/cli v0.0.0-20181223203424-1b0c9793c300/go.mod h1:x9x6qy+tXv17jzYWQup462+j3SIUgDa6vVTzU4IXy/w= github.com/micro/cli v0.1.0 h1:5DT+QdbAPPQvB3gYTgwze7tFO1m+7DU1sz9XfQczbsc= github.com/micro/cli v0.1.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= -github.com/micro/go-micro/util/log v0.1.0 h1:szYSR+yyTsomZM2jyinJC5562DlqffSjHmTZFaeZ2vY= -github.com/micro/go-micro/util/log v0.1.0/go.mod h1:qaFBF6d6Jk01Gz4cbMkCA2vVuLk3FSaLLjmEGrMCreA= +github.com/micro/go-log v0.1.0 h1:szYSR+yyTsomZM2jyinJC5562DlqffSjHmTZFaeZ2vY= +github.com/micro/go-log v0.1.0/go.mod h1:qaFBF6d6Jk01Gz4cbMkCA2vVuLk3FSaLLjmEGrMCreA= github.com/micro/go-micro v0.23.0/go.mod h1:3z3lfMkNU9Sr1L/CxL++8pVJmQapRo0N6kNjwYDtOVs= github.com/micro/go-micro v0.26.0/go.mod h1:CweCFO/pq8dCSIOdzVZ4ooIpUrKlyJ0AcFB269M7PgU= github.com/micro/go-micro v0.26.1/go.mod h1:Jgc5gPEmDiG1TWE5Qnzzx5qyXnU9VTXKT1FkXkfvt8g= @@ -702,16 +523,11 @@ github.com/miekg/dns v1.1.4 h1:rCMZsU2ScVSYcAsOXgmC6+AKOK+6pmQTOcw03nfwYV0= github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.6 h1:jVwb4GDwD65q/gtItR/lIZHjNH93QfeGxZUkzJcW9mc= github.com/miekg/dns v1.1.6/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.8 h1:1QYRAKU3lN5cRfLCkPU08hwvLJFhvjP6MqNMmQz6ZVI= -github.com/miekg/dns v1.1.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.12 h1:WMhc1ik4LNkTg8U9l3hI1LvxKmIL+f1+WV/SZtCbDDA= -github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.13 h1:x7DQtkU0cedzeS8TD36tT/w1Hm4rDtfCaYYAHE7TTBI= github.com/miekg/dns v1.1.13/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v0.0.0-20160804032330-cdac8253d00f/go.mod h1:eOsF2yLPlBBJPvD+nhl5QMTBSOBbOph6N7j/IDUw7PY= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -729,16 +545,11 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/pointerstructure v0.0.0-20190323210102-2db4bb651397 h1:GwYLdFxg/9bWW+e6YMWDNrKZ43gbKKkgC9mtmxai4o0= -github.com/mitchellh/pointerstructure v0.0.0-20190323210102-2db4bb651397/go.mod h1:k4XwG94++jLVsSiTxo7qdIfXA9pj9EAeo0QsNNJOLZ8= -github.com/mitchellh/pointerstructure v0.0.0-20190430161007-f252a8fd71c8/go.mod h1:k4XwG94++jLVsSiTxo7qdIfXA9pj9EAeo0QsNNJOLZ8= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -747,25 +558,22 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW7hr4IVovMwWg0E0PYcyW8CzqDcVmaew9cujU4s= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= +github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= +github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= github.com/oklog/run v0.0.0-20180308005104-6934b124db28/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.4.1 h1:PZSj/UFNaVp3KxrzHOcS7oyuWA7LoOY/77yCTEFu21U= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -776,33 +584,24 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go-opentracing v0.3.4/go.mod h1:js2AbwmHW0YD9DwIw2JhQWmbfFi/UnWyYwdVhqbCDOE= github.com/openzipkin/zipkin-go-opentracing v0.3.5/go.mod h1:js2AbwmHW0YD9DwIw2JhQWmbfFi/UnWyYwdVhqbCDOE= -github.com/ory-am/common v0.4.0 h1:edGPoxYX4hno0IJHXh9TCMUPR6ZcJp+y6aClFYxeuUE= -github.com/ory-am/common v0.4.0/go.mod h1:oCYGuwwM8FyYMKqh9vrhBaeUoyz/edx0bgJN6uS6/+k= -github.com/ory/dockertest v3.3.4+incompatible h1:VrpM6Gqg7CrPm3bL4Wm1skO+zFWLbh7/Xb5kGEbJRh8= github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c h1:vwpFWvAO8DeIZfFeqASzZfsxuWPno9ncAebBEP0N3uE= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v0.0.0-20180527043350-9f6ff22cfff8/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= +github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -815,21 +614,16 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.1 h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6DI= github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= -github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU= -github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/pquerna/otp v1.1.0 h1:q2gMsMuMl3JzneUaAX1MRGxLvOG6bzXV51hivBaStf0= -github.com/pquerna/otp v1.1.0/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= github.com/prometheus/client_golang v0.0.0-20180328130430-f504d69affe1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -837,27 +631,21 @@ github.com/prometheus/common v0.0.0-20180326160409-38c53a9f4bfc/go.mod h1:daVV7q github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.3.0 h1:taZ4h8Tkxv2kNyoSctBvfXEHmBmxrwmIidZTIaHons4= -github.com/prometheus/common v0.3.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20180408092902-8b1c2da0d56d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190416084830-8368d24ba045 h1:Raos9GP+3BlCBicScEQ+SjTLpYYac34fZMoeqj9McSM= -github.com/prometheus/procfs v0.0.0-20190416084830-8368d24ba045/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.1 h1:Vb1OE5ZDNKF3yhna6/G+5pHqADNm4I8hUoHj7YQhbZk= github.com/prometheus/procfs v0.0.1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.8.0/go.mod h1:fSI0j+IUQrDd7+ZtR9WKIGtoYAYAJUKcKhYLG25tN4g= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -867,112 +655,93 @@ github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06Oy github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9LntYM0YBRXkiSaZMmLYeZ/NWcmeB43mMY= -github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 h1:udFKJ0aHUL60LboW/A+DfgoHVedieIzIXE8uylPue0U= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= -github.com/sirupsen/logrus v1.0.6 h1:hcP1GmhGigz/O7h1WVUM5KklBp1JoNS9FggWKdj/j3s= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf h1:6V1qxN6Usn4jy8unvggSJz/NC790tefw8Zdy6OZS5co= github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0= github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= -github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff h1:86HlEv0yBCry9syNuylzqznKXDK11p6D0DT596yNMys= github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d h1:bVQRCxQvfjNUeRqaY/uT0tFuvuFY0ulgnczuR684Xic= github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= -github.com/softlayer/softlayer-go v0.0.0-20190415014515-aa510384a41b h1:88dDriC8WlKTaGOzhMKZVqczu9Pp/n4a3dV3SN7RyQA= -github.com/softlayer/softlayer-go v0.0.0-20190415014515-aa510384a41b/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/softlayer/softlayer-go v0.0.0-20190508182157-7c592eb2559c/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94 h1:0ngsPmuP6XIjiFRNFYlvKwSr5zff2v+uPHaffZ6/M4k= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= +github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9 h1:/Bsw4C+DEdqPjt8vAqaC9LAqpAQnaCQQqmolqq3S1T4= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM= +github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8= +github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= +github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= github.com/tent/http-link-go v0.0.0-20130702225549-ac974c61c2f9/go.mod h1:RHkNRtSLfOK7qBTHaeSX1D6BNpI3qw7NTxsmNr4RvN8= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.1.2 h1:JON3E2/GPW2iDNGoSAusl1KDf5TRQ8k8q7Tp097pZGs= github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= -github.com/ugorji/go/codec v0.0.0-20190309163734-c4a1c341dc93 h1:JnDJ9gMf6CfErtoOXnghtY5hhMuDtW4tUBaWSBrqvKs= github.com/ugorji/go/codec v0.0.0-20190309163734-c4a1c341dc93/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= -github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= -github.com/vmware/govmomi v0.20.0 h1:+1IyhvoVb5JET2Wvgw9J3ZDv6CK4sxzUunpH8LhQqm4= -github.com/vmware/govmomi v0.20.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/vmware/govmomi v0.20.1/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +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.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= -go.opencensus.io v0.19.2 h1:ZZpq6xI6kv/LuE/5s5UQvBU5vMjvRnPb8PvJrIntAnc= -go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= +go.etcd.io/etcd v3.3.13+incompatible h1:jCejD5EMnlGxFvcGRyEV4VGlENZc7oPQX6o0t7n3xbw= +go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2 h1:NAfh7zF0/3/HqtMvJNZ/RFrSlCE6ZTlHmKfhL/Dm1Jk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/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-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f h1:qWFY9ZxP3tfI37wYIs/MnIAqK0vlXp1xnYEa5HxFSSY= golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -980,22 +749,16 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd h1:sMHc2rZHuzQmrbVoSpt9HgerkXPyIeCSO6k0zUMGfFk= -golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f h1:R423Cnkcp5JABoeemiGEPlt9tHXFfw5kvc0yqlxRPWo= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5 h1:8dUaAV7K4uHsF56JQWkprecIQKdPHtR9jCHF5nB8uzc= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190516052701-61b8692d9a5c/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190523035834-f03afa92d3ff/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -1010,7 +773,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1025,8 +787,6 @@ golang.org/x/net v0.0.0-20190327214358-63eda1eb0650/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190403144856-b630fd6fe46b/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190420063019-afa5a82059c6 h1:HdqqaWmYAUI7/dmByKKEw+yxDksGSo+9GjkUc9Zp34E= -golang.org/x/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= @@ -1034,13 +794,8 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/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-20190319182350-c85d3e98c914 h1:jIOcLT9BZzyJ9ce+IwwZ+aF9yeCqzrR+NrD68a/SHKw= -golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1051,45 +806,43 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEha golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180828065106-d99a578cf41b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3 h1:+KlxhGbYkFs8lMfwKn+2ojry1ID5eBSMXprS2u/wqCE= golang.org/x/sys v0.0.0-20190213121743-983097b1a8a3/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222171317-cd391775e71e h1:oF7qaQxUH6KzFdKN4ww7NpPdo53SZi4UlcksLrb2y/o= golang.org/x/sys v0.0.0-20190222171317-cd391775e71e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc h1:4gbWbmmPFp4ySWICouJl6emP0MyS31yy9SrTlAGFT+g= golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5 h1:f005F/Jl5JLP036x7QIvUVhNTqxvSYwFIiyOh2q12iU= -golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1 h1:R4dVlxdmKenVdMRS/tTspEpSTRWINYrHD8ySIU9yCIU= golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531073156-46560c3f3c0a h1:ndj5BW7+tkr8XVsbkZpft/pgCRU+L76ePImF2dpCwek= +golang.org/x/sys v0.0.0-20190531073156-46560c3f3c0a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1102,7 +855,6 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1112,91 +864,75 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190530215528-75312fb06703/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/api v0.0.0-20180829000535-087779f1d2c9 h1:z1TeLUmxf9ws9KLICfmX+KGXTs+rjm+aGWzfsv7MZ9w= google.golang.org/api v0.0.0-20180829000535-087779f1d2c9/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= -google.golang.org/api v0.3.0 h1:UIJY20OEo3+tK5MBlcdx37kmdH6EnRjGkW78mc6+EeA= -google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.3.2 h1:iTp+3yyl/KOtxa/d1/JUE0GGSoR6FuW5udver22iwpw= -google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19 h1:Lj2SnHtxkRGJDqnGaSjo+CCdIieEnwVazbOXILwQemk= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 h1:xtNn7qFlagY2mQNFHMSRPjT2RkOV4OXM7P5TVy9xATo= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190516172635-bb713bdc0e52/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101 h1:wuGevabY6r+ivPNagjUXGGxF+GqgMd+dBhjsxW4q9u4= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/grpc v0.0.0-20180920234847-8997b5fa0873/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.19.1 h1:TrBcJ1yqAl1G++wO39nD/qtgpsW9/1+QGrluyMGEYgM= google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/DataDog/dd-trace-go.v0 v0.6.1/go.mod h1:uxRvUTC61u1w+PTfyHNOzLPTCHYt6CJyGZvZSAzGvZA= -gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a h1:stTHdEoWg1pQ8riaP5ROrjS6zy6wewH/Q2iwnLCQUXY= +gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg= -gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 h1:OAj3g0cR6Dx/R07QgQe8wkA9RNjB2u4i700xBkIT4e0= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/gorethink/gorethink.v4 v4.1.0 h1:xoE9qJ9Ae9KdKEsiQGCF44u2JdnjyohrMBRDtts3Gjw= -gopkg.in/gorethink/gorethink.v4 v4.1.0/go.mod h1:M7JgwrUAmshJ3iUbEK0Pt049MPyPK+CYDGGaEjdZb/c= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/ory-am/dockertest.v2 v2.2.3 h1:vSYvP7tvyfAm9merq0gHmcI4yk5nkPpfXmoBCnSP3/4= -gopkg.in/ory-am/dockertest.v2 v2.2.3/go.mod h1:kDHEsan1UcKFYH1c28sDmqnmeqIpB4Nj682gSNhYDYM= gopkg.in/ory-am/dockertest.v3 v3.3.4/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek= +gopkg.in/redis.v3 v3.6.4 h1:u7XgPH1rWwsdZnR+azldXC6x9qDU2luydOIeU/l52fE= +gopkg.in/redis.v3 v3.6.4/go.mod h1:6XeGv/CrsUFDU9aVbUdNykN7k1zVmoeg83KC9RbQfiU= gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc= gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.3.0 h1:nLzhkFyl5bkblqYBoiWJUt5JkWOzmiaBtCxdJAqJd3U= -gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo= +gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= +gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek= +gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= +gopkg.in/src-d/go-git-fixtures.v3 v3.1.1 h1:XWW/s5W18RaJpmo1l0IYGqXKuJITWRFuA45iOf1dKJs= +gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= +gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU= +gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= +gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g= +gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= @@ -1204,64 +940,29 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190522022531-bad1bd262ba8/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190530170028-a1efa522b896/go.mod h1:wtc9q0E9zm8PjdRMh29DPlTlCCHVzKDwnkT4GskQVzg= istio.io/gogo-genproto v0.0.0-20190124151557-6d926a6e6feb/go.mod h1:eIDJ6jNk/IeJz6ODSksHl5Aiczy5JUq6vFhJWI5OtiI= -k8s.io/api v0.0.0-20180806132203-61b11ee65332 h1:+ED/2NBbOoeWB9QrGTHxZI7UnE7rnHPKKumOl0WXphs= k8s.io/api v0.0.0-20180806132203-61b11ee65332/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/api v0.0.0-20181204000039-89a74a8d264d h1:HQoGWsWUe/FmRcX9BU440AAMnzBFEf+DBo4nbkQlNzs= k8s.io/api v0.0.0-20181204000039-89a74a8d264d/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= k8s.io/api v0.0.0-20190325185214-7544f9db76f6/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/api v0.0.0-20190409092523-d687e77c8ae9 h1:c9UEl5z8gk1DGh/g3snETZ+a52YeR9VdbX/3BQ4PHas= -k8s.io/api v0.0.0-20190409092523-d687e77c8ae9/go.mod h1:FQEUn50aaytlU65qqBn/w+5ugllHwrBzKm7DzbnXdzE= -k8s.io/api v0.0.0-20190419092548-c5cad27821f6 h1:S/8tIFYavaVbM3nFX0yqkw4X0BooJqRO+TrDANFX1Uo= -k8s.io/api v0.0.0-20190419092548-c5cad27821f6/go.mod h1:B0cvvXrD9UkqARVdlFhdZB9SNL0TzJ13UB/p410skE4= -k8s.io/api v0.0.0-20190515023547-db5a9d1c40eb/go.mod h1:fbdFiGtx7GQ3+vkBAYto3QsSImiYIJdpH3YfaclST/U= k8s.io/api v0.0.0-20190528154508-67ef80593b24/go.mod h1:aCWu6byTIKt+TeO2ZJ48xnOrYgDq0jqxbxmzfjXbNqw= -k8s.io/apimachinery v0.0.0-20180821005732-488889b0007f h1:V0PkbgaYp5JqCmzLyRmssDtzim0NShXM8gYi4fcX230= k8s.io/apimachinery v0.0.0-20180821005732-488889b0007f/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 h1:tT6oQBi0qwLbbZSfDkdIsb23EwaLY85hoAV4SpXfdao= k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20190223001710-c182ff3b9841/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/apimachinery v0.0.0-20190409092423-760d1845f48b h1:fVkKJL9FIpA8LSJyHVM00MP45q1WJ7+af77vcxmQP4g= -k8s.io/apimachinery v0.0.0-20190409092423-760d1845f48b/go.mod h1:FW86P8YXVLsbuplGMZeb20J3jYHscrDqw4jELaFJvRU= -k8s.io/apimachinery v0.0.0-20190418212431-b3683fe6b520/go.mod h1:tXkZEnPhecLuffcJcEuO/iNpM8w0n42dM5fNrr9OVVE= -k8s.io/apimachinery v0.0.0-20190419212445-b874eabb9a4e h1:h2UL1ppdZDnaCKNvEFzbRIscOymKZznckYlXgZ3iQME= -k8s.io/apimachinery v0.0.0-20190419212445-b874eabb9a4e/go.mod h1:tXkZEnPhecLuffcJcEuO/iNpM8w0n42dM5fNrr9OVVE= -k8s.io/apimachinery v0.0.0-20190515023456-b74e4c97951f/go.mod h1:Ew3b/24/JSgJdn4RsnrLskv3LvMZDlZ1Fl1xopsJftY= k8s.io/apimachinery v0.0.0-20190528154326-e59c2fb0a8e5/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA= -k8s.io/client-go v8.0.0+incompatible h1:tTI4hRmb1DRMl4fG6Vclfdi6nTM82oIrTT7HfitmxC4= k8s.io/client-go v8.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34= k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o= k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190327210449-e17681d19d3a/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.0.0-20181108234604-8139d8cb77af h1:s6rm8OxBbyDNSRkpyAd5OL4icUdBICVw9+mFADa+t5E= k8s.io/klog v0.0.0-20181108234604-8139d8cb77af/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.0.0-20190306015804-8e90cee79f82 h1:SHucoAy7lRb+w5oC/hbXyZg+zX+Wftn6hD4tGzHCVqA= -k8s.io/klog v0.0.0-20190306015804-8e90cee79f82/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.2/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190306001800-15615b16d372/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= -k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22/go.mod h1:iU+ZGYsNlvU9XKUSso6SQfKTCCw7lFduMZy26Mgr2Fw= k8s.io/kube-openapi v0.0.0-20190530181030-b52b5b0f5a7c/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= -k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7 h1:8r+l4bNWjRlsFYlQJnKJ2p7s1YQPj4XyXiJVqDHRx7c= -k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= -k8s.io/utils v0.0.0-20190520173318-324c5df7d3f0/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20190529001817-6999998975a7/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -layeh.com/radius v0.0.0-20190322222518-890bc1058917 h1:BDXFaFzUt5EIqe/4wrTc4AcYZWP6iC6Ult+jQWLh5eU= -layeh.com/radius v0.0.0-20190322222518-890bc1058917/go.mod h1:fywZKyu//X7iRzaxLgPWsvc0L26IUpVvE/aeIL2JtIQ= -sigs.k8s.io/structured-merge-diff v0.0.0-20190426204423-ea680f03cc65/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190521201008-1c46bef2e9c8/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/sync/leader/etcd/etcd.go b/sync/leader/etcd/etcd.go index 603c698f..6179bf0b 100644 --- a/sync/leader/etcd/etcd.go +++ b/sync/leader/etcd/etcd.go @@ -6,9 +6,9 @@ import ( "path" "strings" + client "github.com/coreos/etcd/clientv3" + cc "github.com/coreos/etcd/clientv3/concurrency" "github.com/micro/go-micro/sync/leader" - client "go.etcd.io/etcd/clientv3" - cc "go.etcd.io/etcd/clientv3/concurrency" ) type etcdLeader struct { diff --git a/sync/lock/etcd/etcd.go b/sync/lock/etcd/etcd.go index d506e7b5..0b8ba823 100644 --- a/sync/lock/etcd/etcd.go +++ b/sync/lock/etcd/etcd.go @@ -9,9 +9,9 @@ import ( "strings" "sync" + client "github.com/coreos/etcd/clientv3" + cc "github.com/coreos/etcd/clientv3/concurrency" "github.com/micro/go-micro/sync/lock" - client "go.etcd.io/etcd/clientv3" - cc "go.etcd.io/etcd/clientv3/concurrency" ) type etcdLock struct { From ef9c223ac850ed6cd6732d4981211b0f272c1539 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 12:38:49 +0100 Subject: [PATCH 16/18] add vault/etcd --- config/source/etcd/README.md | 51 +++++++ config/source/etcd/etcd.go | 134 ++++++++++++++++++ config/source/etcd/options.go | 58 ++++++++ config/source/etcd/util.go | 89 ++++++++++++ config/source/etcd/watcher.go | 113 +++++++++++++++ config/source/vault/README.md | 43 ++++++ config/source/vault/options.go | 63 ++++++++ .../source/vault/testdata/vault_init_commands | 1 + config/source/vault/util.go | 98 +++++++++++++ config/source/vault/vault.go | 96 +++++++++++++ config/source/vault/vault_test.go | 133 +++++++++++++++++ config/source/vault/watcher.go | 32 +++++ 12 files changed, 911 insertions(+) create mode 100644 config/source/etcd/README.md create mode 100644 config/source/etcd/etcd.go create mode 100644 config/source/etcd/options.go create mode 100644 config/source/etcd/util.go create mode 100644 config/source/etcd/watcher.go create mode 100644 config/source/vault/README.md create mode 100644 config/source/vault/options.go create mode 100644 config/source/vault/testdata/vault_init_commands create mode 100644 config/source/vault/util.go create mode 100644 config/source/vault/vault.go create mode 100644 config/source/vault/vault_test.go create mode 100644 config/source/vault/watcher.go diff --git a/config/source/etcd/README.md b/config/source/etcd/README.md new file mode 100644 index 00000000..a3025ad4 --- /dev/null +++ b/config/source/etcd/README.md @@ -0,0 +1,51 @@ +# 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) +``` diff --git a/config/source/etcd/etcd.go b/config/source/etcd/etcd.go new file mode 100644 index 00000000..873c2de7 --- /dev/null +++ b/config/source/etcd/etcd.go @@ -0,0 +1,134 @@ +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, + } +} diff --git a/config/source/etcd/options.go b/config/source/etcd/options.go new file mode 100644 index 00000000..87eff8ef --- /dev/null +++ b/config/source/etcd/options.go @@ -0,0 +1,58 @@ +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}) + } +} diff --git a/config/source/etcd/util.go b/config/source/etcd/util.go new file mode 100644 index 00000000..e57475e4 --- /dev/null +++ b/config/source/etcd/util.go @@ -0,0 +1,89 @@ +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 +} diff --git a/config/source/etcd/watcher.go b/config/source/etcd/watcher.go new file mode 100644 index 00000000..1066c899 --- /dev/null +++ b/config/source/etcd/watcher.go @@ -0,0 +1,113 @@ +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 +} diff --git a/config/source/vault/README.md b/config/source/vault/README.md new file mode 100644 index 00000000..186433c8 --- /dev/null +++ b/config/source/vault/README.md @@ -0,0 +1,43 @@ +# Vault Source + +The vault source reads config from different secret engines in a Vault server. For example: +``` +kv: secret/data/ +database credentials: database/creds/ +``` + +## New Source + +Specify source with data + +```go +vaultSource := vault.NewSource( + // mandatory: it specifies server address. + // It could have different formats: + // 127.0.0.1 -> https://127.0.0.1:8200 + // http://127.0.0.1 -> http://127.0.0.1:8200 + // http://127.0.0.1:2233 + vault.WithAddress("http://127.0.0.1:8200"), + // mandatory: it specifies a resource to been access + vault.WithResourcePath("secret/data/my/secret"), + // mandatory: it specifies a resource to been access + vault.WithToken(""), + // optional: path to store my secret. + // By default use resourcePath value + vault.WithSecretName("my/secret"), + // optional: namespace. + vault.WithNameSpace("myNameSpace"), +) +``` + +## Load Source + +Load the source into config + +```go +// Create new config +conf := config.NewConfig() + +// Load file source +conf.Load(vaultSource) +``` diff --git a/config/source/vault/options.go b/config/source/vault/options.go new file mode 100644 index 00000000..43903b4a --- /dev/null +++ b/config/source/vault/options.go @@ -0,0 +1,63 @@ +package vault + +import ( + "context" + + "github.com/micro/go-micro/config/source" +) + +type addressKey struct{} +type resourcePath struct{} +type nameSpace struct{} +type tokenKey struct{} +type secretName struct{} + +// WithAddress sets the server 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) + } +} + +// WithResourcePath sets the resource that will be access +func WithResourcePath(p string) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, resourcePath{}, p) + } +} + +// WithNameSpace sets the namespace that its going to be access +func WithNameSpace(n string) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, nameSpace{}, n) + } +} + +// WithToken sets the key token to use +func WithToken(t string) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, tokenKey{}, t) + } +} + +// WithSecretName sets the name of the secret to wrap in on a map +func WithSecretName(t string) source.Option { + return func(o *source.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, secretName{}, t) + } +} diff --git a/config/source/vault/testdata/vault_init_commands b/config/source/vault/testdata/vault_init_commands new file mode 100644 index 00000000..4b8d26e0 --- /dev/null +++ b/config/source/vault/testdata/vault_init_commands @@ -0,0 +1 @@ +vault kv put secret/data/db/auth user=myuser password=mypassword2 host=128.23.33.21 port=3307 \ No newline at end of file diff --git a/config/source/vault/util.go b/config/source/vault/util.go new file mode 100644 index 00000000..cdd5a149 --- /dev/null +++ b/config/source/vault/util.go @@ -0,0 +1,98 @@ +package vault + +import ( + "fmt" + "github.com/micro/go-micro/config/source" + "net" + "net/url" + "strings" +) + +func makeMap(kv map[string]interface{}, secretName string) (map[string]interface{}, error) { + data := make(map[string]interface{}) + + // if secret version included + if kv["data"] != nil && kv["metadata"] != nil { + kv = kv["data"].(map[string]interface{}) + } + + target := data + + // if secretName defined, wrap secrets under a map + if secretName != "" { + path := strings.Split(secretName, "/") + // find (or create) the location we want to put this value at + for i, dir := range path { + if _, ok := target[dir]; !ok { + target[dir] = make(map[string]interface{}) + } + if i < len(path)-1 { + target = target[dir].(map[string]interface{}) + } else { + target[dir] = kv + } + } + } + + return data, nil +} + +func getAddress(options source.Options) string { + // check if there are any addrs + a, ok := options.Context.Value(addressKey{}).(string) + if ok { + // check if http protocol is defined + if a[0] != 'h' { + addr, port, err := net.SplitHostPort(a) + if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { + port = "8200" + addr = a + return fmt.Sprintf("https://%s:%s", addr, port) + } else if err == nil { + return fmt.Sprintf("https://%s:%s", addr, port) + } + } else { + u, _ := url.Parse(a) + + if host, port, _ := net.SplitHostPort(u.Host); host == "" { + port = "8200" + return fmt.Sprintf("%s://%s:%s", u.Scheme, u.Host, port) + } else { + return fmt.Sprintf("%s://%s", u.Scheme, u.Host) + } + } + } + return "" +} + +func getToken(options source.Options) string { + token, ok := options.Context.Value(tokenKey{}).(string) + if ok { + return token + } + return "" +} + +func getResourcePath(options source.Options) string { + path, ok := options.Context.Value(resourcePath{}).(string) + if ok { + return path + } + return "" +} + +func getNameSpace(options source.Options) string { + ns, ok := options.Context.Value(nameSpace{}).(string) + if ok { + return ns + } + return "" +} + +func getSecretName(options source.Options) string { + ns, ok := options.Context.Value(secretName{}).(string) + if ok { + return ns + } + return "" +} diff --git a/config/source/vault/vault.go b/config/source/vault/vault.go new file mode 100644 index 00000000..d5067d4f --- /dev/null +++ b/config/source/vault/vault.go @@ -0,0 +1,96 @@ +package vault + +import ( + "fmt" + "github.com/hashicorp/vault/api" + "github.com/micro/go-micro/config/source" + "time" +) + +// Currently a single vault reader +type vault struct { + secretPath string + secretName string + opts source.Options + client *api.Client +} + +func (c *vault) Read() (*source.ChangeSet, error) { + secret, err := c.client.Logical().Read(c.secretPath) + if err != nil { + return nil, err + } + + if secret == nil { + return nil, fmt.Errorf("source not found: %s", c.secretPath) + } + + if secret.Data == nil && secret.Warnings != nil { + return nil, fmt.Errorf("source: %s errors: %v", c.secretPath, secret.Warnings) + } + + data, err := makeMap(secret.Data, c.secretName) + if err != nil { + return nil, fmt.Errorf("error reading data: %v", err) + } + + 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(), + Format: c.opts.Encoder.String(), + Source: c.String(), + Data: b, + } + cs.Checksum = cs.Sum() + + return cs, nil + //return nil, nil +} + +func (c *vault) String() string { + return "vault" +} + +func (c *vault) Watch() (source.Watcher, error) { + w := newWatcher(c.client) + + return w, nil +} + +// NewSource creates a new vault source +func NewSource(opts ...source.Option) source.Source { + options := source.NewOptions(opts...) + + // create the client + client, _ := api.NewClient(api.DefaultConfig()) + + // get and set options + if address := getAddress(options); address != "" { + _ = client.SetAddress(address) + } + + if nameSpace := getNameSpace(options); nameSpace != "" { + client.SetNamespace(nameSpace) + } + + if token := getToken(options); token != "" { + client.SetToken(token) + } + + path := getResourcePath(options) + name := getSecretName(options) + if name == "" { + name = path + } + + return &vault{ + opts: options, + client: client, + secretPath: path, + secretName: name, + } +} diff --git a/config/source/vault/vault_test.go b/config/source/vault/vault_test.go new file mode 100644 index 00000000..0dd2b9a8 --- /dev/null +++ b/config/source/vault/vault_test.go @@ -0,0 +1,133 @@ +package vault + +import ( + "encoding/json" + "fmt" + "github.com/micro/go-micro/config" + "os" + "reflect" + "strings" + "testing" +) + +func TestVaultMakeMap(t *testing.T) { + tt := []struct { + name string + expected []byte + input []byte + secretName string + }{ + { + name: "simple valid data 1", + secretName: "my/secret", + input: []byte(`{"data":{"bar":"bazz", "tar":"par"}, "metadata":{"version":1, "destroyed": false}}`), + expected: []byte(`{"my":{"secret":{"bar":"bazz", "tar":"par"}}}`), + }, + { + name: "simple valid data 2", + secretName: "my/secret", + input: []byte(`{"bar":"bazz", "tar":"par"}`), + expected: []byte(`{"my":{"secret":{"bar":"bazz", "tar":"par"}}}`), + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + var input map[string]interface{} + var expected map[string]interface{} + + _ = json.Unmarshal(tc.input, &input) + _ = json.Unmarshal(tc.expected, &expected) + + out, _ := makeMap(input, tc.secretName) + + if eq := reflect.DeepEqual(out, expected); !eq { + fmt.Println(eq) + t.Fatalf("expected %v and got %v", expected, out) + } + }) + } +} + +func TestVault_Read(t *testing.T) { + if tr := os.Getenv("TRAVIS"); len(tr) > 0 { + t.Skip() + } + + var ( + address = "http://127.0.0.1" + resource = "secret/data/db/auth" + token = "s.Q4Zi0CSowXZl7sh0z96ijcT4" + ) + + data := []byte(`{"secret":{"data":{"db":{"auth":{"host":"128.23.33.21","password":"mypassword","port":"3306","user":"myuser"}}}}}`) + + tt := []struct { + name string + addr string + resource string + token string + }{ + {name: "read data basic", addr: address, resource: resource, token: token}, + {name: "read data without token", addr: address, resource: resource, token: ""}, + {name: "read data full address format", addr: "http://127.0.0.1:8200", resource: resource, token: token}, + {name: "read data wrong resource path", addr: address, resource: "secrets/data/db/auth", token: token}, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + source := NewSource( + WithAddress(tc.addr), + WithResourcePath(tc.resource), + WithToken(tc.token), + ) + + r, err := source.Read() + if err != nil { + if tc.token == "" { + return + } else if strings.Compare(err.Error(), "source not found: secrets/data/db/auth") == 0 { + return + } + t.Errorf("%s: not able to read the config values because: %v", tc.name, err) + return + } + + if string(r.Data) != string(data) { + t.Logf("data expected: %v", string(data)) + t.Logf("data got from configmap: %v", string(r.Data)) + t.Errorf("data from configmap does not match.") + } + }) + } +} + +func TestVault_String(t *testing.T) { + source := NewSource() + + if source.String() != "vault" { + t.Errorf("expecting to get %v and instead got %v", "vault", source) + } +} + +func TestVaultNewSource(t *testing.T) { + if tr := os.Getenv("TRAVIS"); len(tr) > 0 { + t.Skip() + } + + conf := config.NewConfig() + + _ = conf.Load(NewSource( + WithAddress("http://127.0.0.1"), + WithResourcePath("secret/data/db/auth"), + WithToken("s.Q4Zi0CSowXZl7sh0z96ijcT4"), + )) + + if user := conf.Get("secret", "data", "db", "auth", "user").String("user"); user != "myuser" { + t.Errorf("expected %v and got %v", "myuser", user) + } + + if addr := conf.Get("secret", "data", "db", "auth", "host").String("host"); addr != "128.23.33.21" { + t.Errorf("expected %v and got %v", "128.23.33.21", addr) + } +} diff --git a/config/source/vault/watcher.go b/config/source/vault/watcher.go new file mode 100644 index 00000000..a377295c --- /dev/null +++ b/config/source/vault/watcher.go @@ -0,0 +1,32 @@ +package vault + +import ( + "errors" + "github.com/hashicorp/vault/api" + "github.com/micro/go-micro/config/source" +) + +type watcher struct { + c *api.Client + exit chan bool +} + +func newWatcher(c *api.Client) *watcher { + return &watcher{ + c: c, + exit: make(chan bool), + } +} + +func (w *watcher) Next() (*source.ChangeSet, error) { + <-w.exit + return nil, errors.New("url watcher stopped") +} + +func (w *watcher) Stop() error { + select { + case <-w.exit: + default: + } + return nil +} From 508d181f60bed1ab2872dc2d7b4708f3e63c37d1 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 12:38:55 +0100 Subject: [PATCH 17/18] update go.mod --- go.mod | 3 +-- go.sum | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 99f36a71..c741d68e 100644 --- a/go.mod +++ b/go.mod @@ -41,11 +41,11 @@ require ( github.com/hashicorp/consul/api v1.1.0 github.com/hashicorp/go-immutable-radix v1.1.0 // indirect github.com/hashicorp/go-msgpack v0.5.5 // indirect - github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/mdns v1.0.1 // indirect github.com/hashicorp/memberlist v0.1.4 github.com/hashicorp/serf v0.8.3 // indirect + github.com/hashicorp/vault/api v1.0.2 github.com/imdario/mergo v0.3.7 github.com/jonboulle/clockwork v0.1.0 // indirect github.com/json-iterator/go v1.1.6 // indirect @@ -95,7 +95,6 @@ require ( golang.org/x/net v0.0.0-20190522155817-f3200d17e092 golang.org/x/oauth2 v0.0.0-20190523182746-aaccbc9213b0 // indirect golang.org/x/sys v0.0.0-20190531073156-46560c3f3c0a // indirect - golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect golang.org/x/tools v0.0.0-20190530215528-75312fb06703 // indirect google.golang.org/appengine v1.6.0 // indirect google.golang.org/genproto v0.0.0-20190530194941-fb225487d101 // indirect diff --git a/go.sum b/go.sum index d2e9f0c3..a239356c 100644 --- a/go.sum +++ b/go.sum @@ -253,6 +253,7 @@ github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= @@ -398,7 +399,9 @@ github.com/hashicorp/vault v1.1.2/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAb github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20190318174639-195e0e9d07f1/go.mod h1:VJHHT2SC1tAPrfENQeBhLlb5FbZoKZM+oC/ROmEftz0= github.com/hashicorp/vault-plugin-secrets-kv v0.5.1/go.mod h1:PIjaafaRr2QlkGl2SNhIywxlejeW0iMUtmx8u9u/a6c= github.com/hashicorp/vault/api v1.0.1/go.mod h1:AV/+M5VPDpB90arloVX0rVDUIHkONiwz5Uza9HRtpUE= +github.com/hashicorp/vault/api v1.0.2 h1:/V9fULvLwt58vme/6Rkt/p/GtlresQv+Z9E6dgdANhs= github.com/hashicorp/vault/api v1.0.2/go.mod h1:AV/+M5VPDpB90arloVX0rVDUIHkONiwz5Uza9HRtpUE= +github.com/hashicorp/vault/sdk v0.1.8 h1:pfF3KwA1yPlfpmcumNsFM4uo91WMasX5gTuIkItu9r0= github.com/hashicorp/vault/sdk v0.1.8/go.mod h1:tHZfc6St71twLizWNHvnnbiGFo1aq0eD2jGPLtP8kAU= github.com/hashicorp/vault/sdk v0.1.11/go.mod h1:XF2Bod+ahPWGARnyFq5LfkOZwWwvveR5ptYwJLqK0ZI= github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= @@ -602,6 +605,7 @@ github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWo github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -655,6 +659,7 @@ github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06Oy github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -917,6 +922,7 @@ gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc= gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo= gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= From d5f6f82d5c5e316b98dbb978bc3d418655067511 Mon Sep 17 00:00:00 2001 From: Asim Aslam Date: Fri, 31 May 2019 13:05:03 +0100 Subject: [PATCH 18/18] update travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index d7248d68..3a827c94 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,8 @@ language: go go: - 1.11.x - 1.12.x +env: + - GO111MODULE=on notifications: slack: secure: aEvhLbhujaGaKSrOokiG3//PaVHTIrc3fBpoRbCRqfZpyq6WREoapJJhF+tIpWWOwaC9GmChbD6aHo/jMUgwKXVyPSaNjiEL87YzUUpL8B2zslNp1rgfTg/LrzthOx3Q1TYwpaAl3to0fuHUVFX4yMeC2vuThq7WSXgMMxFCtbc=