mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Add a 'start' command
When any non-global-flag parameter appears on the command line make sure there's a "command" even in the 'start' (run) case to ensure its not ambiguous as to what the arg is. For example, w/o this fix its not clear if runc foo means 'foo' is the name of a config file or an unknown command. Or worse, you can't name a config file the same a ANY command, even future (yet to be created) commands. We should fix this now before we ship 1.0 and are forced to support this ambiguous case for a long time. Signed-off-by: Doug Davis <dug@us.ibm.com>
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
// +build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/specs"
|
||||
)
|
||||
|
||||
var startCommand = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "create and run a container",
|
||||
Action: func(context *cli.Context) {
|
||||
spec, err := loadSpec(context.Args().First())
|
||||
|
||||
notifySocket := os.Getenv("NOTIFY_SOCKET")
|
||||
if notifySocket != "" {
|
||||
setupSdNotify(spec, notifySocket)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
if os.Geteuid() != 0 {
|
||||
logrus.Fatal("runc should be run as root")
|
||||
}
|
||||
status, err := startContainer(context, spec)
|
||||
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 init() {
|
||||
if len(os.Args) > 1 && os.Args[1] == "init" {
|
||||
runtime.GOMAXPROCS(1)
|
||||
runtime.LockOSThread()
|
||||
factory, _ := libcontainer.New("")
|
||||
if err := factory.StartInitialization(); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
panic("--this line should have never been executed, congratulations--")
|
||||
}
|
||||
}
|
||||
|
||||
func startContainer(context *cli.Context, spec *specs.LinuxSpec) (int, error) {
|
||||
config, err := createLibcontainerConfig(context.GlobalString("id"), spec)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if _, err := os.Stat(config.Rootfs); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return -1, fmt.Errorf("Rootfs (%q) does not exist", config.Rootfs)
|
||||
}
|
||||
return -1, err
|
||||
}
|
||||
rootuid, err := config.HostUID()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
factory, err := loadFactory(context)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
container, err := factory.Create(context.GlobalString("id"), config)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
// ensure that the container is always removed if we were the process
|
||||
// that created it.
|
||||
defer destroy(container)
|
||||
process := newProcess(spec.Process)
|
||||
tty, err := newTty(spec.Process.Terminal, process, rootuid)
|
||||
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)
|
||||
}
|
||||
|
||||
// default action is to execute a container
|
||||
|
||||
// If systemd is supporting sd_notify protocol, this function will add support
|
||||
// for sd_notify protocol from within the container.
|
||||
func setupSdNotify(spec *specs.LinuxSpec, notifySocket string) {
|
||||
spec.Mounts = append(spec.Mounts, specs.Mount{Type: "bind", Source: notifySocket, Destination: notifySocket, Options: "bind"})
|
||||
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notifySocket))
|
||||
}
|
||||
|
||||
func destroy(container libcontainer.Container) {
|
||||
status, err := container.Status()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
if status != libcontainer.Checkpointed {
|
||||
if err := container.Destroy(); err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user