From d0764f07a40ad6b3ae378b76c438415522d90c07 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Wed, 9 Oct 2019 18:27:11 +0200 Subject: [PATCH] First cut to spawner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Abdelkader Martínez Pérez --- internal/server/user/spawn.go | 22 +++++ internal/server/user/spawn_test.go | 125 +++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 internal/server/user/spawn.go create mode 100644 internal/server/user/spawn_test.go diff --git a/internal/server/user/spawn.go b/internal/server/user/spawn.go new file mode 100644 index 0000000..882eedc --- /dev/null +++ b/internal/server/user/spawn.go @@ -0,0 +1,22 @@ +package user + +import ( + "io" + "os" + "os/exec" + + "github.com/BBVA/kapow/internal/server/model" +) + +func spawn(h *model.Handler, out io.Writer) error { + cmd := exec.Command(h.Route.Entrypoint) + if out != nil { + cmd.Stdout = out + } + cmd.Env = append(os.Environ(), "KAPOW_URL=http://localhost:8081") + cmd.Env = append(cmd.Env, "KAPOW_HANDLER_ID="+h.ID) + + err := cmd.Run() + + return err +} diff --git a/internal/server/user/spawn_test.go b/internal/server/user/spawn_test.go new file mode 100644 index 0000000..370fabd --- /dev/null +++ b/internal/server/user/spawn_test.go @@ -0,0 +1,125 @@ +package user + +import ( + "bytes" + "encoding/json" + "log" + "os/exec" + "strings" + "testing" + + "github.com/BBVA/kapow/internal/server/model" +) + +type Output struct { + Cmdline []string `json:"cmdline"` + Env map[string]string `json:"env"` +} + +func decodeJailLover(out []byte) (jldata Output) { + err := json.Unmarshal(out, &jldata) + if err != nil { + log.Fatal("jaillover output is malformed", err) + } + return +} + +func locateJailLover() string { + out, err := exec.Command("which", "jaillover").Output() + if err != nil { + log.Fatal("jaillover not found in PATH", err) + } + return strings.TrimRight(string(out), "\n") +} + +func TestSpawnRetursErrorWhenEntrypointIsBad(t *testing.T) { + r := &model.Route{ + Entrypoint: "/bin/this_executable_is_not_likely_to_exist", + } + + h := &model.Handler{ + Route: r, + } + + err := spawn(h, nil) + if err == nil { + t.Error("Bad executable not reported") + } +} + +func TestSpawnReturnsNilWhenEntrypointIsGood(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover(), + } + + h := &model.Handler{ + Route: r, + } + + err := spawn(h, nil) + if err != nil { + t.Error("Good executable reported") + } +} + +func TestSpawnWritesToStdout(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover(), + } + + h := &model.Handler{ + Route: r, + } + + out := &bytes.Buffer{} + + _ = spawn(h, out) + + jldata := decodeJailLover(out.Bytes()) + + if jldata.Cmdline[0] != locateJailLover() { + t.Error("Ouput does not match jaillover's") + } + +} + +func TestSpawnSetsKapowURLEnvVar(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover(), + } + + h := &model.Handler{ + Route: r, + } + + out := &bytes.Buffer{} + + _ = spawn(h, out) + + jldata := decodeJailLover(out.Bytes()) + + if v, ok := jldata.Env["KAPOW_URL"]; !ok || v != "http://localhost:8081" { + t.Error("KAPOW_URL is not set properly") + } +} + +func TestSpawnSetsKapowHandlerIDEnvVar(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover(), + } + + h := &model.Handler{ + ID: "HANDLER_ID_FOO", + Route: r, + } + + out := &bytes.Buffer{} + + _ = spawn(h, out) + + jldata := decodeJailLover(out.Bytes()) + + if v, ok := jldata.Env["KAPOW_HANDLER_ID"]; !ok || v != "HANDLER_ID_FOO" { + t.Error("KAPOW_HANDLER_ID is not set properly") + } +}