diff --git a/create.go b/create.go index 1b1c79c8..6b754d8f 100644 --- a/create.go +++ b/create.go @@ -43,30 +43,18 @@ command(s) that get executed on start, edit the args parameter of the spec. See Usage: "do not use pivot root to jail process inside rootfs. This should be used whenever the rootfs is on top of a ramdisk", }, }, - Action: func(context *cli.Context) { - bundle := context.String("bundle") - if bundle != "" { - if err := os.Chdir(bundle); err != nil { - fatal(err) - } - } - spec, err := loadSpec(specConfig) + Action: func(context *cli.Context) error { + spec, err := setupSpec(context) if err != nil { - fatal(err) - } - notifySocket := os.Getenv("NOTIFY_SOCKET") - if notifySocket != "" { - setupSdNotify(spec, notifySocket) - } - if os.Geteuid() != 0 { - fatalf("runc should be run as root") + return err } status, err := startContainer(context, spec, true) if err != nil { - fatal(err) + return 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) + return nil }, } diff --git a/delete.go b/delete.go index ac928315..7135e35a 100644 --- a/delete.go +++ b/delete.go @@ -3,9 +3,9 @@ package main import ( + "fmt" "os" "path/filepath" - "syscall" "github.com/codegangsta/cli" "github.com/opencontainers/runc/libcontainer" @@ -20,7 +20,7 @@ Where "" is the name for the instance of the container. EXAMPLE: For example, if the container id is "ubuntu01" and runc list currently shows the -status of "ubuntu01" as "destroyed" the following will delete resources held for +status of "ubuntu01" as "stopped" the following will delete resources held for "ubuntu01" removing "ubuntu01" from the runc list of containers: # runc delete ubuntu01`, @@ -38,8 +38,11 @@ status of "ubuntu01" as "destroyed" the following will delete resources held for return nil } s, err := container.Status() - if err == nil && s == libcontainer.Created { - container.Signal(syscall.SIGKILL) + if err != nil { + return err + } + if s != libcontainer.Stopped { + return fmt.Errorf("cannot delete container that is not stopped: %s", s) } destroy(container) return nil diff --git a/libcontainer/container.go b/libcontainer/container.go index 7e89422a..5c5c6c77 100644 --- a/libcontainer/container.go +++ b/libcontainer/container.go @@ -76,13 +76,13 @@ type BaseContainer interface { // // errors: // ContainerDestroyed - Container no longer exists, - // Systemerror - System error. + // SystemError - System error. Status() (Status, error) // State returns the current container's state information. // // errors: - // Systemerror - System error. + // SystemError - System error. State() (*State, error) // Returns the current config of the container. @@ -92,7 +92,7 @@ type BaseContainer interface { // // errors: // ContainerDestroyed - Container no longer exists, - // Systemerror - System error. + // SystemError - System error. // // Some of the returned PIDs may no longer refer to processes in the Container, unless // the Container state is PAUSED in which case every PID in the slice is valid. @@ -102,7 +102,7 @@ type BaseContainer interface { // // errors: // ContainerDestroyed - Container no longer exists, - // Systemerror - System error. + // SystemError - System error. Stats() (*Stats, error) // Set resources of container as configured @@ -110,7 +110,7 @@ type BaseContainer interface { // We can use this to change resources when containers are running. // // errors: - // Systemerror - System error. + // SystemError - System error. Set(config configs.Config) error // Start a process inside the container. Returns error if process fails to @@ -120,7 +120,7 @@ type BaseContainer interface { // ContainerDestroyed - Container no longer exists, // ConfigInvalid - config is invalid, // ContainerPaused - Container is paused, - // Systemerror - System error. + // SystemError - System error. Start(process *Process) (err error) // StartI immediatly starts the process inside the conatiner. Returns error if process @@ -131,7 +131,7 @@ type BaseContainer interface { // ContainerDestroyed - Container no longer exists, // ConfigInvalid - config is invalid, // ContainerPaused - Container is paused, - // Systemerror - System error. + // SystemError - System error. StartI(process *Process) (err error) // Destroys the container after killing all running processes. @@ -140,12 +140,12 @@ type BaseContainer interface { // No error is returned if the container is already destroyed. // // errors: - // Systemerror - System error. + // SystemError - System error. Destroy() error // Signal sends the provided signal code to the container's initial process. // // errors: - // Systemerror - System error. + // SystemError - System error. Signal(s os.Signal) error } diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index a0413069..dcced5e8 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -1096,10 +1096,8 @@ func (c *linuxContainer) runType() (Status, error) { return Stopped, newSystemErrorWithCausef(err, "reading /proc/%d/environ", pid) } check := []byte("_LIBCONTAINER") - for _, v := range bytes.Split(environ, []byte("\x00")) { - if bytes.Contains(v, check) { - return Created, nil - } + if bytes.Contains(environ, check) { + return Created, nil } return Running, nil } diff --git a/libcontainer/integration/template_test.go b/libcontainer/integration/template_test.go index 2345dd35..96165684 100644 --- a/libcontainer/integration/template_test.go +++ b/libcontainer/integration/template_test.go @@ -90,12 +90,13 @@ func newTemplateConfig(rootfs string) *configs.Config { Flags: defaultMountFlags, }, /* - { - Source: "mqueue", - Destination: "/dev/mqueue", - Device: "mqueue", - Flags: defaultMountFlags, - }, + CI is broken on the debian based kernels with this + { + Source: "mqueue", + Destination: "/dev/mqueue", + Device: "mqueue", + Flags: defaultMountFlags, + }, */ { Source: "sysfs", diff --git a/run.go b/run.go index 7b892035..b69fcfa7 100644 --- a/run.go +++ b/run.go @@ -3,12 +3,9 @@ package main import ( - "fmt" "os" "github.com/codegangsta/cli" - "github.com/coreos/go-systemd/activation" - "github.com/opencontainers/runtime-spec/specs-go" ) // default action is to start a container @@ -58,23 +55,10 @@ command(s) that get executed on start, edit the args parameter of the spec. See }, }, Action: func(context *cli.Context) error { - bundle := context.String("bundle") - if bundle != "" { - if err := os.Chdir(bundle); err != nil { - return err - } - } - spec, err := loadSpec(specConfig) + spec, err := setupSpec(context) if err != nil { return err } - notifySocket := os.Getenv("NOTIFY_SOCKET") - if notifySocket != "" { - setupSdNotify(spec, notifySocket) - } - if os.Geteuid() != 0 { - return fmt.Errorf("runc should be run as root") - } status, err := startContainer(context, spec, false) if err == nil { // exit with the container's exit status so any external supervisor is @@ -84,31 +68,3 @@ command(s) that get executed on start, edit the args parameter of the spec. See return err }, } - -func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, error) { - id := context.Args().First() - if id == "" { - return -1, errEmptyID - } - container, err := createContainer(context, id, spec) - if err != nil { - return -1, err - } - detach := context.Bool("detach") - // 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) - } - r := &runner{ - enableSubreaper: !context.Bool("no-subreaper"), - shouldDestroy: true, - container: container, - listenFDs: listenFDs, - console: context.String("console"), - detach: detach, - pidFile: context.String("pid-file"), - create: create, - } - return r.run(&spec.Process) -} diff --git a/start.go b/start.go index c440e292..45b39147 100644 --- a/start.go +++ b/start.go @@ -1,32 +1,39 @@ package main import ( + "fmt" + "github.com/codegangsta/cli" "github.com/opencontainers/runc/libcontainer" ) var startCommand = cli.Command{ Name: "start", - Usage: "start signals a created container to execute the users defined process", + Usage: "start signals a created container to execute the user defined process", ArgsUsage: ` Where "" is your name for the instance of the container that you are starting. The name you provide for the container instance must be unique on your host.`, Description: `The start command signals the container to start the user's defined process.`, - Action: func(context *cli.Context) { + Action: func(context *cli.Context) error { container, err := getContainer(context) if err != nil { - fatal(err) + return err } status, err := container.Status() if err != nil { - fatal(err) + return err } - if status == libcontainer.Created { - if err := container.Signal(libcontainer.InitContinueSignal); err != nil { - fatal(err) - } + switch status { + case libcontainer.Created: + return container.Signal(libcontainer.InitContinueSignal) + case libcontainer.Stopped: + return fmt.Errorf("cannot start a container that has run and stopped") + case libcontainer.Running: + return fmt.Errorf("cannot start an already running container") + default: + return fmt.Errorf("cannot start a container in the %s state", status) } }, } diff --git a/utils.go b/utils.go index d1888a2e..75f44d39 100644 --- a/utils.go +++ b/utils.go @@ -5,6 +5,8 @@ import ( "os" "github.com/Sirupsen/logrus" + "github.com/codegangsta/cli" + "github.com/opencontainers/runtime-spec/specs-go" ) // fatal prints the error's details if it is a libcontainer specific error type @@ -15,3 +17,25 @@ func fatal(err error) { fmt.Fprintln(os.Stderr, err) os.Exit(1) } + +// setupSpec performs inital setup based on the cli.Context for the container +func setupSpec(context *cli.Context) (*specs.Spec, error) { + bundle := context.String("bundle") + if bundle != "" { + if err := os.Chdir(bundle); err != nil { + return nil, err + } + } + spec, err := loadSpec(specConfig) + if err != nil { + return nil, err + } + notifySocket := os.Getenv("NOTIFY_SOCKET") + if notifySocket != "" { + setupSdNotify(spec, notifySocket) + } + if os.Geteuid() != 0 { + return nil, fmt.Errorf("runc should be run as root") + } + return spec, nil +} diff --git a/utils_linux.go b/utils_linux.go index 09302049..0fd1fbfa 100644 --- a/utils_linux.go +++ b/utils_linux.go @@ -11,6 +11,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/codegangsta/cli" + "github.com/coreos/go-systemd/activation" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/cgroups/systemd" "github.com/opencontainers/runc/libcontainer/specconv" @@ -290,3 +291,31 @@ func validateProcessSpec(spec *specs.Process) error { } return nil } + +func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, error) { + id := context.Args().First() + if id == "" { + return -1, errEmptyID + } + container, err := createContainer(context, id, spec) + if err != nil { + return -1, err + } + detach := context.Bool("detach") + // 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) + } + r := &runner{ + enableSubreaper: !context.Bool("no-subreaper"), + shouldDestroy: true, + container: container, + listenFDs: listenFDs, + console: context.String("console"), + detach: detach, + pidFile: context.String("pid-file"), + create: create, + } + return r.run(&spec.Process) +}