Ensure the docker daemon creates a file containing its PID under /var/run/docker.pid. The daemon takes care of removing the pid file when it receives either SIGTERM, SIGINT or SIGKILL. The daemon also refuses to start when the pidfile is found. An explanation message is shown to the user when this happens. This change is required to make docker easier to manage by tools like checkproc which rely on this information. Upstream-commit: fb0b375be70e79eaa8349143dceef048db6e0e19 Component: engine
146 lines
3.3 KiB
Go
146 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"github.com/dotcloud/docker"
|
|
"github.com/dotcloud/docker/rcli"
|
|
"github.com/dotcloud/docker/term"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
)
|
|
|
|
var GIT_COMMIT string
|
|
|
|
func main() {
|
|
if docker.SelfPath() == "/sbin/init" {
|
|
// Running in init mode
|
|
docker.SysInit()
|
|
return
|
|
}
|
|
// FIXME: Switch d and D ? (to be more sshd like)
|
|
flDaemon := flag.Bool("d", false, "Daemon mode")
|
|
flDebug := flag.Bool("D", false, "Debug mode")
|
|
bridgeName := flag.String("b", "", "Attach containers to a pre-existing network bridge")
|
|
pidfile := flag.String("p", "/var/run/docker.pid", "File containing process PID")
|
|
flag.Parse()
|
|
if *bridgeName != "" {
|
|
docker.NetworkBridgeIface = *bridgeName
|
|
} else {
|
|
docker.NetworkBridgeIface = docker.DefaultNetworkBridge
|
|
}
|
|
if *flDebug {
|
|
os.Setenv("DEBUG", "1")
|
|
}
|
|
docker.GIT_COMMIT = GIT_COMMIT
|
|
if *flDaemon {
|
|
if flag.NArg() != 0 {
|
|
flag.Usage()
|
|
return
|
|
}
|
|
if err := daemon(*pidfile); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
} else {
|
|
if err := runCommand(flag.Args()); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func createPidFile(pidfile string) error {
|
|
if _, err := os.Stat(pidfile); err == nil {
|
|
return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
|
|
}
|
|
|
|
file, err := os.Create(pidfile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
_, err = fmt.Fprintf(file, "%d", os.Getpid())
|
|
return err
|
|
}
|
|
|
|
func removePidFile(pidfile string) {
|
|
if err := os.Remove(pidfile); err != nil {
|
|
log.Printf("Error removing %s: %s", pidfile, err)
|
|
}
|
|
}
|
|
|
|
func daemon(pidfile string) error {
|
|
if err := createPidFile(pidfile); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer removePidFile(pidfile)
|
|
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt, os.Kill, os.Signal(syscall.SIGTERM))
|
|
go func() {
|
|
sig := <-c
|
|
log.Printf("Received signal '%v', exiting\n", sig)
|
|
removePidFile(pidfile)
|
|
os.Exit(0)
|
|
}()
|
|
|
|
service, err := docker.NewServer()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return rcli.ListenAndServe("tcp", "127.0.0.1:4242", service)
|
|
}
|
|
|
|
func runCommand(args []string) error {
|
|
// FIXME: we want to use unix sockets here, but net.UnixConn doesn't expose
|
|
// CloseWrite(), which we need to cleanly signal that stdin is closed without
|
|
// closing the connection.
|
|
// See http://code.google.com/p/go/issues/detail?id=3345
|
|
if conn, err := rcli.Call("tcp", "127.0.0.1:4242", args...); err == nil {
|
|
options := conn.GetOptions()
|
|
if options.RawTerminal &&
|
|
term.IsTerminal(int(os.Stdin.Fd())) &&
|
|
os.Getenv("NORAW") == "" {
|
|
if oldState, err := rcli.SetRawTerminal(); err != nil {
|
|
return err
|
|
} else {
|
|
defer rcli.RestoreTerminal(oldState)
|
|
}
|
|
}
|
|
receiveStdout := docker.Go(func() error {
|
|
_, err := io.Copy(os.Stdout, conn)
|
|
return err
|
|
})
|
|
sendStdin := docker.Go(func() error {
|
|
_, err := io.Copy(conn, os.Stdin)
|
|
if err := conn.CloseWrite(); err != nil {
|
|
log.Printf("Couldn't send EOF: " + err.Error())
|
|
}
|
|
return err
|
|
})
|
|
if err := <-receiveStdout; err != nil {
|
|
return err
|
|
}
|
|
if !term.IsTerminal(int(os.Stdin.Fd())) {
|
|
if err := <-sendStdin; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
} else {
|
|
service, err := docker.NewServer()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dockerConn := rcli.NewDockerLocalConn(os.Stdout)
|
|
defer dockerConn.Close()
|
|
if err := rcli.LocalCall(service, os.Stdin, dockerConn, args...); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|