diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c8aa970 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c23774c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "env": {}, + "args": [] + } + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8189513 --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +REGISTRY_NAME?=docker.io/sbezverk +IMAGE_VERSION?=0.0.0 + +.PHONY: all jalapeno-gateway jalapeno-client compile-gateway compile-client container-gateway container-client push clean test + +ifdef V +TESTARGS = -v -args -alsologtostderr -v 5 +else +TESTARGS = +endif +BIN=./ + +all: jalapeno-gateway jalapeno-client + +jalapeno-gateway: + mkdir -p bin + $(MAKE) -C ./cmd compile-gateway + +jalapeno-client: + mkdir -p bin + $(MAKE) -C ./cmd/gateway-client compile-client + +container-gateway: jalapeno-gateway + docker build -t $(REGISTRY_NAME)/jalapeno-gateway-debug:$(IMAGE_VERSION) -f ./build/Dockerfile.gateway . + +container-client: jalapeno-client + docker build -t $(REGISTRY_NAME)/jalapeno-client:$(IMAGE_VERSION) -f ./build/Dockerfile.client . + +push: container-gateway container-client + docker push $(REGISTRY_NAME)/jalapeno-gateway-debug:$(IMAGE_VERSION) + docker push $(REGISTRY_NAME)/jalapeno-client:$(IMAGE_VERSION) + +clean: + rm -rf bin + +test: + GO111MODULE=on go test `go list ./... | grep -v 'vendor'` $(TESTARGS) + GO111MODULE=on go vet `go list ./... | grep -v vendor` diff --git a/build/Dockerfile.client b/build/Dockerfile.client new file mode 100644 index 0000000..daeddc8 --- /dev/null +++ b/build/Dockerfile.client @@ -0,0 +1,4 @@ +FROM scratch + +COPY ./bin/jalapeno-client /jalapeno-client +ENTRYPOINT ["/jalapeno-client"] diff --git a/build/Dockerfile.gateway b/build/Dockerfile.gateway new file mode 100644 index 0000000..16aa966 --- /dev/null +++ b/build/Dockerfile.gateway @@ -0,0 +1,4 @@ +FROM scratch + +COPY ./bin/jalapeno-gateway /jalapeno-gateway +ENTRYPOINT ["/jalapeno-gateway"] diff --git a/cmd/Makefile b/cmd/Makefile new file mode 100644 index 0000000..e1ee424 --- /dev/null +++ b/cmd/Makefile @@ -0,0 +1,2 @@ +compile-gateway: + CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -a -ldflags '-extldflags "-static"' -o ../bin/jalapeno-gateway ./jalapeno-gateway.go diff --git a/cmd/gateway-client/Makefile b/cmd/gateway-client/Makefile new file mode 100644 index 0000000..ce7ddc6 --- /dev/null +++ b/cmd/gateway-client/Makefile @@ -0,0 +1,2 @@ +compile-client: + CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -a -ldflags '-extldflags "-static"' -o ../../bin/jalapeno-client ./jalapeno-client.go diff --git a/cmd/gateway-client/go.mod b/cmd/gateway-client/go.mod new file mode 100644 index 0000000..be724e0 --- /dev/null +++ b/cmd/gateway-client/go.mod @@ -0,0 +1,16 @@ +module gateway-client + +go 1.13 + +require ( + github.com/cisco-ie/jalapeno-go-gateway/pkg/apis v0.0.0-00010101000000-000000000000 // indirect + github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient v0.0.0-00010101000000-000000000000 // indirect + github.com/gogo/protobuf v1.3.1 // indirect + github.com/osrg/gobgp v2.0.0+incompatible // indirect + google.golang.org/grpc v1.27.0 // indirect +) + +replace ( + github.com/cisco-ie/jalapeno-go-gateway/pkg/apis => ../../pkg/apis + github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient => ../../pkg/bgpclient +) diff --git a/cmd/gateway-client/go.sum b/cmd/gateway-client/go.sum new file mode 100644 index 0000000..155ac1d --- /dev/null +++ b/cmd/gateway-client/go.sum @@ -0,0 +1,56 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cisco-ie/jalapeno-go-gateway v0.0.0-20200123172347-801b88bf8ded h1:DQGAi6eOu36SjxPzxflMQaOJ/8uhz1kc41P+CQZGmLE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +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/protobuf v1.2.0/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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/osrg/gobgp v2.0.0+incompatible h1:91ARQbE1AtO0U4TIxHPJ7wYVZIqduyBwS1+FjlHlmrY= +github.com/osrg/gobgp v2.0.0+incompatible/go.mod h1:vGVJPLW6JFDD7WA1vJsjB8OKmbbC2TKwHtr90CZS/u4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/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-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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +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.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/cmd/gateway-client/jalapeno-client.go b/cmd/gateway-client/jalapeno-client.go new file mode 100644 index 0000000..01ff5a2 --- /dev/null +++ b/cmd/gateway-client/jalapeno-client.go @@ -0,0 +1,132 @@ +package main + +import ( + "context" + "flag" + "io" + "math/rand" + "net" + "os" + "os/signal" + "time" + + pbapi "github.com/cisco-ie/jalapeno-go-gateway/pkg/apis" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient" + "github.com/golang/glog" + "github.com/golang/protobuf/ptypes/any" + "github.com/osrg/gobgp/pkg/packet/bgp" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +const ( + jalapenoGateway = "jalapeno-gateway:40040" +) + +func main() { + flag.Parse() + flag.Set("logtostderr", "true") + + client := os.Getenv("CLIENT_IP") + if client == "" { + glog.Errorf("env variable \"CLIENT_IP\" is not defined, cannor proceed further, exiting...") + os.Exit(1) + } + if net.ParseIP(client).To4() == nil && net.ParseIP(client).To16() == nil { + glog.Errorf("env variable \"CLIENT_IP\" carries an invalid ip %s", client) + os.Exit(1) + } + glog.Errorf("\"CLIENT_IP:\" %s", client) + + conn, err := grpc.DialContext(context.TODO(), jalapenoGateway, grpc.WithInsecure()) + if err != nil { + glog.Errorf("failed to connect to Jalapeno Gateway at the address: %s with error: %+v", jalapenoGateway, err) + os.Exit(1) + } + defer conn.Close() + gwclient := pbapi.NewGatewayServiceClient(conn) + // Mocking RDs and RTs for 3 VRFs + requests := make([]*pbapi.RequestVPN, 3) + requests[0] = &pbapi.RequestVPN{ + Rt: make([]*any.Any, 0), + } + requests[0].Rd = bgpclient.MarshalRD(bgp.NewRouteDistinguisherTwoOctetAS(577, 65000)) + requests[0].Rt = append(requests[0].Rt, bgpclient.MarshalRT(bgp.NewTwoOctetAsSpecificExtended(bgp.EC_SUBTYPE_ROUTE_TARGET, 577, 65000, false))) + + requests[1] = &pbapi.RequestVPN{ + Rt: make([]*any.Any, 0), + } + requests[1].Rd = bgpclient.MarshalRD(bgp.NewRouteDistinguisherIPAddressAS("57.57.57.57", 65001)) + requests[1].Rt = append(requests[0].Rt, bgpclient.MarshalRT(bgp.NewIPv4AddressSpecificExtended(bgp.EC_SUBTYPE_ROUTE_TARGET, "57.57.57.57", 65001, false))) + requests[2] = &pbapi.RequestVPN{ + Rt: make([]*any.Any, 0), + } + requests[2].Rd = bgpclient.MarshalRD(bgp.NewRouteDistinguisherFourOctetAS(456734567, 65002)) + requests[2].Rt = append(requests[0].Rt, bgpclient.MarshalRT(bgp.NewFourOctetAsSpecificExtended(bgp.EC_SUBTYPE_ROUTE_TARGET, 456734567, 65002, false))) + + stopCh := setupSignalHandler() + // The client will randomly send requests between three VRFs green, blue and red. + ticker := time.NewTicker(time.Second * 10) + ctx := metadata.NewOutgoingContext(context.TODO(), metadata.New(map[string]string{ + "CLIENT_IP": net.ParseIP(client).String(), + })) + for { + i := rand.Intn(3) + stream, err := gwclient.VPN(ctx, requests[i]) + if err != nil { + glog.Errorf("failed to request VPN label for request %+v with error: %+v", requests[i], err) + } else { + for { + entry, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + glog.Errorf("failed to receive a message from the stream with error: %+v", err) + break + } + if entry == nil { + glog.Info("Received empty message\n") + continue + } + rd, err := bgpclient.UnmarshalRD(entry.Rd) + if err != nil { + glog.Errorf("failed to unmarshal received rd with error: %+v", err) + } + glog.Infof("Recived RD: %+v", rd) + rts, err := bgpclient.UnmarshalRT(entry.Rt) + if err != nil { + glog.Errorf("failed to unmarshal received rt with error: %+v", err) + } + glog.Infof("Recived RTs: %+v", rts) + } + } + select { + case <-ticker.C: + case <-stopCh: + glog.Info("Stop signal received, exiting...") + os.Exit(0) + } + } +} + +var ( + onlyOneSignalHandler = make(chan struct{}) + shutdownSignals = []os.Signal{os.Interrupt} +) + +func setupSignalHandler() (stopCh <-chan struct{}) { + close(onlyOneSignalHandler) // panics when called twice + + stop := make(chan struct{}) + c := make(chan os.Signal, 2) + signal.Notify(c, shutdownSignals...) + go func() { + <-c + close(stop) + <-c + os.Exit(1) // second signal. Exit directly. + }() + + return stop +} diff --git a/cmd/jalapeno-gateway.go b/cmd/jalapeno-gateway.go new file mode 100644 index 0000000..60dad5b --- /dev/null +++ b/cmd/jalapeno-gateway.go @@ -0,0 +1,103 @@ +package main + +import ( + "flag" + "math" + "net" + "os" + "os/signal" + "strconv" + + "github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient/mock" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/gateway" + "github.com/golang/glog" +) + +const ( + // DefaultGatewayPort defines default port Gateway's gRPC server listens on + // this port is a container port, not the port used for Gateway Kubernetes Service. + defaultGatewayPort = "15151" +) + +func main() { + flag.Parse() + flag.Set("logtostderr", "true") + + // Getting port for gRPC server to listen on, from environment varialbe + // GATEWAY_PORT + strPort := os.Getenv("GATEWAY_PORT") + if strPort == "" { + // TODO, should it fallback to the default port? + strPort = defaultGatewayPort + glog.Warningf("env variable \"GATEWAY_PORT\" is not defined, using default Gateway port: %s", strPort) + } + srvPort, err := strconv.Atoi(strPort) + if err != nil { + glog.Warningf("env variable \"GATEWAY_PORT\" containes an invalid value %s, using default Gateway port instead: %s", strPort, defaultGatewayPort) + srvPort, _ = strconv.Atoi(defaultGatewayPort) + } + // The value of port cannot be more than max uint16 + if srvPort == 0 || srvPort > math.MaxUint16 { + glog.Warningf("env variable \"GATEWAY_PORT\" containes an invalid value %d, using default Gateway port instead: %s\n", srvPort, defaultGatewayPort) + srvPort, _ = strconv.Atoi(defaultGatewayPort) + } + // Instantiate BGP client + // TODO, the address:port of gobgp should be provided as a parameter. + bgp, err := bgpclient.NewBGPClient("gobgpd.default:50051") + if err != nil { + glog.Warningf("failed to instantiate bgp client with error: %+v", err) + } else { + // Just for a test requesting one prefix + if err := bgp.GetPrefix(); err != nil { + glog.Warningf("failed to list path with error: %+v", err) + } + if err := bgp.AddPrefix(); err != nil { + glog.Warningf("failed to add path with error: %+v", err) + } + } + // Get interface to the database + // TODO, since it is not clear which database will be used, for now use mock DB + db := mock.NewMockDB() + // Initialize DB client + dbc := dbclient.NewDBClient(db) + // Initialize gRPC server + conn, err := net.Listen("tcp", ":"+strPort) + if err != nil { + glog.Errorf("failed to setup listener with with error: %+v", err) + os.Exit(1) + } + gSrv := gateway.NewGateway(conn, dbc, bgp) + gSrv.Start() + + // For now just get stuck on stop channel, later add signal processing + stopCh := setupSignalHandler() + <-stopCh + // Clean up section + // Cleanup DB connection + // Cleanup gRPC server + gSrv.Stop() + +} + +var ( + onlyOneSignalHandler = make(chan struct{}) + shutdownSignals = []os.Signal{os.Interrupt} +) + +func setupSignalHandler() (stopCh <-chan struct{}) { + close(onlyOneSignalHandler) // panics when called twice + + stop := make(chan struct{}) + c := make(chan os.Signal, 2) + signal.Notify(c, shutdownSignals...) + go func() { + <-c + close(stop) + <-c + os.Exit(1) // second signal. Exit directly. + }() + + return stop +} diff --git a/deployment/jalapeno-client.yaml b/deployment/jalapeno-client.yaml new file mode 100644 index 0000000..1186ada --- /dev/null +++ b/deployment/jalapeno-client.yaml @@ -0,0 +1,27 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: jalapeno-client +spec: + replicas: 1 + selector: + matchLabels: + app: jalapeno-client + template: + metadata: + labels: + app: jalapeno-client + spec: + containers: + - name: jalapeno-client + image: docker.io/sbezverk/jalapeno-client:0.0.0 + imagePullPolicy: Always + env: + - name: CLIENT_IP + valueFrom: + fieldRef: + fieldPath: status.podIP +metadata: + name: jalapeno-client + namespace: default diff --git a/deployment/jalapeno-gateway.yaml b/deployment/jalapeno-gateway.yaml new file mode 100644 index 0000000..ad4f9d2 --- /dev/null +++ b/deployment/jalapeno-gateway.yaml @@ -0,0 +1,63 @@ +apiVersion: v1 +kind: ConfigMap +data: + gateway-config.yaml: | +metadata: + name: jalapeno-gateway-config + namespace: default +--- +apiVersion: v1 +kind: Service +spec: + ports: + - name: jalapeno-gateway + port: 40040 + protocol: TCP + targetPort: gateway-port + selector: + app: jalapeno-gateway + type: ClusterIP + externalIPs: + - 192.168.80.104 +metadata: + name: jalapeno-gateway + namespace: default +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: jalapeno-gateway +spec: + replicas: 1 + selector: + matchLabels: + app: jalapeno-gateway + template: + metadata: + labels: + app: jalapeno-gateway + spec: + containers: + - name: jalapeno-gateway + image: docker.io/sbezverk/jalapeno-gateway-debug:0.0.0 + imagePullPolicy: Always + ports: + - containerPort: 40040 + name: gateway-port + protocol: TCP + volumeMounts: + - name: config-volume + mountPath: /config + env: + - name: GATEWAY_PORT + value: "40040" + args: + - --v + - "5" + volumes: + - name: config-volume + configMap: + name: jalapeno-gateway-config +metadata: + name: jalapeno-gateway + namespace: default diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..27698f0 --- /dev/null +++ b/go.mod @@ -0,0 +1,27 @@ +module github.com/cisco-ie/jalapeno-go-gateway/jalapeno-gateway + +go 1.13 + +require ( + github.com/cisco-ie/jalapeno-go-gateway/pkg/apis v0.0.0-00010101000000-000000000000 + github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient v0.0.0-00010101000000-000000000000 + github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient v0.0.0-00010101000000-000000000000 + github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient/mock v0.0.0-00010101000000-000000000000 + github.com/cisco-ie/jalapeno-go-gateway/pkg/gateway v0.0.0-00010101000000-000000000000 + github.com/coredns/coredns v1.6.7 // indirect + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b + github.com/google/go-cmp v0.4.0 // indirect + github.com/osrg/gobgp v2.0.0+incompatible // indirect + golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect + golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 // indirect + google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba // indirect + google.golang.org/grpc v1.26.0 +) + +replace ( + github.com/cisco-ie/jalapeno-go-gateway/pkg/apis => ./pkg/apis + github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient => ./pkg/bgpclient + github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient => ./pkg/dbclient + github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient/mock => ./pkg/dbclient/mock + github.com/cisco-ie/jalapeno-go-gateway/pkg/gateway => ./pkg/gateway +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f060cfa --- /dev/null +++ b/go.sum @@ -0,0 +1,542 @@ +cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.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.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= +contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= +github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v32.6.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= +github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw= +github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= +github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest v0.9.4/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= +github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= +github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= +github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= +github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM= +github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= +github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U= +github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= +github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= +github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= +github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.3.1+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/DataDog/zstd v1.3.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.21.0/go.mod h1:yuqtN/pe8cXRWG5zPaO7hCfNJp5MwmkoJEoLjkm5tCQ= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k= +github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE= +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/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= +github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.28.9/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/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/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/caddyserver/caddy v1.0.4 h1:wwuGSkUHo6RZ3oMpeTt7J09WBB87X5o+IZN4dKehcQE= +github.com/caddyserver/caddy v1.0.4/go.mod h1:uruyfVsyMcDb3IOzSKsi1x0wOjy1my/PxOSTcD+24jM= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +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/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/cisco-ie/jalapeno-go-gateway v0.0.0-20200123172347-801b88bf8ded h1:DQGAi6eOu36SjxPzxflMQaOJ/8uhz1kc41P+CQZGmLE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/coredns/coredns v1.6.7 h1:q3F5gAB/SPzE5uPjnP5Z5q5eTzWKzjK0rck9GyfrY1M= +github.com/coredns/coredns v1.6.7/go.mod h1:jGC7ZBgMf6n4LM4VMrgYbiNefNRH/hjyqCkXlngNykw= +github.com/coredns/federation v0.0.0-20190818181423-e032b096babe/go.mod h1:MoqTEFX8GlnKkyq8eBCF94VzkNAOgjdlCJ+Pz/oCLPk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190212144455-93d5ec2c7f76/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +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/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= +github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= +github.com/dnstap/golang-dnstap v0.0.0-20170829151710-2cf77a2b5e11/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/elazarl/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/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE= +github.com/farsightsec/golang-framestream v0.0.0-20181102145529-8a0cb8ba8710/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/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/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE= +github.com/go-acme/lego/v3 v3.2.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE= +github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +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/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/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +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 v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= +github.com/golang/protobuf v1.3.1/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.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +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/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/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= +github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +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/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/infobloxopen/go-trees v0.0.0-20190313150506-2af4e13f9062/go.mod h1:PcNJqIlcX/dj3DTG/+QQnRvSgTMG6CLpRMjWcv4+J6w= +github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +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.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= +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.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= +github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= +github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= +github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= +github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ= +github.com/lucas-clemente/quic-go v0.13.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE= +github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= +github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mholt/certmagic v0.8.3/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ= +github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM= +github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0= +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/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw= +github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ= +github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +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.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/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.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.3.5/go.mod h1:uVHyebswE1cCXr2A73cRM2frx5ld1RJUCJkFNZ90ZiI= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/osrg/gobgp v2.0.0+incompatible h1:91ARQbE1AtO0U4TIxHPJ7wYVZIqduyBwS1+FjlHlmrY= +github.com/osrg/gobgp v2.0.0+incompatible/go.mod h1:vGVJPLW6JFDD7WA1vJsjB8OKmbbC2TKwHtr90CZS/u4= +github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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 v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/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.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +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.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +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/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +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 v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/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/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY= +github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY= +github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.5.0-alpha.5.0.20190917205325-a14579fbfb1a/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-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/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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-20181220203305-927f97764cc3/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-20190125091013-d26f9f9a57f3/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-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +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/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/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-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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-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-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/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-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +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.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +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/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-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-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-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +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/genproto v0.0.0-20200115191322-ca5a22157cba h1:pRj9OXZbwNtbtZtOB4dLwfK4u+EVRMvP+e9zKkg2grM= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= +gopkg.in/DataDog/dd-trace-go.v1 v1.20.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw= +gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/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= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4= +k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/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 v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/pkg/apis/gateway.pb.go b/pkg/apis/gateway.pb.go new file mode 100644 index 0000000..7fc5696 --- /dev/null +++ b/pkg/apis/gateway.pb.go @@ -0,0 +1,1132 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: gateway.proto + +package apis + +import ( + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" + any "github.com/golang/protobuf/ptypes/any" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// EndpointType defines supported endpoints' types +type EndpointType int32 + +const ( + EndpointType_UNKNOWN EndpointType = 0 + EndpointType_IPV4 EndpointType = 1 + EndpointType_IPV6 EndpointType = 2 + EndpointType_SID EndpointType = 3 +) + +var EndpointType_name = map[int32]string{ + 0: "UNKNOWN", + 1: "IPV4", + 2: "IPV6", + 3: "SID", +} + +var EndpointType_value = map[string]int32{ + "UNKNOWN": 0, + "IPV4": 1, + "IPV6": 2, + "SID": 3, +} + +func (x EndpointType) String() string { + return proto.EnumName(EndpointType_name, int32(x)) +} + +func (EndpointType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{0} +} + +// Errors defines error codes which a gateway can return to a client +type GatewayErrors int32 + +const ( + GatewayErrors_OK GatewayErrors = 0 + // Returned when a gateway encountered a generic error + GatewayErrors_EIO GatewayErrors = 1 + // Returned when request key does not exist + GatewayErrors_ENOENT GatewayErrors = 2 + // Returned when an operation triggered by the client's requested timed out + // and was canceled + GatewayErrors_ETIMEDOUT GatewayErrors = 3 + // Returned when a gateway cannot reach a DB host + GatewayErrors_EHOSTDOWN GatewayErrors = 4 +) + +var GatewayErrors_name = map[int32]string{ + 0: "OK", + 1: "EIO", + 2: "ENOENT", + 3: "ETIMEDOUT", + 4: "EHOSTDOWN", +} + +var GatewayErrors_value = map[string]int32{ + "OK": 0, + "EIO": 1, + "ENOENT": 2, + "ETIMEDOUT": 3, + "EHOSTDOWN": 4, +} + +func (x GatewayErrors) String() string { + return proto.EnumName(GatewayErrors_name, int32(x)) +} + +func (GatewayErrors) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{1} +} + +// endpoint is an object defining a source or a destination of a communication +// path. The type of the endpoint is defined by EndpointType, it can be ipv4, +// ipv6 addresses or segment routing SIDs etc. The list of supported endpoint +// types may be extended in future. The address of endpoint is stored in a slice +// of bytes and should be decoded according to the endpoint type. +type Endpoint struct { + Type EndpointType `protobuf:"varint,1,opt,name=type,proto3,enum=apis.EndpointType" json:"type,omitempty"` + Address []byte `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Endpoint) Reset() { *m = Endpoint{} } +func (m *Endpoint) String() string { return proto.CompactTextString(m) } +func (*Endpoint) ProtoMessage() {} +func (*Endpoint) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{0} +} + +func (m *Endpoint) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Endpoint.Unmarshal(m, b) +} +func (m *Endpoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Endpoint.Marshal(b, m, deterministic) +} +func (m *Endpoint) XXX_Merge(src proto.Message) { + xxx_messageInfo_Endpoint.Merge(m, src) +} +func (m *Endpoint) XXX_Size() int { + return xxx_messageInfo_Endpoint.Size(m) +} +func (m *Endpoint) XXX_DiscardUnknown() { + xxx_messageInfo_Endpoint.DiscardUnknown(m) +} + +var xxx_messageInfo_Endpoint proto.InternalMessageInfo + +func (m *Endpoint) GetType() EndpointType { + if m != nil { + return m.Type + } + return EndpointType_UNKNOWN +} + +func (m *Endpoint) GetAddress() []byte { + if m != nil { + return m.Address + } + return nil +} + +// latency defines one of available QoE metrics +// value expresses latency value in milliseconds. +// variation expresses percent of the acceptable variation from value. +type Latency struct { + Value int32 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` + Variation int32 `protobuf:"varint,2,opt,name=variation,proto3" json:"variation,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Latency) Reset() { *m = Latency{} } +func (m *Latency) String() string { return proto.CompactTextString(m) } +func (*Latency) ProtoMessage() {} +func (*Latency) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{1} +} + +func (m *Latency) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Latency.Unmarshal(m, b) +} +func (m *Latency) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Latency.Marshal(b, m, deterministic) +} +func (m *Latency) XXX_Merge(src proto.Message) { + xxx_messageInfo_Latency.Merge(m, src) +} +func (m *Latency) XXX_Size() int { + return xxx_messageInfo_Latency.Size(m) +} +func (m *Latency) XXX_DiscardUnknown() { + xxx_messageInfo_Latency.DiscardUnknown(m) +} + +var xxx_messageInfo_Latency proto.InternalMessageInfo + +func (m *Latency) GetValue() int32 { + if m != nil { + return m.Value + } + return 0 +} + +func (m *Latency) GetVariation() int32 { + if m != nil { + return m.Variation + } + return 0 +} + +// qoe_parameters defines a list of QoE parameters a client can request. +// Currently only latency is supported. +type QoeParameters struct { + Latency *Latency `protobuf:"bytes,1,opt,name=latency,proto3" json:"latency,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *QoeParameters) Reset() { *m = QoeParameters{} } +func (m *QoeParameters) String() string { return proto.CompactTextString(m) } +func (*QoeParameters) ProtoMessage() {} +func (*QoeParameters) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{2} +} + +func (m *QoeParameters) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_QoeParameters.Unmarshal(m, b) +} +func (m *QoeParameters) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_QoeParameters.Marshal(b, m, deterministic) +} +func (m *QoeParameters) XXX_Merge(src proto.Message) { + xxx_messageInfo_QoeParameters.Merge(m, src) +} +func (m *QoeParameters) XXX_Size() int { + return xxx_messageInfo_QoeParameters.Size(m) +} +func (m *QoeParameters) XXX_DiscardUnknown() { + xxx_messageInfo_QoeParameters.DiscardUnknown(m) +} + +var xxx_messageInfo_QoeParameters proto.InternalMessageInfo + +func (m *QoeParameters) GetLatency() *Latency { + if m != nil { + return m.Latency + } + return nil +} + +type Qoe struct { + Src *Endpoint `protobuf:"bytes,1,opt,name=src,proto3" json:"src,omitempty"` + Dst *Endpoint `protobuf:"bytes,2,opt,name=dst,proto3" json:"dst,omitempty"` + Qoe *QoeParameters `protobuf:"bytes,3,opt,name=qoe,proto3" json:"qoe,omitempty"` + Label []uint32 `protobuf:"varint,4,rep,packed,name=label,proto3" json:"label,omitempty"` + Err GatewayErrors `protobuf:"varint,5,opt,name=err,proto3,enum=apis.GatewayErrors" json:"err,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Qoe) Reset() { *m = Qoe{} } +func (m *Qoe) String() string { return proto.CompactTextString(m) } +func (*Qoe) ProtoMessage() {} +func (*Qoe) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{3} +} + +func (m *Qoe) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Qoe.Unmarshal(m, b) +} +func (m *Qoe) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Qoe.Marshal(b, m, deterministic) +} +func (m *Qoe) XXX_Merge(src proto.Message) { + xxx_messageInfo_Qoe.Merge(m, src) +} +func (m *Qoe) XXX_Size() int { + return xxx_messageInfo_Qoe.Size(m) +} +func (m *Qoe) XXX_DiscardUnknown() { + xxx_messageInfo_Qoe.DiscardUnknown(m) +} + +var xxx_messageInfo_Qoe proto.InternalMessageInfo + +func (m *Qoe) GetSrc() *Endpoint { + if m != nil { + return m.Src + } + return nil +} + +func (m *Qoe) GetDst() *Endpoint { + if m != nil { + return m.Dst + } + return nil +} + +func (m *Qoe) GetQoe() *QoeParameters { + if m != nil { + return m.Qoe + } + return nil +} + +func (m *Qoe) GetLabel() []uint32 { + if m != nil { + return m.Label + } + return nil +} + +func (m *Qoe) GetErr() GatewayErrors { + if m != nil { + return m.Err + } + return GatewayErrors_OK +} + +// RequestQoE defines the rpc message sent by the client to the gateway. +// Multiple Src/Dst/QoE are supported in a single request. +type RequestQoE struct { + Qoes map[int32]*Qoe `protobuf:"bytes,1,rep,name=qoes,proto3" json:"qoes,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RequestQoE) Reset() { *m = RequestQoE{} } +func (m *RequestQoE) String() string { return proto.CompactTextString(m) } +func (*RequestQoE) ProtoMessage() {} +func (*RequestQoE) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{4} +} + +func (m *RequestQoE) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RequestQoE.Unmarshal(m, b) +} +func (m *RequestQoE) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RequestQoE.Marshal(b, m, deterministic) +} +func (m *RequestQoE) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequestQoE.Merge(m, src) +} +func (m *RequestQoE) XXX_Size() int { + return xxx_messageInfo_RequestQoE.Size(m) +} +func (m *RequestQoE) XXX_DiscardUnknown() { + xxx_messageInfo_RequestQoE.DiscardUnknown(m) +} + +var xxx_messageInfo_RequestQoE proto.InternalMessageInfo + +func (m *RequestQoE) GetQoes() map[int32]*Qoe { + if m != nil { + return m.Qoes + } + return nil +} + +// ResponseQoE defines the rpc message sent as a reply to the client. +// it is the same message as request, but the gateway populates labels and +// err for each qoe. +type ResponseQoE struct { + Qoes map[int32]*Qoe `protobuf:"bytes,1,rep,name=qoes,proto3" json:"qoes,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResponseQoE) Reset() { *m = ResponseQoE{} } +func (m *ResponseQoE) String() string { return proto.CompactTextString(m) } +func (*ResponseQoE) ProtoMessage() {} +func (*ResponseQoE) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{5} +} + +func (m *ResponseQoE) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResponseQoE.Unmarshal(m, b) +} +func (m *ResponseQoE) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResponseQoE.Marshal(b, m, deterministic) +} +func (m *ResponseQoE) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseQoE.Merge(m, src) +} +func (m *ResponseQoE) XXX_Size() int { + return xxx_messageInfo_ResponseQoE.Size(m) +} +func (m *ResponseQoE) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseQoE.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseQoE proto.InternalMessageInfo + +func (m *ResponseQoE) GetQoes() map[int32]*Qoe { + if m != nil { + return m.Qoes + } + return nil +} + +type RouteDistinguisherTwoOctetAS struct { + Admin uint32 `protobuf:"varint,1,opt,name=admin,proto3" json:"admin,omitempty"` + Assigned uint32 `protobuf:"varint,2,opt,name=assigned,proto3" json:"assigned,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RouteDistinguisherTwoOctetAS) Reset() { *m = RouteDistinguisherTwoOctetAS{} } +func (m *RouteDistinguisherTwoOctetAS) String() string { return proto.CompactTextString(m) } +func (*RouteDistinguisherTwoOctetAS) ProtoMessage() {} +func (*RouteDistinguisherTwoOctetAS) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{6} +} + +func (m *RouteDistinguisherTwoOctetAS) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RouteDistinguisherTwoOctetAS.Unmarshal(m, b) +} +func (m *RouteDistinguisherTwoOctetAS) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RouteDistinguisherTwoOctetAS.Marshal(b, m, deterministic) +} +func (m *RouteDistinguisherTwoOctetAS) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteDistinguisherTwoOctetAS.Merge(m, src) +} +func (m *RouteDistinguisherTwoOctetAS) XXX_Size() int { + return xxx_messageInfo_RouteDistinguisherTwoOctetAS.Size(m) +} +func (m *RouteDistinguisherTwoOctetAS) XXX_DiscardUnknown() { + xxx_messageInfo_RouteDistinguisherTwoOctetAS.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteDistinguisherTwoOctetAS proto.InternalMessageInfo + +func (m *RouteDistinguisherTwoOctetAS) GetAdmin() uint32 { + if m != nil { + return m.Admin + } + return 0 +} + +func (m *RouteDistinguisherTwoOctetAS) GetAssigned() uint32 { + if m != nil { + return m.Assigned + } + return 0 +} + +type RouteDistinguisherIPAddress struct { + Admin string `protobuf:"bytes,1,opt,name=admin,proto3" json:"admin,omitempty"` + Assigned uint32 `protobuf:"varint,2,opt,name=assigned,proto3" json:"assigned,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RouteDistinguisherIPAddress) Reset() { *m = RouteDistinguisherIPAddress{} } +func (m *RouteDistinguisherIPAddress) String() string { return proto.CompactTextString(m) } +func (*RouteDistinguisherIPAddress) ProtoMessage() {} +func (*RouteDistinguisherIPAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{7} +} + +func (m *RouteDistinguisherIPAddress) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RouteDistinguisherIPAddress.Unmarshal(m, b) +} +func (m *RouteDistinguisherIPAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RouteDistinguisherIPAddress.Marshal(b, m, deterministic) +} +func (m *RouteDistinguisherIPAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteDistinguisherIPAddress.Merge(m, src) +} +func (m *RouteDistinguisherIPAddress) XXX_Size() int { + return xxx_messageInfo_RouteDistinguisherIPAddress.Size(m) +} +func (m *RouteDistinguisherIPAddress) XXX_DiscardUnknown() { + xxx_messageInfo_RouteDistinguisherIPAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteDistinguisherIPAddress proto.InternalMessageInfo + +func (m *RouteDistinguisherIPAddress) GetAdmin() string { + if m != nil { + return m.Admin + } + return "" +} + +func (m *RouteDistinguisherIPAddress) GetAssigned() uint32 { + if m != nil { + return m.Assigned + } + return 0 +} + +type RouteDistinguisherFourOctetAS struct { + Admin uint32 `protobuf:"varint,1,opt,name=admin,proto3" json:"admin,omitempty"` + Assigned uint32 `protobuf:"varint,2,opt,name=assigned,proto3" json:"assigned,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RouteDistinguisherFourOctetAS) Reset() { *m = RouteDistinguisherFourOctetAS{} } +func (m *RouteDistinguisherFourOctetAS) String() string { return proto.CompactTextString(m) } +func (*RouteDistinguisherFourOctetAS) ProtoMessage() {} +func (*RouteDistinguisherFourOctetAS) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{8} +} + +func (m *RouteDistinguisherFourOctetAS) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RouteDistinguisherFourOctetAS.Unmarshal(m, b) +} +func (m *RouteDistinguisherFourOctetAS) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RouteDistinguisherFourOctetAS.Marshal(b, m, deterministic) +} +func (m *RouteDistinguisherFourOctetAS) XXX_Merge(src proto.Message) { + xxx_messageInfo_RouteDistinguisherFourOctetAS.Merge(m, src) +} +func (m *RouteDistinguisherFourOctetAS) XXX_Size() int { + return xxx_messageInfo_RouteDistinguisherFourOctetAS.Size(m) +} +func (m *RouteDistinguisherFourOctetAS) XXX_DiscardUnknown() { + xxx_messageInfo_RouteDistinguisherFourOctetAS.DiscardUnknown(m) +} + +var xxx_messageInfo_RouteDistinguisherFourOctetAS proto.InternalMessageInfo + +func (m *RouteDistinguisherFourOctetAS) GetAdmin() uint32 { + if m != nil { + return m.Admin + } + return 0 +} + +func (m *RouteDistinguisherFourOctetAS) GetAssigned() uint32 { + if m != nil { + return m.Assigned + } + return 0 +} + +type TwoOctetAsSpecificExtended struct { + IsTransitive bool `protobuf:"varint,1,opt,name=is_transitive,json=isTransitive,proto3" json:"is_transitive,omitempty"` + SubType uint32 `protobuf:"varint,2,opt,name=sub_type,json=subType,proto3" json:"sub_type,omitempty"` + As uint32 `protobuf:"varint,3,opt,name=as,proto3" json:"as,omitempty"` + LocalAdmin uint32 `protobuf:"varint,4,opt,name=local_admin,json=localAdmin,proto3" json:"local_admin,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *TwoOctetAsSpecificExtended) Reset() { *m = TwoOctetAsSpecificExtended{} } +func (m *TwoOctetAsSpecificExtended) String() string { return proto.CompactTextString(m) } +func (*TwoOctetAsSpecificExtended) ProtoMessage() {} +func (*TwoOctetAsSpecificExtended) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{9} +} + +func (m *TwoOctetAsSpecificExtended) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_TwoOctetAsSpecificExtended.Unmarshal(m, b) +} +func (m *TwoOctetAsSpecificExtended) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_TwoOctetAsSpecificExtended.Marshal(b, m, deterministic) +} +func (m *TwoOctetAsSpecificExtended) XXX_Merge(src proto.Message) { + xxx_messageInfo_TwoOctetAsSpecificExtended.Merge(m, src) +} +func (m *TwoOctetAsSpecificExtended) XXX_Size() int { + return xxx_messageInfo_TwoOctetAsSpecificExtended.Size(m) +} +func (m *TwoOctetAsSpecificExtended) XXX_DiscardUnknown() { + xxx_messageInfo_TwoOctetAsSpecificExtended.DiscardUnknown(m) +} + +var xxx_messageInfo_TwoOctetAsSpecificExtended proto.InternalMessageInfo + +func (m *TwoOctetAsSpecificExtended) GetIsTransitive() bool { + if m != nil { + return m.IsTransitive + } + return false +} + +func (m *TwoOctetAsSpecificExtended) GetSubType() uint32 { + if m != nil { + return m.SubType + } + return 0 +} + +func (m *TwoOctetAsSpecificExtended) GetAs() uint32 { + if m != nil { + return m.As + } + return 0 +} + +func (m *TwoOctetAsSpecificExtended) GetLocalAdmin() uint32 { + if m != nil { + return m.LocalAdmin + } + return 0 +} + +type IPv4AddressSpecificExtended struct { + IsTransitive bool `protobuf:"varint,1,opt,name=is_transitive,json=isTransitive,proto3" json:"is_transitive,omitempty"` + SubType uint32 `protobuf:"varint,2,opt,name=sub_type,json=subType,proto3" json:"sub_type,omitempty"` + Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` + LocalAdmin uint32 `protobuf:"varint,4,opt,name=local_admin,json=localAdmin,proto3" json:"local_admin,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IPv4AddressSpecificExtended) Reset() { *m = IPv4AddressSpecificExtended{} } +func (m *IPv4AddressSpecificExtended) String() string { return proto.CompactTextString(m) } +func (*IPv4AddressSpecificExtended) ProtoMessage() {} +func (*IPv4AddressSpecificExtended) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{10} +} + +func (m *IPv4AddressSpecificExtended) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IPv4AddressSpecificExtended.Unmarshal(m, b) +} +func (m *IPv4AddressSpecificExtended) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IPv4AddressSpecificExtended.Marshal(b, m, deterministic) +} +func (m *IPv4AddressSpecificExtended) XXX_Merge(src proto.Message) { + xxx_messageInfo_IPv4AddressSpecificExtended.Merge(m, src) +} +func (m *IPv4AddressSpecificExtended) XXX_Size() int { + return xxx_messageInfo_IPv4AddressSpecificExtended.Size(m) +} +func (m *IPv4AddressSpecificExtended) XXX_DiscardUnknown() { + xxx_messageInfo_IPv4AddressSpecificExtended.DiscardUnknown(m) +} + +var xxx_messageInfo_IPv4AddressSpecificExtended proto.InternalMessageInfo + +func (m *IPv4AddressSpecificExtended) GetIsTransitive() bool { + if m != nil { + return m.IsTransitive + } + return false +} + +func (m *IPv4AddressSpecificExtended) GetSubType() uint32 { + if m != nil { + return m.SubType + } + return 0 +} + +func (m *IPv4AddressSpecificExtended) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *IPv4AddressSpecificExtended) GetLocalAdmin() uint32 { + if m != nil { + return m.LocalAdmin + } + return 0 +} + +type FourOctetAsSpecificExtended struct { + IsTransitive bool `protobuf:"varint,1,opt,name=is_transitive,json=isTransitive,proto3" json:"is_transitive,omitempty"` + SubType uint32 `protobuf:"varint,2,opt,name=sub_type,json=subType,proto3" json:"sub_type,omitempty"` + As uint32 `protobuf:"varint,3,opt,name=as,proto3" json:"as,omitempty"` + LocalAdmin uint32 `protobuf:"varint,4,opt,name=local_admin,json=localAdmin,proto3" json:"local_admin,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FourOctetAsSpecificExtended) Reset() { *m = FourOctetAsSpecificExtended{} } +func (m *FourOctetAsSpecificExtended) String() string { return proto.CompactTextString(m) } +func (*FourOctetAsSpecificExtended) ProtoMessage() {} +func (*FourOctetAsSpecificExtended) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{11} +} + +func (m *FourOctetAsSpecificExtended) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FourOctetAsSpecificExtended.Unmarshal(m, b) +} +func (m *FourOctetAsSpecificExtended) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FourOctetAsSpecificExtended.Marshal(b, m, deterministic) +} +func (m *FourOctetAsSpecificExtended) XXX_Merge(src proto.Message) { + xxx_messageInfo_FourOctetAsSpecificExtended.Merge(m, src) +} +func (m *FourOctetAsSpecificExtended) XXX_Size() int { + return xxx_messageInfo_FourOctetAsSpecificExtended.Size(m) +} +func (m *FourOctetAsSpecificExtended) XXX_DiscardUnknown() { + xxx_messageInfo_FourOctetAsSpecificExtended.DiscardUnknown(m) +} + +var xxx_messageInfo_FourOctetAsSpecificExtended proto.InternalMessageInfo + +func (m *FourOctetAsSpecificExtended) GetIsTransitive() bool { + if m != nil { + return m.IsTransitive + } + return false +} + +func (m *FourOctetAsSpecificExtended) GetSubType() uint32 { + if m != nil { + return m.SubType + } + return 0 +} + +func (m *FourOctetAsSpecificExtended) GetAs() uint32 { + if m != nil { + return m.As + } + return 0 +} + +func (m *FourOctetAsSpecificExtended) GetLocalAdmin() uint32 { + if m != nil { + return m.LocalAdmin + } + return 0 +} + +type Prefix struct { + Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + MaskLength uint32 `protobuf:"varint,2,opt,name=mask_length,json=maskLength,proto3" json:"mask_length,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Prefix) Reset() { *m = Prefix{} } +func (m *Prefix) String() string { return proto.CompactTextString(m) } +func (*Prefix) ProtoMessage() {} +func (*Prefix) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{12} +} + +func (m *Prefix) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Prefix.Unmarshal(m, b) +} +func (m *Prefix) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Prefix.Marshal(b, m, deterministic) +} +func (m *Prefix) XXX_Merge(src proto.Message) { + xxx_messageInfo_Prefix.Merge(m, src) +} +func (m *Prefix) XXX_Size() int { + return xxx_messageInfo_Prefix.Size(m) +} +func (m *Prefix) XXX_DiscardUnknown() { + xxx_messageInfo_Prefix.DiscardUnknown(m) +} + +var xxx_messageInfo_Prefix proto.InternalMessageInfo + +func (m *Prefix) GetAddress() []byte { + if m != nil { + return m.Address + } + return nil +} + +func (m *Prefix) GetMaskLength() uint32 { + if m != nil { + return m.MaskLength + } + return 0 +} + +// RequestVPN call used to request L3 VPN entries, identified by one Route +// Distinguisher which can be one of listed below types, and one or more Route +// Targets. +type RequestVPN struct { + // Route Distinguisher must be one of + // RouteDistinguisherTwoOctetAS, + // RouteDistinguisherIPAddressAS, + // or RouteDistinguisherFourOctetAS. + Rd *any.Any `protobuf:"bytes,1,opt,name=rd,proto3" json:"rd,omitempty"` + // List of the Route Targets. Each must be one of + // TwoOctetAsSpecificExtended, + // IPv4AddressSpecificExtended, + // or FourOctetAsSpecificExtended. + Rt []*any.Any `protobuf:"bytes,2,rep,name=rt,proto3" json:"rt,omitempty"` + // vpn_prefix is L3 VPN prefix which vpn label is requested for. + VpnPrefix *Prefix `protobuf:"bytes,3,opt,name=vpn_prefix,json=vpnPrefix,proto3" json:"vpn_prefix,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RequestVPN) Reset() { *m = RequestVPN{} } +func (m *RequestVPN) String() string { return proto.CompactTextString(m) } +func (*RequestVPN) ProtoMessage() {} +func (*RequestVPN) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{13} +} + +func (m *RequestVPN) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RequestVPN.Unmarshal(m, b) +} +func (m *RequestVPN) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RequestVPN.Marshal(b, m, deterministic) +} +func (m *RequestVPN) XXX_Merge(src proto.Message) { + xxx_messageInfo_RequestVPN.Merge(m, src) +} +func (m *RequestVPN) XXX_Size() int { + return xxx_messageInfo_RequestVPN.Size(m) +} +func (m *RequestVPN) XXX_DiscardUnknown() { + xxx_messageInfo_RequestVPN.DiscardUnknown(m) +} + +var xxx_messageInfo_RequestVPN proto.InternalMessageInfo + +func (m *RequestVPN) GetRd() *any.Any { + if m != nil { + return m.Rd + } + return nil +} + +func (m *RequestVPN) GetRt() []*any.Any { + if m != nil { + return m.Rt + } + return nil +} + +func (m *RequestVPN) GetVpnPrefix() *Prefix { + if m != nil { + return m.VpnPrefix + } + return nil +} + +type ResponseVPNEntry struct { + // Route Distinguisher must be one of + // RouteDistinguisherTwoOctetAS, + // RouteDistinguisherIPAddressAS, + // or RouteDistinguisherFourOctetAS. + Rd *any.Any `protobuf:"bytes,1,opt,name=rd,proto3" json:"rd,omitempty"` + // List of the Route Targets. Each must be one of + // TwoOctetAsSpecificExtended, + // IPv4AddressSpecificExtended, + // or FourOctetAsSpecificExtended. + Rt []*any.Any `protobuf:"bytes,2,rep,name=rt,proto3" json:"rt,omitempty"` + Label uint32 `protobuf:"varint,3,opt,name=label,proto3" json:"label,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ResponseVPNEntry) Reset() { *m = ResponseVPNEntry{} } +func (m *ResponseVPNEntry) String() string { return proto.CompactTextString(m) } +func (*ResponseVPNEntry) ProtoMessage() {} +func (*ResponseVPNEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_f1a937782ebbded5, []int{14} +} + +func (m *ResponseVPNEntry) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ResponseVPNEntry.Unmarshal(m, b) +} +func (m *ResponseVPNEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ResponseVPNEntry.Marshal(b, m, deterministic) +} +func (m *ResponseVPNEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResponseVPNEntry.Merge(m, src) +} +func (m *ResponseVPNEntry) XXX_Size() int { + return xxx_messageInfo_ResponseVPNEntry.Size(m) +} +func (m *ResponseVPNEntry) XXX_DiscardUnknown() { + xxx_messageInfo_ResponseVPNEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_ResponseVPNEntry proto.InternalMessageInfo + +func (m *ResponseVPNEntry) GetRd() *any.Any { + if m != nil { + return m.Rd + } + return nil +} + +func (m *ResponseVPNEntry) GetRt() []*any.Any { + if m != nil { + return m.Rt + } + return nil +} + +func (m *ResponseVPNEntry) GetLabel() uint32 { + if m != nil { + return m.Label + } + return 0 +} + +func init() { + proto.RegisterEnum("apis.EndpointType", EndpointType_name, EndpointType_value) + proto.RegisterEnum("apis.GatewayErrors", GatewayErrors_name, GatewayErrors_value) + proto.RegisterType((*Endpoint)(nil), "apis.endpoint") + proto.RegisterType((*Latency)(nil), "apis.latency") + proto.RegisterType((*QoeParameters)(nil), "apis.qoe_parameters") + proto.RegisterType((*Qoe)(nil), "apis.qoe") + proto.RegisterType((*RequestQoE)(nil), "apis.RequestQoE") + proto.RegisterMapType((map[int32]*Qoe)(nil), "apis.RequestQoE.QoesEntry") + proto.RegisterType((*ResponseQoE)(nil), "apis.ResponseQoE") + proto.RegisterMapType((map[int32]*Qoe)(nil), "apis.ResponseQoE.QoesEntry") + proto.RegisterType((*RouteDistinguisherTwoOctetAS)(nil), "apis.RouteDistinguisherTwoOctetAS") + proto.RegisterType((*RouteDistinguisherIPAddress)(nil), "apis.RouteDistinguisherIPAddress") + proto.RegisterType((*RouteDistinguisherFourOctetAS)(nil), "apis.RouteDistinguisherFourOctetAS") + proto.RegisterType((*TwoOctetAsSpecificExtended)(nil), "apis.TwoOctetAsSpecificExtended") + proto.RegisterType((*IPv4AddressSpecificExtended)(nil), "apis.IPv4AddressSpecificExtended") + proto.RegisterType((*FourOctetAsSpecificExtended)(nil), "apis.FourOctetAsSpecificExtended") + proto.RegisterType((*Prefix)(nil), "apis.Prefix") + proto.RegisterType((*RequestVPN)(nil), "apis.RequestVPN") + proto.RegisterType((*ResponseVPNEntry)(nil), "apis.ResponseVPNEntry") +} + +func init() { proto.RegisterFile("gateway.proto", fileDescriptor_f1a937782ebbded5) } + +var fileDescriptor_f1a937782ebbded5 = []byte{ + // 827 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0x5d, 0x6f, 0x23, 0x35, + 0x14, 0xdd, 0x99, 0x49, 0x9a, 0xe4, 0xa6, 0x13, 0x0d, 0xa6, 0x42, 0xd9, 0x74, 0xd1, 0x46, 0xc3, + 0x57, 0x55, 0xa4, 0x14, 0xca, 0x0a, 0x2d, 0x48, 0x3c, 0x14, 0x3a, 0x40, 0xd8, 0x25, 0x49, 0x9d, + 0x6c, 0x79, 0x8c, 0x9c, 0x8c, 0x9b, 0xb5, 0x36, 0xb5, 0xa7, 0xb6, 0x93, 0xdd, 0xbc, 0x21, 0x24, + 0x1e, 0xe1, 0x99, 0x5f, 0xc1, 0x6f, 0x44, 0xb6, 0x67, 0xa6, 0x0d, 0x45, 0x80, 0x50, 0x91, 0xf6, + 0x6d, 0xee, 0xf5, 0xf1, 0xf1, 0xf1, 0x71, 0xee, 0x09, 0x84, 0x0b, 0xa2, 0xe9, 0x4b, 0xb2, 0xe9, + 0x65, 0x52, 0x68, 0x81, 0x2a, 0x24, 0x63, 0xaa, 0x73, 0x7f, 0x21, 0xc4, 0x62, 0x49, 0x8f, 0x6c, + 0x6f, 0xb6, 0xba, 0x38, 0x22, 0x3c, 0x07, 0xc4, 0x4f, 0xa1, 0x4e, 0x79, 0x9a, 0x09, 0xc6, 0x35, + 0x7a, 0x1f, 0x2a, 0x7a, 0x93, 0xd1, 0xb6, 0xd7, 0xf5, 0x0e, 0x5a, 0xc7, 0xa8, 0x67, 0xf6, 0xf6, + 0x92, 0x7c, 0x75, 0xb2, 0xc9, 0x28, 0xb6, 0xeb, 0xa8, 0x0d, 0x35, 0x92, 0xa6, 0x92, 0x2a, 0xd5, + 0xf6, 0xbb, 0xde, 0xc1, 0x2e, 0x2e, 0xca, 0xf8, 0x0b, 0xa8, 0x2d, 0x89, 0xa6, 0x7c, 0xbe, 0x41, + 0x7b, 0x50, 0x5d, 0x93, 0xe5, 0xca, 0xb1, 0x55, 0xb1, 0x2b, 0xd0, 0x03, 0x68, 0xac, 0x89, 0x64, + 0x44, 0x33, 0xc1, 0xed, 0xe6, 0x2a, 0xbe, 0x6e, 0xc4, 0x9f, 0x41, 0xeb, 0x4a, 0xd0, 0x69, 0x46, + 0x24, 0xb9, 0xa4, 0x9a, 0x4a, 0x85, 0x3e, 0x28, 0x09, 0x2d, 0x4f, 0xf3, 0x38, 0x74, 0xaa, 0xf2, + 0x26, 0x2e, 0x56, 0xe3, 0xdf, 0x3d, 0x08, 0xae, 0x04, 0x45, 0x5d, 0x08, 0x94, 0x9c, 0xe7, 0xe0, + 0x96, 0x03, 0x17, 0x17, 0xc4, 0x66, 0xc9, 0x20, 0x52, 0xa5, 0xed, 0xe1, 0x7f, 0x81, 0x48, 0x95, + 0xf1, 0xc1, 0x50, 0xb5, 0x03, 0x8b, 0xd8, 0x73, 0x88, 0x6d, 0x5d, 0xd8, 0x9e, 0xb5, 0x07, 0xd5, + 0x25, 0x99, 0xd1, 0x65, 0xbb, 0xd2, 0x0d, 0x0e, 0x42, 0xec, 0x0a, 0xf4, 0x1e, 0x04, 0x54, 0xca, + 0x76, 0xd5, 0x9a, 0xf8, 0xa6, 0xdb, 0xfd, 0x8d, 0x7b, 0x94, 0x44, 0x4a, 0x61, 0x36, 0x53, 0x29, + 0xe3, 0x1f, 0x3d, 0x00, 0x4c, 0xaf, 0x56, 0x54, 0xe9, 0x33, 0x91, 0xa0, 0x1e, 0x54, 0xae, 0x04, + 0x55, 0x6d, 0xaf, 0x1b, 0x1c, 0x34, 0x8f, 0x3b, 0x6e, 0xdb, 0xf5, 0x7a, 0xef, 0x4c, 0x50, 0x95, + 0x70, 0x2d, 0x37, 0xd8, 0xe2, 0x3a, 0x5f, 0x42, 0xa3, 0x6c, 0xa1, 0x08, 0x82, 0x17, 0x74, 0x93, + 0x3b, 0x6d, 0x3e, 0xd1, 0xc3, 0xc2, 0x7d, 0x77, 0xcd, 0x46, 0x79, 0x89, 0xfc, 0x21, 0x3e, 0xf7, + 0x1f, 0x7b, 0xf1, 0x4f, 0x1e, 0x34, 0x31, 0x55, 0x99, 0xe0, 0x8a, 0x1a, 0x0d, 0x47, 0x5b, 0x1a, + 0xf6, 0x0b, 0x0d, 0x25, 0xe0, 0x7f, 0x11, 0x31, 0x82, 0x07, 0x58, 0xac, 0x34, 0x3d, 0x65, 0x4a, + 0x33, 0xbe, 0x58, 0x31, 0xf5, 0x9c, 0xca, 0xc9, 0x4b, 0x31, 0x9c, 0x6b, 0xaa, 0x4f, 0xc6, 0xc6, + 0x64, 0x92, 0x5e, 0x32, 0x6e, 0x89, 0x43, 0xec, 0x0a, 0xd4, 0x81, 0x3a, 0x51, 0x8a, 0x2d, 0x38, + 0x4d, 0x2d, 0x7b, 0x88, 0xcb, 0x3a, 0x1e, 0xc2, 0xfe, 0x6d, 0xc6, 0xfe, 0xe8, 0xc4, 0xfd, 0x46, + 0xb7, 0x09, 0x1b, 0xff, 0x86, 0xf0, 0x0c, 0xde, 0xbe, 0x4d, 0xf8, 0xb5, 0x58, 0xc9, 0xff, 0xae, + 0xf1, 0x17, 0x0f, 0x3a, 0xe5, 0x25, 0xd5, 0x38, 0xa3, 0x73, 0x76, 0xc1, 0xe6, 0xc9, 0x2b, 0x4d, + 0x79, 0x4a, 0x53, 0xf4, 0x0e, 0x84, 0x4c, 0x4d, 0xb5, 0x24, 0x5c, 0x31, 0xcd, 0xd6, 0x6e, 0x88, + 0xea, 0x78, 0x97, 0xa9, 0x49, 0xd9, 0x43, 0xf7, 0xa1, 0xae, 0x56, 0xb3, 0xa9, 0x1d, 0x59, 0xc7, + 0x5f, 0x53, 0xab, 0x99, 0x99, 0x53, 0xd4, 0x02, 0x9f, 0x28, 0xfb, 0x03, 0x0e, 0xb1, 0x4f, 0x14, + 0x7a, 0x08, 0xcd, 0xa5, 0x98, 0x93, 0xe5, 0xd4, 0xc9, 0xac, 0xd8, 0x05, 0xb0, 0xad, 0x13, 0xd3, + 0x89, 0x7f, 0xf3, 0x60, 0xbf, 0x3f, 0x5a, 0x3f, 0xca, 0x4d, 0xba, 0x73, 0x41, 0x37, 0x22, 0x23, + 0xb0, 0xb6, 0x17, 0xe5, 0x3f, 0x4b, 0xfb, 0xd5, 0x83, 0xfd, 0x6b, 0xb3, 0x5f, 0x03, 0xaf, 0xbe, + 0x82, 0x9d, 0x91, 0xa4, 0x17, 0xec, 0xd5, 0xcd, 0x5b, 0x79, 0x5b, 0x41, 0x68, 0x48, 0x2e, 0x89, + 0x7a, 0x31, 0x5d, 0x52, 0xbe, 0xd0, 0xcf, 0xf3, 0x23, 0xc1, 0xb4, 0x9e, 0xda, 0x4e, 0xfc, 0xf3, + 0xf5, 0xf8, 0x9f, 0x8f, 0x06, 0xe8, 0x5d, 0xf0, 0x65, 0x9a, 0xa7, 0xd6, 0x5e, 0xcf, 0xc5, 0x75, + 0xaf, 0x88, 0xeb, 0xde, 0x09, 0xdf, 0x60, 0x5f, 0xa6, 0x16, 0x65, 0x92, 0x2b, 0xf8, 0x1b, 0x94, + 0x46, 0x1f, 0x02, 0xac, 0x33, 0x3e, 0xcd, 0xac, 0xc6, 0x3c, 0xc5, 0x76, 0xdd, 0xec, 0x39, 0xdd, + 0xb8, 0xb1, 0xce, 0xb8, 0xfb, 0x8c, 0x35, 0x44, 0xc5, 0x84, 0x9f, 0x8f, 0x06, 0x6e, 0x92, 0xef, + 0x52, 0x4c, 0x99, 0x91, 0xce, 0x60, 0x57, 0x1c, 0x3e, 0x86, 0xdd, 0x9b, 0xff, 0x2b, 0xa8, 0x09, + 0xb5, 0x67, 0x83, 0x27, 0x83, 0xe1, 0x0f, 0x83, 0xe8, 0x1e, 0xaa, 0x43, 0xa5, 0x3f, 0x3a, 0x7f, + 0x14, 0x79, 0xf9, 0xd7, 0xa7, 0x91, 0x8f, 0x6a, 0x10, 0x8c, 0xfb, 0xa7, 0x51, 0x70, 0xf8, 0x1d, + 0x84, 0x5b, 0x61, 0x8a, 0x76, 0xc0, 0x1f, 0x3e, 0x89, 0xee, 0x19, 0x44, 0xd2, 0x1f, 0x46, 0x1e, + 0x02, 0xd8, 0x49, 0x06, 0xc3, 0x64, 0x30, 0x89, 0x7c, 0x14, 0x42, 0x23, 0x99, 0xf4, 0xbf, 0x4f, + 0x4e, 0x87, 0xcf, 0x26, 0x51, 0x60, 0xcb, 0x6f, 0x87, 0xe3, 0xc9, 0xa9, 0x39, 0xa8, 0x72, 0x2c, + 0xa0, 0x95, 0x73, 0x8d, 0xa9, 0x5c, 0xb3, 0x39, 0x45, 0x87, 0x10, 0x98, 0x20, 0x8c, 0xfe, 0x1c, + 0xbf, 0x9d, 0x37, 0x6e, 0x85, 0x21, 0xfa, 0x18, 0x02, 0xf3, 0x72, 0xdb, 0xd8, 0xf3, 0xd1, 0xa0, + 0xf3, 0xd6, 0x36, 0xb6, 0xb0, 0xf5, 0x23, 0x6f, 0xb6, 0x63, 0xed, 0xf9, 0xe4, 0x8f, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x23, 0x51, 0xb2, 0x66, 0xa5, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// GatewayServiceClient is the client API for GatewayService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type GatewayServiceClient interface { + // API to request specified Quality of Experience + QoE(ctx context.Context, in *RequestQoE, opts ...grpc.CallOption) (*ResponseQoE, error) + // API to request L3 VPN label for specified VRF, identified by Route + // Distinguisher + VPN(ctx context.Context, in *RequestVPN, opts ...grpc.CallOption) (GatewayService_VPNClient, error) +} + +type gatewayServiceClient struct { + cc *grpc.ClientConn +} + +func NewGatewayServiceClient(cc *grpc.ClientConn) GatewayServiceClient { + return &gatewayServiceClient{cc} +} + +func (c *gatewayServiceClient) QoE(ctx context.Context, in *RequestQoE, opts ...grpc.CallOption) (*ResponseQoE, error) { + out := new(ResponseQoE) + err := c.cc.Invoke(ctx, "/apis.GatewayService/QoE", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *gatewayServiceClient) VPN(ctx context.Context, in *RequestVPN, opts ...grpc.CallOption) (GatewayService_VPNClient, error) { + stream, err := c.cc.NewStream(ctx, &_GatewayService_serviceDesc.Streams[0], "/apis.GatewayService/VPN", opts...) + if err != nil { + return nil, err + } + x := &gatewayServiceVPNClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type GatewayService_VPNClient interface { + Recv() (*ResponseVPNEntry, error) + grpc.ClientStream +} + +type gatewayServiceVPNClient struct { + grpc.ClientStream +} + +func (x *gatewayServiceVPNClient) Recv() (*ResponseVPNEntry, error) { + m := new(ResponseVPNEntry) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// GatewayServiceServer is the server API for GatewayService service. +type GatewayServiceServer interface { + // API to request specified Quality of Experience + QoE(context.Context, *RequestQoE) (*ResponseQoE, error) + // API to request L3 VPN label for specified VRF, identified by Route + // Distinguisher + VPN(*RequestVPN, GatewayService_VPNServer) error +} + +// UnimplementedGatewayServiceServer can be embedded to have forward compatible implementations. +type UnimplementedGatewayServiceServer struct { +} + +func (*UnimplementedGatewayServiceServer) QoE(ctx context.Context, req *RequestQoE) (*ResponseQoE, error) { + return nil, status.Errorf(codes.Unimplemented, "method QoE not implemented") +} +func (*UnimplementedGatewayServiceServer) VPN(req *RequestVPN, srv GatewayService_VPNServer) error { + return status.Errorf(codes.Unimplemented, "method VPN not implemented") +} + +func RegisterGatewayServiceServer(s *grpc.Server, srv GatewayServiceServer) { + s.RegisterService(&_GatewayService_serviceDesc, srv) +} + +func _GatewayService_QoE_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RequestQoE) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GatewayServiceServer).QoE(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apis.GatewayService/QoE", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GatewayServiceServer).QoE(ctx, req.(*RequestQoE)) + } + return interceptor(ctx, in, info, handler) +} + +func _GatewayService_VPN_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(RequestVPN) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(GatewayServiceServer).VPN(m, &gatewayServiceVPNServer{stream}) +} + +type GatewayService_VPNServer interface { + Send(*ResponseVPNEntry) error + grpc.ServerStream +} + +type gatewayServiceVPNServer struct { + grpc.ServerStream +} + +func (x *gatewayServiceVPNServer) Send(m *ResponseVPNEntry) error { + return x.ServerStream.SendMsg(m) +} + +var _GatewayService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "apis.GatewayService", + HandlerType: (*GatewayServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "QoE", + Handler: _GatewayService_QoE_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "VPN", + Handler: _GatewayService_VPN_Handler, + ServerStreams: true, + }, + }, + Metadata: "gateway.proto", +} diff --git a/pkg/apis/gateway.proto b/pkg/apis/gateway.proto new file mode 100644 index 0000000..1aaabba --- /dev/null +++ b/pkg/apis/gateway.proto @@ -0,0 +1,138 @@ +syntax = "proto3"; + +import "google/protobuf/any.proto"; + +package apis; + +// EndpointType defines supported endpoints' types +enum EndpointType { + UNKNOWN = 0; + IPV4 = 1; + IPV6 = 2; + SID = 3; +} + +// Errors defines error codes which a gateway can return to a client +enum GatewayErrors { + OK = 0; + // Returned when a gateway encountered a generic error + EIO = 1; + // Returned when request key does not exist + ENOENT = 2; + // Returned when an operation triggered by the client's requested timed out + // and was canceled + ETIMEDOUT = 3; + // Returned when a gateway cannot reach a DB host + EHOSTDOWN = 4; +} +// endpoint is an object defining a source or a destination of a communication +// path. The type of the endpoint is defined by EndpointType, it can be ipv4, +// ipv6 addresses or segment routing SIDs etc. The list of supported endpoint +// types may be extended in future. The address of endpoint is stored in a slice +// of bytes and should be decoded according to the endpoint type. +message endpoint { + EndpointType type = 1; + bytes address = 2; +} +// latency defines one of available QoE metrics +// value expresses latency value in milliseconds. +// variation expresses percent of the acceptable variation from value. +message latency { + int32 value = 1; + int32 variation = 2; +} +// qoe_parameters defines a list of QoE parameters a client can request. +// Currently only latency is supported. +message qoe_parameters { latency latency = 1; } +message qoe { + endpoint src = 1; + endpoint dst = 2; + qoe_parameters qoe = 3; + repeated uint32 label = 4; + GatewayErrors err = 5; +} +// RequestQoE defines the rpc message sent by the client to the gateway. +// Multiple Src/Dst/QoE are supported in a single request. +message RequestQoE { map qoes = 1; } +// ResponseQoE defines the rpc message sent as a reply to the client. +// it is the same message as request, but the gateway populates labels and +// err for each qoe. +message ResponseQoE { map qoes = 1; } + +message RouteDistinguisherTwoOctetAS { + uint32 admin = 1; + uint32 assigned = 2; +} +message RouteDistinguisherIPAddress { + string admin = 1; + uint32 assigned = 2; +} +message RouteDistinguisherFourOctetAS { + uint32 admin = 1; + uint32 assigned = 2; +} +message TwoOctetAsSpecificExtended { + bool is_transitive = 1; + uint32 sub_type = 2; + uint32 as = 3; + uint32 local_admin = 4; +} + +message IPv4AddressSpecificExtended { + bool is_transitive = 1; + uint32 sub_type = 2; + string address = 3; + uint32 local_admin = 4; +} + +message FourOctetAsSpecificExtended { + bool is_transitive = 1; + uint32 sub_type = 2; + uint32 as = 3; + uint32 local_admin = 4; +} + +message Prefix { + bytes address = 1; + uint32 mask_length = 2; +} +// RequestVPN call used to request L3 VPN entries, identified by one Route +// Distinguisher which can be one of listed below types, and one or more Route +// Targets. +message RequestVPN { + // Route Distinguisher must be one of + // RouteDistinguisherTwoOctetAS, + // RouteDistinguisherIPAddressAS, + // or RouteDistinguisherFourOctetAS. + google.protobuf.Any rd = 1; + // List of the Route Targets. Each must be one of + // TwoOctetAsSpecificExtended, + // IPv4AddressSpecificExtended, + // or FourOctetAsSpecificExtended. + repeated google.protobuf.Any rt = 2; + // vpn_prefix is L3 VPN prefix which vpn label is requested for. + Prefix vpn_prefix = 3; +} + +message ResponseVPNEntry { + // Route Distinguisher must be one of + // RouteDistinguisherTwoOctetAS, + // RouteDistinguisherIPAddressAS, + // or RouteDistinguisherFourOctetAS. + google.protobuf.Any rd = 1; + // List of the Route Targets. Each must be one of + // TwoOctetAsSpecificExtended, + // IPv4AddressSpecificExtended, + // or FourOctetAsSpecificExtended. + repeated google.protobuf.Any rt = 2; + uint32 label = 3; +} + +// GatewayService lists rpc services supported by the gateway api +service GatewayService { + // API to request specified Quality of Experience + rpc QoE(RequestQoE) returns (ResponseQoE); + // API to request L3 VPN label for specified VRF, identified by Route + // Distinguisher + rpc VPN(RequestVPN) returns (stream ResponseVPNEntry); +} \ No newline at end of file diff --git a/pkg/apis/go.mod b/pkg/apis/go.mod new file mode 100644 index 0000000..2240b03 --- /dev/null +++ b/pkg/apis/go.mod @@ -0,0 +1,3 @@ +module github.com/cisco-ie/jalapeno-go-gateway/pkg/apis + +go 1.13 diff --git a/pkg/bgpclient/bgpclient.go b/pkg/bgpclient/bgpclient.go new file mode 100644 index 0000000..7b5e769 --- /dev/null +++ b/pkg/bgpclient/bgpclient.go @@ -0,0 +1,303 @@ +package bgpclient + +import ( + "context" + "fmt" + "io" + + pbapi "github.com/cisco-ie/jalapeno-go-gateway/pkg/apis" + "github.com/gogo/protobuf/proto" + "github.com/golang/glog" + "github.com/golang/protobuf/ptypes" + "github.com/golang/protobuf/ptypes/any" + api "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/pkg/packet/bgp" + "google.golang.org/grpc" +) + +type VPNRequest struct { + RD bgp.RouteDistinguisherInterface + RT []bgp.ExtendedCommunityInterface +} + +// VPNReply carries values of labels along with corresponding to the label RD and RTs +type VPNReply struct { + RD bgp.RouteDistinguisherInterface + RT []bgp.ExtendedCommunityInterface + Label uint32 +} + +// BGPClient defines the interface for communication with gobgpd process +type BGPClient interface { + GetPrefix() error + AddPrefix() error +} + +type bgpclient struct { + conn *grpc.ClientConn + bgp api.GobgpApiClient +} + +// NewBGPClient creates a new instance of BGP client, addr variable carries +// the address of gobgp process, it could in ip:port or dns-name:port formats. +func NewBGPClient(addr string) (BGPClient, error) { + conn, err := grpc.DialContext(context.TODO(), addr, grpc.WithInsecure()) + if err != nil { + return nil, err + } + client := api.NewGobgpApiClient(conn) + // Testing connection to gobgp by requesting its global config + if _, err := client.GetBgp(context.TODO(), &api.GetBgpRequest{}); err != nil { + return nil, err + } + return &bgpclient{ + conn: conn, + bgp: client, + }, nil +} + +func (c *bgpclient) Stop() { + c.conn.Close() +} + +// NewVPNRequest creates VPNRequest struct and populates its fields with information +// came in gRPC request. +func NewVPNRequest(reqVPN *pbapi.RequestVPN) (*VPNRequest, error) { + var err error + vpnRequest := VPNRequest{} + // Processing RD found in the VPN request + if vpnRequest.RD, err = UnmarshalRD(reqVPN.Rd); err != nil { + return nil, err + } + // Processing all RTs found in VPN reuqest + if vpnRequest.RT, err = UnmarshalRT(reqVPN.Rt); err != nil { + return nil, err + } + glog.V(5).Infof("vpn request RD: %+v RT: %+v", vpnRequest.RD, vpnRequest.RT) + + return &vpnRequest, nil +} + +// NewVPNReply creates pbapi.ResponseVPNEntry struct and populates its fields with information +// came in VPNReply. +func NewVPNReply(repl *VPNReply) (*pbapi.ResponseVPNEntry, error) { + gRepl := pbapi.ResponseVPNEntry{ + Label: repl.Label, + } + // Marshalling RD from VPNReply + gRepl.Rd = MarshalRD(repl.RD) + // Marshalling RTs from VPNReply + gRepl.Rt = append(gRepl.Rt, MarshalRTs(repl.RT)...) + + return &gRepl, nil +} + +func UnmarshalRD(rd *any.Any) (bgp.RouteDistinguisherInterface, error) { + var rdValue ptypes.DynamicAny + if err := ptypes.UnmarshalAny(rd, &rdValue); err != nil { + return nil, fmt.Errorf("failed to unmarshal route distinguisher with error: %+v", err) + } + + switch v := rdValue.Message.(type) { + case *api.RouteDistinguisherTwoOctetAS: + return bgp.NewRouteDistinguisherTwoOctetAS(uint16(v.Admin), v.Assigned), nil + case *api.RouteDistinguisherIPAddress: + return bgp.NewRouteDistinguisherIPAddressAS(v.Admin, uint16(v.Assigned)), nil + case *api.RouteDistinguisherFourOctetAS: + return bgp.NewRouteDistinguisherFourOctetAS(v.Admin, uint16(v.Assigned)), nil + default: + return nil, fmt.Errorf("Unknown route distinguisher type: %+v", v) + } +} + +func UnmarshalRT(rts []*any.Any) ([]bgp.ExtendedCommunityInterface, error) { + repl := make([]bgp.ExtendedCommunityInterface, 0) + for i := 0; i < len(rts); i++ { + var rtValue ptypes.DynamicAny + if err := ptypes.UnmarshalAny(rts[i], &rtValue); err != nil { + return nil, fmt.Errorf("failed to unmarshal route target with error: %+v", err) + } + switch v := rtValue.Message.(type) { + case *api.TwoOctetAsSpecificExtended: + repl = append(repl, bgp.NewTwoOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), uint16(v.As), v.LocalAdmin, v.IsTransitive)) + case *api.IPv4AddressSpecificExtended: + repl = append(repl, bgp.NewIPv4AddressSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.Address, uint16(v.LocalAdmin), v.IsTransitive)) + case *api.FourOctetAsSpecificExtended: + repl = append(repl, bgp.NewFourOctetAsSpecificExtended(bgp.ExtendedCommunityAttrSubType(v.SubType), v.As, uint16(v.LocalAdmin), v.IsTransitive)) + default: + return nil, fmt.Errorf("Unknown route target type: %+v", v) + } + } + + return repl, nil +} + +func MarshalRD(rd bgp.RouteDistinguisherInterface) *any.Any { + var r proto.Message + switch v := rd.(type) { + case *bgp.RouteDistinguisherTwoOctetAS: + glog.Infof("Admin: %+v Assigned: %+v", v.Admin, v.Assigned) + r = &api.RouteDistinguisherTwoOctetAS{ + Admin: uint32(v.Admin), + Assigned: v.Assigned, + } + case *bgp.RouteDistinguisherIPAddressAS: + glog.Infof("Admin: %+v Assigned: %+v", v.Admin, v.Assigned) + r = &api.RouteDistinguisherIPAddress{ + Admin: v.Admin.String(), + Assigned: uint32(v.Assigned), + } + case *bgp.RouteDistinguisherFourOctetAS: + glog.Infof("Admin: %+v Assigned: %+v", v.Admin, v.Assigned) + r = &api.RouteDistinguisherFourOctetAS{ + Admin: v.Admin, + Assigned: uint32(v.Assigned), + } + default: + glog.Infof("Unknown type: %+v", v) + return nil + } + a, _ := ptypes.MarshalAny(r) + return a +} + +func MarshalRT(rt bgp.ExtendedCommunityInterface) *any.Any { + var r proto.Message + switch v := rt.(type) { + case *bgp.TwoOctetAsSpecificExtended: + r = &api.TwoOctetAsSpecificExtended{ + IsTransitive: true, + SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET), + As: uint32(v.AS), + LocalAdmin: uint32(v.LocalAdmin), + } + case *bgp.IPv4AddressSpecificExtended: + r = &api.IPv4AddressSpecificExtended{ + IsTransitive: true, + SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET), + Address: v.IPv4.String(), + LocalAdmin: uint32(v.LocalAdmin), + } + case *bgp.FourOctetAsSpecificExtended: + r = &api.FourOctetAsSpecificExtended{ + IsTransitive: true, + SubType: uint32(bgp.EC_SUBTYPE_ROUTE_TARGET), + As: uint32(v.AS), + LocalAdmin: uint32(v.LocalAdmin), + } + + default: + glog.Infof("Marshal RT Unknown type: %+v", v) + return nil + } + a, _ := ptypes.MarshalAny(r) + return a +} + +func MarshalRTs(rts []bgp.ExtendedCommunityInterface) []*any.Any { + a := make([]*any.Any, len(rts)) + for i := 0; i < len(rts); i++ { + a[i] = MarshalRT(rts[i]) + } + + return a +} + +func (c *bgpclient) GetPrefix() error { + return c.getPrefix() +} + +func (c *bgpclient) getPrefix() error { + list, err := c.bgp.ListPath(context.TODO(), &api.ListPathRequest{ + TableType: api.TableType_GLOBAL, + Family: &api.Family{Afi: api.Family_AFI_IP, Safi: api.Family_SAFI_UNICAST}, + Prefixes: []*api.TableLookupPrefix{ + { + Prefix: "2.2.2.2/32", + LookupOption: api.TableLookupOption_LOOKUP_EXACT, + }, + }, + }) + if err != nil { + return err + } + for { + entry, err := list.Recv() + if err == io.EOF { + glog.Info("Received EOF message.") + return nil + } + if err != nil { + glog.Errorf("failed to receive a message from the stream with error: %+v", err) + return err + } + + if entry != nil { + glog.Infof("Received message: %+v", *entry.Destination) + } else { + glog.Info("Received empty message.") + } + } +} + +func (c *bgpclient) AddPrefix() error { + return c.addPrefix() +} + +func (c *bgpclient) addPrefix() error { + rd := bgp.NewRouteDistinguisherTwoOctetAS(577, 65002) + nlrivpn, _ := ptypes.MarshalAny(&api.LabeledVPNIPAddressPrefix{ + Labels: []uint32{2000}, + Rd: MarshalRD(rd), + PrefixLen: 32, + Prefix: "5.5.5.5", + }) + + a1, _ := ptypes.MarshalAny(&api.OriginAttribute{ + Origin: 0, + }) + a2, _ := ptypes.MarshalAny(&api.NextHopAttribute{ + NextHop: "9.9.9.9", + }) + a3, _ := ptypes.MarshalAny(&api.ExtendedCommunitiesAttribute{ + Communities: []*any.Any{MarshalRT(bgp.NewTwoOctetAsSpecificExtended(bgp.EC_SUBTYPE_ROUTE_TARGET, 577, 65002, false))}, + }) + attrs := []*any.Any{a1, a2, a3} + _, err := c.bgp.AddPath(context.TODO(), &api.AddPathRequest{ + TableType: api.TableType_GLOBAL, + Path: &api.Path{ + Nlri: nlrivpn, + Pattrs: attrs, + Family: &api.Family{Afi: api.Family_AFI_IP, Safi: api.Family_SAFI_MPLS_VPN}, + Best: true, + SourceAsn: 65070, + }, + }) + if err != nil { + return err + } + + nlrilu, _ := ptypes.MarshalAny(&api.LabeledIPAddressPrefix{ + Labels: []uint32{3000}, + PrefixLen: 32, + Prefix: "9.9.9.9", + }) + a2, _ = ptypes.MarshalAny(&api.NextHopAttribute{ + NextHop: "10.0.0.1", + }) + attrs = []*any.Any{a1, a2} + _, err = c.bgp.AddPath(context.TODO(), &api.AddPathRequest{ + TableType: api.TableType_GLOBAL, + Path: &api.Path{ + Nlri: nlrilu, + Pattrs: attrs, + Family: &api.Family{Afi: api.Family_AFI_IP, Safi: api.Family_SAFI_MPLS_LABEL}, + Best: true, + }, + }) + if err != nil { + return err + } + + return nil +} diff --git a/pkg/bgpclient/go.mod b/pkg/bgpclient/go.mod new file mode 100644 index 0000000..87624e0 --- /dev/null +++ b/pkg/bgpclient/go.mod @@ -0,0 +1,3 @@ +module github.com/cisco-ie/jalapeno-go-gateway/pkg/bgplient + +go 1.13 diff --git a/pkg/dbclient/dbclient.go b/pkg/dbclient/dbclient.go new file mode 100644 index 0000000..195c8f3 --- /dev/null +++ b/pkg/dbclient/dbclient.go @@ -0,0 +1,110 @@ +package dbclient + +import ( + "context" + "sync" + "time" + + pbapi "github.com/cisco-ie/jalapeno-go-gateway/pkg/apis" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient" + "github.com/golang/glog" +) + +var ( + // maxDBRequestTimeout defines a maximum wait time for db worker to retrieve QoE information + maxDBRequestTimeout = time.Millisecond * 2000 +) + +// DB defines methods to access database +type DB interface { + GetQoE(context.Context, *pbapi.Qoe, chan *pbapi.Qoe) + GetVPN(context.Context, *bgpclient.VPNRequest, chan *bgpclient.VPNReply) +} + +// DBClient defines public method for gRPC server to handle QoE related requests +type DBClient interface { + GetQoE(context.Context, *pbapi.RequestQoE, chan *pbapi.ResponseQoE) + GetVPN(context.Context, *bgpclient.VPNRequest, chan *bgpclient.VPNReply) +} + +// dbClient defines the database client, it stores the databse interface, +// the database interface can be either a real database or a mock database used in unit testing. +type dbClient struct { + db DB +} + +// GetVPN defines a function to request from DB VPN label based on RD and RTs passed by the client. +func (dbc *dbClient) GetVPN(ctx context.Context, req *bgpclient.VPNRequest, result chan *bgpclient.VPNReply) { + glog.V(5).Infof("DB Client received request for RD: %+v RT: %+v", req.RD, req.RT) + // Initializing reply + var repl *bgpclient.VPNReply + ch := make(chan *bgpclient.VPNReply) + // Starting DB's Get as a go routine and wait either for a result + // received from ch channel or a context timeout event. + go dbc.db.GetVPN(ctx, req, ch) + // Wait for all go routine either to complete or the context to timeout + for { + select { + case repl = <-ch: + result <- repl + if repl != nil && repl.RD != nil { + glog.V(5).Infof("Data store returned RD: %+v RT: %+v Label: %d", repl.RD, repl.RT, repl.Label) + } else { + glog.V(5).Infof("Data store returned nil") + } + return + case <-ctx.Done(): + // Context was canceled, returning to prevent go routine leaking. + result <- &bgpclient.VPNReply{} + glog.V(5).Infof("Data store returned error: %+v ", ctx.Err()) + return + } + } +} + +// GetQoE is function called by gRPC client to retrieve QoE related information from the database. +// The request can carry multiple QoE entries. FOr each entry a go routine function is invoked +// which calls DB interface Get. +func (dbc *dbClient) GetQoE(ctx context.Context, reqQoes *pbapi.RequestQoE, result chan *pbapi.ResponseQoE) { + // Initializing reply + replQoEs := pbapi.ResponseQoE{} + replQoEs.Qoes = make(map[int32]*pbapi.Qoe) + // Wait group will be used to wait until all workers are done + // In case worker hangs, grpc client's context will destroy it when + // timeout expires. + var wg sync.WaitGroup + for i, req := range reqQoes.Qoes { + wg.Add(1) + go func(ctx context.Context, i int32, req *pbapi.Qoe) { + defer wg.Done() + // Make channel for DB's Get method to return found data + ch := make(chan *pbapi.Qoe) + // Starting DB's Get as a go routine and wait either for a result + // received from ch channel or a context timeout event. + go dbc.db.GetQoE(ctx, req, ch) + for { + select { + case repl := <-ch: + // Result received, storing it in the reply map with the right key + replQoEs.Qoes[i] = repl + return + case <-ctx.Done(): + // Context was canceled, returning to prevent go routine leaking. + return + } + } + + }(ctx, i, req) + } + // Wait for all go routine either to complete or the context to timeout + wg.Wait() + glog.V(5).Infof("Sending %d QoE back to gRPC server", len(replQoEs.Qoes)) + result <- &replQoEs +} + +// NewDBClient return a new instance of a DB client +func NewDBClient(db DB) DBClient { + return &dbClient{ + db: db, + } +} diff --git a/pkg/dbclient/go.mod b/pkg/dbclient/go.mod new file mode 100644 index 0000000..70facd6 --- /dev/null +++ b/pkg/dbclient/go.mod @@ -0,0 +1,11 @@ +module github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient + +go 1.13 + +require ( + github.com/cisco-ie/jalapeno-go-gateway/pkg/apis v0.0.0-00010101000000-000000000000 + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b + google.golang.org/grpc v1.26.0 +) + +replace github.com/cisco-ie/jalapeno-go-gateway/pkg/apis => ../apis \ No newline at end of file diff --git a/pkg/dbclient/mock/dbmock.go b/pkg/dbclient/mock/dbmock.go new file mode 100644 index 0000000..bf9ef64 --- /dev/null +++ b/pkg/dbclient/mock/dbmock.go @@ -0,0 +1,213 @@ +package mock + +import ( + "bytes" + "context" + "net" + "sync" + "time" + + pbapi "github.com/cisco-ie/jalapeno-go-gateway/pkg/apis" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient" + "github.com/golang/glog" + "github.com/osrg/gobgp/pkg/packet/bgp" +) + +var ( + // maxDBRequestTimeout defines a maximum wait time for db worker to retrieve QoE information + maxDBRequestTimeout = time.Millisecond * 2000 +) + +type labelInfo struct { + label uint32 + rt []bgp.ExtendedCommunityInterface +} +type dbMock struct { + mu sync.Mutex + qoe map[int32]*pbapi.Qoe + vpn map[string]labelInfo +} + +func (db *dbMock) GetVPN(ctx context.Context, r *bgpclient.VPNRequest, ch chan *bgpclient.VPNReply) { + glog.V(5).Infof("Mocked Data Store received request for RD: %+v RT: %+v", r.RD.String(), r.RT) + var repl *bgpclient.VPNReply + db.mu.Lock() + defer db.mu.Unlock() + + li, ok := db.vpn[r.RD.String()] + if !ok { + ch <- &bgpclient.VPNReply{} + glog.V(5).Infof("Mocked Data Store did not find requested RD: %+v", r.RD.String()) + return + } + repl = &bgpclient.VPNReply{ + RD: r.RD, + RT: li.rt, + Label: li.label, + } + ch <- repl + glog.V(5).Infof("Mocked Data store returns RD: %+v RT: %+v Label: %d", repl.RD.String(), repl.RT, repl.Label) +} + +// GetQoE is required method by DB interface, it takes requested QoE and searches through +// stored in memory map with mock entries. If found, it returns the value, otherwise return ENOENT error. +func (db *dbMock) GetQoE(ctx context.Context, req *pbapi.Qoe, ch chan *pbapi.Qoe) { + repl := &pbapi.Qoe{} + db.mu.Lock() + defer db.mu.Unlock() + + // Simulating hung DB's Get routine + // time.Sleep(time.Second *3) + + for _, qoe := range db.qoe { + if bytes.Compare(req.Src.Address, qoe.Src.Address) == 0 && bytes.Compare(req.Dst.Address, qoe.Dst.Address) == 0 { + // TODO add more precise calculation of latency with considerring variation. + if req.Qoe.Latency.Value == qoe.Qoe.Latency.Value { + repl := qoe + repl.Err = pbapi.GatewayErrors_OK + ch <- repl + return + } + } + } + repl.Err = pbapi.GatewayErrors_ENOENT + ch <- repl +} + +// loadTestData loads test data into the mock DB. +func (db *dbMock) loadTestData() { + // TODO Consider more flexible way to load test data + vpn := map[string]labelInfo{ + bgp.NewRouteDistinguisherTwoOctetAS(577, 65000).String(): { + label: 24000, + rt: []bgp.ExtendedCommunityInterface{bgp.NewTwoOctetAsSpecificExtended(bgp.EC_SUBTYPE_ROUTE_TARGET, 577, 65000, false)}, + }, + bgp.NewRouteDistinguisherIPAddressAS("57.57.57.57", 65001).String(): { + label: 24001, + rt: []bgp.ExtendedCommunityInterface{bgp.NewIPv4AddressSpecificExtended(bgp.EC_SUBTYPE_ROUTE_TARGET, "57.57.57.57", 65001, false)}, + }, + bgp.NewRouteDistinguisherFourOctetAS(456734567, 65002).String(): { + label: 24002, + rt: []bgp.ExtendedCommunityInterface{bgp.NewFourOctetAsSpecificExtended(bgp.EC_SUBTYPE_ROUTE_TARGET, 456734567, 65002, false)}, + }, + } + qoe := map[int32]*pbapi.Qoe{ + 0: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("10.0.0.1"), + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("20.0.0.1"), + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 200, + Variation: 10, + }, + }, + Label: []uint32{10024, 20024}, + }, + 1: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV6, + Address: net.ParseIP("2001:1::1"), + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV6, + Address: net.ParseIP("2001:2::1"), + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 200, + Variation: 10, + }, + }, + Label: []uint32{31024, 41024}, + }, + 2: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("10.0.0.1"), + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("30.0.0.1"), + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 20, + Variation: 10, + }, + }, + Label: []uint32{12024, 22024}, + }, + 3: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV6, + Address: net.ParseIP("2001:3::1"), + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV6, + Address: net.ParseIP("2001:4::1"), + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 150, + Variation: 10, + }, + }, + Label: []uint32{33024, 43024}, + }, + 4: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_SID, + Address: []byte{1, 1, 1, 1}, + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_SID, + Address: []byte{2, 2, 2, 2}, + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 200, + Variation: 10, + }, + }, + Label: []uint32{34024, 44024}, + }, + 5: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_SID, + Address: []byte{3, 3, 3, 3}, + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_SID, + Address: []byte{4, 4, 4, 4}, + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 1500, + Variation: 10, + }, + }, + Label: []uint32{35024, 45024}, + }, + } + db.mu.Lock() + defer db.mu.Unlock() + db.qoe = qoe + db.vpn = vpn +} + +// NewMockDB return a new instance of a DB client +func NewMockDB() dbclient.DB { + db := dbMock{ + qoe: make(map[int32]*pbapi.Qoe), + } + db.loadTestData() + + return &db +} diff --git a/pkg/dbclient/mock/go.mod b/pkg/dbclient/mock/go.mod new file mode 100644 index 0000000..e4b8e9a --- /dev/null +++ b/pkg/dbclient/mock/go.mod @@ -0,0 +1,11 @@ +module github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient/mock + +go 1.13 + +require ( + github.com/cisco-ie/jalapeno-go-gateway/pkg/apis v0.0.0-00010101000000-000000000000 + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b + google.golang.org/grpc v1.26.0 +) + +replace github.com/cisco-ie/jalapeno-go-gateway/pkg/apis => ../apis diff --git a/pkg/gateway/go.mod b/pkg/gateway/go.mod new file mode 100644 index 0000000..b84934f --- /dev/null +++ b/pkg/gateway/go.mod @@ -0,0 +1,17 @@ +module github.com/cisco-ie/jalapeno-go-gateway/pkg/gateway + +go 1.13 + +require ( + github.com/cisco-ie/jalapeno-go-gateway/pkg/apis v0.0.0-00010101000000-000000000000 + github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient v0.0.0-00010101000000-000000000000 + github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient/mock v0.0.0-00010101000000-000000000000 + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b + google.golang.org/grpc v1.26.0 +) + +replace ( + github.com/cisco-ie/jalapeno-go-gateway/pkg/apis => ../apis + github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient => ../dbclient + github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient/mock => ../dbclient/mock +) diff --git a/pkg/gateway/go.sum b/pkg/gateway/go.sum new file mode 100644 index 0000000..26823ef --- /dev/null +++ b/pkg/gateway/go.sum @@ -0,0 +1,49 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cisco-ie/jalapeno-go-gateway v0.0.0-20200123172347-801b88bf8ded h1:DQGAi6eOu36SjxPzxflMQaOJ/8uhz1kc41P+CQZGmLE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +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/protobuf v1.2.0/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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +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.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/gateway/server.go b/pkg/gateway/server.go new file mode 100644 index 0000000..806ae24 --- /dev/null +++ b/pkg/gateway/server.go @@ -0,0 +1,141 @@ +package gateway + +import ( + "context" + "net" + "time" + + pbapi "github.com/cisco-ie/jalapeno-go-gateway/pkg/apis" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/bgpclient" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient" + "github.com/golang/glog" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/peer" +) + +var ( + // maxRequestProcessTime defines a maximum wait time for a client request processing by DB client + // and returning results + maxRequestProcessTime = time.Millisecond * 2000 +) + +// Gateway defines interface to Gateway gRPC server +type Gateway interface { + Start() + Stop() +} +type gateway struct { + gSrv *grpc.Server + conn net.Listener + dbc dbclient.DBClient + bgp bgpclient.BGPClient +} + +func (g *gateway) Start() { + glog.Infof("Starting Gateway's gRPC on %s\n", g.conn.Addr().String()) + go g.gSrv.Serve(g.conn) +} + +func (g *gateway) Stop() { + glog.Infof("Stopping Gateway's gRPC server...") + g.gSrv.Stop() +} + +func (g *gateway) VPN(reqVPN *pbapi.RequestVPN, stream pbapi.GatewayService_VPNServer) error { + ctx := stream.Context() + md, ok := metadata.FromIncomingContext(ctx) + if ok { + client := md.Get("CLIENT_IP") + if len(client) != 0 { + glog.Infof("VPN request from client: %+v", client) + } + } + // Building new vpn reuqest from info recieved in grpc packet + vpnRequest, err := bgpclient.NewVPNRequest(reqVPN) + if err != nil { + return err + } + glog.Infof("request for Route Distinguisher: %+v", vpnRequest.RD.String()) + repl, err := g.processVPNRequest(ctx, vpnRequest) + if err != nil { + return err + } + r, err := bgpclient.NewVPNReply(repl) + if err != nil { + return err + } + if err := stream.Send(r); err != nil { + return err + } + + return nil +} + +func (g *gateway) QoE(ctx context.Context, reqQoes *pbapi.RequestQoE) (*pbapi.ResponseQoE, error) { + peer, ok := peer.FromContext(ctx) + if ok { + glog.V(5).Infof("QoE request from client: %+v", *peer) + } + // Gateway has DB Interface which is used to get requested by a client QoE information. + // To protect from hung connections, the context passed to DB client interface will be canceled + // up on reaching a timeout. + dbctx, cancel := context.WithTimeout(ctx, maxRequestProcessTime) + defer cancel() + replQoes, err := g.processQoERequest(dbctx, reqQoes) + if err != nil { + return nil, err + } + return replQoes, nil +} + +// NewGateway return an instance of Gateway interface +func NewGateway(conn net.Listener, dbc dbclient.DBClient, bgp bgpclient.BGPClient) Gateway { + gSrv := gateway{ + conn: conn, + gSrv: grpc.NewServer([]grpc.ServerOption{}...), + dbc: dbc, + bgp: bgp, + } + pbapi.RegisterGatewayServiceServer(gSrv.gSrv, &gSrv) + + return &gSrv + +} + +// processQoERequest start DB client and wait for either of 2 events, result comming back from a result channel +// or a context timing out. +func (g *gateway) processQoERequest(ctx context.Context, reqQoEs *pbapi.RequestQoE) (*pbapi.ResponseQoE, error) { + var replQoEs *pbapi.ResponseQoE + result := make(chan *pbapi.ResponseQoE) + // Requesting DB client to retrieve requested infotmation + go g.dbc.GetQoE(ctx, reqQoEs, result) + select { + case replQoEs = <-result: + return replQoEs, nil + case <-ctx.Done(): + return nil, ctx.Err() + } +} + +// processQoERequest start DB client and wait for either of 2 events, result comming back from a result channel +// or a context timing out. +func (g *gateway) processVPNRequest(ctx context.Context, req *bgpclient.VPNRequest) (*bgpclient.VPNReply, error) { + glog.V(5).Infof("processing VPN Request for RD: %+v RT: %+v", req.RD.String(), req.RT) + var repl *bgpclient.VPNReply + result := make(chan *bgpclient.VPNReply) + // Requesting DB client to retrieve requested infotmation + go g.dbc.GetVPN(ctx, req, result) + select { + case repl = <-result: + if repl != nil && repl.RD != nil { + glog.V(5).Infof("DB client returned RD: %+v RT: %+v Label: %d", repl.RD.String(), repl.RT, repl.Label) + } else { + glog.V(5).Infof("DB client returned nil") + } + return repl, nil + case <-ctx.Done(): + glog.V(5).Infof("DB client returned error: %+v ", ctx.Err()) + return nil, ctx.Err() + } +} diff --git a/pkg/gateway/server_test.go b/pkg/gateway/server_test.go new file mode 100644 index 0000000..685d050 --- /dev/null +++ b/pkg/gateway/server_test.go @@ -0,0 +1,163 @@ +package gateway + +import ( + "context" + "flag" + "net" + "os" + "testing" + "time" + + pbapi "github.com/cisco-ie/jalapeno-go-gateway/pkg/apis" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient" + "github.com/cisco-ie/jalapeno-go-gateway/pkg/dbclient/mock" + "google.golang.org/grpc" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/test/bufconn" +) + +const bufSize = 4096 * 1024 + +var conn *bufconn.Listener + +func TestMain(m *testing.M) { + flag.Parse() + flag.Set("logtostderr", "true") + conn = bufconn.Listen(bufSize) + db := mock.NewMockDB() + dbc := dbclient.NewDBClient(db) + gSrv := NewGateway(conn, dbc) + gSrv.Start() + os.Exit(m.Run()) +} + +func bufDialer(string, time.Duration) (net.Conn, error) { + return conn.Dial() +} + +func TestClientRequestQoE(t *testing.T) { + tests := []struct { + name string + qoeRequest map[int32]*pbapi.Qoe + peer *peer.Peer + }{ + { + name: "Single QoE successful request", + qoeRequest: map[int32]*pbapi.Qoe{ + 0: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("10.0.0.1"), + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("20.0.0.1"), + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 200, + Variation: 10, + }, + }, + // here is used as "expected" label stack, the server portion will override label stack with actual value + Label: []uint32{10024, 20024}, + // Err here is used as "expected" error, the server portion will override err with actual value + Err: pbapi.GatewayErrors_OK, + }, + }, + peer: &peer.Peer{ + Addr: &net.IPAddr{ + IP: net.ParseIP("1.1.1.1"), + }, + }, + }, + { + name: "2 QoEs successful request", + qoeRequest: map[int32]*pbapi.Qoe{ + 0: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("10.0.0.1"), + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("20.0.0.1"), + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 200, + Variation: 10, + }, + }, + // here is used as "expected" label stack, the server portion will override label stack with actual value + Label: []uint32{10024, 20024}, + // Err here is used as "expected" error, the server portion will override err with actual value + Err: pbapi.GatewayErrors_OK, + }, + 1: &pbapi.Qoe{ + Src: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("10.0.0.1"), + }, + Dst: &pbapi.Endpoint{ + Type: pbapi.EndpointType_IPV4, + Address: net.ParseIP("30.0.0.1"), + }, + Qoe: &pbapi.QoeParameters{ + Latency: &pbapi.Latency{ + Value: 20, + Variation: 10, + }, + }, + // here is used as "expected" label stack, the server portion will override label stack with actual value + Label: []uint32{12024, 22024}, + // Err here is used as "expected" error, the server portion will override err with actual value + Err: pbapi.GatewayErrors_OK, + }, + }, + peer: &peer.Peer{ + Addr: &net.IPAddr{ + IP: net.ParseIP("1.1.1.2"), + }, + }, + }, + } + for _, tt := range tests { + ctx := peer.NewContext(context.TODO(), tt.peer) + conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithDialer(bufDialer), grpc.WithInsecure()) + if err != nil { + t.Fatalf("failed to dial bufnet with error: %v", err) + } + defer conn.Close() + client := pbapi.NewGatewayServiceClient(conn) + resp, err := client.QoE(ctx, &pbapi.RequestQoE{Qoes: tt.qoeRequest}) + if err != nil { + t.Fatalf("QoE request failed with error: %v", err) + } + for key, qoe := range resp.Qoes { + // First check if expected error state matches to the one returned by the server + if qoe.Err != tt.qoeRequest[key].Err { + t.Fatalf("test \"%s\" failed, expected error: %+v but got %+v", tt.name, tt.qoeRequest[key].Err, qoe.Err) + } + // If error was expected, then nothing else left to do, on to the next item. + if qoe.Err != pbapi.GatewayErrors_OK { + continue + } + // Now check if returned by the server stack matches to the expected stack. + for i, label := range tt.qoeRequest[key].Label { + if !labelExists(qoe.Label, label) { + t.Fatalf("test \"%s\" failed, expected label %d is not found in server's reply.", tt.name, tt.qoeRequest[key].Label[i]) + } + } + } + } +} + +func labelExists(labels []uint32, label uint32) bool { + for _, l := range labels { + if l == label { + return true + } + } + return false +}