Skip to content

Commit

Permalink
Add documentation for generic gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
dgkanatsios committed Jan 28, 2019
1 parent 5d832c1 commit b3a1e8b
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 24 deletions.
65 changes: 65 additions & 0 deletions docs/topics/genericwebhook.md
@@ -0,0 +1,65 @@
# Generic Webhook

Brigade contains a Generic Webhook which is part of its API Server and can be used to accept requests from other platforms or systems.

Generic Webhook is _not enabled by default_.

## Intro to Generic Webhook

Brigade API Server can optionally be activated to accept `POST` webhook requests at `/webhook/:projectID/:secret` path. When this endpoint is called, Brigade will respond by creating a Build with a `webhook` event. This provides Brigade developers with the ability to trigger scripts based on messages received from any platform that can send a POST HTTP request.

## Configuring Brigade API Server for Generic Webhook

Generic Webhook support is disabled by default, but can easily be turned on during installation or upgrade of Brigade:

```
$ helm install -n brigade brigade/brigade --set genericGateway.enabled=true
```

This will enable the Generic Webhook on Brigade API Server. However, be aware that Brigade API Server is not exposed outside the cluster. In case you are certain from a security perspective that you want to expose the entire API Server via a [Kubernetes LoadBalancer Service](https://kubernetes.io/docs/concepts/services-networking/#loadbalancer), you can install Brigade via the following command:

```
$ helm install -n brigade brigade/brigade --set genericGateway.enabled=true,api.service.type=LoadBalancer
```

Alternatively, for enhanced security, you can install an SSL proxy (like `cert-manager`) and direct it to the internal API Server service.

## Using the Generic Webhook

As mentioned, Generic Webhook accepts POST requests at `/webhook/:projectID/:secret` endpoint. These requests should also carry a JSON payload.

- `projectID` is the Brigade Project ID
- `secret` is a custom secret for this specific project's Generic Webhook support. You can think of it as a simple authentication mechanism for this Project's Generic Webhook support. Every Project has its own unique secret.

When you create a new Brigade Project via Brig CLI, you can optionally create such a secret by adding a secret named `genericWebhookSecret`, containing your desired value. Alternatively, Brig will generate and output one for you.

When calling the Generic Webhook endpoint, you can include a custom JSON payload such as this one:

```json
{
"ref": "refs/heads/changes",
"commit": "b60ad9543b2ddbbe73430dd6898b75883306cecc"
}
```

`Ref` and `commit` values would be used to configure the specific revision that Brigade will pull from your repository.

Last but not least, here is a sample Brigade.js file that could be used as a base for your own scripts that respond to Generic Webhook's `webhook` event. This script will echo the name of your project and 'webhook'.

```javascript
const { events, Job } = require("brigadier");
events.on("webhook", (e, p) => {
var echo = new Job("echo", "alpine:3.8");
echo.storage.enabled = false;
echo.tasks = [
"echo Project " + p.name,
"echo Event $EVENT_NAME"
];

echo.env = {
"EVENT_NAME": e.type
};

echo.run();
});
```
1 change: 1 addition & 0 deletions docs/topics/index.md
Expand Up @@ -14,6 +14,7 @@ If you don't see a topic guide here and have a reasonable level of knowledge on
- [Scripting Guide - Advanced](scripting_advanced.md): Advanced examples for `brigade.js` files.
- [GitHub Integration](github.md): A guide for configuring GitHub integration.
- [Container Registry Integration](dockerhub.md): A guide for configuring integration with DockerHub or Azure Container Registry.
- [Generic Webhook](genericwebhook.md): How to use Brigade's Generic Webhook functionality.
- [Using Secrets](secrets.md): How to pass sensitive data into builds.
- [Brigade Gateways](gateways.md): Learn how to write your own Brigade gateway.
- Configuring and Running Brigade
Expand Down
46 changes: 23 additions & 23 deletions pkg/webhook/generic.go
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/Azure/brigade/pkg/brigade"
"github.com/Azure/brigade/pkg/storage"

"github.com/emicklei/go-restful"
restful "github.com/emicklei/go-restful"
)

type genericWebhook struct {
Expand All @@ -34,25 +34,6 @@ func (g *genericWebhook) Handle(request *restful.Request, response *restful.Resp
projectID := request.PathParameter("projectID")
secret := request.PathParameter("secret")

gwData := &genericWebhookData{}
err := request.ReadEntity(gwData)

if err != nil {
log.Printf("Failed to read GenericWebHookData: %s", err)
response.WriteErrorString(http.StatusBadRequest, "{\"status\": \"Malformed genericWebhookData\"}")
return
}

log.Printf("gwData: %#v\n", gwData)

body, err := ioutil.ReadAll(request.Request.Body)
if err != nil {
log.Printf("Failed to read body: %s", err)
response.WriteErrorString(http.StatusBadRequest, "{\"status\": \"Malformed body\"}")
return
}
defer request.Request.Body.Close()

proj, err := g.store.GetProject(projectID)

if err != nil {
Expand All @@ -62,19 +43,39 @@ func (g *genericWebhook) Handle(request *restful.Request, response *restful.Resp
}

// if the secret is "" (probably due to a Brigade upgrade)
// refuse to serve it, so user will be forced to update it
// refuse to serve it, so Brigade admin will be forced to update the project with a non-empty secret
if proj.GenericWebhookSecret == "" {
log.Printf("Secret for project %s is empty, please update it and try again", projectID)
response.WriteErrorString(http.StatusUnauthorized, "{\"status\": \"secret is empty, please update it\"}")
response.WriteErrorString(http.StatusUnauthorized, "{\"status\": \"secret is empty, please update it and try again\"}")
return
}

// compare secrets
if secret != proj.GenericWebhookSecret {
log.Printf("Secret %s for project %s is wrong", secret, projectID)
response.WriteErrorString(http.StatusUnauthorized, "{\"status\": \"secret is wrong\"}")
return
}

gwData := &genericWebhookData{}
err = request.ReadEntity(gwData)

if err != nil {
log.Printf("Failed to read GenericWebHookData: %s", err)
response.WriteErrorString(http.StatusBadRequest, "{\"status\": \"Malformed genericWebhookData\"}")
return
}

log.Printf("gwData: %#v\n", gwData)

body, err := ioutil.ReadAll(request.Request.Body)
if err != nil {
log.Printf("Failed to read body: %s", err)
response.WriteErrorString(http.StatusBadRequest, "{\"status\": \"Malformed body\"}")
return
}
defer request.Request.Body.Close()

go g.notifyGenericWebhookEvent(proj, body, gwData)
response.Write([]byte("{\"status\": \"Success\"}"))
}
Expand All @@ -86,7 +87,6 @@ func (g *genericWebhook) notifyGenericWebhookEvent(proj *brigade.Project, payloa
}

func (g *genericWebhook) genericWebhookEvent(proj *brigade.Project, payload []byte, gwData *genericWebhookData) error {

revision := &brigade.Revision{}
revision.Commit = gwData.Commit
revision.Ref = gwData.Ref
Expand Down
2 changes: 1 addition & 1 deletion pkg/webhook/generic_test.go
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/Azure/brigade/pkg/storage"
"github.com/Azure/brigade/pkg/storage/mock"

"github.com/emicklei/go-restful"
restful "github.com/emicklei/go-restful"
)

func newTestGenericWebhookHandler(store storage.Store) *genericWebhook {
Expand Down

0 comments on commit b3a1e8b

Please sign in to comment.