Skip to content

Commit

Permalink
Split container.Start() into create() and runProcess()
Browse files Browse the repository at this point in the history
While in there, to show why someone may want it, I also added support for:
runc run cmd args...
runc batch batchFileOfCommands | -

Signed-off-by: Doug Davis <[email protected]>
  • Loading branch information
Doug Davis committed Mar 16, 2016
1 parent 69fe79d commit deba9b7
Show file tree
Hide file tree
Showing 17 changed files with 656 additions and 31 deletions.
125 changes: 125 additions & 0 deletions batch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// +build linux

package main

import (
"bufio"
"fmt"
"os"
"strings"

"github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
"github.com/coreos/go-systemd/activation"
"github.com/opencontainers/specs/specs-go"
)

var batchCommand = cli.Command{
Name: "batch",
Usage: "create and run a container with a series of commands",
Flags: []cli.Flag{
cli.StringFlag{
Name: "config-file, c",
Value: "config.json",
Usage: "path to spec config file",
},
cli.StringFlag{
Name: "runtime-file, r",
Value: "runtime.json",
Usage: "path to runtime config file",
},
},
Action: func(context *cli.Context) {
spec, err := loadSpec(context.String("config-file"))
if err != nil {
fatal(err)
}

id := context.Args().First()
if id == "" {
fatal(errEmptyID)
}

batchFilename := context.Args().Get(1)
if batchFilename == "" {
fatal(fmt.Errorf("Missing batch-file-name"))
}

notifySocket := os.Getenv("NOTIFY_SOCKET")
if notifySocket != "" {
setupSdNotify(spec, notifySocket)
}

if os.Geteuid() != 0 {
logrus.Fatal("runc should be run as root")
}

status, err := batchContainer(context, id, spec, batchFilename)
if err != nil {
logrus.Fatalf("Container start failed: %v", err)
}
// exit with the container's exit status so any external supervisor is
// notified of the exit with the correct exit status.
os.Exit(status)
},
}

func batchContainer(context *cli.Context, id string, spec *specs.Spec, batchFilename string) (int, error) {
var file *os.File
var err error

if batchFilename == "-" {
file = os.Stdin
} else {
if file, err = os.Open(batchFilename); err != nil {
return -1, err
}
defer file.Close()
}

scanner := bufio.NewScanner(file)

container, err := createContainer(context, id, spec)
if err != nil {
return -1, err
}
defer deleteContainer(container)

// Support on-demand socket activation by passing file descriptors into the container init process.
listenFDs := []*os.File{}
if os.Getenv("LISTEN_FDS") != "" {
listenFDs = activation.Files(false)
}

// Loop over the list of processes that people want executed.
// Use the config Process as the template for now
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || line[0] == '#' {
continue
}

proc := specs.Process{
Terminal: spec.Process.Terminal,
User: spec.Process.User,
Args: strings.Split(line, " "),
Env: spec.Process.Env,
Cwd: spec.Process.Cwd,
}

if batchFilename == "-" {
proc.Terminal = false
}

fmt.Printf("--> %q\n", proc.Args)

rc, err := runProcess(container, &proc, listenFDs, context.String("console"), context.String("pid-file"), false)
if rc != 0 || err != nil {
// For now just stop on first error
return rc, nil
}
}

// All is well
return 0, nil
}
57 changes: 57 additions & 0 deletions create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// +build linux

package main

import (
"os"

"github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
)

var createCommand = cli.Command{
Name: "create",
Usage: "create container",
Flags: []cli.Flag{
cli.StringFlag{
Name: "bundle, b",
Value: "",
Usage: "path to the root of the bundle directory",
},
cli.StringFlag{
Name: "console",
Value: "",
Usage: "specify the pty slave path for use with the container",
},
},
Action: func(context *cli.Context) {
id := context.Args().First()
if id == "" {
fatal(errEmptyID)
}

bundle := context.String("bundle")
if bundle != "" {
if err := os.Chdir(bundle); err != nil {
fatal(err)
}
}
spec, err := loadSpec(specConfig)
if err != nil {
fatal(err)
}

notifySocket := os.Getenv("NOTIFY_SOCKET")
if notifySocket != "" {
setupSdNotify(spec, notifySocket)
}

if os.Geteuid() != 0 {
logrus.Fatal("runc should be run as root")
}
_, err = createContainer(context, id, spec)
if err != nil {
logrus.Fatalf("Container create failed: %v", err)
}
},
}
16 changes: 13 additions & 3 deletions delete.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package main

import "github.com/codegangsta/cli"
import (
"os"

"github.com/Sirupsen/logrus"
"github.com/codegangsta/cli"
)

var deleteCommand = cli.Command{
Name: "delete",
Expand All @@ -14,11 +19,16 @@ status of "ubuntu01" as "destroyed" the following will delete resources held for
"ubuntu01" removing "ubuntu01" from the runc list of containers:
# runc delete ubuntu01`,
Flags: []cli.Flag{},
Action: func(context *cli.Context) {
if os.Geteuid() != 0 {
logrus.Fatal("runc should be run as root")
}
container, err := getContainer(context)
if err != nil {
fatal(err)
logrus.Fatalf("Container delete failed: %v", err)
os.Exit(-1)
}
destroy(container)
deleteContainer(container)
},
}
14 changes: 14 additions & 0 deletions exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"

"github.com/codegangsta/cli"
"github.com/opencontainers/runc/libcontainer"
"github.com/opencontainers/specs/specs-go"
)

Expand Down Expand Up @@ -94,16 +95,28 @@ func execProcess(context *cli.Context) (int, error) {
if err != nil {
return -1, err
}

detach := context.Bool("detach")

state, err := container.State()
if err != nil {
return -1, err
}
bundle := searchLabels(state.Config.Labels, "bundle")

status, err := container.Status()
if err != nil {
return -1, err
}
if status != libcontainer.Running {
return -1, fmt.Errorf("Container not running")
}

p, err := getProcess(context, bundle)
if err != nil {
return -1, err
}

return runProcess(container, p, nil, context.String("console"), context.String("pid-file"), detach)
}

Expand All @@ -130,6 +143,7 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) {
}
p := spec.Process
p.Args = context.Args()[1:]

// override the cwd, if passed
if context.String("cwd") != "" {
p.Cwd = context.String("cwd")
Expand Down
3 changes: 3 additions & 0 deletions libcontainer/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ type BaseContainer interface {
// Systemerror - System error.
Set(config configs.Config) error

// Create will setup a new container but not actually run a user process
Create(process *Process) (err error)

// Start a process inside the container. Returns error if process fails to
// start. You can track process lifecycle with passed Process structure.
//
Expand Down
Loading

0 comments on commit deba9b7

Please sign in to comment.