From 29be1c27ec99c0f1a1999f52641112bf2958c667 Mon Sep 17 00:00:00 2001 From: Jeremy Lewi Date: Fri, 15 May 2020 15:37:36 -0700 Subject: [PATCH] Create the scaffolding for a simple webserver to fulfill dialogflow requests. (#143) * This is intended to be a simple web server that will answer queries about who owns which GitHub labels. * This PR is just the scaffolding for the server * The server provides an endpoint for the Dialogflow webhook but the endpoint isn't actually returning valid responses yet. Related to #142 --- .gitignore | 1 + chatbot/Dockerfile | 27 +++ chatbot/README.md | 75 ++++++ chatbot/cmd/main.go | 49 ++++ chatbot/cmd/options/options.go | 41 ++++ chatbot/go.mod | 17 ++ chatbot/go.sum | 278 +++++++++++++++++++++++ chatbot/pkg/dialogflow/webhook.go | 50 ++++ chatbot/pkg/kfgokit/doc.go | 2 + chatbot/pkg/kfgokit/encoders.go | 20 ++ chatbot/pkg/kfgokit/errors.go | 59 +++++ chatbot/pkg/labels.go | 58 +++++ chatbot/pkg/labels_test.go | 23 ++ chatbot/pkg/server.go | 154 +++++++++++++ chatbot/pkg/services.go | 8 + chatbot/pkg/test_data/labels-owners.yaml | 180 +++++++++++++++ chatbot/pkg/util.go | 18 ++ chatbot/skaffold.yaml | 34 +++ 18 files changed, 1094 insertions(+) create mode 100644 chatbot/Dockerfile create mode 100644 chatbot/README.md create mode 100644 chatbot/cmd/main.go create mode 100644 chatbot/cmd/options/options.go create mode 100644 chatbot/go.mod create mode 100644 chatbot/go.sum create mode 100644 chatbot/pkg/dialogflow/webhook.go create mode 100644 chatbot/pkg/kfgokit/doc.go create mode 100644 chatbot/pkg/kfgokit/encoders.go create mode 100644 chatbot/pkg/kfgokit/errors.go create mode 100644 chatbot/pkg/labels.go create mode 100644 chatbot/pkg/labels_test.go create mode 100644 chatbot/pkg/server.go create mode 100644 chatbot/pkg/services.go create mode 100644 chatbot/pkg/test_data/labels-owners.yaml create mode 100644 chatbot/pkg/util.go create mode 100644 chatbot/skaffold.yaml diff --git a/.gitignore b/.gitignore index 99a8f27dbc..4e63c5524d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ fairing/__pycache__/** *.pyc py/code_intelligence/.data/** +**/.idea # ignore coredumps **/core.* # ignore checkpoints diff --git a/chatbot/Dockerfile b/chatbot/Dockerfile new file mode 100644 index 0000000000..7988cb4e2e --- /dev/null +++ b/chatbot/Dockerfile @@ -0,0 +1,27 @@ +# Build the manager binary +ARG GOLANG_VERSION=1.13.1 +FROM golang:${GOLANG_VERSION} as builder + +WORKDIR /workspace +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the go source +COPY . ./ + +# Build +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o server ./cmd/main.go + +# Use distroless as minimal base image to package the manager binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +FROM gcr.io/distroless/base:latest as serve +WORKDIR / +COPY --from=builder /workspace/server /server + +EXPOSE 8080 + +ENTRYPOINT ["/server"] \ No newline at end of file diff --git a/chatbot/README.md b/chatbot/README.md new file mode 100644 index 0000000000..2cf1848518 --- /dev/null +++ b/chatbot/README.md @@ -0,0 +1,75 @@ +# Chatbot + +This is a Dialogflow fulfillment server. + +## Deployment + +It is currently running in + +* **Full cluster name**: gke_issue-label-bot-dev_us-east1-d_issue-label-bot +* **project**: issue-label-bot-dev +* **cluster**: issue-label-bot + +## Notes. + +To expose the webhook we need to bypass IAP. To do this we create a second K8s service to create a second GCP Backend Service +but with IAP enabled. + +``` +kubectl --context=issue-label-bot-dev -n istio-system create -f istio-ingressgateway.yaml +``` + +We need to modify the security policy applied at the ingress gateway so that it won't reject requests without a valid +JWT. + +To deploy the fullfilment server we need to modify the Kubeflow ingress policy to allow traffic from the dialgoflow webserver. +This traffic can't be routed through IAP. We will still use a JWT to restrict traffic but it will be a JWT we create. + +So we need to add a second JWT origin rule to match this traffic to the policy. + +We can do this as + +``` +kubectl --context=issue-label-bot-dev -n istio-system patch policy ingress-jwt -p "$(cat ingress-jwt.patch.yaml)" --type=merge +``` + +To verify that is working we can port-forward to the service. + +``` +kubectl --context=issue-label-bot-dev -n istio-system port-forward service/chatbot-istio-ingressgateway 9080:80 +``` + +Send a request with a JWT this should fail with "Origin Authentication Failure" since there is no JWT. + +``` +curl localhost:9080/chatbot/dev/ -d '{}' -H "Content-Type: application/json" +``` + + + +To authorize Dialogflow webhook we will use a JWT. We use the jose-util to generate a public private key pair + +``` +git clone git@github.com:square/go-jose.git git_go-jose +cd git_go-jose/jose-uitl +go build. +``` + +Generate a key pair + + +``` +./jose-util generate-key --alg=ES256 --use sig --kid=chatbot +``` + +Upload the public bit to a public GCS bucket + +``` +https://storage.cloud.google.com/issue-label-bot-dev_public/chatbot/keys/jwk-sig-chatbot-pub.json +``` + +## Referencess + +* [ISTIO 1.1 Policy Resource](https://archive.istio.io/v1.1/docs/reference/config/istio.authentication.v1alpha1/#Policy) +* [ISTIO 1.5 JWT policy example](https://istio.io/docs/tasks/security/authorization/authz-jwt/) + * This example includes some static JWTs that can be used for testing. \ No newline at end of file diff --git a/chatbot/cmd/main.go b/chatbot/cmd/main.go new file mode 100644 index 0000000000..87bbfc3987 --- /dev/null +++ b/chatbot/cmd/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "flag" + "github.com/kubeflow/code-intelligence/chatbot/cmd/options" + "github.com/kubeflow/code-intelligence/chatbot/pkg" + "github.com/onrik/logrus/filename" + log "github.com/sirupsen/logrus" +) + +func init() { + // Add filename as one of the fields of the structured log message + filenameHook := filename.NewHook() + filenameHook.Field = "filename" + log.AddHook(filenameHook) +} + +// Run the application. +func Run(opt *options.ServerOption) error { + log.Info("Creating server") + server, err := pkg.NewKubeflowInfoServer(opt.AreaConfigPath) + if err != nil { + return err + } + + + server.RegisterEndpoints() + + log.Infof("Starting http server.") + return server.StartHttp(opt.Port) +} + +func main() { + s := options.NewServerOption() + s.AddFlags(flag.CommandLine) + + flag.Parse() + + if s.AreaConfigPath == "" { + log.Fatalf("--area-config-path must be specified. This should be the path to a YAML file defining the areas and their associated owners") + } + if s.JsonLogFormat { + // Output logs in a json format so that it can be parsed by services like Stackdriver + log.SetFormatter(&log.JSONFormatter{}) + } + if err := Run(s); err != nil { + log.Fatalf("%v\n", err) + } +} \ No newline at end of file diff --git a/chatbot/cmd/options/options.go b/chatbot/cmd/options/options.go new file mode 100644 index 0000000000..bb017f7330 --- /dev/null +++ b/chatbot/cmd/options/options.go @@ -0,0 +1,41 @@ + +// Copyright 2018 The Kubeflow Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package options + +import ( + "flag" +) + +// ServerOption is the main context object for terver. +type ServerOption struct { + PrintVersion bool + JsonLogFormat bool + AreaConfigPath string + Port int +} + +// NewServerOption creates a new CMServer with a default config. +func NewServerOption() *ServerOption { + s := ServerOption{} + return &s +} + +// AddFlags adds flags for a specific Server to the specified FlagSet +func (s *ServerOption) AddFlags(fs *flag.FlagSet) { + fs.BoolVar(&s.JsonLogFormat, "json-log-format", true, "Set true to use json style log format. Set false to use plaintext style log format") + fs.StringVar(&s.AreaConfigPath, "area-config-path", "https://raw.githubusercontent.com/kubeflow/community/master/labels-owners.yaml", "Path to the YAML file mapping area labels to owners.") + fs.IntVar(&s.Port, "port", 8080, "The port to use for an http server.") +} \ No newline at end of file diff --git a/chatbot/go.mod b/chatbot/go.mod new file mode 100644 index 0000000000..24bb5be352 --- /dev/null +++ b/chatbot/go.mod @@ -0,0 +1,17 @@ +module github.com/kubeflow/code-intelligence/chatbot + +go 1.13 + +require ( + github.com/ghodss/yaml v1.0.0 + github.com/go-kit/kit v0.9.0 + github.com/hashicorp/go-getter v1.4.1 + github.com/onrik/logrus v0.5.1 + github.com/pkg/errors v0.9.1 + github.com/prometheus/client_golang v1.6.0 + github.com/sirupsen/logrus v1.6.0 + github.com/square/go-jose/v3 v3.0.0-20200430180204-d84c719419c2 + github.com/tidwall/gjson v1.6.0 // indirect + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 + gopkg.in/yaml.v2 v2.2.8 // indirect +) diff --git a/chatbot/go.sum b/chatbot/go.sum new file mode 100644 index 0000000000..34ffbac3e9 --- /dev/null +++ b/chatbot/go.sum @@ -0,0 +1,278 @@ +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= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +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/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/aws/aws-sdk-go v1.15.78 h1:LaXy6lWR0YK7LKyuU0QWy2ws/LWTPfYV/UgfiBu4tvY= +github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM= +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/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +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/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +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= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +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/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-getter v1.4.1 h1:3A2Mh8smGFcf5M+gmcv898mZdrxpseik45IpcyISLsA= +github.com/hashicorp/go-getter v1.4.1/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +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/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +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/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +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.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/onrik/logrus v0.5.1 h1:f+dStGd/hIk6qUb8CUESjczzd4MrdeGHuOLoJ5msr44= +github.com/onrik/logrus v0.5.1/go.mod h1:qfe9NeZVAJfIxviw3cYkZo3kvBtLoPRJriAO8zl7qTk= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A= +github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/square/go-jose/v3 v3.0.0-20200430180204-d84c719419c2 h1:OgwC+PITZfsuGwYeD1+jNi7jkw8Rr5oQp9N6dFr9YUo= +github.com/square/go-jose/v3 v3.0.0-20200430180204-d84c719419c2/go.mod h1:E4R1fKDMXKIdcGA568juVdKOeMqCu9M3yhZRvtXdwrA= +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/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok= +github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/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-20190510132918-efd6b22b2522/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/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +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/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= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/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-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-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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= +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/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-20181116152217-5ac8a444bdc5/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 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-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +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/tools v0.0.0-20180917221912-90fa682c2a6e/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= +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-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +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= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/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-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-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/chatbot/pkg/dialogflow/webhook.go b/chatbot/pkg/dialogflow/webhook.go new file mode 100644 index 0000000000..507d1ec56e --- /dev/null +++ b/chatbot/pkg/dialogflow/webhook.go @@ -0,0 +1,50 @@ +package dialogflow + +import "context" + +// Define go structs to deserialize Dialgoflow webhooks into. +// Code is copied from +// https://cloud.google.com/dialogflow/docs/fulfillment-webhook#go + +type Intent struct { + DisplayName string `json:"displayName"` +} + +type QueryResult struct { + Intent Intent `json:"intent"` +} + +type Text struct { + Text []string `json:"text"` +} + +type Message struct { + Text Text `json:"text"` +} + +// WebhookRequest is used to unmarshal a WebhookRequest JSON object. Note that +// not all members need to be defined--just those that you need to process. +// As an alternative, you could use the types provided by +// the Dialogflow protocol buffers: +// https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookRequest +type WebhookRequest struct { + Session string `json:"session"` + ResponseID string `json:"responseId"` + QueryResult QueryResult `json:"queryResult"` +} + +// WebhookResponse is used to marshal a WebhookResponse JSON object. Note that +// not all members need to be defined--just those that you need to process. +// As an alternative, you could use the types provided by +// the Dialogflow protocol buffers: +// https://godoc.org/google.golang.org/genproto/googleapis/cloud/dialogflow/v2#WebhookResponse +type WebhookResponse struct { + FulfillmentMessages []Message `json:"fulfillmentMessages"` +} + + +// DialogFlowWebhookService defines an interface for handling Dialgflow webhook fulfillments. +// https://cloud.google.com/dialogflow/docs/fulfillment-webhook#go +type DialogFlowWebhookService interface { + HandleWebhook(ctx context.Context, req WebhookRequest) (*WebhookResponse, error) +} \ No newline at end of file diff --git a/chatbot/pkg/kfgokit/doc.go b/chatbot/pkg/kfgokit/doc.go new file mode 100644 index 0000000000..9f62802625 --- /dev/null +++ b/chatbot/pkg/kfgokit/doc.go @@ -0,0 +1,2 @@ +// kfgokit package contains some utilities for working with https://github.com/go-kit/kit +package kfgokit diff --git a/chatbot/pkg/kfgokit/encoders.go b/chatbot/pkg/kfgokit/encoders.go new file mode 100644 index 0000000000..a637f9685a --- /dev/null +++ b/chatbot/pkg/kfgokit/encoders.go @@ -0,0 +1,20 @@ +package kfgokit + +import ( + "encoding/json" + "github.com/go-kit/kit/endpoint" + "golang.org/x/net/context" + "net/http" +) + +// EncodeResponse endodes responses. +// This is a generic json encoder. It takes arbitrary go structurs and encodes them as json. +func EncodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error { + // If the response + if f, ok := response.(endpoint.Failer); ok && f.Failed() != nil { + ErrorEncoder(ctx, f.Failed(), w) + return nil + } + w.Header().Set("Content-Type", "application/json; charset=utf-8") + return json.NewEncoder(w).Encode(response) +} diff --git a/chatbot/pkg/kfgokit/errors.go b/chatbot/pkg/kfgokit/errors.go new file mode 100644 index 0000000000..4199eeaf85 --- /dev/null +++ b/chatbot/pkg/kfgokit/errors.go @@ -0,0 +1,59 @@ +package kfgokit + +import ( +"bytes" +"encoding/json" +"golang.org/x/net/context" +"io/ioutil" +"net/http" +) + +func err2code(err error) int { + // TODO(jlewi): We should map different errors to different http status codes. + return http.StatusInternalServerError +} + +// ErrorEncoder is a custom error used to encode errors into the http response. +// If the error is of type httpError then is used to obtain the statuscode. +// TODO(jlewi): Should we follow the model +func ErrorEncoder(_ context.Context, err error, w http.ResponseWriter) { + h, ok := err.(*httpError) + + if ok { + w.WriteHeader(h.Code) + } else { + w.WriteHeader(err2code(err)) + } + json.NewEncoder(w).Encode(err) +} + +// httpError allows us to attach add an http status code to an error +// +// Inspired by on https://cloud.google.com/apis/design/errors +// +// TODO(jlewi): We should support adding an internal message that would be logged on the server but not returned +// to the user. We should attach to that log message a unique id that can also be returned to the user to make +// it easy to look errors shown to the user and our logs. +type httpError struct { + Message string + Code int +} + +func (e *httpError) Error() string { + return e.Message +} + +type errorWrapper struct { + Error string `json:"error"` +} + +// encodeHTTPGenericRequest is a transport/http.EncodeRequestFunc that +// JSON-encodes any request to the request body. Primarily useful in a client. +func encodeHTTPGenericRequest(_ context.Context, r *http.Request, request interface{}) error { + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(request); err != nil { + return err + } + r.Body = ioutil.NopCloser(&buf) + return nil +} diff --git a/chatbot/pkg/labels.go b/chatbot/pkg/labels.go new file mode 100644 index 0000000000..04f85e91dd --- /dev/null +++ b/chatbot/pkg/labels.go @@ -0,0 +1,58 @@ +package pkg + +import ( + "github.com/ghodss/yaml" + gogetter "github.com/hashicorp/go-getter" + "github.com/pkg/errors" + "io/ioutil" +) + +// KubeflowLabels is a struct representing information about Kubeflow labels. +// We deserialize https://github.com/kubeflow/community/blob/master/labels-owners.yaml +// into this file. +type KubeflowLabels struct { + Labels map[string]LabelInfo `json:"labels,omitempty"` +} + +// LabelInfo provides information about a specific label. +type LabelInfo struct{ + Owners []string `json:"owners,omitempty"` +} + +// LoadLabels loads the labels from the given URI. The URI can be any URI understood by hashi-corps go-getter. +func LoadLabels(labelMapUri string) (*KubeflowLabels, error) { + localCopy, err := ioutil.TempFile("", "chatBotLabelMap.yaml") + + if err != nil { + return nil, errors.WithStack(err) + } + + if err := gogetter.GetFile(localCopy.Name(), labelMapUri); err != nil { + return nil, errors.WithStack(errors.Wrapf(err, "Could not get file %v", labelMapUri)) + } + + contents, err := ioutil.ReadFile(localCopy.Name()) + + if err != nil { + return nil, errors.WithStack(errors.Wrapf(err, "Could not read file: %v; which is a copy of %v", localCopy, labelMapUri)) + } + + labels := &KubeflowLabels{} + if err := yaml.Unmarshal(contents,labels); err != nil { + return nil, errors.WithStack(errors.Wrapf(err, "Error trying to deserialize %v (which is a copy of %v) to KubeflowLabels; this likely means the YAML file isn't formatted correctly", localCopy, labelMapUri)) + } + + return labels, nil +} + +// GetLabelOwners returns the owners of the given label. +// Returns an empty array if the label is unknown. +func (l *KubeflowLabels) GetLabelOwners(area string)[]string { + i, ok := l.Labels[area] + + if !ok { + return []string{} + } + + return i.Owners +} \ No newline at end of file diff --git a/chatbot/pkg/labels_test.go b/chatbot/pkg/labels_test.go new file mode 100644 index 0000000000..835a691cb9 --- /dev/null +++ b/chatbot/pkg/labels_test.go @@ -0,0 +1,23 @@ +package pkg + +import ( + "os" + "path" + "testing" +) + +func Test_PaseLabels(t *testing.T) { + wd , err := os.Getwd() + + if err != nil { + t.Fatalf("Could not get working directory; %v", err) + } + + testFile := path.Join(wd, "test_data", "labels-owners.yaml") + + _, err = LoadLabels(testFile) + + if err != nil { + t.Fatalf("Could not load labels from %v; error: %v", testFile, err) + } +} \ No newline at end of file diff --git a/chatbot/pkg/server.go b/chatbot/pkg/server.go new file mode 100644 index 0000000000..026c721816 --- /dev/null +++ b/chatbot/pkg/server.go @@ -0,0 +1,154 @@ +package pkg + +import ( + "encoding/json" + "fmt" + "github.com/go-kit/kit/endpoint" + httptransport "github.com/go-kit/kit/transport/http" + "github.com/kubeflow/code-intelligence/chatbot/pkg/kfgokit" + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" + log "github.com/sirupsen/logrus" + "golang.org/x/net/context" + "net" + "net/http" + "time" + //"cloud.google.com/go/dialogflow/apiv2" + dfext "github.com/kubeflow/code-intelligence/chatbot/pkg/dialogflow" +) + +var ( + serviceHeartbeat = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "service_heartbeat", + Help: "Heartbeat signal every 10 seconds indicating pods are alive.", + }) +) + +const ( + DialogFlowWebhookPath = "/dialogflow/webhook" +) +// kubeflowInfoServer provides information about Kubeflow. +// It is used to fulfill information requests from the chatbot. +type kubeflowInfoServer struct { + listener net.Listener + labelMapUri string + labels *KubeflowLabels +} + +// NewKubeflowInfoServer constructs an info server. +// labelMapUri is the path to the file mapping area labels to owners. +func NewKubeflowInfoServer(labelMapUri string) (*kubeflowInfoServer, error) { + labels, err := LoadLabels(labelMapUri) + + if err != nil { + return nil, errors.WithStack(err) + } + s := &kubeflowInfoServer{ + labelMapUri: labelMapUri, + labels: labels, + } + + return s, nil +} + +// Add heartbeat every 10 seconds +func countHeartbeat() { + for { + time.Sleep(10 * time.Second) + serviceHeartbeat.Inc() + } +} + +type HealthzResponse struct { + Reply string +} + +func makeHealthzEndpoint() endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + r := &HealthzResponse{} + r.Reply = "Request accepted! Still alive!" + return r, nil + } +} + +func getHealthzHandler() http.Handler { + return httptransport.NewServer( + makeHealthzEndpoint(), + func(_ context.Context, r *http.Request) (interface{}, error) { + return nil, nil + }, + kfgokit.EncodeResponse, + ) +} + +func makeDialogFlowWebhookEndpoint(svc dfext.DialogFlowWebhookService) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + req := request.(dfext.WebhookRequest) + r, err := svc.HandleWebhook(ctx, req) + return r, err + } +} + + +// RegisterEndpoints creates the http endpoints for the server. +func (s *kubeflowInfoServer) RegisterEndpoints() { + webhook := httptransport.NewServer( + makeDialogFlowWebhookEndpoint(s), + func(_ context.Context, r *http.Request) (interface{}, error) { + var request dfext.WebhookRequest + if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + log.Errorf("Err decoding Dialogflow WebhookRequest: " + err.Error()) + return nil, err + } + return request, nil + }, + kfgokit.EncodeResponse, + ) + + http.Handle(DialogFlowWebhookPath, webhook) + http.Handle("/", getHealthzHandler()) +} + +func (s *kubeflowInfoServer) StartHttp(port int) error { + portS := fmt.Sprintf(":%d", port) + if port <= 0 { + log.Info("No port specified; using next available.") + portS = ":0" + } + + listener, err := net.Listen("tcp", portS) + + if err != nil { + panic(err) + } + + s.listener = listener + + // add an http handler for prometheus metrics + http.Handle("/metrics", promhttp.Handler()) + + go countHeartbeat() + + log.Infof("Listening on address: %+v", listener.Addr()) + + err = http.Serve(s.listener, nil) + + return err +} + +func (s *kubeflowInfoServer) HandleWebhook(ctx context.Context, req dfext.WebhookRequest)(*dfext.WebhookResponse, error) { + log.Errorf("TODO need to implement actual webhook") + res := &dfext.WebhookResponse{ + FulfillmentMessages:[]dfext.Message { + { + Text: dfext.Text{ + Text: []string { + "Need to add actual webhook message", + } , + }, + }, + }, + } + return res, nil +} \ No newline at end of file diff --git a/chatbot/pkg/services.go b/chatbot/pkg/services.go new file mode 100644 index 0000000000..ef5fffdc56 --- /dev/null +++ b/chatbot/pkg/services.go @@ -0,0 +1,8 @@ +package pkg + + +// LabelServiceV1Alpha1 defines an interface suitable for getting information about labels +type LabelServiceV1Alpha1 interface { + // GetLabelOwners returns a list of owners of the specified label. + GetLabelOwners(label string)[]string +} diff --git a/chatbot/pkg/test_data/labels-owners.yaml b/chatbot/pkg/test_data/labels-owners.yaml new file mode 100644 index 0000000000..ffa00c9ccd --- /dev/null +++ b/chatbot/pkg/test_data/labels-owners.yaml @@ -0,0 +1,180 @@ + +# This file provides information about labels and owners behind them +# +# Please keep this file alphabetized by label name and owner name +labels: + area/airgapped: + owners: + - krishnadurai + - swiftdiaries + - yanniszark + area/applications: + owners: + - kkasravi + area/auth: + owners: + - yanniszark + area/centraldashboard: + owners: + - avdaredevil + - prodonjs + area/docs: + owners: + - jlewi + - joeliedtke + area/example: + owners: + - dansanche + - jinchihe + - lluunn + - texasmichelle + area/gcp: + owners: + - gabrielwen + - jlewi + - kunmingg + - lluunn + - richardsliu + - zhenghuiwang + area/inference: + owners: + - animeshsingh + - cliveseldon + - ellis-bigelow + - rakelkar + - yuzisun + area/istio: + owners: + - krishnadurai + - kunmingg + - lluunn + - yanniszark + area/jupyter: + owners: + - kimwnasptd + - vkoukis + area/katib: + owners: + - andreyvelich + - gaocegege + - hougangliu + - johnugeorge + area/kubebench: + owners: + - andreyvelich + - swiftdiaries + - xyhuang + area/kustomize: + owners: + - jinchihe + - kkasravi + - swiftdiaries + - yanniszark + area/logging: + owners: + - jlewi + - kunmingg + area/multiuser: + owners: + - yanniszark + area/mxnet: + owners: + - gaocegege + - suleisl2000 + - wackxu + area/openmpi: + owners: + - alsrgv + - jiezhang + - jlewi + area/openvino: + owners: + - kkasravi + area/pipelines: + owners: + - ark-kun + - jessiezcc + - ironPan + - neuromage + - paveldournov + area/sdk: + owners: + - animeshsingh + - jlewi + - jinchihe + area/enterprise_readiness: + owners: + - jbottum + - yanniszark + area/seldon: + owners: + - cliveseldon + area/testing: + owners: + - gabrielwen + - jlewi + - kunmingg + - lluunn + - richardsliu + - zhenghuiwang + area/tfjob: + owners: + - gaocegege + - johnugeorge + - richardsliu + area/training: + owners: + - johnugeorge + - richardsliu + platform/arm: + owners: + - animeshsingh + - mrXinWang + platform/aws: + owners: + - jeffwan + platform/azure: + owners: + - aronchick + - rakelkar + platform/gcp: + owners: + - gabrielwen + - jlewi + - kunmingg + - lluunn + - richardsliu + - zhenghuiwang + platform/ibmcloud: + owners: + - animeshsingh + - tomcli + platform/microk8s: + owners: + - carmine + platform/minikf: + owners: + - cspavlou + - elikatsis + - jbottum + - vkoukis + - yanniszark + platform/minikube: + owners: + - lluunn + platform/onprem: + owners: + - elviraux + - jbottum + - krishnadurai + - swiftdiaries + - vkoukis + - yanniszark + platform/openshift: + owners: + - animeshsingh + - pdmack + platform/power: + owners: + - animeshsingh + - jinchihe diff --git a/chatbot/pkg/util.go b/chatbot/pkg/util.go new file mode 100644 index 0000000000..0ba77a7100 --- /dev/null +++ b/chatbot/pkg/util.go @@ -0,0 +1,18 @@ +package pkg + +import ( + + "encoding/json" +) + +// Pformat returns a pretty format output of any value. +func Pformat(value interface{}) (string, error) { + if s, ok := value.(string); ok { + return s, nil + } + valueJson, err := json.MarshalIndent(value, "", " ") + if err != nil { + return "", err + } + return string(valueJson), nil +} \ No newline at end of file diff --git a/chatbot/skaffold.yaml b/chatbot/skaffold.yaml new file mode 100644 index 0000000000..e2d14b7ffb --- /dev/null +++ b/chatbot/skaffold.yaml @@ -0,0 +1,34 @@ +# Reference: https://skaffold.dev/docs/references/yaml/ +apiVersion: skaffold/v2alpha1 +kind: Config +metadata: + name: label-microservice +build: + artifacts: + - image: gcr.io/issue-label-bot-dev/chatbot/server + # Set the context to the root directory. + # All paths in the Dockerfile should be relative to this one. + context: . + kaniko: + dockerfile: Dockerfile + buildContext: + gcsBucket: issue-label-bot-dev_skaffold-kaniko + env: + # TODO(GoogleContainerTools/skaffold#3468) skaffold doesn't + # appear to work with workload identity + - name: GOOGLE_APPLICATION_CREDENTIALS + value: /secret/user-gcp-sa.json + cache: {} + cluster: + pullSecretName: user-gcp-sa + # Build in the kaniko namespace because we need to disable ISTIO sidecar injection + # see GoogleContainerTools/skaffold#3442 + namespace: kaniko + resources: + requests: + cpu: 8 + memory: 16Gi + +deploy: + kustomize: + path: manifest/dev \ No newline at end of file