plugin_linux.go 3.8 KB

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