Enable routing via /functions/ endpoint

This commit is contained in:
Alex 2017-01-04 09:14:21 +00:00
parent f2fdfde43c
commit 84d1c0eaef
6 changed files with 84 additions and 18 deletions

View File

@ -19,9 +19,9 @@ This container acts in a similar way to the API Gateway on AWS. Requests can be
There are three options for routing:
* Routing is enabled through a `X-Function` header which matches a service name (function) directly.
* Functions created on the overlay network can be invoked by: http://localhost:8080/function/{servicename}
* Routing automatically detects Alexa SDK requests and forwards to a service name (function) that matches the Intent name
* [todo] individual routes can be set up mapping to a specific service name (function).
* Routing is enabled through a `X-Function` header which matches a service name (function) directly.
Features:

View File

@ -1,5 +1,4 @@
#!/bin/sh
echo Building catservice:latest
docker build -t catservice .
echo Building server:latest
docker build -t server .

View File

@ -51,6 +51,7 @@ func lookupSwarmService(serviceName string) (bool, error) {
if err != nil {
log.Fatal("Error with Docker client.")
}
fmt.Printf("Resolving: '%s'\n", serviceName)
serviceFilter := filters.NewArgs()
serviceFilter.Add("name", serviceName)
services, err := c.ServiceList(context.Background(), types.ServiceListOptions{Filters: serviceFilter})
@ -95,6 +96,7 @@ func invokeService(w http.ResponseWriter, r *http.Request, metrics metrics.Metri
return
}
w.WriteHeader(http.StatusOK)
w.Write(responseBody)
seconds := time.Since(start).Seconds()
fmt.Printf("[%s] took %f seconds\n", stamp, seconds)
@ -102,7 +104,22 @@ func invokeService(w http.ResponseWriter, r *http.Request, metrics metrics.Metri
metrics.GatewayFunctions.Observe(seconds)
}
func makeProxy(metrics metrics.MetricOptions) http.HandlerFunc {
func lookupInvoke(w http.ResponseWriter, r *http.Request, metrics metrics.MetricOptions, name string) {
exists, err := lookupSwarmService(name)
if err != nil || exists == false {
if err != nil {
log.Fatalln(err)
}
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Error resolving service."))
}
if exists == true {
requestBody, _ := ioutil.ReadAll(r.Body)
invokeService(w, r, metrics, name, requestBody)
}
}
func makeProxy(metrics metrics.MetricOptions, wildcard bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
metrics.GatewayRequestsTotal.Inc()
@ -110,16 +127,15 @@ func makeProxy(metrics metrics.MetricOptions) http.HandlerFunc {
log.Println(r.Header)
header := r.Header["X-Function"]
log.Println(header)
fmt.Println(wildcard)
if len(header) > 0 {
exists, err := lookupSwarmService(header[0])
if err != nil {
log.Fatalln(err)
}
if exists == true {
requestBody, _ := ioutil.ReadAll(r.Body)
invokeService(w, r, metrics, header[0], requestBody)
}
if wildcard == true {
vars := mux.Vars(r)
name := vars["name"]
fmt.Println("invoke by name")
lookupInvoke(w, r, metrics, name)
} else if len(header) > 0 {
lookupInvoke(w, r, metrics, header[0])
} else {
requestBody, _ := ioutil.ReadAll(r.Body)
alexaService := isAlexa(requestBody)
@ -160,12 +176,16 @@ func main() {
prometheus.Register(GatewayServerlessServedTotal)
prometheus.Register(GatewayFunctions)
r := mux.NewRouter()
r.HandleFunc("/", makeProxy(metrics.MetricOptions{
metricsOptions := metrics.MetricOptions{
GatewayRequestsTotal: GatewayRequestsTotal,
GatewayServerlessServedTotal: GatewayServerlessServedTotal,
GatewayFunctions: GatewayFunctions,
}))
}
r := mux.NewRouter()
r.HandleFunc("/", makeProxy(metricsOptions, false))
r.HandleFunc("/function/{name:[a-zA-Z]+}", makeProxy(metricsOptions, true))
metricsHandler := metrics.PrometheusHandler()
r.Handle("/metrics", metricsHandler)

View File

@ -0,0 +1,11 @@
FROM golang:1.7.3
RUN mkdir -p /go/src/app
COPY handler.go /go/src/app
WORKDIR /go/src/app
RUN go get -d -v
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
COPY fwatchdog /usr/bin/
ENV fprocess="/go/src/app/app"
CMD ["fwatchdog"]

View File

@ -0,0 +1,18 @@
WebhookStash
============
Example serverless function shows how to stash way contents of webhooks called via API gateway.
Each file is saved with the UNIX timestamp in nano seconds plus an extension of .txt
Example:
```
# curl -X POST -v -d @$HOME/.ssh/id_rsa.pub localhost:8080/function/webhookstash
```
Then if you find the replica you can check the disk:
```
# docker exec webhookstash.1.z054csrh70tgk9s5k4bb8uefq find
```

View File

@ -0,0 +1,18 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"strconv"
"time"
)
func main() {
input, _ := ioutil.ReadAll(os.Stdin)
fmt.Println("Stashing request")
now := time.Now()
stamp := strconv.FormatInt(now.UnixNano(), 10)
ioutil.WriteFile(stamp+".txt", input, 0644)
}