github.com/olljanat/moby@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  }