From a39e0f66052c86c2d9194f254e3195a65012c856 Mon Sep 17 00:00:00 2001 From: pancho horrillo Date: Thu, 10 Oct 2019 11:49:03 +0200 Subject: [PATCH] Spawner ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Abdelkader Martínez Pérez --- go.mod | 1 + go.sum | 2 + internal/server/user/spawn.go | 15 ++++- internal/server/user/spawn_test.go | 100 +++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 2d1bdd2..54d34e5 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d // indirect github.com/golangci/golangci-lint v1.20.0 // indirect github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039 // indirect + github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/uuid v1.1.1 // indirect github.com/gorilla/mux v1.7.3 github.com/gostaticanalysis/analysisutil v0.0.3 // indirect diff --git a/go.sum b/go.sum index a8f9703..f685478 100644 --- a/go.sum +++ b/go.sum @@ -111,6 +111,8 @@ github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg= +github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= diff --git a/internal/server/user/spawn.go b/internal/server/user/spawn.go index 882eedc..48495d8 100644 --- a/internal/server/user/spawn.go +++ b/internal/server/user/spawn.go @@ -5,18 +5,29 @@ import ( "os" "os/exec" + "github.com/google/shlex" + "github.com/BBVA/kapow/internal/server/model" ) func spawn(h *model.Handler, out io.Writer) error { - cmd := exec.Command(h.Route.Entrypoint) + args, err := shlex.Split(h.Route.Entrypoint) + if err != nil { + return err + } + + if h.Route.Command != "" { + args = append(args, h.Route.Command) + } + + cmd := exec.Command(args[0], args[1:]...) 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() + err = cmd.Run() return err } diff --git a/internal/server/user/spawn_test.go b/internal/server/user/spawn_test.go index 370fabd..a8b5116 100644 --- a/internal/server/user/spawn_test.go +++ b/internal/server/user/spawn_test.go @@ -5,6 +5,7 @@ import ( "encoding/json" "log" "os/exec" + "reflect" "strings" "testing" @@ -123,3 +124,102 @@ func TestSpawnSetsKapowHandlerIDEnvVar(t *testing.T) { t.Error("KAPOW_HANDLER_ID is not set properly") } } + +func TestSpawnRunsOKEntrypointsWithAParam(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover() + " -foo", + } + + h := &model.Handler{ + Route: r, + } + + out := &bytes.Buffer{} + + _ = spawn(h, out) + + jldata := decodeJailLover(out.Bytes()) + + if !reflect.DeepEqual(jldata.Cmdline, []string{locateJailLover(), "-foo"}) { + t.Error("Args not as expected") + } +} + +func TestSpawnRunsOKEntrypointWithArgWithSpace(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover() + ` "foo bar"`, + } + + h := &model.Handler{ + Route: r, + } + + out := &bytes.Buffer{} + + _ = spawn(h, out) + + jldata := decodeJailLover(out.Bytes()) + + if !reflect.DeepEqual(jldata.Cmdline, []string{locateJailLover(), "foo bar"}) { + t.Error("Args not parsed as expected") + } +} + +func TestSpawnErrorsWhenEntrypointIsInvalidShell(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover() + ` "`, + } + + h := &model.Handler{ + Route: r, + } + + out := &bytes.Buffer{} + + err := spawn(h, out) + + if err == nil { + t.Error("Invalid args not reported") + } +} + +func TestSpawnRunsOKEntrypointWithMultipleArgs(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover() + " foo bar", + } + + h := &model.Handler{ + Route: r, + } + + out := &bytes.Buffer{} + + _ = spawn(h, out) + + jldata := decodeJailLover(out.Bytes()) + + if !reflect.DeepEqual(jldata.Cmdline, []string{locateJailLover(), "foo", "bar"}) { + t.Error("Args not parsed as expected") + } +} + +func TestSpawnRunsOKEntrypointAndCommand(t *testing.T) { + r := &model.Route{ + Entrypoint: locateJailLover() + " foo bar", + Command: "baz qux", + } + + h := &model.Handler{ + Route: r, + } + + out := &bytes.Buffer{} + + _ = spawn(h, out) + + jldata := decodeJailLover(out.Bytes()) + + if !reflect.DeepEqual(jldata.Cmdline, []string{locateJailLover(), "foo", "bar", "baz qux"}) { + t.Error("Malformed cmdline") + } +}