plugin_linux.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // +build linux
  2. package v2
  3. import (
  4. "os"
  5. "path/filepath"
  6. "runtime"
  7. "strings"
  8. "github.com/docker/docker/api/types"
  9. "github.com/docker/docker/oci"
  10. "github.com/docker/docker/pkg/system"
  11. specs "github.com/opencontainers/runtime-spec/specs-go"
  12. "github.com/pkg/errors"
  13. )
  14. // InitSpec creates an OCI spec from the plugin's config.
  15. func (p *Plugin) InitSpec(execRoot string) (*specs.Spec, error) {
  16. s := oci.DefaultSpec()
  17. s.Root = &specs.Root{
  18. Path: p.Rootfs,
  19. Readonly: false, // TODO: all plugins should be readonly? settable in config?
  20. }
  21. userMounts := make(map[string]struct{}, len(p.PluginObj.Settings.Mounts))
  22. for _, m := range p.PluginObj.Settings.Mounts {
  23. userMounts[m.Destination] = struct{}{}
  24. }
  25. execRoot = filepath.Join(execRoot, p.PluginObj.ID)
  26. if err := os.MkdirAll(execRoot, 0700); err != nil {
  27. return nil, errors.WithStack(err)
  28. }
  29. mounts := append(p.PluginObj.Config.Mounts, types.PluginMount{
  30. Source: &execRoot,
  31. Destination: defaultPluginRuntimeDestination,
  32. Type: "bind",
  33. Options: []string{"rbind", "rshared"},
  34. })
  35. if p.PluginObj.Config.Network.Type != "" {
  36. // TODO: if net == bridge, use libnetwork controller to create a new plugin-specific bridge, bind mount /etc/hosts and /etc/resolv.conf look at the docker code (allocateNetwork, initialize)
  37. if p.PluginObj.Config.Network.Type == "host" {
  38. oci.RemoveNamespace(&s, specs.LinuxNamespaceType("network"))
  39. }
  40. etcHosts := "/etc/hosts"
  41. resolvConf := "/etc/resolv.conf"
  42. mounts = append(mounts,
  43. types.PluginMount{
  44. Source: &etcHosts,
  45. Destination: etcHosts,
  46. Type: "bind",
  47. Options: []string{"rbind", "ro"},
  48. },
  49. types.PluginMount{
  50. Source: &resolvConf,
  51. Destination: resolvConf,
  52. Type: "bind",
  53. Options: []string{"rbind", "ro"},
  54. })
  55. }
  56. if p.PluginObj.Config.PidHost {
  57. oci.RemoveNamespace(&s, specs.LinuxNamespaceType("pid"))
  58. }
  59. if p.PluginObj.Config.IpcHost {
  60. oci.RemoveNamespace(&s, specs.LinuxNamespaceType("ipc"))
  61. }
  62. for _, mnt := range mounts {
  63. m := specs.Mount{
  64. Destination: mnt.Destination,
  65. Type: mnt.Type,
  66. Options: mnt.Options,
  67. }
  68. if mnt.Source == nil {
  69. return nil, errors.New("mount source is not specified")
  70. }
  71. m.Source = *mnt.Source
  72. s.Mounts = append(s.Mounts, m)
  73. }
  74. for i, m := range s.Mounts {
  75. if strings.HasPrefix(m.Destination, "/dev/") {
  76. if _, ok := userMounts[m.Destination]; ok {
  77. s.Mounts = append(s.Mounts[:i], s.Mounts[i+1:]...)
  78. }
  79. }
  80. }
  81. if p.PluginObj.Config.PropagatedMount != "" {
  82. p.PropagatedMount = filepath.Join(p.Rootfs, p.PluginObj.Config.PropagatedMount)
  83. s.Linux.RootfsPropagation = "rshared"
  84. }
  85. if p.PluginObj.Config.Linux.AllowAllDevices {
  86. s.Linux.Resources.Devices = []specs.LinuxDeviceCgroup{{Allow: true, Access: "rwm"}}
  87. }
  88. for _, dev := range p.PluginObj.Settings.Devices {
  89. path := *dev.Path
  90. d, dPermissions, err := oci.DevicesFromPath(path, path, "rwm")
  91. if err != nil {
  92. return nil, errors.WithStack(err)
  93. }
  94. s.Linux.Devices = append(s.Linux.Devices, d...)
  95. s.Linux.Resources.Devices = append(s.Linux.Resources.Devices, dPermissions...)
  96. }
  97. envs := make([]string, 1, len(p.PluginObj.Settings.Env)+1)
  98. envs[0] = "PATH=" + system.DefaultPathEnv(runtime.GOOS)
  99. envs = append(envs, p.PluginObj.Settings.Env...)
  100. args := append(p.PluginObj.Config.Entrypoint, p.PluginObj.Settings.Args...)
  101. cwd := p.PluginObj.Config.WorkDir
  102. if len(cwd) == 0 {
  103. cwd = "/"
  104. }
  105. s.Process.Terminal = false
  106. s.Process.Args = args
  107. s.Process.Cwd = cwd
  108. s.Process.Env = envs
  109. caps := s.Process.Capabilities
  110. caps.Bounding = append(caps.Bounding, p.PluginObj.Config.Linux.Capabilities...)
  111. caps.Permitted = append(caps.Permitted, p.PluginObj.Config.Linux.Capabilities...)
  112. caps.Inheritable = append(caps.Inheritable, p.PluginObj.Config.Linux.Capabilities...)
  113. caps.Effective = append(caps.Effective, p.PluginObj.Config.Linux.Capabilities...)
  114. return &s, nil
  115. }