Binary Environment (#256)
Adds a fission environment for arbitrary linux binaries.
This commit is contained in:
committed by
Soam Vasani
parent
a8fc7a7029
commit
85983c91cd
@@ -0,0 +1,134 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
DEFAULT_CODE_PATH = "/userfunc/user"
|
||||
DEFAULT_INTERNAL_CODE_PATH = "/bin/userfunc"
|
||||
)
|
||||
|
||||
var specialized bool
|
||||
|
||||
type BinaryServer struct {
|
||||
fetchedCodePath string
|
||||
internalCodePath string
|
||||
}
|
||||
|
||||
func (bs *BinaryServer) SpecializeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if specialized {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("Not a generic container"))
|
||||
return
|
||||
}
|
||||
|
||||
_, err := os.Stat(bs.fetchedCodePath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte(bs.fetchedCodePath + ": not found"))
|
||||
return
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Future: Check if executable is correct architecture/executable.
|
||||
|
||||
// Copy the executable to ensure that file is executable and immutable.
|
||||
userFunc, err := ioutil.ReadFile(bs.fetchedCodePath)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("Failed to read executable."))
|
||||
return
|
||||
}
|
||||
err = ioutil.WriteFile(bs.internalCodePath, userFunc, 0555)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("Failed to write executable to target location."))
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Specializing ...")
|
||||
specialized = true
|
||||
fmt.Println("Done")
|
||||
}
|
||||
|
||||
func (bs *BinaryServer) InvocationHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !specialized {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("Generic container: no requests supported"))
|
||||
return
|
||||
}
|
||||
|
||||
// CGI-like passing of environment variables
|
||||
execEnv := NewEnv(nil)
|
||||
execEnv.SetEnv(&EnvVar{"REQUEST_METHOD", r.Method})
|
||||
execEnv.SetEnv(&EnvVar{"REQUEST_URI", r.RequestURI})
|
||||
execEnv.SetEnv(&EnvVar{"CONTENT_LENGTH", fmt.Sprintf("%d", r.ContentLength)})
|
||||
|
||||
for header, val := range r.Header {
|
||||
execEnv.SetEnv(&EnvVar{fmt.Sprintf("HTTP_%s", strings.ToUpper(header)), val[0]})
|
||||
}
|
||||
|
||||
// Future: could be improved by keeping subprocess open while environment is specialized
|
||||
cmd := exec.Command(bs.internalCodePath)
|
||||
cmd.Env = execEnv.ToStringEnv()
|
||||
|
||||
if r.ContentLength != 0 {
|
||||
fmt.Println(r.ContentLength)
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("Failed to get STDIN pipe: %s", err)))
|
||||
panic(err)
|
||||
}
|
||||
_, err = io.Copy(stdin, r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("Failed to pipe input: %s", err)))
|
||||
}
|
||||
stdin.Close()
|
||||
}
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("Function error: %s", err)))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(out)
|
||||
}
|
||||
|
||||
func main() {
|
||||
codePath := flag.String("c", DEFAULT_CODE_PATH, "Path to expected fetched executable.")
|
||||
internalCodePath := flag.String("i", DEFAULT_INTERNAL_CODE_PATH, "Path to specialized executable.")
|
||||
flag.Parse()
|
||||
absInternalCodePath, err := filepath.Abs(*internalCodePath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("Using fetched code path: %s\n", *codePath)
|
||||
fmt.Printf("Using internal code path: %s\n", absInternalCodePath)
|
||||
|
||||
server := &BinaryServer{*codePath, absInternalCodePath}
|
||||
http.HandleFunc("/", server.InvocationHandler)
|
||||
http.HandleFunc("/specialize", server.SpecializeHandler)
|
||||
|
||||
fmt.Println("Listening on 8888 ...")
|
||||
err = http.ListenAndServe(":8888", nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user