mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Add detach and pid-file to restore
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
@@ -72,13 +73,13 @@ func execProcess(context *cli.Context) (int, error) {
|
|||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
detach = context.Bool("detach")
|
detach = context.Bool("detach")
|
||||||
bundle = container.Config().Rootfs
|
rootfs = container.Config().Rootfs
|
||||||
)
|
)
|
||||||
rootuid, err := container.Config().HostUID()
|
rootuid, err := container.Config().HostUID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
p, err := getProcess(context, path.Dir(bundle))
|
p, err := getProcess(context, path.Dir(rootfs))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
@@ -91,7 +92,9 @@ func execProcess(context *cli.Context) (int, error) {
|
|||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
if pidFile := context.String("pid-file"); pidFile != "" {
|
if pidFile := context.String("pid-file"); pidFile != "" {
|
||||||
if err := createPidile(pidFile, process); err != nil {
|
if err := createPidFile(pidFile, process); err != nil {
|
||||||
|
process.Signal(syscall.SIGKILL)
|
||||||
|
process.Wait()
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-8
@@ -5,6 +5,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
@@ -53,6 +54,15 @@ var restoreCommand = cli.Command{
|
|||||||
Value: "",
|
Value: "",
|
||||||
Usage: "path to the root of the bundle directory",
|
Usage: "path to the root of the bundle directory",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "detach,d",
|
||||||
|
Usage: "detach from the container's process",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "pid-file",
|
||||||
|
Value: "",
|
||||||
|
Usage: "specify the file to write the process id to",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(context *cli.Context) {
|
Action: func(context *cli.Context) {
|
||||||
imagePath := context.String("image-path")
|
imagePath := context.String("image-path")
|
||||||
@@ -108,21 +118,30 @@ func restoreContainer(context *cli.Context, spec *specs.LinuxSpec, config *confi
|
|||||||
|
|
||||||
// ensure that the container is always removed if we were the process
|
// ensure that the container is always removed if we were the process
|
||||||
// that created it.
|
// that created it.
|
||||||
defer destroy(container)
|
detach := context.Bool("detach")
|
||||||
process := &libcontainer.Process{
|
if !detach {
|
||||||
Stdin: os.Stdin,
|
defer destroy(container)
|
||||||
Stdout: os.Stdout,
|
|
||||||
Stderr: os.Stderr,
|
|
||||||
}
|
}
|
||||||
tty, err := newTty(spec.Process.Terminal, process, rootuid, "")
|
process := &libcontainer.Process{}
|
||||||
|
tty, err := setupIO(process, rootuid, "", false, detach)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
handler := newSignalHandler(tty)
|
|
||||||
defer handler.Close()
|
|
||||||
if err := container.Restore(process, options); err != nil {
|
if err := container.Restore(process, options); err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
if pidFile := context.String("pid-file"); pidFile != "" {
|
||||||
|
if err := createPidFile(pidFile, process); err != nil {
|
||||||
|
process.Signal(syscall.SIGKILL)
|
||||||
|
process.Wait()
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if detach {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
handler := newSignalHandler(tty)
|
||||||
|
defer handler.Close()
|
||||||
return handler.forward(process)
|
return handler.forward(process)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,9 @@ func startContainer(context *cli.Context, spec *specs.LinuxSpec, rspec *specs.Li
|
|||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
if pidFile := context.String("pid-file"); pidFile != "" {
|
if pidFile := context.String("pid-file"); pidFile != "" {
|
||||||
if err := createPidile(pidFile, process); err != nil {
|
if err := createPidFile(pidFile, process); err != nil {
|
||||||
|
process.Signal(syscall.SIGKILL)
|
||||||
|
process.Wait()
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,76 +153,3 @@ func startContainer(context *cli.Context, spec *specs.LinuxSpec, rspec *specs.Li
|
|||||||
defer handler.Close()
|
defer handler.Close()
|
||||||
return handler.forward(process)
|
return handler.forward(process)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dupStdio(process *libcontainer.Process, rootuid int) error {
|
|
||||||
process.Stdin = os.Stdin
|
|
||||||
process.Stdout = os.Stdout
|
|
||||||
process.Stderr = os.Stderr
|
|
||||||
for _, fd := range []uintptr{
|
|
||||||
os.Stdin.Fd(),
|
|
||||||
os.Stdout.Fd(),
|
|
||||||
os.Stderr.Fd(),
|
|
||||||
} {
|
|
||||||
if err := syscall.Fchown(int(fd), rootuid, rootuid); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, rspec *specs.LinuxRuntimeSpec, notifySocket string) {
|
|
||||||
mountName := "sdNotify"
|
|
||||||
spec.Mounts = append(spec.Mounts, specs.MountPoint{Name: mountName, Path: notifySocket})
|
|
||||||
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notifySocket))
|
|
||||||
rspec.Mounts[mountName] = specs.Mount{Type: "bind", Source: notifySocket, Options: []string{"bind"}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If systemd is supporting on-demand socket activation, this function will add support
|
|
||||||
// for on-demand socket activation for the containerized service.
|
|
||||||
func setupSocketActivation(spec *specs.LinuxSpec, listenFds string) {
|
|
||||||
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("LISTEN_FDS=%s", listenFds), "LISTEN_PID=1")
|
|
||||||
}
|
|
||||||
|
|
||||||
func destroy(container libcontainer.Container) {
|
|
||||||
if err := container.Destroy(); err != nil {
|
|
||||||
logrus.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupIO(process *libcontainer.Process, rootuid int, console string, createTTY, detach bool) (*tty, error) {
|
|
||||||
// detach and createTty will not work unless a console path is passed
|
|
||||||
// so error out here before changing any terminal settings
|
|
||||||
if createTTY && detach && console == "" {
|
|
||||||
return nil, fmt.Errorf("cannot allocate tty if runc will detach")
|
|
||||||
}
|
|
||||||
if createTTY {
|
|
||||||
return createTty(process, rootuid, console)
|
|
||||||
}
|
|
||||||
if detach {
|
|
||||||
if err := dupStdio(process, rootuid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return createStdioPipes(process, rootuid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPidile(path string, process *libcontainer.Process) error {
|
|
||||||
pid, err := process.Pid()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f, err := os.Create(path)
|
|
||||||
if err != nil {
|
|
||||||
logrus.WithField("pid", pid).Error("create pid file")
|
|
||||||
} else {
|
|
||||||
_, err = fmt.Fprintf(f, "%d", pid)
|
|
||||||
f.Close()
|
|
||||||
if err != nil {
|
|
||||||
logrus.WithField("error", err).Error("write pid file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ func createStdioPipes(p *libcontainer.Process, rootuid int) (*tty, error) {
|
|||||||
i.Stderr,
|
i.Stderr,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
go io.Copy(i.Stdin, os.Stdin)
|
go func() {
|
||||||
|
io.Copy(i.Stdin, os.Stdin)
|
||||||
|
i.Stdin.Close()
|
||||||
|
}()
|
||||||
go io.Copy(os.Stdout, i.Stdout)
|
go io.Copy(os.Stdout, i.Stdout)
|
||||||
go io.Copy(os.Stderr, i.Stderr)
|
go io.Copy(os.Stderr, i.Stderr)
|
||||||
return t, nil
|
return t, nil
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/opencontainers/runc/libcontainer"
|
"github.com/opencontainers/runc/libcontainer"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
@@ -154,3 +156,72 @@ func newProcess(p specs.Process) *libcontainer.Process {
|
|||||||
Cwd: p.Cwd,
|
Cwd: p.Cwd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dupStdio(process *libcontainer.Process, rootuid int) error {
|
||||||
|
process.Stdin = os.Stdin
|
||||||
|
process.Stdout = os.Stdout
|
||||||
|
process.Stderr = os.Stderr
|
||||||
|
for _, fd := range []uintptr{
|
||||||
|
os.Stdin.Fd(),
|
||||||
|
os.Stdout.Fd(),
|
||||||
|
os.Stderr.Fd(),
|
||||||
|
} {
|
||||||
|
if err := syscall.Fchown(int(fd), rootuid, rootuid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, rspec *specs.LinuxRuntimeSpec, notifySocket string) {
|
||||||
|
mountName := "sdNotify"
|
||||||
|
spec.Mounts = append(spec.Mounts, specs.MountPoint{Name: mountName, Path: notifySocket})
|
||||||
|
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notifySocket))
|
||||||
|
rspec.Mounts[mountName] = specs.Mount{Type: "bind", Source: notifySocket, Options: []string{"bind"}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If systemd is supporting on-demand socket activation, this function will add support
|
||||||
|
// for on-demand socket activation for the containerized service.
|
||||||
|
func setupSocketActivation(spec *specs.LinuxSpec, listenFds string) {
|
||||||
|
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("LISTEN_FDS=%s", listenFds), "LISTEN_PID=1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func destroy(container libcontainer.Container) {
|
||||||
|
if err := container.Destroy(); err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupIO(process *libcontainer.Process, rootuid int, console string, createTTY, detach bool) (*tty, error) {
|
||||||
|
// detach and createTty will not work unless a console path is passed
|
||||||
|
// so error out here before changing any terminal settings
|
||||||
|
if createTTY && detach && console == "" {
|
||||||
|
return nil, fmt.Errorf("cannot allocate tty if runc will detach")
|
||||||
|
}
|
||||||
|
if createTTY {
|
||||||
|
return createTty(process, rootuid, console)
|
||||||
|
}
|
||||||
|
if detach {
|
||||||
|
if err := dupStdio(process, rootuid); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return createStdioPipes(process, rootuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPidFile(path string, process *libcontainer.Process) error {
|
||||||
|
pid, err := process.Pid()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
_, err = fmt.Fprintf(f, "%d", pid)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user