From 1e6b7a4fc82d1e010edcaaffe2fea098a9e5b6fb Mon Sep 17 00:00:00 2001 From: Soam Vasani Date: Wed, 6 Dec 2017 23:03:05 -0600 Subject: [PATCH] Golang v2 environment -- runtime and builder (#427) v2 environment for Go; includes runtime and builder. --- environments/go/Dockerfile | 4 +- environments/go/builder/Dockerfile | 11 ++- environments/go/builder/build.sh | 4 ++ environments/go/builder/go-function-build | 11 --- environments/go/server.go | 87 +++++++++++++++++++++-- 5 files changed, 99 insertions(+), 18 deletions(-) create mode 100755 environments/go/builder/build.sh delete mode 100755 environments/go/builder/go-function-build diff --git a/environments/go/Dockerfile b/environments/go/Dockerfile index c4dbc635..9c1daf04 100644 --- a/environments/go/Dockerfile +++ b/environments/go/Dockerfile @@ -1,4 +1,6 @@ -FROM golang:1.8.1 +ARG GO_VERSION=1.9.2 + +FROM golang:${GO_VERSION} ENV GOPATH /usr ENV APP ${GOPATH}/src/github.com/fission/fission/environments/go diff --git a/environments/go/builder/Dockerfile b/environments/go/builder/Dockerfile index 4980d7c8..45f19c37 100644 --- a/environments/go/builder/Dockerfile +++ b/environments/go/builder/Dockerfile @@ -1,5 +1,14 @@ -FROM golang:1.8.1 +ARG BUILDER_IMAGE=fission/builder +ARG GO_VERSION=1.9.2 + +FROM ${BUILDER_IMAGE} + +FROM golang:${GO_VERSION} + +COPY --from=0 /builder /builder ENV GOPATH /usr RUN go get github.com/fission/fission +ADD build.sh /usr/local/bin/build + diff --git a/environments/go/builder/build.sh b/environments/go/builder/build.sh new file mode 100755 index 00000000..62bed36d --- /dev/null +++ b/environments/go/builder/build.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd ${SRC_PKG} +go build -buildmode=plugin -i -o ${DEPLOY_PKG} . diff --git a/environments/go/builder/go-function-build b/environments/go/builder/go-function-build deleted file mode 100755 index 019ecb16..00000000 --- a/environments/go/builder/go-function-build +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -if [ $# -eq 0 ] -then - echo "No arguments, building current dir" - filename='.' -else - filename=$1 -fi - -docker run --rm -v $(pwd):/build -w /build fission/go-builder:1.8.1 go build -buildmode=plugin -o function.so $filename && echo "Compiled plugin: function.so. Use 'fission function create' to upload to fission." diff --git a/environments/go/server.go b/environments/go/server.go index 94e51afb..1114ad7d 100644 --- a/environments/go/server.go +++ b/environments/go/server.go @@ -1,9 +1,12 @@ package main import ( + "encoding/json" "fmt" + "io/ioutil" "net/http" "os" + "path/filepath" "plugin" "github.com/fission/fission/environments/go/context" @@ -13,14 +16,52 @@ const ( CODE_PATH = "/userfunc/user" ) +type ( + FunctionLoadRequest struct { + // FilePath is an absolute filesystem path to the + // function. What exactly is stored here is + // env-specific. Optional. + FilePath string `json:"filepath"` + + // FunctionName has an environment-specific meaning; + // usually, it defines a function within a module + // containing multiple functions. Optional; default is + // environment-specific. + FunctionName string `json:"functionName"` + + // URL to expose this function at. Optional; defaults + // to "/". + URL string `json:"url"` + } +) + var userFunc http.HandlerFunc -func loadPlugin() http.HandlerFunc { - p, err := plugin.Open(CODE_PATH) +func loadPlugin(codePath, entrypoint string) http.HandlerFunc { + + // if codepath's a directory, load the file inside it + info, err := os.Stat(codePath) if err != nil { panic(err) } - sym, err := p.Lookup("Handler") + if info.IsDir() { + files, err := ioutil.ReadDir(codePath) + if err != nil { + panic(err) + } + if len(files) == 0 { + panic("No files to load") + } + fi := files[0] + codePath = filepath.Join(codePath, fi.Name()) + } + + fmt.Printf("loading plugin from %v\n", codePath) + p, err := plugin.Open(codePath) + if err != nil { + panic(err) + } + sym, err := p.Lookup(entrypoint) if err != nil { panic("Entry point not found") } @@ -44,7 +85,7 @@ func loadPlugin() http.HandlerFunc { func specializeHandler(w http.ResponseWriter, r *http.Request) { if userFunc != nil { - w.WriteHeader(400) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte("Not a generic container")) return } @@ -61,12 +102,48 @@ func specializeHandler(w http.ResponseWriter, r *http.Request) { } fmt.Println("Specializing ...") - userFunc = loadPlugin() + userFunc = loadPlugin(CODE_PATH, "Handler") + fmt.Println("Done") +} + +func specializeHandlerV2(w http.ResponseWriter, r *http.Request) { + if userFunc != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("Not a generic container")) + return + } + + body, err := ioutil.ReadAll(r.Body) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + var loadreq FunctionLoadRequest + err = json.Unmarshal(body, &loadreq) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + _, err = os.Stat(loadreq.FilePath) + if err != nil { + if os.IsNotExist(err) { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte(CODE_PATH + ": not found")) + return + } else { + panic(err) + } + } + + fmt.Println("Specializing ...") + userFunc = loadPlugin(loadreq.FilePath, loadreq.FunctionName) fmt.Println("Done") } func main() { http.HandleFunc("/specialize", specializeHandler) + http.HandleFunc("/v2/specialize", specializeHandlerV2) // Generic route -- all http requests go to the user function. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {