From f931e446b4f9d0f06aed4996b684cf2b9409850d Mon Sep 17 00:00:00 2001 From: Jessica Frazelle Date: Fri, 15 Jan 2016 10:54:02 -0800 Subject: [PATCH] update exec to pass args and --tty on run Signed-off-by: Jessica Frazelle --- exec.go | 102 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 30 deletions(-) diff --git a/exec.go b/exec.go index 38a4153d6..73753d43d 100644 --- a/exec.go +++ b/exec.go @@ -3,13 +3,14 @@ package main import ( - "encoding/json" "fmt" "os" + "path" + "strconv" + "strings" "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" - "github.com/opencontainers/specs" ) var execCommand = cli.Command{ @@ -18,22 +19,33 @@ var execCommand = cli.Command{ Flags: []cli.Flag{ cli.StringFlag{ Name: "console", - Value: "", Usage: "specify the pty slave path for use with the container", }, + cli.StringFlag{ + Name: "cwd", + Usage: "current working directory in the container", + }, + cli.StringSliceFlag{ + Name: "env, e", + Usage: "set environment variables", + }, + cli.BoolFlag{ + Name: "tty, t", + Usage: "allocate a pseudo-TTY", + }, + cli.StringFlag{ + Name: "user, u", + Usage: "UID (format: [:])", + }, }, Action: func(context *cli.Context) { - config, err := loadProcessConfig(context.Args().First()) - if err != nil { - fatal(err) + if len(context.Args()) == 0 { + logrus.Fatal("pass the command") } if os.Geteuid() != 0 { logrus.Fatal("runc should be run as root") } - if config.Args == nil { - logrus.Fatal("args missing in process configuration") - } - status, err := execProcess(context, config) + status, err := execProcess(context, context.Args()) if err != nil { logrus.Fatalf("exec failed: %v", err) } @@ -41,42 +53,72 @@ var execCommand = cli.Command{ }, } -func execProcess(context *cli.Context, config *specs.Process) (int, error) { +func execProcess(context *cli.Context, args []string) (int, error) { container, err := getContainer(context) if err != nil { return -1, err } - process := newProcess(*config) + bundle := container.Config().Rootfs + if err := os.Chdir(path.Dir(bundle)); err != nil { + return -1, err + } + spec, _, err := loadSpec(specConfig, runtimeConfig) + if err != nil { + return -1, err + } + + p := spec.Process + + // override the cwd, if passed + if context.String("cwd") != "" { + p.Cwd = context.String("cwd") + } + + // append the passed env variables + for _, e := range context.StringSlice("env") { + p.Env = append(p.Env, e) + } + + // set the tty + if context.IsSet("tty") { + p.Terminal = context.Bool("tty") + } + + // override the user, if passed + if context.String("user") != "" { + u := strings.SplitN(context.String("user"), ":", 2) + if len(u) > 1 { + gid, err := strconv.Atoi(u[1]) + if err != nil { + return -1, fmt.Errorf("parsing %s as int for gid failed: %v", u[1], err) + } + p.User.GID = uint32(gid) + } + uid, err := strconv.Atoi(u[0]) + if err != nil { + return -1, fmt.Errorf("parsing %s as int for uid failed: %v", u[0], err) + } + p.User.UID = uint32(uid) + } + + process := newProcess(p) + process.Args = args rootuid, err := container.Config().HostUID() if err != nil { return -1, err } - tty, err := newTty(config.Terminal, process, rootuid, context.String("console")) + + tty, err := newTty(p.Terminal, process, rootuid, context.String("console")) if err != nil { return -1, err } + handler := newSignalHandler(tty) defer handler.Close() if err := container.Start(process); err != nil { return -1, err } + return handler.forward(process) } - -// loadProcessConfig loads the process configuration from the provided path. -func loadProcessConfig(path string) (*specs.Process, error) { - f, err := os.Open(path) - if err != nil { - if os.IsNotExist(err) { - return nil, fmt.Errorf("JSON configuration file for %s not found", path) - } - return nil, err - } - defer f.Close() - var s *specs.Process - if err := json.NewDecoder(f).Decode(&s); err != nil { - return nil, err - } - return s, nil -}