github.com/rish1988/moby@v25.0.2+incompatible/plugin/v2/plugin_linux.go (about)

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