From b0acb8745136554d18b44a24707ad0a01a282c1f Mon Sep 17 00:00:00 2001 From: User Date: Mon, 2 Dec 2019 21:31:15 +0530 Subject: [PATCH 1/6] update events configured to watch specific fields --- deploy-all-in-one.yaml | 20 +++++++++ helm/botkube/values.yaml | 15 +++++++ pkg/config/config.go | 16 +++++-- pkg/controller/controller.go | 11 ++++- pkg/utils/cmp.go | 31 ++++++++------ pkg/utils/cmp_test.go | 81 +++++++++++++++++++++++++++++++++--- pkg/utils/utils.go | 20 ++++++++- resource_config.yaml | 16 ++++++- 8 files changed, 186 insertions(+), 24 deletions(-) diff --git a/deploy-all-in-one.yaml b/deploy-all-in-one.yaml index e80de7c09..47dbd2b0d 100644 --- a/deploy-all-in-one.yaml +++ b/deploy-all-in-one.yaml @@ -41,6 +41,11 @@ data: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: statefulset namespaces: include: @@ -52,6 +57,11 @@ data: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: ingress namespaces: include: @@ -123,6 +133,11 @@ data: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: job namespaces: include: @@ -134,6 +149,11 @@ data: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: role namespaces: include: diff --git a/helm/botkube/values.yaml b/helm/botkube/values.yaml index 7616b8898..776ffc482 100644 --- a/helm/botkube/values.yaml +++ b/helm/botkube/values.yaml @@ -61,6 +61,11 @@ config: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: statefulset namespaces: include: @@ -72,6 +77,11 @@ config: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: ingress namespaces: include: @@ -153,6 +163,11 @@ config: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: role namespaces: include: diff --git a/pkg/config/config.go b/pkg/config/config.go index 319f827a7..13b8f0b9f 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -46,6 +46,9 @@ var Notify = true // NotifType to change notification type type NotifType string +// FieldType to specify the resource fields for which to get notification +type FieldType string + // Config structure of configuration yaml file type Config struct { Resources []Resource @@ -56,9 +59,16 @@ type Config struct { // Resource contains resources to watch type Resource struct { - Name string - Namespaces Namespaces - Events []EventType + Name string + Namespaces Namespaces + Events []EventType + UpdateSetting UpdateSetting `yaml:"updateSetting"` +} + +//UpdateSetting struct defines updateEvent fields specification +type UpdateSetting struct { + Fields []FieldType + IncludeDiff bool `yaml:"includeDiff"` } // Namespaces contains namespaces to include and ignore diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 5ea5fab79..bb5e71b65 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -163,7 +163,16 @@ func sendEvent(obj, oldObj interface{}, c *config.Config, notifiers []notify.Not // check for siginificant Update Events in objects if eventType == config.UpdateEvent { - updateMsg := utils.Diff(oldObj, obj) + var updateMsg string + // Check if all namespaces allowed + updateSetting, exist := utils.AllowedUpdateEventsMap[utils.KindNS{Resource: kind, Namespace: "all"}] + if !exist { + // Check if specified namespace is allowed + updateSetting, exist = utils.AllowedUpdateEventsMap[utils.KindNS{Resource: kind, Namespace: objectMeta.Namespace}] + } + if exist { + updateMsg = utils.Diff(oldObj, obj, updateSetting) + } if len(updateMsg) > 0 { event.Messages = append(event.Messages, updateMsg) } else { diff --git a/pkg/utils/cmp.go b/pkg/utils/cmp.go index a9e102c1d..af45f0d1f 100644 --- a/pkg/utils/cmp.go +++ b/pkg/utils/cmp.go @@ -5,44 +5,51 @@ import ( "strings" "github.com/google/go-cmp/cmp" + "github.com/infracloudio/botkube/pkg/config" ) -// SpecDiffReporter is a simple custom reporter that only records differences -// detected in Object Spec during comparison. -type SpecDiffReporter struct { +// DiffReporter is a simple custom reporter that records differences +// detected in Object during comparison. +type DiffReporter struct { + field string path cmp.Path diffs []string } // PushStep custom implements Reporter interface -func (r *SpecDiffReporter) PushStep(ps cmp.PathStep) { +func (r *DiffReporter) PushStep(ps cmp.PathStep) { r.path = append(r.path, ps) } // Report custom implements Reporter interface -func (r *SpecDiffReporter) Report(rs cmp.Result) { +func (r *DiffReporter) Report(rs cmp.Result) { if !rs.Equal() { vx, vy := r.path.Last().Values() path := fmt.Sprintf("%#v", r.path) - if ok := strings.Contains(path, ".Spec."); ok { + if ok := strings.Contains(path, "."+strings.Title(r.field)); ok { r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy)) } } } // PopStep custom implements Reporter interface -func (r *SpecDiffReporter) PopStep() { +func (r *DiffReporter) PopStep() { r.path = r.path[:len(r.path)-1] } // String custom implements Reporter interface -func (r *SpecDiffReporter) String() string { +func (r *DiffReporter) String() string { return strings.Join(r.diffs, "\n") } // Diff provides differences between two objects spec -func Diff(x, y interface{}) string { - var r SpecDiffReporter - cmp.Equal(x, y, cmp.Reporter(&r)) - return r.String() +func Diff(x, y interface{}, updatesetting config.UpdateSetting) string { + msg := "" + for _, val := range updatesetting.Fields { + var r DiffReporter + r.field = string(val) + cmp.Equal(x, y, cmp.Reporter(&r)) + msg = msg + r.String() + } + return msg } diff --git a/pkg/utils/cmp_test.go b/pkg/utils/cmp_test.go index 69633dc6e..59548152a 100644 --- a/pkg/utils/cmp_test.go +++ b/pkg/utils/cmp_test.go @@ -3,12 +3,17 @@ package utils import ( "fmt" "testing" + + "github.com/infracloudio/botkube/pkg/config" ) // Object mocks kubernetes objects type Object struct { - Spec Spec - Other Other + Spec Spec + Status Status + Data Data + Rules Rules + Other Other } // Other mocks fileds like MetaData, Status etc in kubernetes objects @@ -21,6 +26,21 @@ type Spec struct { Port int } +// Status mocks ObjectStatus field in kubernetes object +type Status struct { + Replicas int +} + +// Data mocks ObjectData field in kubernetes object like configmap +type Data struct { + Properties string +} + +// Rules mocks ObjectRules field in kubernetes object +type Rules struct { + Verbs string +} + // ExpectedDiff struct to generate expected diff type ExpectedDiff struct { Path string @@ -32,11 +52,13 @@ func TestDiff(t *testing.T) { tests := map[string]struct { old Object new Object + update config.UpdateSetting expected ExpectedDiff }{ `Spec Diff`: { - old: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "bar"}}, - new: Object{Spec: Spec{Port: 83}, Other: Other{Foo: "bar"}}, + old: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "bar"}}, + new: Object{Spec: Spec{Port: 83}, Other: Other{Foo: "bar"}}, + update: config.UpdateSetting{Fields: []config.FieldType{"Spec"}, IncludeDiff: true}, expected: ExpectedDiff{ Path: "{utils.Object}.Spec.Port", X: "81", @@ -46,13 +68,62 @@ func TestDiff(t *testing.T) { `Non Spec Diff`: { old: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "bar"}}, new: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "boo"}}, + update: config.UpdateSetting{Fields: []config.FieldType{"metadata"}, IncludeDiff: true}, + expected: ExpectedDiff{}, + }, + `Status Diff`: { + old: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "bar"}}, + new: Object{Status: Status{Replicas: 2}, Other: Other{Foo: "bar"}}, + update: config.UpdateSetting{Fields: []config.FieldType{"Status"}, IncludeDiff: true}, + expected: ExpectedDiff{ + Path: "{utils.Object}.Status.Replicas", + X: "1", + Y: "2", + }, + }, + `Non Status Diff`: { + old: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "bar"}}, + new: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "boo"}}, + update: config.UpdateSetting{Fields: []config.FieldType{"metadata"}, IncludeDiff: true}, + expected: ExpectedDiff{}, + }, + `Data Diff`: { + old: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "bar"}}, + new: Object{Data: Data{Properties: "Color: red"}, Other: Other{Foo: "bar"}}, + update: config.UpdateSetting{Fields: []config.FieldType{"Data"}, IncludeDiff: true}, + expected: ExpectedDiff{ + Path: "{utils.Object}.Data.Properties", + X: "Color: blue", + Y: "Color: red", + }, + }, + `Non Data Diff`: { + old: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "bar"}}, + new: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "boo"}}, + update: config.UpdateSetting{Fields: []config.FieldType{"metadata"}, IncludeDiff: true}, + expected: ExpectedDiff{}, + }, + `Rules Diff`: { + old: Object{Rules: Rules{Verbs: "list"}, Other: Other{Foo: "bar"}}, + new: Object{Rules: Rules{Verbs: "watch"}, Other: Other{Foo: "bar"}}, + update: config.UpdateSetting{Fields: []config.FieldType{"Rules"}, IncludeDiff: true}, + expected: ExpectedDiff{ + Path: "{utils.Object}.Rules.Verbs", + X: "list", + Y: "watch", + }, + }, + `Non Rules Diff`: { + old: Object{Rules: Rules{Verbs: "list"}, Other: Other{Foo: "bar"}}, + new: Object{Rules: Rules{Verbs: "list"}, Other: Other{Foo: "boo"}}, + update: config.UpdateSetting{Fields: []config.FieldType{"metadata"}, IncludeDiff: true}, expected: ExpectedDiff{}, }, } for name, test := range tests { name, test := name, test t.Run(name, func(t *testing.T) { - if actual := Diff(test.old, test.new); actual != test.expected.MockDiff() { + if actual := Diff(test.old, test.new, test.update); actual != test.expected.MockDiff() { t.Errorf("expected: %+v != actual: %+v\n", test.expected.MockDiff(), actual) } }) diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 6f0b1c784..ea9960c8b 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -26,6 +26,8 @@ var ( ResourceInformerMap map[string]cache.SharedIndexInformer // AllowedEventKindsMap is a map to filter valid event kinds AllowedEventKindsMap map[EventKind]bool + // AllowedUpdateEventsMap is a map of resourceand namespace to updateconfig + AllowedUpdateEventsMap map[KindNS]config.UpdateSetting // KubeClient is a global kubernetes client to communicate to apiserver KubeClient kubernetes.Interface // KubeInformerFactory is a global SharedInformerFactory object to watch resources @@ -63,6 +65,12 @@ type EventKind struct { EventType config.EventType } +// KindNS used in AllowedUpdateEventsMap +type KindNS struct { + Resource string + Namespace string +} + // InitInformerMap initializes helper maps to filter events func InitInformerMap() { botkubeConf, err := config.New() @@ -86,6 +94,7 @@ func InitInformerMap() { // Init maps ResourceInformerMap = make(map[string]cache.SharedIndexInformer) AllowedEventKindsMap = make(map[EventKind]bool) + AllowedUpdateEventsMap = make(map[KindNS]config.UpdateSetting) // Informer map ResourceInformerMap["pod"] = KubeInformerFactory.Core().V1().Pods().Informer() @@ -112,7 +121,7 @@ func InitInformerMap() { ResourceInformerMap["clusterrole"] = KubeInformerFactory.Rbac().V1().ClusterRoles().Informer() ResourceInformerMap["clusterrolebinding"] = KubeInformerFactory.Rbac().V1().RoleBindings().Informer() - // Allowed event kinds map + // Allowed event kinds map and Allowed Update Events Map for _, r := range botkubeConf.Resources { allEvents := false for _, e := range r.Events { @@ -123,6 +132,12 @@ func InitInformerMap() { for _, ns := range r.Namespaces.Include { AllowedEventKindsMap[EventKind{Resource: r.Name, Namespace: ns, EventType: e}] = true } + // AllowedUpdateEventsMap entry is created only for UpdateEvent + if e == config.UpdateEvent { + for _, ns := range r.Namespaces.Include { + AllowedUpdateEventsMap[KindNS{Resource: r.Name, Namespace: ns}] = r.UpdateSetting + } + } } // For AllEvent type, add all events to map @@ -131,12 +146,13 @@ func InitInformerMap() { for _, ev := range events { for _, ns := range r.Namespaces.Include { AllowedEventKindsMap[EventKind{Resource: r.Name, Namespace: ns, EventType: ev}] = true + AllowedUpdateEventsMap[KindNS{Resource: r.Name, Namespace: ns}] = r.UpdateSetting } } } - } log.Logger.Infof("Allowed Events - %+v", AllowedEventKindsMap) + log.Logger.Infof("Allowed UpdateEvents - %+v", AllowedUpdateEventsMap) } // GetObjectMetaData returns metadata of the given object diff --git a/resource_config.yaml b/resource_config.yaml index acd954328..13984da6b 100644 --- a/resource_config.yaml +++ b/resource_config.yaml @@ -30,8 +30,12 @@ resources: - create - update - delete - - update - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: statefulset namespaces: include: @@ -43,6 +47,11 @@ resources: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: ingress namespaces: include: @@ -134,6 +143,11 @@ resources: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec + - status - name: role namespaces: include: From a2dbcd3a17a88d7122a5933bab4b210d10ee4fc2 Mon Sep 17 00:00:00 2001 From: Prasad Ghangal Date: Wed, 8 Jan 2020 11:49:24 +0530 Subject: [PATCH 2/6] Add support for jsonpath in updateSetting Signed-off-by: Prasad Ghangal --- go.mod | 14 +-- go.sum | 158 ++++++++++++++++++++---- pkg/config/config.go | 5 +- pkg/controller/controller.go | 6 +- pkg/utils/cmp.go | 55 --------- pkg/utils/diff.go | 42 +++++++ pkg/utils/{cmp_test.go => diff_test.go} | 0 pkg/utils/jsonpath.go | 35 ++++++ 8 files changed, 220 insertions(+), 95 deletions(-) delete mode 100644 pkg/utils/cmp.go create mode 100644 pkg/utils/diff.go rename pkg/utils/{cmp_test.go => diff_test.go} (100%) create mode 100644 pkg/utils/jsonpath.go diff --git a/go.mod b/go.mod index e79fe97ef..6f18c0495 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/go-sql-driver/mysql v1.4.1 // indirect github.com/gogo/protobuf v1.3.0 // indirect github.com/golang/groupcache v0.0.0-20191002201903-404acd9df4cc // indirect - github.com/google/go-cmp v0.3.1 + github.com/google/go-cmp v0.3.1 // indirect github.com/google/go-github/v27 v27.0.4 github.com/googleapis/gnostic v0.3.1 // indirect github.com/gorilla/websocket v1.4.1 // indirect @@ -21,7 +21,6 @@ require ( github.com/imdario/mergo v0.3.7 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/lib/pq v1.2.0 // indirect - github.com/mailru/easyjson v0.7.0 // indirect github.com/mattermost/gorp v2.0.0+incompatible // indirect github.com/mattermost/mattermost-server v5.11.1+incompatible github.com/mattn/go-sqlite3 v1.11.0 // indirect @@ -33,8 +32,6 @@ require ( github.com/pelletier/go-toml v1.5.0 // indirect github.com/prometheus/client_golang v1.2.1 github.com/sirupsen/logrus v1.4.2 - github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.4.0 github.com/ziutek/mymysql v1.5.4 // indirect go.uber.org/atomic v1.4.0 // indirect @@ -46,13 +43,12 @@ require ( google.golang.org/appengine v1.6.5 // indirect gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.2.4 - k8s.io/api v0.0.0-20191009075622-910e671eb668 - k8s.io/apimachinery v0.0.0-20191006235458-f9f2f3f8ab02 - k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90 - k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d // indirect + k8s.io/api v0.17.0 + k8s.io/apimachinery v0.17.0 + k8s.io/client-go v0.17.0 + k8s.io/kubectl v0.17.0 ) go 1.13 diff --git a/go.sum b/go.sum index 877ad234f..f8357dd1d 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ cloud.google.com/go v0.26.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.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +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/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -10,44 +12,72 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= 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/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/squirrel v1.1.0 h1:baP1qLdoQCeTw3ifCdOq2dkYc6vGcmRdaociKLbEJXs= github.com/Masterminds/squirrel v1.1.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA= github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 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/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 h1:w3NnFcKR5241cfmQU5ZZAsf0xcpId6mWOupTvJlUX2U= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dyatlov/go-opengraph v0.0.0-20180429202543-816b6608b3c8 h1:6muCmMJat6z7qptVrIf/+OWPxsjAfvhw5/6t+FwEkgg= github.com/dyatlov/go-opengraph v0.0.0-20180429202543-816b6608b3c8/go.mod h1:nYia/MIs9OyvXXYboPmNOj0gVWo97Wx0sde+ZuKkoM4= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/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 h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= 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/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/go-gorp/gorp v2.0.0+incompatible h1:dIQPsBtl6/H1MjVseWuWPXa7ET4p6Dve4j3Hg+UjqYw= github.com/go-gorp/gorp v2.0.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -58,9 +88,20 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= @@ -82,7 +123,12 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= +github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= 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/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= @@ -108,20 +154,27 @@ github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEo github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +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/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 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.5/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/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -134,6 +187,7 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= @@ -142,7 +196,13 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mattermost/gorp v2.0.0+incompatible h1:/aLYsuWjk4kSVP3P3kn3zTGNUQxaCB6DjTejmwddKEs= @@ -153,6 +213,10 @@ github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 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= @@ -171,22 +235,20 @@ github.com/olivere/elastic v6.2.21+incompatible h1:QnTuofzxOCV5FrYLywjkMxOmOWhAe github.com/olivere/elastic v6.2.21+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.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/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.2 h1:uqH7bpe+ERSiDa34FDOF7RikN6RzXgduUF8yarlZp94= github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 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/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.5.0 h1:5BakdOZdtKJ1FFk6QdL8iSGrMWsXgchNJcrnarjbmJQ= github.com/pelletier/go-toml v1.5.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -209,15 +271,24 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.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/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/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/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -228,6 +299,10 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1 h1:j2hhcujLRHAg872RWAV5yaUrEjHEObwDv3aImCaNLek= +github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -238,15 +313,21 @@ go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ 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-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4= golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/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-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/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/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -258,8 +339,9 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191009170851-d66e71096ffb h1:TR699M2v0qoKTOHxeLgp6zPqaQNs74f01a/ob9W0qko= golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -270,16 +352,20 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ 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= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-20180830151530-49385e6e1522/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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -288,14 +374,23 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w= golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -316,7 +411,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -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/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= @@ -328,31 +422,43 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/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-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20190918155943-95b840bb6a1f h1:8FRUST8oUkEI45WYKyD8ed7Ad0Kg5v11zHyPkEVb2xo= -k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48= -k8s.io/api v0.0.0-20191009075622-910e671eb668 h1:BpoWgtmOP2aRkiHb+ofs+tmEqBAOj0XIPClrLACYEsY= -k8s.io/api v0.0.0-20191009075622-910e671eb668/go.mod h1:X3kixOyiuC4u4LU6y2BxLg5tsvw+hrMhstfga7LZ4Gw= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 h1:CS1tBQz3HOXiseWZu6ZicKX361CZLT97UFnnPx0aqBw= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= -k8s.io/apimachinery v0.0.0-20191006235458-f9f2f3f8ab02 h1:arf6Ha+cae2UQsu4JW0KNMhXRDYzV4Il6NnTI/0npUc= -k8s.io/apimachinery v0.0.0-20191006235458-f9f2f3f8ab02/go.mod h1:92mWDd8Ji2sw2157KIgino5wCxffA8KSvhW2oY4ypdw= -k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90 h1:mLmhKUm1X+pXu0zXMEzNsOF5E2kKFGe5o6BZBIIqA6A= -k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk= +k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/cli-runtime v0.17.0 h1:XEuStbJBHCQlEKFyTQmceDKEWOSYHZkcYWKp3SsQ9Hk= +k8s.io/cli-runtime v0.17.0/go.mod h1:1E5iQpMODZq2lMWLUJELwRu2MLWIzwvMgDBpn3Y81Qo= +k8s.io/client-go v0.17.0 h1:8QOGvUGdqDMFrm9sD6IUFl256BcffynGoe80sxgTEDg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/code-generator v0.17.0/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/component-base v0.17.0 h1:BnDFcmBDq+RPpxXjmuYnZXb59XNN9CaFrX8ba9+3xrA= +k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0 h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf h1:EYm5AW/UUDbnmnI+gK0TJDVK9qPLhM+sRHYanNKw0EQ= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d h1:Xpe6sK+RY4ZgCTyZ3y273UmFmURhjtoJiwOMbQsXitY= -k8s.io/kube-openapi v0.0.0-20190918143330-0270cf2f1c1d/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kubectl v0.17.0 h1:xD4EWlL+epc/JTO1gvSjmV9yiYF0Z2wiHK2DIek6URY= +k8s.io/kubectl v0.17.0/go.mod h1:jIPrUAW656Vzn9wZCCe0PC+oTcu56u2HgFD21Xbfk1s= +k8s.io/metrics v0.17.0/go.mod h1:EH1D3YAwN6d7bMelrElnLhLg72l/ERStyv2SIQVt6Do= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= +modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= +modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= +modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= +modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= +sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= 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= +vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc h1:MksmcCZQWAQJCTA5T0jgI/0sJ51AVm4Z41MrmfczEoc= +vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/pkg/config/config.go b/pkg/config/config.go index 13b8f0b9f..6b02bb46a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -46,9 +46,6 @@ var Notify = true // NotifType to change notification type type NotifType string -// FieldType to specify the resource fields for which to get notification -type FieldType string - // Config structure of configuration yaml file type Config struct { Resources []Resource @@ -67,7 +64,7 @@ type Resource struct { //UpdateSetting struct defines updateEvent fields specification type UpdateSetting struct { - Fields []FieldType + Fields []string IncludeDiff bool `yaml:"includeDiff"` } diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index bb5e71b65..f33cd7006 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -173,8 +173,12 @@ func sendEvent(obj, oldObj interface{}, c *config.Config, notifiers []notify.Not if exist { updateMsg = utils.Diff(oldObj, obj, updateSetting) } + + // Send update notification only if fields in updateSetting are changed if len(updateMsg) > 0 { - event.Messages = append(event.Messages, updateMsg) + if updateSetting.IncludeDiff { + event.Messages = append(event.Messages, updateMsg) + } } else { // skipping least significant update log.Logger.Debug("skipping least significant Update event") diff --git a/pkg/utils/cmp.go b/pkg/utils/cmp.go deleted file mode 100644 index af45f0d1f..000000000 --- a/pkg/utils/cmp.go +++ /dev/null @@ -1,55 +0,0 @@ -package utils - -import ( - "fmt" - "strings" - - "github.com/google/go-cmp/cmp" - "github.com/infracloudio/botkube/pkg/config" -) - -// DiffReporter is a simple custom reporter that records differences -// detected in Object during comparison. -type DiffReporter struct { - field string - path cmp.Path - diffs []string -} - -// PushStep custom implements Reporter interface -func (r *DiffReporter) PushStep(ps cmp.PathStep) { - r.path = append(r.path, ps) -} - -// Report custom implements Reporter interface -func (r *DiffReporter) Report(rs cmp.Result) { - if !rs.Equal() { - vx, vy := r.path.Last().Values() - path := fmt.Sprintf("%#v", r.path) - if ok := strings.Contains(path, "."+strings.Title(r.field)); ok { - r.diffs = append(r.diffs, fmt.Sprintf("%#v:\n\t-: %+v\n\t+: %+v\n", r.path, vx, vy)) - } - } -} - -// PopStep custom implements Reporter interface -func (r *DiffReporter) PopStep() { - r.path = r.path[:len(r.path)-1] -} - -// String custom implements Reporter interface -func (r *DiffReporter) String() string { - return strings.Join(r.diffs, "\n") -} - -// Diff provides differences between two objects spec -func Diff(x, y interface{}, updatesetting config.UpdateSetting) string { - msg := "" - for _, val := range updatesetting.Fields { - var r DiffReporter - r.field = string(val) - cmp.Equal(x, y, cmp.Reporter(&r)) - msg = msg + r.String() - } - return msg -} diff --git a/pkg/utils/diff.go b/pkg/utils/diff.go new file mode 100644 index 000000000..313d10f3f --- /dev/null +++ b/pkg/utils/diff.go @@ -0,0 +1,42 @@ +package utils + +import ( + "fmt" + + "github.com/infracloudio/botkube/pkg/config" +) + +type diffReporter struct { + field string +} + +func (d diffReporter) exec(x, y interface{}) (string, bool) { + vx, err := parseJsonpath(x, d.field) + if err != nil { + return "", false + } + + vy, err := parseJsonpath(y, d.field) + if err != nil { + return "", false + } + + // treat and false as same fields + if vx == vy || (vx == "" && vy == "false") { + return "", false + } + return fmt.Sprintf("%s:\n\t-: %+v\n\t+: %+v\n", d.field, vx, vy), true +} + +// Diff provides differences between two objects spec +func Diff(x, y interface{}, updatesetting config.UpdateSetting) string { + msg := "" + for _, val := range updatesetting.Fields { + var d diffReporter + d.field = val + if diff, ok := d.exec(x, y); ok { + msg = msg + diff + } + } + return msg +} diff --git a/pkg/utils/cmp_test.go b/pkg/utils/diff_test.go similarity index 100% rename from pkg/utils/cmp_test.go rename to pkg/utils/diff_test.go diff --git a/pkg/utils/jsonpath.go b/pkg/utils/jsonpath.go new file mode 100644 index 000000000..7df08be95 --- /dev/null +++ b/pkg/utils/jsonpath.go @@ -0,0 +1,35 @@ +package utils + +import ( + "fmt" + "strings" + + "k8s.io/client-go/util/jsonpath" + "k8s.io/kubectl/pkg/cmd/get" +) + +func parseJsonpath(obj interface{}, jsonpathStr string) (string, error) { + // Parse and print jsonpath + fields, err := get.RelaxedJSONPathExpression(jsonpathStr) + if err != nil { + return "", err + } + + j := jsonpath.New("jsonpath") + if err := j.Parse(fields); err != nil { + return "", err + } + + values, err := j.FindResults(obj) + + valueStrings := []string{} + if len(values) == 0 || len(values[0]) == 0 { + valueStrings = append(valueStrings, "") + } + for arrIx := range values { + for valIx := range values[arrIx] { + valueStrings = append(valueStrings, fmt.Sprintf("%v", values[arrIx][valIx].Interface())) + } + } + return strings.Join(valueStrings, ","), nil +} From e979c1b18bd78bdf6fc6eb865edb6ac20cd2e3f3 Mon Sep 17 00:00:00 2001 From: Prasad Ghangal Date: Wed, 8 Jan 2020 12:02:40 +0530 Subject: [PATCH 3/6] Update BotKube config to send update events in specific fields Signed-off-by: Prasad Ghangal --- deploy-all-in-one-tls.yaml | 23 +++++++++++++++- deploy-all-in-one.yaml | 18 ++++++------- helm/botkube/values.yaml | 54 +++++++++++++++++++++----------------- resource_config.yaml | 50 +++++++++++++++++++---------------- 4 files changed, 89 insertions(+), 56 deletions(-) diff --git a/deploy-all-in-one-tls.yaml b/deploy-all-in-one-tls.yaml index 32b9d82f6..95e7498bd 100644 --- a/deploy-all-in-one-tls.yaml +++ b/deploy-all-in-one-tls.yaml @@ -10,6 +10,7 @@ data: config.yaml: | ## Resources you want to watch resources: + - name: pod # Name of the resources e.g pod, deployment, ingress, etc. (Resource name must be in singular form) namespaces: include: - all @@ -40,6 +41,11 @@ data: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.availableReplicas - name: statefulset namespaces: include: @@ -51,6 +57,11 @@ data: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.readyReplicas - name: ingress namespaces: include: @@ -119,9 +130,14 @@ data: - events: - create - - delete - update + - delete - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.numberReady - name: job namespaces: include: @@ -133,6 +149,11 @@ data: - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.conditions[*].type - name: role namespaces: include: diff --git a/deploy-all-in-one.yaml b/deploy-all-in-one.yaml index 47dbd2b0d..c36d63ad2 100644 --- a/deploy-all-in-one.yaml +++ b/deploy-all-in-one.yaml @@ -44,8 +44,8 @@ data: updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.availableReplicas - name: statefulset namespaces: include: @@ -59,9 +59,9 @@ data: - error updateSetting: includeDiff: true - fields: - - spec - - status + fields: + - spec.template.spec.containers[*].image + - status.readyReplicas - name: ingress namespaces: include: @@ -136,8 +136,8 @@ data: updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.numberReady - name: job namespaces: include: @@ -152,8 +152,8 @@ data: updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.conditions[*].type - name: role namespaces: include: diff --git a/helm/botkube/values.yaml b/helm/botkube/values.yaml index 776ffc482..a64564304 100644 --- a/helm/botkube/values.yaml +++ b/helm/botkube/values.yaml @@ -32,7 +32,7 @@ config: resources: - name: pod # Name of the resources e.g pod, deployment, ingress, etc. (Resource name must be in singular form) namespaces: - include: + include: - all ignore: # List of namespaces to be ignored (omitempty), used only with include: all - # example : include [all], ignore [x,y,z] @@ -42,17 +42,17 @@ config: - error - name: service namespaces: - include: + include: - all ignore: - - + - events: - create - delete - error - name: deployment namespaces: - include: + include: - all ignore: - @@ -64,11 +64,11 @@ config: updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.availableReplicas - name: statefulset namespaces: - include: + include: - all ignore: - @@ -80,11 +80,11 @@ config: updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.readyReplicas - name: ingress namespaces: - include: + include: - all ignore: - @@ -94,7 +94,7 @@ config: - error - name: node namespaces: - include: + include: - all ignore: - @@ -104,7 +104,7 @@ config: - error - name: namespace namespaces: - include: + include: - all ignore: - @@ -114,7 +114,7 @@ config: - error - name: persistentvolume namespaces: - include: + include: - all ignore: - @@ -124,7 +124,7 @@ config: - error - name: persistentvolumeclaim namespaces: - include: + include: - all ignore: - @@ -134,7 +134,7 @@ config: - error - name: configmap namespaces: - include: + include: - all ignore: - @@ -144,17 +144,23 @@ config: - error - name: daemonset namespaces: - include: + include: - all ignore: - events: - create + - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.numberReady - name: job namespaces: - include: + include: - all ignore: - @@ -163,14 +169,14 @@ config: - update - delete - error - updateSetting: + updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.conditions[*].type - name: role namespaces: - include: + include: - all ignore: - @@ -180,7 +186,7 @@ config: - error - name: rolebinding namespaces: - include: + include: - all ignore: - @@ -193,14 +199,14 @@ config: include: - all ignore: - - + - events: - create - delete - error - name: clusterrolebinding namespaces: - include: + include: - all ignore: - diff --git a/resource_config.yaml b/resource_config.yaml index 13984da6b..bef225639 100644 --- a/resource_config.yaml +++ b/resource_config.yaml @@ -15,7 +15,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -25,7 +25,7 @@ resources: include: - all ignore: - - + - events: - create - update @@ -34,14 +34,14 @@ resources: updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.availableReplicas - name: statefulset namespaces: include: - all ignore: - - + - events: - create - update @@ -50,14 +50,14 @@ resources: updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.readyReplicas - name: ingress namespaces: include: - all ignore: - - + - events: - create - delete @@ -67,7 +67,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -77,7 +77,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -87,7 +87,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -97,7 +97,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -107,7 +107,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -117,7 +117,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -127,17 +127,23 @@ resources: include: - all ignore: - - + - events: - create + - update - delete - error + updateSetting: + includeDiff: true + fields: + - spec.template.spec.containers[*].image + - status.numberReady - name: job namespaces: include: - all ignore: - - + - events: - create - update @@ -146,14 +152,14 @@ resources: updateSetting: includeDiff: true fields: - - spec - - status + - spec.template.spec.containers[*].image + - status.conditions[*].type - name: role namespaces: include: - all ignore: - - + - events: - create - delete @@ -163,7 +169,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -173,7 +179,7 @@ resources: include: - all ignore: - - + - events: - create - delete @@ -183,7 +189,7 @@ resources: include: - all ignore: - - + - events: - create - delete From f837c56653b8760b6878123142aa090b7dc250d9 Mon Sep 17 00:00:00 2001 From: Prasad Ghangal Date: Wed, 8 Jan 2020 12:03:24 +0530 Subject: [PATCH 4/6] Remove Job status checker filter Signed-off-by: Prasad Ghangal --- .../filters/job_status_checker.go | 66 ------------------- 1 file changed, 66 deletions(-) delete mode 100644 pkg/filterengine/filters/job_status_checker.go diff --git a/pkg/filterengine/filters/job_status_checker.go b/pkg/filterengine/filters/job_status_checker.go deleted file mode 100644 index eb1f5fbab..000000000 --- a/pkg/filterengine/filters/job_status_checker.go +++ /dev/null @@ -1,66 +0,0 @@ -// JobStatusChecker filter to send notifications only when job succeeds -// and ignore other update events - -package filters - -import ( - "time" - - "github.com/infracloudio/botkube/pkg/config" - "github.com/infracloudio/botkube/pkg/events" - "github.com/infracloudio/botkube/pkg/filterengine" - log "github.com/infracloudio/botkube/pkg/logging" - - batchV1 "k8s.io/api/batch/v1" -) - -// JobStatusChecker checks job status and adds message in the events structure -type JobStatusChecker struct { - Description string -} - -// Register filter -func init() { - filterengine.DefaultFilterEngine.Register(JobStatusChecker{ - Description: "Sends notifications only when job succeeds and ignores other job update events.", - }) -} - -// Run filers and modifies event struct -func (f JobStatusChecker) Run(object interface{}, event *events.Event) { - // Run filter only on Job update event - if event.Kind != "Job" || event.Type != config.UpdateEvent { - return - } - jobObj, ok := object.(*batchV1.Job) - if !ok { - return - } - - event.Skip = true - // Check latest job conditions - jobLen := len(jobObj.Status.Conditions) - if jobLen == 0 { - return - } - c := jobObj.Status.Conditions[jobLen-1] - if c.Type == batchV1.JobComplete { - event.Messages = []string{"Job succeeded!"} - // Make sure that we are not considering older events - // Skip older update events if timestamp difference is more than 30sec - if !event.TimeStamp.IsZero() && time.Now().Sub(c.LastTransitionTime.Time) > 30*time.Second { - log.Logger.Debugf("JobStatusChecker Skipping older event: %#v", event) - return - } - event.TimeStamp = c.LastTransitionTime.Time - // overwrite event.Skip in case of Job succeeded (Job update) events - event.Skip = false - } - event.Reason = c.Reason - log.Logger.Debug("Job status checker filter successful!") -} - -// Describe filter -func (f JobStatusChecker) Describe() string { - return f.Description -} From e8da727b4ee7541cfc25bf56daa058b109ee3d2b Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 8 Jan 2020 18:34:19 +0530 Subject: [PATCH 5/6] Add tests for jsonpath support --- pkg/utils/diff_test.go | 44 +++++++++++++++++++++---------------- test/e2e/command/botkube.go | 3 +-- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/pkg/utils/diff_test.go b/pkg/utils/diff_test.go index 59548152a..4c0d5df6c 100644 --- a/pkg/utils/diff_test.go +++ b/pkg/utils/diff_test.go @@ -23,7 +23,13 @@ type Other struct { // Spec mocks ObjectSpec field in kubernetes object type Spec struct { - Port int + Port int + Containers []Container +} + +// Container mocks ObjectSpec.Container field in kubernetes object +type Container struct { + Image string } // Status mocks ObjectStatus field in kubernetes object @@ -56,27 +62,27 @@ func TestDiff(t *testing.T) { expected ExpectedDiff }{ `Spec Diff`: { - old: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "bar"}}, - new: Object{Spec: Spec{Port: 83}, Other: Other{Foo: "bar"}}, - update: config.UpdateSetting{Fields: []config.FieldType{"Spec"}, IncludeDiff: true}, + old: Object{Spec: Spec{Containers: []Container{{Image: "nginx:1.14"}}}, Other: Other{Foo: "bar"}}, + new: Object{Spec: Spec{Containers: []Container{{Image: "nginx:latest"}}}, Other: Other{Foo: "bar"}}, + update: config.UpdateSetting{Fields: []string{"Spec.Containers[*].Image"}, IncludeDiff: true}, expected: ExpectedDiff{ - Path: "{utils.Object}.Spec.Port", - X: "81", - Y: "83", + Path: "Spec.Containers[*].Image", + X: "nginx:1.14", + Y: "nginx:latest", }, }, `Non Spec Diff`: { - old: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "bar"}}, - new: Object{Spec: Spec{Port: 81}, Other: Other{Foo: "boo"}}, - update: config.UpdateSetting{Fields: []config.FieldType{"metadata"}, IncludeDiff: true}, + old: Object{Spec: Spec{Containers: []Container{{Image: "nginx:1.14"}}}, Other: Other{Foo: "bar"}}, + new: Object{Spec: Spec{Containers: []Container{{Image: "nginx:1.14"}}}, Other: Other{Foo: "boo"}}, + update: config.UpdateSetting{Fields: []string{"metadata.name"}, IncludeDiff: true}, expected: ExpectedDiff{}, }, `Status Diff`: { old: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "bar"}}, new: Object{Status: Status{Replicas: 2}, Other: Other{Foo: "bar"}}, - update: config.UpdateSetting{Fields: []config.FieldType{"Status"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"Status.Replicas"}, IncludeDiff: true}, expected: ExpectedDiff{ - Path: "{utils.Object}.Status.Replicas", + Path: "Status.Replicas", X: "1", Y: "2", }, @@ -84,15 +90,15 @@ func TestDiff(t *testing.T) { `Non Status Diff`: { old: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "bar"}}, new: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "boo"}}, - update: config.UpdateSetting{Fields: []config.FieldType{"metadata"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"metadata.labels"}, IncludeDiff: true}, expected: ExpectedDiff{}, }, `Data Diff`: { old: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "bar"}}, new: Object{Data: Data{Properties: "Color: red"}, Other: Other{Foo: "bar"}}, - update: config.UpdateSetting{Fields: []config.FieldType{"Data"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"Data.Properties"}, IncludeDiff: true}, expected: ExpectedDiff{ - Path: "{utils.Object}.Data.Properties", + Path: "Data.Properties", X: "Color: blue", Y: "Color: red", }, @@ -100,15 +106,15 @@ func TestDiff(t *testing.T) { `Non Data Diff`: { old: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "bar"}}, new: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "boo"}}, - update: config.UpdateSetting{Fields: []config.FieldType{"metadata"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"metadata.name"}, IncludeDiff: true}, expected: ExpectedDiff{}, }, `Rules Diff`: { old: Object{Rules: Rules{Verbs: "list"}, Other: Other{Foo: "bar"}}, new: Object{Rules: Rules{Verbs: "watch"}, Other: Other{Foo: "bar"}}, - update: config.UpdateSetting{Fields: []config.FieldType{"Rules"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"Rules.Verbs"}, IncludeDiff: true}, expected: ExpectedDiff{ - Path: "{utils.Object}.Rules.Verbs", + Path: "Rules.Verbs", X: "list", Y: "watch", }, @@ -116,7 +122,7 @@ func TestDiff(t *testing.T) { `Non Rules Diff`: { old: Object{Rules: Rules{Verbs: "list"}, Other: Other{Foo: "bar"}}, new: Object{Rules: Rules{Verbs: "list"}, Other: Other{Foo: "boo"}}, - update: config.UpdateSetting{Fields: []config.FieldType{"metadata"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"metadata.name"}, IncludeDiff: true}, expected: ExpectedDiff{}, }, } diff --git a/test/e2e/command/botkube.go b/test/e2e/command/botkube.go index f55363849..600d9024f 100644 --- a/test/e2e/command/botkube.go +++ b/test/e2e/command/botkube.go @@ -38,8 +38,7 @@ func (c *context) testBotkubeCommand(t *testing.T) { "ObjectAnnotationChecker true Checks if annotations botkube.io/* present in object specs and filters them.\n" + "PodLabelChecker true Checks and adds recommedations if labels are missing in the pod specs.\n" + "ImageTagChecker true Checks and adds recommendation if 'latest' image tag is used for container image.\n" + - "IngressValidator true Checks if services and tls secrets used in ingress specs are available.\n" + - "JobStatusChecker true Sends notifications only when job succeeds and ignores other job update events.\n", + "IngressValidator true Checks if services and tls secrets used in ingress specs are available.\n", }, } From 8deccf845a712a59717806dbe171f05cf42794f0 Mon Sep 17 00:00:00 2001 From: Prasad Ghangal Date: Thu, 9 Jan 2020 19:06:13 +0530 Subject: [PATCH 6/6] Add json tags in diff tests Signed-off-by: Prasad Ghangal --- pkg/utils/diff_test.go | 52 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/pkg/utils/diff_test.go b/pkg/utils/diff_test.go index 4c0d5df6c..9f214a185 100644 --- a/pkg/utils/diff_test.go +++ b/pkg/utils/diff_test.go @@ -9,42 +9,42 @@ import ( // Object mocks kubernetes objects type Object struct { - Spec Spec - Status Status - Data Data - Rules Rules - Other Other + Spec Spec `json:"spec"` + Status Status `json:"status"` + Data Data `json:"data"` + Rules Rules `json:"rules"` + Other Other `json:"other"` } // Other mocks fileds like MetaData, Status etc in kubernetes objects type Other struct { - Foo string + Foo string `json:"foo"` } // Spec mocks ObjectSpec field in kubernetes object type Spec struct { - Port int - Containers []Container + Port int `json:"port"` + Containers []Container `json:"containers"` } // Container mocks ObjectSpec.Container field in kubernetes object type Container struct { - Image string + Image string `json:"image"` } // Status mocks ObjectStatus field in kubernetes object type Status struct { - Replicas int + Replicas int `json:"replicas"` } // Data mocks ObjectData field in kubernetes object like configmap type Data struct { - Properties string + Properties string `json:"properties"` } // Rules mocks ObjectRules field in kubernetes object type Rules struct { - Verbs string + Verbs string `json:"verbs"` } // ExpectedDiff struct to generate expected diff @@ -64,9 +64,9 @@ func TestDiff(t *testing.T) { `Spec Diff`: { old: Object{Spec: Spec{Containers: []Container{{Image: "nginx:1.14"}}}, Other: Other{Foo: "bar"}}, new: Object{Spec: Spec{Containers: []Container{{Image: "nginx:latest"}}}, Other: Other{Foo: "bar"}}, - update: config.UpdateSetting{Fields: []string{"Spec.Containers[*].Image"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"spec.containers[*].image"}, IncludeDiff: true}, expected: ExpectedDiff{ - Path: "Spec.Containers[*].Image", + Path: "spec.containers[*].image", X: "nginx:1.14", Y: "nginx:latest", }, @@ -80,9 +80,9 @@ func TestDiff(t *testing.T) { `Status Diff`: { old: Object{Status: Status{Replicas: 1}, Other: Other{Foo: "bar"}}, new: Object{Status: Status{Replicas: 2}, Other: Other{Foo: "bar"}}, - update: config.UpdateSetting{Fields: []string{"Status.Replicas"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"status.replicas"}, IncludeDiff: true}, expected: ExpectedDiff{ - Path: "Status.Replicas", + Path: "status.replicas", X: "1", Y: "2", }, @@ -94,27 +94,27 @@ func TestDiff(t *testing.T) { expected: ExpectedDiff{}, }, `Data Diff`: { - old: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "bar"}}, - new: Object{Data: Data{Properties: "Color: red"}, Other: Other{Foo: "bar"}}, - update: config.UpdateSetting{Fields: []string{"Data.Properties"}, IncludeDiff: true}, + old: Object{Data: Data{Properties: "color: blue"}, Other: Other{Foo: "bar"}}, + new: Object{Data: Data{Properties: "color: red"}, Other: Other{Foo: "bar"}}, + update: config.UpdateSetting{Fields: []string{"data.properties"}, IncludeDiff: true}, expected: ExpectedDiff{ - Path: "Data.Properties", - X: "Color: blue", - Y: "Color: red", + Path: "data.properties", + X: "color: blue", + Y: "color: red", }, }, `Non Data Diff`: { - old: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "bar"}}, - new: Object{Data: Data{Properties: "Color: blue"}, Other: Other{Foo: "boo"}}, + old: Object{Data: Data{Properties: "color: blue"}, Other: Other{Foo: "bar"}}, + new: Object{Data: Data{Properties: "color: blue"}, Other: Other{Foo: "boo"}}, update: config.UpdateSetting{Fields: []string{"metadata.name"}, IncludeDiff: true}, expected: ExpectedDiff{}, }, `Rules Diff`: { old: Object{Rules: Rules{Verbs: "list"}, Other: Other{Foo: "bar"}}, new: Object{Rules: Rules{Verbs: "watch"}, Other: Other{Foo: "bar"}}, - update: config.UpdateSetting{Fields: []string{"Rules.Verbs"}, IncludeDiff: true}, + update: config.UpdateSetting{Fields: []string{"rules.verbs"}, IncludeDiff: true}, expected: ExpectedDiff{ - Path: "Rules.Verbs", + Path: "rules.verbs", X: "list", Y: "watch", },