diff --git a/go.mod b/go.mod index 51a875f70..afb5ccdee 100644 --- a/go.mod +++ b/go.mod @@ -12,9 +12,9 @@ require ( github.com/emirpasic/gods v1.12.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/goinggo/mapstructure v0.0.0-20140717182941-194205d9b4a9 - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.2 github.com/google/uuid v1.2.0 // indirect - github.com/hashicorp/consul/api v1.5.0 + github.com/jhump/protoreflect v1.9.0 github.com/mitchellh/mapstructure v1.4.1 github.com/pkg/errors v0.9.1 github.com/prometheus/common v0.29.0 // indirect @@ -33,12 +33,12 @@ require ( go.uber.org/zap v1.16.0 golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc // indirect golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/grpc v1.40.0 + google.golang.org/protobuf v1.27.1 gopkg.in/yaml.v2 v2.4.0 ) replace ( - github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 => github.com/envoyproxy/go-control-plane v0.8.0 + github.com/envoyproxy/go-control-plane => github.com/envoyproxy/go-control-plane v0.8.0 google.golang.org/api => google.golang.org/api v0.13.0 - google.golang.org/grpc => google.golang.org/grpc v1.27.0 -) +) \ No newline at end of file diff --git a/go.sum b/go.sum index 0fa6a3a6c..dd68e5156 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= @@ -152,6 +153,9 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E= @@ -348,6 +352,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -373,6 +378,7 @@ github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 h1:AtvtonGEH/fZK0X github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2/go.mod h1:DavVbd41y+b7ukKDmlnPR4nGYmkWXR6vHUkjQNiHPBs= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -386,6 +392,7 @@ github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEo github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= 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= @@ -517,6 +524,8 @@ github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGk github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= +github.com/jhump/protoreflect v1.9.0 h1:npqHz788dryJiR/l6K/RUQAyh2SwV91+d1dnh4RjO9w= +github.com/jhump/protoreflect v1.9.0/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8 h1:mGIXW/lubQ4B+3bXTLxcTMTjUNDqoF6T/HUW9LbFx9s= github.com/jinzhu/copier v0.0.0-20190625015134-976e0346caa8/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= @@ -571,6 +580,7 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linode/linodego v0.7.1 h1:4WZmMpSA2NRwlPZcc0+4Gyn7rr99Evk9bnr0B3gXRKE= github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= @@ -647,6 +657,7 @@ github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 h1:BQ1HW github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -954,6 +965,7 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +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= @@ -1037,6 +1049,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVs golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-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-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1119,9 +1132,11 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/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= @@ -1162,8 +1177,10 @@ golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWc golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= @@ -1176,6 +1193,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.13.0 h1:Q3Ui3V3/CVinFWFiW39Iw0kMuVrRzYX0wN6OPFp0lTA= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1217,8 +1235,30 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +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.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +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.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1228,6 +1268,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= @@ -1269,6 +1311,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +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= diff --git a/igt/Makefile b/igt/Makefile index 922349c3b..bb64db99a 100644 --- a/igt/Makefile +++ b/igt/Makefile @@ -91,6 +91,7 @@ config: $(info > Setting up config files) @mkdir -p $(OUT_DIR)/server @mkdir -p $(OUT_DIR)/pixiuconf + @mkdir -p $(OUT_DIR)/proto @-test -f $(PROJECT_DIR)/server/profiles/dev/log.yml && cat $(PROJECT_DIR)/server/profiles/dev/log.yml | sed "s#\$$HOST_IP#$(DOCKER_HOST_IP)#g" > $(OUT_DIR)/server/log.yml && echo " > $(OUT_DIR)/conf/log.yml" @-test -f $(PROJECT_DIR)/server/profiles/dev/server.yml && cat $(PROJECT_DIR)/server/profiles/dev/server.yml | sed "s#\$$HOST_IP#$(DOCKER_HOST_IP)#g" > $(OUT_DIR)/server/server.yml && echo " > $(OUT_DIR)/conf/server.yml" @-test -f $(PROJECT_DIR)/pixiu/api_config.yaml && cat $(PROJECT_DIR)/pixiu/api_config.yaml | sed "s#\$$HOST_IP#$(DOCKER_HOST_IP)#g" > $(OUT_DIR)/pixiuconf/api_config.yaml && echo " > $(OUT_DIR)/pixiuconf/api_config.yaml" @@ -100,13 +101,13 @@ config: .PHONY: docker-up docker-up: $(info > Starting dependency services with $(PROJECT_DIR)/docker/docker-compose.yml) - @docker-compose -f $(PROJECT_DIR)/docker/docker-compose.yml up -d + @-test -f $(PROJECT_DIR)/docker/docker-compose.yml && docker-compose -f $(PROJECT_DIR)/docker/docker-compose.yml up -d ## docker-down: Shutdown dependency services on docker .PHONY: docker-down docker-down: $(info > Stopping dependency services with $(PROJECT_DIR)/docker/docker-compose.yml) - @docker-compose -f $(PROJECT_DIR)/docker/docker-compose.yml down + @-test -f $(PROJECT_DIR)/docker/docker-compose.yml && docker-compose -f $(PROJECT_DIR)/docker/docker-compose.yml down ## clean: Clean up the output and the binary of the application .PHONY: clean diff --git a/pkg/filter/http/grpcproxy/descriptor_operation.go b/pkg/filter/http/grpcproxy/descriptor_operation.go new file mode 100644 index 000000000..815a7b489 --- /dev/null +++ b/pkg/filter/http/grpcproxy/descriptor_operation.go @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package grpcproxy + +import ( + "fmt" + "sync" +) + +import ( + "github.com/jhump/protoreflect/desc" + "github.com/jhump/protoreflect/desc/protoparse" + "github.com/jhump/protoreflect/dynamic" +) + +type fileSource struct { + files map[string]*desc.FileDescriptor + er *dynamic.ExtensionRegistry + erInit sync.Once +} + +// initFromFileDescriptor +// protoparse.ResolveFilenames(importPaths, fileNames...) +// rel: https://pkg.go.dev/github.com/jhump/protoreflect/desc/protoparse?utm_source=godoc#ResolveFilenames +func (f *Filter) initFromFileDescriptor(importPaths []string, fileNames ...string) error { + fileNames, err := protoparse.ResolveFilenames(importPaths, fileNames...) + if err != nil { + return err + } + p := protoparse.Parser{ + ImportPaths: importPaths, + InferImportPaths: len(importPaths) == 0, + IncludeSourceCodeInfo: true, + } + fds, err := p.ParseFiles(fileNames...) + if err != nil { + return fmt.Errorf("could not parse given files: %v", err) + } + + fsrc.files = make(map[string]*desc.FileDescriptor) + for _, fd := range fds { + name := fd.GetName() + fsrc.files[name] = fd + } + + return nil +} + +func DescriptorSourceFromFileDescriptors(files ...*desc.FileDescriptor) (*fileSource, error) { + fds := map[string]*desc.FileDescriptor{} + for _, fd := range files { + if err := addFile(fd, fds); err != nil { + return nil, err + } + } + return &fileSource{files: fds}, nil +} + +func addFile(fd *desc.FileDescriptor, fds map[string]*desc.FileDescriptor) error { + name := fd.GetName() + if existing, ok := fds[name]; ok { + // already added this file + if existing != fd { + // doh! duplicate files provided + return fmt.Errorf("given files include multiple copies of %q", name) + } + return nil + } + fds[name] = fd + for _, dep := range fd.GetDependencies() { + if err := addFile(dep, fds); err != nil { + return err + } + } + return nil +} + +func (fs *fileSource) ListServices() ([]string, error) { + set := map[string]bool{} + for _, fd := range fs.files { + for _, svc := range fd.GetServices() { + set[svc.GetFullyQualifiedName()] = true + } + } + sl := make([]string, 0, len(set)) + for svc := range set { + sl = append(sl, svc) + } + return sl, nil +} + +func (fs *fileSource) GetAllFiles() ([]*desc.FileDescriptor, error) { + files := make([]*desc.FileDescriptor, len(fs.files)) + i := 0 + for _, fd := range fs.files { + files[i] = fd + i++ + } + return files, nil +} + +func (fs *fileSource) FindSymbol(fullyQualifiedName string) (desc.Descriptor, error) { + for _, fd := range fs.files { + if dsc := fd.FindSymbol(fullyQualifiedName); dsc != nil { + return dsc, nil + } + } + return nil, fmt.Errorf("could not found symbol %v", fullyQualifiedName) +} + +func (fs *fileSource) AllExtensionsForType(typeName string) ([]*desc.FieldDescriptor, error) { + fs.erInit.Do(func() { + fs.er = &dynamic.ExtensionRegistry{} + for _, fd := range fs.files { + fs.er.AddExtensionsFromFile(fd) + } + }) + return fs.er.AllExtensionsForType(typeName), nil +} diff --git a/pkg/filter/http/grpcproxy/grpc.go b/pkg/filter/http/grpcproxy/grpc.go new file mode 100644 index 000000000..04144d8e9 --- /dev/null +++ b/pkg/filter/http/grpcproxy/grpc.go @@ -0,0 +1,364 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package grpcproxy + +import ( + "errors" + "fmt" + "io" + "io/ioutil" + stdHttp "net/http" + "os" + "path/filepath" + "strings" + "sync" +) + +import ( + "github.com/golang/protobuf/jsonpb" //nolint + "github.com/golang/protobuf/proto" //nolint + "github.com/jhump/protoreflect/desc" + "github.com/jhump/protoreflect/dynamic" + "github.com/jhump/protoreflect/dynamic/grpcdynamic" + perrors "github.com/pkg/errors" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +import ( + "github.com/apache/dubbo-go-pixiu/pkg/common/constant" + "github.com/apache/dubbo-go-pixiu/pkg/common/extension/filter" + "github.com/apache/dubbo-go-pixiu/pkg/context/http" + "github.com/apache/dubbo-go-pixiu/pkg/logger" + "github.com/apache/dubbo-go-pixiu/pkg/server" +) + +const ( + // Kind is the kind of Fallback. + Kind = constant.HTTPGrpcProxyFilter + + loggerHeader = "[grpc-proxy]" +) + +var ( + fsrc fileSource +) + +func init() { + filter.RegisterHttpFilter(&Plugin{}) +} + +type ( + // Plugin is grpc filter plugin. + Plugin struct { + } + + // Filter is grpc filter instance + Filter struct { + cfg *Config + // hold grpc.ClientConns, key format: cluster name + "." + endpoint + pools map[string]*sync.Pool + + extReg dynamic.ExtensionRegistry + registered map[string]bool + } + + // Config describe the config of AccessFilter + Config struct { + Path string `yaml:"path" json:"path"` + Rules []*Rule `yaml:"rules" json:"rules"` //nolint + } + + Rule struct { + Selector string `yaml:"selector" json:"selector"` + Match Match `yaml:"match" json:"match"` + } + + Match struct { + Method string `yaml:"method" json:"method"` //nolint + } +) + +func (p *Plugin) Kind() string { + return Kind +} + +func (p *Plugin) CreateFilter() (filter.HttpFilter, error) { + return &Filter{cfg: &Config{}}, nil +} + +func (f *Filter) PrepareFilterChain(ctx *http.HttpContext) error { + ctx.AppendFilterFunc(f.Handle) + return nil +} + +// getServiceAndMethod first return value is package.service, second one is method name +func getServiceAndMethod(path string) (string, string) { + pos := strings.LastIndex(path, "/") + if pos < 0 { + return "", "" + } + + mth := path[pos+1:] + prefix := strings.TrimSuffix(path, "/"+mth) + + pos = strings.LastIndex(prefix, "/") + if pos < 0 { + return "", "" + } + + svc := prefix[pos+1:] + return svc, mth +} + +// Handle use the default http to grpc transcoding strategy https://cloud.google.com/endpoints/docs/grpc/transcoding +func (f *Filter) Handle(c *http.HttpContext) { + svc, mth := getServiceAndMethod(c.GetUrl()) + + dscp, err := fsrc.FindSymbol(svc) + if err != nil { + logger.Errorf("%s err {%s}", loggerHeader, "request path invalid") + c.Err = perrors.New("method not allow") + c.Next() + return + } + + svcDesc, ok := dscp.(*desc.ServiceDescriptor) + if !ok { + logger.Errorf("%s err {service not expose, %s}", loggerHeader, svc) + c.Err = perrors.New(fmt.Sprintf("service not expose, %s", svc)) + c.Next() + return + } + + mthDesc := svcDesc.FindMethodByName(mth) + + err = f.registerExtension(mthDesc) + if err != nil { + logger.Errorf("%s err {%s}", loggerHeader, "register extension failed") + c.Err = err + c.Next() + return + } + + msgFac := dynamic.NewMessageFactoryWithExtensionRegistry(&f.extReg) + grpcReq := msgFac.NewMessage(mthDesc.GetInputType()) + + err = jsonToProtoMsg(c.Request.Body, grpcReq) + if err != nil && !errors.Is(err, io.EOF) { + logger.Errorf("%s err {failed to convert json to proto msg, %s}", loggerHeader, err.Error()) + c.Err = err + c.Next() + return + } + + var clientConn *grpc.ClientConn + re := c.GetRouteEntry() + logger.Debugf("%s client choose endpoint from cluster :%v", loggerHeader, re.Cluster) + + e := server.GetClusterManager().PickEndpoint(re.Cluster) + if e == nil { + logger.Errorf("%s err {cluster not exists}", loggerHeader) + c.Err = perrors.New("cluster not exists") + c.Next() + return + } + + ep := e.Address.GetAddress() + + p, ok := f.pools[strings.Join([]string{re.Cluster, ep}, ".")] + if !ok { + p = &sync.Pool{} + } + + clientConn, ok = p.Get().(*grpc.ClientConn) + if !ok || clientConn == nil { + // TODO(Kenway): Support Credential and TLS + clientConn, err = grpc.DialContext(c.Ctx, ep, grpc.WithInsecure()) + if err != nil || clientConn == nil { + logger.Errorf("%s err {failed to connect to grpc service provider}", loggerHeader) + c.Err = err + c.Next() + return + } + } + + stub := grpcdynamic.NewStubWithMessageFactory(clientConn, msgFac) + + // metadata in grpc has the same feature in http + md := mapHeaderToMetadata(c.AllHeaders()) + ctx := metadata.NewOutgoingContext(c.Ctx, md) + + md = metadata.MD{} + t := metadata.MD{} + + resp, err := Invoke(ctx, stub, mthDesc, grpcReq, grpc.Header(&md), grpc.Trailer(&t)) + // judge err is server side error or not + if st, ok := status.FromError(err); !ok || isServerError(st) { + logger.Error("%s err {failed to invoke grpc service provider, %s}", loggerHeader, err.Error()) + c.Err = err + c.Next() + return + } + + res, err := protoMsgToJson(resp) + if err != nil { + logger.Error("%s err {failed to convert proto msg to json, %s}", loggerHeader, err.Error()) + c.Err = err + c.Next() + return + } + + h := mapMetadataToHeader(md) + th := mapMetadataToHeader(t) + + // let response filter handle resp + c.SourceResp = &stdHttp.Response{ + StatusCode: stdHttp.StatusOK, + Header: h, + Body: ioutil.NopCloser(strings.NewReader(res)), + Trailer: th, + Request: c.Request, + } + p.Put(clientConn) + c.Next() +} + +func (f *Filter) registerExtension(mthDesc *desc.MethodDescriptor) error { + err := RegisterExtension(&f.extReg, mthDesc.GetInputType(), f.registered) + if err != nil { + return perrors.New("register extension failed") + } + + err = RegisterExtension(&f.extReg, mthDesc.GetOutputType(), f.registered) + if err != nil { + return perrors.New("register extension failed") + } + return nil +} + +func RegisterExtension(extReg *dynamic.ExtensionRegistry, msgDesc *desc.MessageDescriptor, registered map[string]bool) error { + msgType := msgDesc.GetFullyQualifiedName() + if _, ok := registered[msgType]; ok { + return nil + } + + if len(msgDesc.GetExtensionRanges()) > 0 { + fds, err := fsrc.AllExtensionsForType(msgType) + if err != nil { + return fmt.Errorf("failed to find msg type {%s} in file source", msgType) + } + + err = extReg.AddExtension(fds...) + if err != nil { + return fmt.Errorf("failed to register extensions of msgType {%s}, err is {%s}", msgType, err.Error()) + } + } + + for _, fd := range msgDesc.GetFields() { + if fd.GetMessageType() != nil { + err := RegisterExtension(extReg, fd.GetMessageType(), registered) + if err != nil { + return err + } + } + } + + return nil +} + +func mapHeaderToMetadata(header stdHttp.Header) metadata.MD { + md := metadata.MD{} + for key, val := range header { + md.Append(key, val...) + } + return md +} + +func mapMetadataToHeader(md metadata.MD) stdHttp.Header { + h := stdHttp.Header{} + for key, val := range md { + for _, v := range val { + h.Add(key, v) + } + } + return h +} + +func jsonToProtoMsg(reader io.Reader, msg proto.Message) error { + body, err := ioutil.ReadAll(reader) + if err != nil { + return err + } + return jsonpb.UnmarshalString(string(body), msg) +} + +func protoMsgToJson(msg proto.Message) (string, error) { + m := jsonpb.Marshaler{} + return m.MarshalToString(msg) +} + +func isServerError(st *status.Status) bool { + return st.Code() == codes.DeadlineExceeded || st.Code() == codes.ResourceExhausted || st.Code() == codes.Internal || + st.Code() == codes.Unavailable +} + +func (f *Filter) Config() interface{} { + return f.cfg +} + +func (f *Filter) Apply() error { + gc := f.cfg + + cur := gc.Path + if len(cur) != 0 && cur[0] != '/' { + ex, err := os.Executable() + if err != nil { + return err + } + cur = filepath.Dir(ex) + "/" + gc.Path + } + + logger.Infof("%s load proto files from %s", loggerHeader, cur) + fileLists := make([]string, 0) + items, err := ioutil.ReadDir(cur) + if err != nil { + return err + } + + for _, item := range items { + if !item.IsDir() { + sp := strings.Split(item.Name(), ".") + length := len(sp) + if length >= 2 && sp[length-1] == "proto" { + fileLists = append(fileLists, item.Name()) + } + } + } + + if err != nil { + return err + } + err = f.initFromFileDescriptor([]string{gc.Path}, fileLists...) + if err != nil { + return err + } + return nil +} diff --git a/pkg/filter/http/grpcproxy/invoke.go b/pkg/filter/http/grpcproxy/invoke.go new file mode 100644 index 000000000..305ef7762 --- /dev/null +++ b/pkg/filter/http/grpcproxy/invoke.go @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package grpcproxy + +import ( + "context" +) + +import ( + "github.com/golang/protobuf/proto" //nolint + "github.com/jhump/protoreflect/desc" + "github.com/jhump/protoreflect/dynamic/grpcdynamic" + perrors "github.com/pkg/errors" + "google.golang.org/grpc" +) + +func Invoke(ctx context.Context, stub grpcdynamic.Stub, mthDesc *desc.MethodDescriptor, grpcReq proto.Message, opts ...grpc.CallOption) (proto.Message, error) { + var resp proto.Message + var err error + // Bi-direction Stream + if mthDesc.IsServerStreaming() && mthDesc.IsClientStreaming() { + err = perrors.New("currently not support bi-direction stream") + } else if mthDesc.IsClientStreaming() { + err = perrors.New("currently not support client side stream") + } else if mthDesc.IsServerStreaming() { + err = perrors.New("currently not support server side stream") + } else { + resp, err = invokeUnary(ctx, stub, mthDesc, grpcReq, opts...) + } + + return resp, err +} + +func invokeUnary(ctx context.Context, stub grpcdynamic.Stub, mthDesc *desc.MethodDescriptor, grpcReq proto.Message, opts ...grpc.CallOption) (proto.Message, error) { + return stub.InvokeRpc(ctx, mthDesc, grpcReq, opts...) +} diff --git a/pkg/model/base.go b/pkg/model/base.go index 26776a7af..4e0820c69 100644 --- a/pkg/model/base.go +++ b/pkg/model/base.go @@ -42,10 +42,11 @@ const ( ) const ( - HTTP ProtocolType = 0 + iota // support for 1.0 - TCP - UDP - HTTPS + ProtocolTypeHTTP ProtocolType = 0 + iota // support for 1.0 + ProtocolTypeTCP + ProtocolTypeUDP + ProtocolTypeHTTPS + ProtocolTypeGRPC ) const ( @@ -55,9 +56,9 @@ const ( ) const ( - REST api.ApiType = 0 + iota // support for 1.0 - GRPC - DUBBO + ApiTypeREST api.ApiType = 0 + iota // support for 1.0 + ApiTypeGRPC + ApiTypeDUBBO ) var ( @@ -73,20 +74,22 @@ var ( "Unknown": 2, } - // ProtocolTypeName + // ProtocolTypeName enum seq to protocol type name ProtocolTypeName = map[int32]string{ 0: "HTTP", 1: "TCP", 2: "UDP", 3: "HTTPS", + 4: "GRPC", } - // ProtocolTypeValue + // ProtocolTypeValue protocol type name to enum seq ProtocolTypeValue = map[string]int32{ "HTTP": 0, "TCP": 1, "UDP": 2, "HTTPS": 3, + "GRPC": 4, } ApiTypeName = map[int32]string{ @@ -103,7 +106,7 @@ var ( ) type ( - // ProtocolType + // ProtocolType protocol type enum ProtocolType int32 // Address the address @@ -112,7 +115,7 @@ type ( Name string `yaml:"name" json:"name" mapstructure:"name"` } - // Address specify either a logical or physical address and port, which are + // SocketAddress specify either a logical or physical address and port, which are // used to tell server where to bind/listen, connect to upstream and find // management servers SocketAddress struct { diff --git a/pkg/pluginregistry/registry.go b/pkg/pluginregistry/registry.go index 7e0b14ade..5e385c3b9 100644 --- a/pkg/pluginregistry/registry.go +++ b/pkg/pluginregistry/registry.go @@ -27,6 +27,7 @@ import ( _ "github.com/apache/dubbo-go-pixiu/pkg/filter/header" _ "github.com/apache/dubbo-go-pixiu/pkg/filter/host" _ "github.com/apache/dubbo-go-pixiu/pkg/filter/http/apiconfig" + _ "github.com/apache/dubbo-go-pixiu/pkg/filter/http/grpcproxy" _ "github.com/apache/dubbo-go-pixiu/pkg/filter/http/httpproxy" _ "github.com/apache/dubbo-go-pixiu/pkg/filter/http/remote" _ "github.com/apache/dubbo-go-pixiu/pkg/filter/metric" diff --git a/pkg/registry/consul.go b/pkg/registry/consul.go deleted file mode 100644 index f64d04cd5..000000000 --- a/pkg/registry/consul.go +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package registry - -import ( - "net/url" - "strconv" - "strings" -) - -import ( - "github.com/apache/dubbo-go/common" - "github.com/apache/dubbo-go/common/constant" - - consul "github.com/hashicorp/consul/api" - - perrors "github.com/pkg/errors" -) - -import ( - "github.com/apache/dubbo-go-pixiu/pkg/logger" -) - -func init() { - var _ Loader = new(ConsulRegistryLoad) -} - -const ( - dubboAPIFilter = "dubbo in Tags" -) - -// ConsulRegistryLoad load dubbo apis from consul registry -type ConsulRegistryLoad struct { - Address string - // Consul client. - client *consul.Client - cluster string -} - -func newConsulRegistryLoad(address, cluster string) (Loader, error) { - config := &consul.Config{Address: address} - client, err := consul.NewClient(config) - if err != nil { - return nil, err - } - - r := &ConsulRegistryLoad{ - Address: address, - client: client, - cluster: cluster, - } - - return r, nil -} - -// nolint -func (crl *ConsulRegistryLoad) GetCluster() (string, error) { - return crl.cluster, nil -} - -func (crl *ConsulRegistryLoad) transfer2Url(service consul.AgentService) (*common.URL, error) { - params := url.Values{} - var protocol string - - for _, tag := range service.Tags { - kv := strings.Split(tag, "=") - if len(kv) != 2 { - continue - } - params.Add(kv[0], kv[1]) - } - - if url, ok := service.Meta["url"]; ok { - protocol = strings.Split(url, ":")[0] - } - - methodsParam := strings.Split(params.Get(constant.METHODS_KEY), ",") - methods := make([]string, len(methodsParam)) - for _, method := range methodsParam { - if method != "" { - methods = append(methods, method) - } - } - url := common.NewURLWithOptions(common.WithPort(strconv.Itoa(service.Port)), - common.WithProtocol(protocol), common.WithMethods(methods), - common.WithIp(service.Address), common.WithParams(params)) - - return url, nil -} - -// LoadAllServices load all services from consul registry -func (crl *ConsulRegistryLoad) LoadAllServices() ([]*common.URL, error) { - agentServices, err := crl.client.Agent().ServicesWithFilter(dubboAPIFilter) - if err != nil { - logger.Error("consul load all apis error:%v", err) - return nil, perrors.Wrap(err, "consul load all apis") - } - var urls []*common.URL - for _, service := range agentServices { - url, err := crl.transfer2Url(*service) - if err != nil { - logger.Warnf("consul transfer service to url error:%v", err) - continue - } - urls = append(urls, url) - } - return urls, nil -} diff --git a/pkg/registry/consul_test.go b/pkg/registry/consul_test.go deleted file mode 100644 index f9c8cab96..000000000 --- a/pkg/registry/consul_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package registry - -import ( - "net/url" - "strconv" - "strings" - "testing" -) - -import ( - "github.com/apache/dubbo-go/common" - "github.com/apache/dubbo-go/common/constant" - "github.com/apache/dubbo-go/common/extension" - _ "github.com/apache/dubbo-go/registry/consul" - "github.com/apache/dubbo-go/remoting/consul" - - "github.com/stretchr/testify/assert" -) - -var ( - registryHost = "localhost" - registryPort = 8500 - providerHost = "localhost" - providerPort = 8000 - consumerHost = "localhost" - consumerPort = 8001 - service = "HelloWorld" - protocol = "tcp" - cluster = "test_cluster" -) - -func TestConsulRegistryLoad_GetCluster(t *testing.T) { - loader, err := newConsulRegistryLoad(registryHost+":"+strconv.Itoa(registryPort), "test_cluster") - assert.Nil(t, err) - consulCluster, err := loader.GetCluster() - assert.Nil(t, err) - assert.Equal(t, cluster, consulCluster) -} - -func TestConsulRegistryLoad_LoadAllServices(t *testing.T) { - consulAgent := consul.NewConsulAgent(t, registryPort) - defer consulAgent.Shutdown() - registryURL, _ := common.NewURL(protocol + "://" + providerHost + ":" + strconv.Itoa(providerPort) + "/" + service + "?anyhost=true&" + - "application=BDTService&category=providers&default.timeout=10000&dubbo=dubbo-provider-golang-1.0.0&" + - "environment=dev&interface=com.ikurento.user.UserProvider&ip=192.168.56.1&methods=GetUser%2C&" + - "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + - "side=provider&timeout=3000×tamp=1556509797245") - - registry, err := extension.GetRegistry("consul", common.NewURLWithOptions(common.WithParams(url.Values{}), common.WithIp("localhost"), common.WithPort("8500"), common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))) - assert.Nil(t, err) - err = registry.Register(registryURL) - assert.Nil(t, err) - defer registry.UnRegister(registryURL) - loader, err := newConsulRegistryLoad(registryHost+":"+strconv.Itoa(registryPort), "test_cluster") - assert.Nil(t, err) - services, err := loader.LoadAllServices() - assert.Nil(t, err) - assert.Len(t, services, 1) - assert.Contains(t, services[0].Methods, "GetUser") - assert.Equal(t, services[0].GetParams(), registryURL.GetParams()) -} - -func TestName(t *testing.T) { - s := "1,,,1" - right := strings.TrimRight(s, ",") - t.Log(right) -} diff --git a/pkg/server/listener.go b/pkg/server/listener.go index 2682e2277..d265c7ad5 100644 --- a/pkg/server/listener.go +++ b/pkg/server/listener.go @@ -60,9 +60,9 @@ func CreateListenerService(lc *model.Listener, bs *model.Bootstrap) *ListenerSer func (ls *ListenerService) Start() { sa := ls.cfg.Address.SocketAddress switch sa.Protocol { - case model.HTTP: + case model.ProtocolTypeHTTP: ls.httpListener() - case model.HTTPS: + case model.ProtocolTypeHTTPS: ls.httpsListener() default: panic("unsupported protocol start: " + sa.ProtocolStr) diff --git a/pkg/server/listener_test.go b/pkg/server/listener_test.go index 28fca8ebc..4220242f6 100644 --- a/pkg/server/listener_test.go +++ b/pkg/server/listener_test.go @@ -32,7 +32,7 @@ func getTestContext() *ctxHttp.HttpContext { Name: "test", Address: model.Address{ SocketAddress: model.SocketAddress{ - Protocol: model.HTTP, + Protocol: model.ProtocolTypeHTTP, Address: "0.0.0.0", Port: 8888, }, diff --git a/samples/http/grpc/pixiu/api_config.yaml b/samples/http/grpc/pixiu/api_config.yaml new file mode 100644 index 000000000..3ecd3118a --- /dev/null +++ b/samples/http/grpc/pixiu/api_config.yaml @@ -0,0 +1,49 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +name: pixiu +description: pixiu sample +resources: + - path: '/api/v1/provider.UserProvider/GetUser' + type: restful + description: user + methods: + - httpVerb: GET + enable: true + timeout: 1000ms + inboundRequest: + requestType: http + integrationRequest: + requestType: grpc + group: "test" + version: 1.0.0 + clusterName: "test_grpc" + - path: '/api/v1/provider.UserProvider/GetUser' + type: restful + description: user + methods: + - httpVerb: POST + enable: true + timeout: 1000ms + inboundRequest: + requestType: http + integrationRequest: + requestType: grpc + group: "test" + version: 1.0.0 + clusterName: "test_grpc" \ No newline at end of file diff --git a/samples/http/grpc/pixiu/conf.yaml b/samples/http/grpc/pixiu/conf.yaml new file mode 100644 index 000000000..c69b99b07 --- /dev/null +++ b/samples/http/grpc/pixiu/conf.yaml @@ -0,0 +1,72 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +--- +static_resources: + listeners: + - name: "net/http" + address: + socket_address: + protocol_type: "HTTP" + address: "0.0.0.0" + port: 8881 + filter_chains: + - filter_chain_match: + domains: + - api.dubbo.com + - api.pixiu.com + filters: + - name: dgp.filter.httpconnectionmanager + config: + route_config: + routes: + - match: + prefix: "/api/v1" + route: + cluster: "test-grpc" + cluster_not_found_response_code: 505 + http_filters: + - name: dgp.filter.http.apiconfig + config: + path: $PROJECT_DIR/pixiu/api_config.yaml + - name: dgp.filter.http.grpcproxy + config: + path: $PROJECT_DIR/proto + - name: dgp.filter.http.response + config: + server_name: "test-http-grpc" + generate_request_id: false + config: + idle_timeout: 5s + read_timeout: 5s + write_timeout: 5s + clusters: + - name: "test-grpc" + lb_policy: "RoundRobin" + endpoints: + - socket_address: + address: 127.0.0.1 + port: 50001 + protocol_type: "GRPC" + timeout_config: + connect_timeout: "5s" + request_timeout: "10s" + shutdown_config: + timeout: "60s" + step_timeout: "10s" + reject_policy: "immediacy" \ No newline at end of file diff --git a/samples/http/grpc/proto/hello_grpc.pb.go b/samples/http/grpc/proto/hello_grpc.pb.go new file mode 100644 index 000000000..47b9066b4 --- /dev/null +++ b/samples/http/grpc/proto/hello_grpc.pb.go @@ -0,0 +1,316 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// protoc --proto_path=. --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative .\hello_grpc.proto + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc v3.15.0--rc2 +// source: hello_grpc.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId int32 `protobuf:"varint,1,opt,name=userId,proto3" json:"userId,omitempty"` +} + +func (x *GetUserRequest) Reset() { + *x = GetUserRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_hello_grpc_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserRequest) ProtoMessage() {} + +func (x *GetUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_hello_grpc_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserRequest.ProtoReflect.Descriptor instead. +func (*GetUserRequest) Descriptor() ([]byte, []int) { + return file_hello_grpc_proto_rawDescGZIP(), []int{0} +} + +func (x *GetUserRequest) GetUserId() int32 { + if x != nil { + return x.UserId + } + return 0 +} + +type GetUserResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + Users []*User `protobuf:"bytes,2,rep,name=users,proto3" json:"users,omitempty"` +} + +func (x *GetUserResponse) Reset() { + *x = GetUserResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_hello_grpc_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUserResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUserResponse) ProtoMessage() {} + +func (x *GetUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_hello_grpc_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUserResponse.ProtoReflect.Descriptor instead. +func (*GetUserResponse) Descriptor() ([]byte, []int) { + return file_hello_grpc_proto_rawDescGZIP(), []int{1} +} + +func (x *GetUserResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *GetUserResponse) GetUsers() []*User { + if x != nil { + return x.Users + } + return nil +} + +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId int32 `protobuf:"varint,1,opt,name=userId,proto3" json:"userId,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_hello_grpc_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_hello_grpc_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_hello_grpc_proto_rawDescGZIP(), []int{2} +} + +func (x *User) GetUserId() int32 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *User) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +var File_hello_grpc_proto protoreflect.FileDescriptor + +var file_hello_grpc_proto_rawDesc = []byte{ + 0x0a, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x5f, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x22, 0x28, 0x0a, 0x0e, + 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x51, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x32, 0x0a, 0x04, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0x4e, 0x0a, + 0x0c, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x3e, 0x0a, + 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3a, 0x5a, + 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x70, 0x61, 0x63, + 0x68, 0x65, 0x2f, 0x64, 0x75, 0x62, 0x62, 0x6f, 0x2d, 0x67, 0x6f, 0x2d, 0x70, 0x69, 0x78, 0x69, + 0x75, 0x2f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x67, + 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_hello_grpc_proto_rawDescOnce sync.Once + file_hello_grpc_proto_rawDescData = file_hello_grpc_proto_rawDesc +) + +func file_hello_grpc_proto_rawDescGZIP() []byte { + file_hello_grpc_proto_rawDescOnce.Do(func() { + file_hello_grpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_hello_grpc_proto_rawDescData) + }) + return file_hello_grpc_proto_rawDescData +} + +var file_hello_grpc_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_hello_grpc_proto_goTypes = []interface{}{ + (*GetUserRequest)(nil), // 0: provider.GetUserRequest + (*GetUserResponse)(nil), // 1: provider.GetUserResponse + (*User)(nil), // 2: provider.User +} +var file_hello_grpc_proto_depIdxs = []int32{ + 2, // 0: provider.GetUserResponse.users:type_name -> provider.User + 0, // 1: provider.UserProvider.GetUser:input_type -> provider.GetUserRequest + 1, // 2: provider.UserProvider.GetUser:output_type -> provider.GetUserResponse + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_hello_grpc_proto_init() } +func file_hello_grpc_proto_init() { + if File_hello_grpc_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_hello_grpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_hello_grpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUserResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_hello_grpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_hello_grpc_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_hello_grpc_proto_goTypes, + DependencyIndexes: file_hello_grpc_proto_depIdxs, + MessageInfos: file_hello_grpc_proto_msgTypes, + }.Build() + File_hello_grpc_proto = out.File + file_hello_grpc_proto_rawDesc = nil + file_hello_grpc_proto_goTypes = nil + file_hello_grpc_proto_depIdxs = nil +} diff --git a/samples/http/grpc/proto/hello_grpc.proto b/samples/http/grpc/proto/hello_grpc.proto new file mode 100644 index 000000000..f3d4bcba6 --- /dev/null +++ b/samples/http/grpc/proto/hello_grpc.proto @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +// protoc --proto_path=. --go_out=. --go-grpc_out=. --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative .\hello_grpc.proto +syntax = "proto3"; + +option go_package = "github.com/apache/dubbo-go-pixiu/samples/http/grpc/proto"; + +package provider; + +service UserProvider { + rpc GetUser (GetUserRequest) returns (GetUserResponse); +} + +message GetUserRequest { + int32 userId = 1; +} + +message GetUserResponse { + string message = 1; + repeated User users = 2; +} + +message User { + int32 userId = 1; + string name = 2; +} \ No newline at end of file diff --git a/samples/http/grpc/proto/hello_grpc_grpc.pb.go b/samples/http/grpc/proto/hello_grpc_grpc.pb.go new file mode 100644 index 000000000..61e9734a6 --- /dev/null +++ b/samples/http/grpc/proto/hello_grpc_grpc.pb.go @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// 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.SupportPackageIsVersion7 + +// UserProviderClient is the client API for UserProvider service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type UserProviderClient interface { + GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) +} + +type userProviderClient struct { + cc grpc.ClientConnInterface +} + +func NewUserProviderClient(cc grpc.ClientConnInterface) UserProviderClient { + return &userProviderClient{cc} +} + +func (c *userProviderClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) { + out := new(GetUserResponse) + err := c.cc.Invoke(ctx, "/provider.UserProvider/GetUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserProviderServer is the server API for UserProvider service. +// All implementations must embed UnimplementedUserProviderServer +// for forward compatibility +type UserProviderServer interface { + GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) + mustEmbedUnimplementedUserProviderServer() +} + +// UnimplementedUserProviderServer must be embedded to have forward compatible implementations. +type UnimplementedUserProviderServer struct { +} + +func (UnimplementedUserProviderServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") +} +func (UnimplementedUserProviderServer) mustEmbedUnimplementedUserProviderServer() {} + +// UnsafeUserProviderServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to UserProviderServer will +// result in compilation errors. +type UnsafeUserProviderServer interface { + mustEmbedUnimplementedUserProviderServer() +} + +func RegisterUserProviderServer(s *grpc.Server, srv UserProviderServer) { + s.RegisterService(&_UserProvider_serviceDesc, srv) +} + +func _UserProvider_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserProviderServer).GetUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/provider.UserProvider/GetUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserProviderServer).GetUser(ctx, req.(*GetUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _UserProvider_serviceDesc = grpc.ServiceDesc{ + ServiceName: "provider.UserProvider", + HandlerType: (*UserProviderServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetUser", + Handler: _UserProvider_GetUser_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "hello_grpc.proto", +} diff --git a/samples/http/grpc/server/app/server.go b/samples/http/grpc/server/app/server.go new file mode 100644 index 000000000..d1faea1e6 --- /dev/null +++ b/samples/http/grpc/server/app/server.go @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "context" + "net" +) + +import ( + "google.golang.org/grpc" +) + +import ( + "github.com/apache/dubbo-go-pixiu/pkg/logger" + "github.com/apache/dubbo-go-pixiu/samples/http/grpc/proto" +) + +const ( + MsgUserNotFound = "user not found" + MsgUserQuerySuccessfully = "user(s) query successfully" +) + +// Test Cases +// curl http://127.0.0.1:8881/api/v1/provider.UserProvider/GetUser +// curl http://127.0.0.1:8881/api/v1/provider.UserProvider/GetUser -X POST -d '{"userId":1}' + +type server struct { + users map[int32]*proto.User + proto.UnimplementedUserProviderServer +} + +func (s *server) GetUser(ctx context.Context, request *proto.GetUserRequest) (*proto.GetUserResponse, error) { + us := make([]*proto.User, 0) + if request.GetUserId() == 0 { + for _, user := range s.users { + us = append(us, user) + } + } else { + u, ok := s.users[request.GetUserId()] + if !ok { + return &proto.GetUserResponse{Message: MsgUserNotFound}, nil + } + us = append(us, u) + } + return &proto.GetUserResponse{Message: MsgUserQuerySuccessfully, Users: us}, nil +} + +func main() { + l, err := net.Listen("tcp", ":50001") //nolint:gosec + if err != nil { + panic(err) + } + + s := &server{users: make(map[int32]*proto.User)} + initUsers(s) + + gs := grpc.NewServer() + proto.RegisterUserProviderServer(gs, s) + logger.Info("grpc test server is now running...") + err = gs.Serve(l) + if err != nil { + panic(err) + } +} + +func initUsers(s *server) { + s.users[1] = &proto.User{UserId: 1, Name: "Kenway"} + s.users[2] = &proto.User{UserId: 2, Name: "Ken"} +} diff --git a/samples/http/grpc/test/pixiu_test.go b/samples/http/grpc/test/pixiu_test.go new file mode 100644 index 000000000..57392f581 --- /dev/null +++ b/samples/http/grpc/test/pixiu_test.go @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test + +import ( + "bytes" + "encoding/json" + "github.com/apache/dubbo-go-pixiu/samples/http/grpc/proto" + "github.com/stretchr/testify/assert" + "io/ioutil" + "net/http" + "strings" + "testing" + "time" +) + +const ( + url = "http://localhost:8881/api/v1/provider.UserProvider/GetUser" + data = "{\"userId\":1}" +) + +func TestGet(t *testing.T) { + c := http.Client{Timeout: 5 * time.Second} + req, err := http.NewRequest(http.MethodGet, url, bytes.NewReader([]byte{})) + assert.NoError(t, err) + resp, err := c.Do(req) + assert.NoError(t, err) + body, err := ioutil.ReadAll(resp.Body) + assert.NoError(t, err) + assert.NotNil(t, body) + var r proto.GetUserResponse + err = json.Unmarshal(body, &r) + assert.NoError(t, err) + assert.Equal(t, "user(s) query successfully", r.Message) + assert.Equal(t, 2, len(r.Users)) + assert.Equal(t, int32(1), r.Users[0].UserId) + assert.Equal(t, "Kenway", r.Users[0].Name) + assert.Equal(t, int32(2), r.Users[1].UserId) + assert.Equal(t, "Ken", r.Users[1].Name) +} + +func TestPost(t *testing.T) { + c := http.Client{Timeout: 5 * time.Second} + req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(data)) + assert.NoError(t, err) + resp, err := c.Do(req) + assert.NoError(t, err) + body, err := ioutil.ReadAll(resp.Body) + assert.NoError(t, err) + assert.NotNil(t, body) + var r proto.GetUserResponse + err = json.Unmarshal(body, &r) + assert.NoError(t, err) + assert.Equal(t, "user(s) query successfully", r.Message) + assert.Equal(t, 1, len(r.Users)) + assert.Equal(t, int32(1), r.Users[0].UserId) + assert.Equal(t, "Kenway", r.Users[0].Name) +} diff --git a/samples/http/simple/docker/docker-compose.yml b/samples/http/simple/docker/docker-compose.yml deleted file mode 100644 index 7ca8ee583..000000000 --- a/samples/http/simple/docker/docker-compose.yml +++ /dev/null @@ -1,27 +0,0 @@ -# -# Licensed to Apache Software Foundation (ASF) under one or more contributor -# license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright -# ownership. Apache Software Foundation (ASF) licenses this file to you under -# the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -version: '3' - -services: - zookeeper: - image: zookeeper - ports: - - 2181:2181 - restart: on-failure diff --git a/start_integrate_test.sh b/start_integrate_test.sh index 226a42e0b..d4f055e4c 100755 --- a/start_integrate_test.sh +++ b/start_integrate_test.sh @@ -23,10 +23,9 @@ array+=("samples/dubbogo/simple/uri") array+=("samples/dubbogo/http") #http +array+=("samples/http/grpc") array+=("samples/http/simple") - - for((i=0;i<${#array[*]};i++)) do sh ./integrate_test.sh ${array[i]}