Skip to content
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

Plugin documentation request for adding an route to the OPA runtime params #3937

Closed
jalyng opened this issue Oct 27, 2021 · 2 comments
Closed
Labels

Comments

@jalyng
Copy link

jalyng commented Oct 27, 2021

Request
I was wondering if anyone could provide a code snippet/example for a plugin extension that adds an http route to the OPA runtime params, similar to "println_decision_logger" plugin example on the OPA website (ref: println_decision_logger example).

Background
Hello,
Looking to extend OPA via custom plugins for the OPA runtime (ref: Custom Plugins for OPA Runtime). I would like to implement an additional http endpoint (ex: /hello-world) and register it with OPA. I have discovered I can use the "net/http" package and create an endpoint that way (see bellow code example), but that would require I use a separate port from OPA (8090 instead of OPA's 8181).

I found a PR (PR: Add Router to runtime.Params) that may solve my multi-port issue that has been merged recently, but I can't seem to figure out how I would get it to work and can't find any code snippets/examples.

net/http code snippet using a separate port:

func (p *PartialParser) Start(ctx context.Context) error {	
	http.HandleFunc("/hello-world", p.hello)
	http.ListenAndServe(":8090", nil)
	return nil
}

Note
This issue is a pull over from my OPA Slack channel question. (Original Slack Channel Question)

@srenatus
Copy link
Contributor

Heya! Thanks for filing the issue. I had another close look at the code and found two things:

  1. Plugins cannot add routes. That is tracked by Plugin to extend the REST API? #2777.
  2. To add a custom route, you'll need to instantiate the runtime yourself, like exemplified in this test.

I'm a bit hesitant documenting this extension path at large, but here's a snippet that hopefully unblocks you:

package main

import (
	"context"
	"log"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/open-policy-agent/opa/runtime"
)

func main() {
	ctx := context.Background()
	router := mux.NewRouter()
	router.HandleFunc("/customEndpoint", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(`{"myCustomResponse": true}`)) // ignore error
	})
	params := runtime.Params{
		Addrs:  &[]string{"0.0.0.0:8080"},
		Router: router,
	}
	rt, err := runtime.NewRuntime(ctx, params)
	if err != nil {
		log.Fatal(err)
	}
	log.Fatal(rt.Serve(ctx))
}

@jalyng
Copy link
Author

jalyng commented Oct 28, 2021

Heya! Thanks for filing the issue. I had another close look at the code and found two things:

  1. Plugins cannot add routes. That is tracked by Plugin to extend the REST API? #2777.
  2. To add a custom route, you'll need to instantiate the runtime yourself, like exemplified in this test.

I'm a bit hesitant documenting this extension path at large, but here's a snippet that hopefully unblocks you:

package main

import (
	"context"
	"log"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/open-policy-agent/opa/runtime"
)

func main() {
	ctx := context.Background()
	router := mux.NewRouter()
	router.HandleFunc("/customEndpoint", func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(`{"myCustomResponse": true}`)) // ignore error
	})
	params := runtime.Params{
		Addrs:  &[]string{"0.0.0.0:8080"},
		Router: router,
	}
	rt, err := runtime.NewRuntime(ctx, params)
	if err != nil {
		log.Fatal(err)
	}
	log.Fatal(rt.Serve(ctx))
}

Thank you for the response! Your explanation answers and satisfies my original ask.

Feel free to let me know if this not the place to ask, but I ended up going with the raw net/http implementation in the meantime. Are there any benefits to wrapping the extended api serve in the OPA runtime object?

Also feel free to point me in the right direction if this tradeoff is already documented somewhere.

Update
I see the benefit in using the OPA runtime now haha. I did not realize creating a new listener using the built-in net/http package (even on a separate port) would disable/discard the default OPA port and routes. I only discovered it once our Kubernetes pods were unable hit the :8181/health probe, live and you learn haha.
I am now using your snippet with no issues and able to run my custom extended API plugin on the same port as the default OPA routes.

Thanks bigtime!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants