-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes #971 Adds initial capability to add a gRPC Proxy to Tyk using bundler or direct API Def config #1111
Conversation
…or grpc and trace as grpc plugins fail hard because of type mismatches. Needs more investigation.
…conflicts *except* golang.org/x/net/trace, which keeps generating duplicate paths on /debug/trace in the muxer. The only solution is to compile tyk with that vendored lib removed - then plugins work.
…lugins and reload
…we can retain vendoring and plugin functionality
…vendor by renaming and make the vendor dir the GOPATH to guarantee the same build path and versions for plugins
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first pass before bed, will take a more careful look another day.
.travis.yml
Outdated
@@ -25,6 +25,9 @@ services: | |||
- redis-server | |||
|
|||
install: | |||
# gRPC Proxy as plugins means we can't have these vendored | |||
- go get "github.com/grpc-ecosystem/grpc-gateway/runtime" | |||
- go get "golang.org/x/net/trace" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now fixed and they're vendored - remove?
api_loader.go
Outdated
if spec.CustomMiddlewareBundle != "" { | ||
pathPrefix = path.Join(getTykBundlePath(), spec.APIID+"-"+spec.CustomMiddlewareBundle) | ||
} | ||
filePath := path.Join(pathPrefix, pluginPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filepath.Join
api_loader.go
Outdated
pluginPath := spec.CustomMiddleware.GRPCProxy.Path | ||
pathPrefix := globalConf.MiddlewarePath | ||
if spec.CustomMiddlewareBundle != "" { | ||
pathPrefix = path.Join(getTykBundlePath(), spec.APIID+"-"+spec.CustomMiddlewareBundle) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filepath.Join
grpcproxy/grpcproxy.go
Outdated
"google.golang.org/grpc" | ||
) | ||
|
||
type conf struct{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this global name throws me off a bit - reading its declaration, I have no idea what it's for.
grpcproxy/grpcproxy.go
Outdated
var p *plugin.Plugin | ||
|
||
// Load our plugin | ||
if p, err = plugin.Open(path); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace these three lines with
p, err := ...
if err != nil {
grpcproxy/grpcproxy.go
Outdated
tmapObj, err := p.Lookup("Types") | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "error: failed to lookup type map: %v\n", err) | ||
os.Exit(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A func that errors but may also exit? (here and below)
grpcproxy/grpcproxy.go
Outdated
modGo := lib.NewModule("register") | ||
|
||
ctx := context.Background() | ||
ctx, _ = context.WithCancel(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the point of this line if you discard the cancel
func?
grpcproxy/grpcproxy.go
Outdated
type v2Config struct { | ||
ctx context.Context | ||
mux *runtime.ServeMux | ||
e string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
e
is a bit too short to know what it is
```sh | ||
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway | ||
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger | ||
go get -u github.com/golang/protobuf/protoc-gen-go |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we vendored them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure my last comment saved - if building the pb.go files manually you need to do this otherwise you can't actually generate the templates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we would rely on our vendored copies - otherwise plenty of things can go wrong, e.g. if those libs ever have any breaking changes
For example, we could tell people to use our vendor/
as their GOPATH
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't affect these instructions, this command generates the plugins needed by protoc
in the previous step to do the generating, so the stuff in our vendor dir won;t be part of the go bin path.
They would need to change their GOPATH after when they actually build the plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A better review, now that I'm awake.
grpcproxy/grpcproxy.go
Outdated
// register the plug-in's modules | ||
tmapObj, err := p.Lookup("Types") | ||
if err != nil { | ||
return fmt.Errorf("error: failed to lookup type map: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the errors have an error:
prefix, that can be removed
grpcproxy/grpcproxy.go
Outdated
|
||
// assert that the type map pointer is not nil | ||
if tmapPtr == nil { | ||
return fmt.Errorf("error: nil type map: type=%[1]T val=%[1]v", tmapPtr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like bad formatting, even github highlights the %
chars in red
} | ||
|
||
// Get returns the value for the specified key | ||
func (c *v2Config) Get(ctx context.Context, key string) interface{} { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you come up with the Get/Set
interface? If so, why not make it type-safe, like:
func (c *v2Config) Ctx() *context.Context { return c.ctx }
(or just exporting the fields, which is even easier)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the last comment, this mechanism solves a whole bunch of type conversion headaches. I'm not confident enough to redesign it, so if you want to take a shot, be my guest.
```sh | ||
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway | ||
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger | ||
go get -u github.com/golang/protobuf/protoc-gen-go |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we would rely on our vendored copies - otherwise plenty of things can go wrong, e.g. if those libs ever have any breaking changes
For example, we could tell people to use our vendor/
as their GOPATH
plugin_build/wrap.go.tmpl
Outdated
} | ||
|
||
// Do not edit this function | ||
func changeMe(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changeMe
that says do not edit
? :)
plugin_build/README.md
Outdated
|
||
Copy these to the same directory as your stubs. | ||
|
||
Open the *.pb.gw.go and *.pb.go files, you must change the package name from whatever was generated, to `main`, so the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whenever you use *
you should quote it, otherwise the format gets fucked up
plugin_build/README.md
Outdated
|
||
It will generate a reverse proxy `path/to/your_service.pb.gw.go`. | ||
|
||
Note: After generating the code for each of the stubs, in order to build the code, you will want to run ```go get .``` from the directory containing the stubs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for a single line, a single `
is enough?
grpcproxy/grpcproxy.go
Outdated
// Instantiate a copy of the module registered by the plug-in. | ||
modGo := lib.NewModule("register") | ||
|
||
ctx := context.Background() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to the question below on the Get/Set
interface - why is a context in the mix? We don't seem to make any use of it. And it seems unnecessary for getter/setters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really don't want to mess with these because it's part of the plugin fix for type passing - it's literally a lift and shift from the github.com/akutz/gpds/lib
code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've had a look and it seems like context isn't used there at all. Are we going to make use of it? If not, I'd leave it out of the API.
@@ -0,0 +1,162 @@ | |||
# GRPC Proxy How To |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand plugin_build
is just a guide. Is this going to move to the docs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually, this is alpha, so keeping a readme here is a good idea until we formalize
plugin_build/README.md
Outdated
docker image that will make this process more automated** | ||
|
||
*Edit* To make this easier, use the `tykio/bakery` container, it will generate a plugin file from your proto | ||
files without any additional steps. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two notes seem to contradict each other a bit.
…ges were mirrored in docker hub
@mvdan If you can suggest a good alternative to |
log.Debug("====> Calling: ", outreq.URL.String()) | ||
if breakerEnforced { | ||
if breakerConf.CB.Ready() { | ||
rec := httptest.NewRecorder() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if we're using the grpc proxy, we're buffering the entire response? That seems pretty bad to me. If someone wishes to use a grpc API that writes tons of data or writes data incrementally or over time, this won't work at all.
I assume you did this because you only have ServeHTTP
to use from grpc. We should be calling that directly with the user's ResponseWriter
, instead of reading the whole response into memory first like this.
Note that this is different from what RoundTrip
does - that one does the request, but it doesn't buffer the entire response body into memory.
plugin_build/README.md
Outdated
|
||
Now you must edit the `opts.go` file: | ||
|
||
1. For specific gRPC options, edit the `getOpts()`` return value with the gRPC Options you need for your gateway |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one too many `
this time I think
plugin_build/README.md
Outdated
1. For specific gRPC options, edit the `getOpts()`` return value with the gRPC Options you need for your gateway | ||
2. Change the name of `var doRegister = changeMe` to whatever is in the `*.pb.gw.go` file, it will be something like: | ||
|
||
```RegisterYourServiceHandlerFromEndpoint``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you indent something with four spaces or more, it's already a blockquote - no need for the quotes
The |
Also, I just noticed no tests? I realise that a plugin test would be a nightmare, but you could decouple the plugin loading stuff from the actual important code and test that part. |
… on the duymmy wrapper
Which ones in particular? Some I won't fix (like the context). |
The markdown formatting ones :) |
Bump |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM now, but I'd still like @buger's eyes on this before it's merged.
Also, conflicts - feel free to just merge master into this, and we can squash-merge at the end.
vendor/vendor.json
Outdated
@@ -6,9 +6,7 @@ | |||
"checksumSHA1": "9BfDgevpBgdiP4B6DT9SvcuVyLs=", | |||
"path": "github.com/Jeffail/gabs", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you moved the vendor copy from Jeffail
to jeffail
, so update this too
grpcproxy/grpcproxy_test.go
Outdated
pName := fmt.Sprintf("%v.so", uuid.NewV4().String()) | ||
fileArg := fmt.Sprintf("-o=%v", pName) | ||
|
||
cmd := exec.Command("go", "build", "--tags='dummy'", "--buildmode=plugin", fileArg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't run in a shell, so remove the quotes around dummy
(otherwise you really are using 'dummy'
with quotes as the build tag)
Looks good! However, I'm not sure what "Step 3" with adding custom option does, and why it is needed https://github.com/TykTechnologies/tyk/blob/f07bd7ab0c7312b52258a3755875ef5712d1698e/plugin_build/README.md#step-3-add-a-custom-option-to-the-proto-file If so, seems like bakery don't do it, and readme should mention that this step needed even with bakery. |
That's the gRPC proxy specific code annotations to have the proto file generate a proxy in the first place. You're right though the readme should be clear that yu need to do this with the bakery. |
Bump |
@matiasinsaurralde pls do the QA of this task. Once you confirm that everything works, can be merged. |
bump @matiasinsaurralde |
We may need to drop this for v2.4, happy to do so, it's hyper experimental. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs, please add comments to this ticket if you would like it to stay open. Thank you for your contributions. |
Fixes #971