Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ dist/**
implants/imix/imix-test-config.json

implants/golem/embed_files_golem_prod/*
!implants/golem/embed_files_golem_prod/.gitkeep
!implants/golem/embed_files_golem_prod/.gitkeep

# Profiling
.pprof/
38 changes: 34 additions & 4 deletions docs/_docs/dev-guide/tavern.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ ENABLE_TEST_DATA=1 go run ./tavern
2023/02/24 01:02:37 Starting HTTP server on 0.0.0.0:80
```

### PPROF

Running Tavern with the `ENABLE_PPROF` environment variable set will enable performance profiling information to be collected and accessible. This should never be set for a production deployment as it will be unauthenticated and may provide access to sensitive information, it is intended for development purposes only. Read more on how to use `pprof` with tavern under the [Performance Profiling](#performance-profiling) section of this guide.

#### How it Works

Tavern hosts two endpoints to support OAuth:
Expand All @@ -110,28 +114,31 @@ Tavern hosts two endpoints to support OAuth:
Tavern supports a Trust on First Use (TOFU) authentication model, meaning the first user to successfully authenticate will be granted admin permissions. Subsequent users that login will have accounts created, but will require activation before they can interact with any Tavern APIs. Only admin users may activate other users.

## Build and publish tavern container

If you want to deploy tavern without using the published version you'll have to build and publish your own container.

**Build your container**
### Build your container

```bash
cd ./realm
docker build --tag tavern:dev --file ./docker/tavern.Dockerfile .
```

**Publish your container to docker hub**
### Publish your container to docker hub

If you haven't before [sign-up for a docker hub account](https://hub.docker.com/signup) and login with the CLI `docker login`

```bash
docker tag tavern:dev <YOUR_DOCKER_HUB_USERNAME>/tavern:dev
docker push <YOUR_DOCKER_HUB_USERNAME>/tavern:dev
```

**Specify your container during terraform deploy**
### Specify your container during terraform deploy

```bash
terraform apply -var="gcp_project=<PROJECT_ID>" -var="oauth_client_id=<OAUTH_CLIENT_ID>" -var="oauth_client_secret=<OAUTH_CLIENT_SECRET>" -var="oauth_domain=<OAUTH_DOMAIN>" -var="tavern_container_image=<YOUR_DOCKER_HUB_USERNAME>/tavern:dev"
```


## User Interface

## CDN API
Expand Down Expand Up @@ -285,6 +292,29 @@ query get_task_res {
* [Example Ent + GraphQL project](https://github.com/ent/contrib/tree/master/entgql/internal/todo)
* [GQLGen Repo](https://github.com/99designs/gqlgen)

## Performance Profiling

Tavern supports built in performance monitoring and debugging via the Golang [pprof tool](https://go.dev/blog/pprof) developed by Google. To run tavern with profiling enabled, ensure the `ENABLE_PPROF=1` environment variable is set.

### Install Graphviz

Ensure you have an updated version of [Graphviz](https://graphviz.org/about/) installed for visualizing profile outputs.

```bash
apt install -y graphviz
```

### Collect a Profile

1. Start Tavern with profiling enabled: `ENABLE_PPROF=1 go run ./tavern`.
2. Collect a Profile in desired format (e.g. png): `go tool pprof -png -seconds=10 http://127.0.0.1:80/debug/pprof/allocs?seconds=10 > .pprof/allocs.png`
a. Replace "allocs" with the [name of the profile](https://pkg.go.dev/runtime/pprof#Profile) to collect.
b. Replace the value of seconds with the amount of time you need to reproduce performance issues.
c. Read more about the available profiling URL parameters [here](https://pkg.go.dev/net/http/pprof#hdr-Parameters).
d. `go tool pprof` does not need to run on the same host as Tavern, just ensure you provide the correct HTTP url in the command. Note that Graphviz must be installed on the system you're running `pprof` from.
3. Reproduce any interactions with Tavern that you'd like to collect profiling information for.
4. A graph visualization of the requested performance profile should now be saved locally, take a look and see what's going on 🕵️.

## Agent Development

Tavern provides an HTTP(s) GraphQL API that agents may use directly to claim tasks and submit execution results. This is the standard request flow, and is supported as a core function of realm. To learn more about how to interface with GraphQL APIs, please read [this documentation](https://www.graphql.com/tutorials/#clients) or read on for a simple example.
Expand Down
20 changes: 20 additions & 0 deletions tavern/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"log"
"net/http"
pprof "net/http/pprof"
"os"

"entgo.io/contrib/entgql"
Expand Down Expand Up @@ -118,6 +119,12 @@ func NewServer(ctx context.Context, options ...func(*Config)) (*Server, error) {
router.Handle("/", auth.WithLoginRedirect("/oauth/login", www.NewHandler(httpLogger)))
router.Handle("/playground", auth.WithLoginRedirect("/oauth/login", playground.Handler("Tavern", "/graphql")))

// Setup Profiling
if cfg.IsPProfEnabled() {
log.Printf("[WARN] Performance profiling is enabled, do not use in production as this may leak sensitive information")
registerProfiler(router)
}

// Log Middleware
handlerWithLogging := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authName := "unknown"
Expand Down Expand Up @@ -184,3 +191,16 @@ func newGraphQLHandler(client *ent.Client) http.Handler {
srv.ServeHTTP(w, req)
})
}

func registerProfiler(router *http.ServeMux) {
router.HandleFunc("/debug/pprof/", pprof.Index)
router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
router.HandleFunc("/debug/pprof/profile", pprof.Profile)
router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)

// Manually add support for paths linked to by index page at /debug/pprof/
router.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
router.Handle("/debug/pprof/heap", pprof.Handler("heap"))
router.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
router.Handle("/debug/pprof/block", pprof.Handler("block"))
}
8 changes: 8 additions & 0 deletions tavern/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ var (
EnvDBMaxIdleConns = EnvInteger{"DB_MAX_IDLE_CONNS", 10}
EnvDBMaxOpenConns = EnvInteger{"DB_MAX_OPEN_CONNS", 100}
EnvDBMaxConnLifetime = EnvInteger{"DB_MAX_CONN_LIFETIME", 3600}

// EnvEnablePProf enables performance profiling and should not be enabled in production.
EnvEnablePProf = EnvString{"ENABLE_PPROF", ""}
)

// Config holds information that controls the behaviour of Tavern
Expand Down Expand Up @@ -99,6 +102,11 @@ func (cfg *Config) Connect(options ...ent.Option) (*ent.Client, error) {
return ent.NewClient(append(options, ent.Driver(drv))...), nil
}

// IsPProfEnabled returns true if performance profiling has been enabled.
func (cfg *Config) IsPProfEnabled() bool {
return EnvEnablePProf.String() != ""
}

// IsTestDataEnabled returns true if a value for the "ENABLE_TEST_DATA" environment variable is set.
func (cfg *Config) IsTestDataEnabled() bool {
return EnvEnableTestData.String() != ""
Expand Down