-
Notifications
You must be signed in to change notification settings - Fork 246
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #762 from radu-matei/generic-webhook-cleanup
Add generic gateway
- Loading branch information
Showing
18 changed files
with
597 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
FROM alpine:3.8 | ||
|
||
RUN apk update && apk add --no-cache \ | ||
ca-certificates \ | ||
git \ | ||
&& update-ca-certificates | ||
|
||
COPY rootfs/brigade-generic-gateway /usr/bin/brigade-generic-gateway | ||
|
||
CMD /usr/bin/brigade-generic-gateway |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Brigade Generic Gateway | ||
|
||
This server provides a generic gateway. You can check [here](https://azure.github.io/brigade/topics/genericgateway.html) for the relevant documentation. |
73 changes: 73 additions & 0 deletions
73
brigade-generic-gateway/cmd/brigade-generic-gateway/server.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"log" | ||
"net/http" | ||
"os" | ||
|
||
gin "gopkg.in/gin-gonic/gin.v1" | ||
|
||
v1 "k8s.io/api/core/v1" | ||
|
||
"github.com/Azure/brigade/pkg/storage" | ||
"github.com/Azure/brigade/pkg/storage/kube" | ||
"github.com/Azure/brigade/pkg/webhook" | ||
) | ||
|
||
var ( | ||
kubeconfig string | ||
master string | ||
namespace string | ||
) | ||
|
||
func init() { | ||
flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file") | ||
flag.StringVar(&master, "master", "", "master url") | ||
flag.StringVar(&namespace, "namespace", defaultNamespace(), "kubernetes namespace") | ||
} | ||
|
||
func main() { | ||
flag.Parse() | ||
|
||
clientset, err := kube.GetClient(master, kubeconfig) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
if namespace == "" { | ||
namespace = v1.NamespaceDefault | ||
} | ||
|
||
store := kube.New(clientset, namespace) | ||
|
||
router := newRouter(store) | ||
router.Run(":8000") | ||
} | ||
|
||
func newRouter(store storage.Store) *gin.Engine { | ||
router := gin.New() | ||
router.Use(gin.Recovery()) | ||
|
||
handler := webhook.NewGenericWebhook(store) | ||
|
||
events := router.Group("/webhook") | ||
{ | ||
events.Use(gin.Logger()) | ||
events.POST("/:projectID/:secret", handler) | ||
} | ||
|
||
router.GET("/healthz", healthz) | ||
return router | ||
} | ||
|
||
func healthz(c *gin.Context) { | ||
c.String(http.StatusOK, http.StatusText(http.StatusOK)) | ||
} | ||
|
||
func defaultNamespace() string { | ||
if ns, ok := os.LookupEnv("BRIGADE_NAMESPACE"); ok { | ||
return ns | ||
} | ||
return v1.NamespaceDefault | ||
} |
72 changes: 72 additions & 0 deletions
72
brigade-generic-gateway/cmd/brigade-generic-gateway/server_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"io/ioutil" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/Azure/brigade/pkg/storage/mock" | ||
) | ||
|
||
func TestNewRouter(t *testing.T) { | ||
s := mock.New() | ||
s.ProjectList[0].ID = "brigade-4625a05cf6914e556aa254cb2af234203744de2f" | ||
s.ProjectList[0].Name = "deis/empty-testbed" | ||
s.ProjectList[0].GenericGatewaySecret = "mysecret" | ||
r := newRouter(s) | ||
|
||
if r == nil { | ||
t.Fail() | ||
} | ||
|
||
ts := httptest.NewServer(r) | ||
defer ts.Close() | ||
|
||
res, err := http.Get(ts.URL + "/healthz") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if res.StatusCode != 200 { | ||
t.Fatalf("Unexpected status on healthz: %s", res.Status) | ||
} | ||
|
||
body, err := ioutil.ReadFile("./testdata/genericwebhook.json") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
route400 := "/webhook/brigade-4625a05cf6914e556aa254cb2af234203744de2f_WRONG_URL/mysecret" | ||
res, err = http.Post(ts.URL+route400, "application/json", bytes.NewBuffer(body)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if res.StatusCode != 400 { | ||
t.Fatalf("Expected 400 status, got: %s", res.Status) | ||
} | ||
|
||
route401 := "/webhook/brigade-4625a05cf6914e556aa254cb2af234203744de2f/mysecret2" | ||
res, err = http.Post(ts.URL+route401, "application/json", bytes.NewBuffer(body)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if res.StatusCode != 401 { | ||
t.Fatalf("Expected 401 status, got: %s", res.Status) | ||
} | ||
|
||
corruptbody, err := ioutil.ReadFile("./testdata/genericwebhook.json.corrupt") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
routeCorruptBody := "/webhook/brigade-4625a05cf6914e556aa254cb2af234203744de2f/mysecret" | ||
res, err = http.Post(ts.URL+routeCorruptBody, "application/json", bytes.NewBuffer(corruptbody)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if res.StatusCode != 400 { | ||
t.Fatalf("Expected 400 status, got: %s", res.Status) | ||
} | ||
|
||
} |
4 changes: 4 additions & 0 deletions
4
brigade-generic-gateway/cmd/brigade-generic-gateway/testdata/genericwebhook.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"ref": "0.2", | ||
"commit": "1e175a8" | ||
} |
5 changes: 5 additions & 0 deletions
5
brigade-generic-gateway/cmd/brigade-generic-gateway/testdata/genericwebhook.json.corrupt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"ref": "0.2", | ||
"commit": "1e175a8" | ||
BLABLABLA | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Generic Gateway | ||
|
||
Brigade contains a Generic Gateway that can be used to accept requests from other platforms or systems. Generic Gateway is a separate component in the Brigade system, like Github and Container Registry (CR) Gateways. | ||
|
||
Generic Gateway is _not enabled by default_. | ||
|
||
## Intro to Generic Gateway | ||
|
||
Generic Gateway 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. | ||
|
||
## Generic Gateway | ||
|
||
Generic Gateway 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 Gateway Deployment/Services/RBAC permissions. However, be aware that Generic Gateway is not exposed outside the cluster. In case you are certain from a security perspective that you want to expose the Generic Gateway 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,genericGateway.service.type=LoadBalancer | ||
``` | ||
|
||
Alternatively, for enhanced security, you can install an SSL proxy (like `cert-manager`) and direct it to the Generic Gateway Service. | ||
|
||
## Using the Generic Gateway | ||
|
||
As mentioned, Generic Gateway 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 Gateway webhook support. In other words, each project that wants to accept Generic Gateway events should have its own Generic Gateway secret. This secret serves as a simple authentication mechanism. | ||
|
||
When you create a new Brigade Project via Brig CLI, you can optionally create such a secret by using the Advanced Options during `brig project create`. This secret must contain only alphanumeric characters. If you provide an empty string, Brig will generate and output a secret for you. | ||
|
||
*Important*: If you do not go into "Advanced Options" during `brig project create`, a secret will not be created and you will not be able to use Generic Gateway for your project. However, you can always use `brig project create --replace` (or just `kubectl edit` your project Secret) to update your project and include a `genericGatewaySecret` string value. | ||
|
||
When calling the Generic Gateway webhook endpoint, you can include a custom JSON payload such as: | ||
|
||
```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 Gateway'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(); | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.