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