exec.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. // +build linux
  2. package namespaces
  3. import (
  4. "os"
  5. "os/exec"
  6. "syscall"
  7. "github.com/dotcloud/docker/pkg/libcontainer"
  8. "github.com/dotcloud/docker/pkg/libcontainer/cgroups"
  9. "github.com/dotcloud/docker/pkg/libcontainer/cgroups/fs"
  10. "github.com/dotcloud/docker/pkg/libcontainer/cgroups/systemd"
  11. "github.com/dotcloud/docker/pkg/libcontainer/network"
  12. "github.com/dotcloud/docker/pkg/system"
  13. )
  14. // Exec performes setup outside of a namespace so that a container can be
  15. // executed. Exec is a high level function for working with container namespaces.
  16. func Exec(container *libcontainer.Container, term Terminal, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) {
  17. var (
  18. master *os.File
  19. console string
  20. err error
  21. )
  22. // create a pipe so that we can syncronize with the namespaced process and
  23. // pass the veth name to the child
  24. syncPipe, err := NewSyncPipe()
  25. if err != nil {
  26. return -1, err
  27. }
  28. if container.Tty {
  29. master, console, err = system.CreateMasterAndConsole()
  30. if err != nil {
  31. return -1, err
  32. }
  33. term.SetMaster(master)
  34. }
  35. command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.child, args)
  36. if err := term.Attach(command); err != nil {
  37. return -1, err
  38. }
  39. defer term.Close()
  40. if err := command.Start(); err != nil {
  41. return -1, err
  42. }
  43. started, err := system.GetProcessStartTime(command.Process.Pid)
  44. if err != nil {
  45. return -1, err
  46. }
  47. if err := WritePid(dataPath, command.Process.Pid, started); err != nil {
  48. command.Process.Kill()
  49. command.Wait()
  50. return -1, err
  51. }
  52. defer DeletePid(dataPath)
  53. // Do this before syncing with child so that no children
  54. // can escape the cgroup
  55. cleaner, err := SetupCgroups(container, command.Process.Pid)
  56. if err != nil {
  57. command.Process.Kill()
  58. command.Wait()
  59. return -1, err
  60. }
  61. if cleaner != nil {
  62. defer cleaner.Cleanup()
  63. }
  64. if err := InitializeNetworking(container, command.Process.Pid, syncPipe); err != nil {
  65. command.Process.Kill()
  66. command.Wait()
  67. return -1, err
  68. }
  69. // Sync with child
  70. syncPipe.Close()
  71. if startCallback != nil {
  72. startCallback()
  73. }
  74. if err := command.Wait(); err != nil {
  75. if _, ok := err.(*exec.ExitError); !ok {
  76. return -1, err
  77. }
  78. }
  79. return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
  80. }
  81. // DefaultCreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
  82. // defined on the container's configuration and use the current binary as the init with the
  83. // args provided
  84. //
  85. // console: the /dev/console to setup inside the container
  86. // init: the progam executed inside the namespaces
  87. // root: the path to the container json file and information
  88. // pipe: sync pipe to syncronize the parent and child processes
  89. // args: the arguemnts to pass to the container to run as the user's program
  90. func DefaultCreateCommand(container *libcontainer.Container, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd {
  91. // get our binary name from arg0 so we can always reexec ourself
  92. env := []string{
  93. "console=" + console,
  94. "pipe=3",
  95. "data_path=" + dataPath,
  96. }
  97. /*
  98. TODO: move user and wd into env
  99. if user != "" {
  100. env = append(env, "user="+user)
  101. }
  102. if workingDir != "" {
  103. env = append(env, "wd="+workingDir)
  104. }
  105. */
  106. command := exec.Command(init, append([]string{"init"}, args...)...)
  107. // make sure the process is executed inside the context of the rootfs
  108. command.Dir = rootfs
  109. command.Env = append(os.Environ(), env...)
  110. system.SetCloneFlags(command, uintptr(GetNamespaceFlags(container.Namespaces)))
  111. command.SysProcAttr.Pdeathsig = syscall.SIGKILL
  112. command.ExtraFiles = []*os.File{pipe}
  113. return command
  114. }
  115. // SetupCgroups applies the cgroup restrictions to the process running in the contaienr based
  116. // on the container's configuration
  117. func SetupCgroups(container *libcontainer.Container, nspid int) (cgroups.ActiveCgroup, error) {
  118. if container.Cgroups != nil {
  119. c := container.Cgroups
  120. if systemd.UseSystemd() {
  121. return systemd.Apply(c, nspid)
  122. }
  123. return fs.Apply(c, nspid)
  124. }
  125. return nil, nil
  126. }
  127. // InitializeNetworking creates the container's network stack outside of the namespace and moves
  128. // interfaces into the container's net namespaces if necessary
  129. func InitializeNetworking(container *libcontainer.Container, nspid int, pipe *SyncPipe) error {
  130. context := libcontainer.Context{}
  131. for _, config := range container.Networks {
  132. strategy, err := network.GetStrategy(config.Type)
  133. if err != nil {
  134. return err
  135. }
  136. if err := strategy.Create(config, nspid, context); err != nil {
  137. return err
  138. }
  139. }
  140. return pipe.SendToChild(context)
  141. }
  142. // GetNamespaceFlags parses the container's Namespaces options to set the correct
  143. // flags on clone, unshare, and setns
  144. func GetNamespaceFlags(namespaces map[string]bool) (flag int) {
  145. for key, enabled := range namespaces {
  146. if enabled {
  147. if ns := libcontainer.GetNamespace(key); ns != nil {
  148. flag |= ns.Value
  149. }
  150. }
  151. }
  152. return flag
  153. }