github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/plugin/v2/plugin.go (about)

     1  package v2 // import "github.com/docker/docker/plugin/v2"
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"path/filepath"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/docker/docker/api/types"
    12  	"github.com/docker/docker/pkg/plugingetter"
    13  	"github.com/docker/docker/pkg/plugins"
    14  	digest "github.com/opencontainers/go-digest"
    15  	specs "github.com/opencontainers/runtime-spec/specs-go"
    16  )
    17  
    18  // Plugin represents an individual plugin.
    19  type Plugin struct {
    20  	mu        sync.RWMutex
    21  	PluginObj types.Plugin `json:"plugin"` // todo: embed struct
    22  	pClient   *plugins.Client
    23  	refCount  int
    24  	Rootfs    string // TODO: make private
    25  
    26  	Config   digest.Digest
    27  	Blobsums []digest.Digest
    28  	Manifest digest.Digest
    29  
    30  	modifyRuntimeSpec func(*specs.Spec)
    31  
    32  	SwarmServiceID string
    33  	timeout        time.Duration
    34  	addr           net.Addr
    35  }
    36  
    37  const defaultPluginRuntimeDestination = "/run/docker/plugins"
    38  
    39  // ErrInadequateCapability indicates that the plugin did not have the requested capability.
    40  type ErrInadequateCapability struct {
    41  	cap string
    42  }
    43  
    44  func (e ErrInadequateCapability) Error() string {
    45  	return fmt.Sprintf("plugin does not provide %q capability", e.cap)
    46  }
    47  
    48  // ScopedPath returns the path scoped to the plugin rootfs
    49  func (p *Plugin) ScopedPath(s string) string {
    50  	if p.PluginObj.Config.PropagatedMount != "" && strings.HasPrefix(s, p.PluginObj.Config.PropagatedMount) {
    51  		// re-scope to the propagated mount path on the host
    52  		return filepath.Join(filepath.Dir(p.Rootfs), "propagated-mount", strings.TrimPrefix(s, p.PluginObj.Config.PropagatedMount))
    53  	}
    54  	return filepath.Join(p.Rootfs, s)
    55  }
    56  
    57  // Client returns the plugin client.
    58  // Deprecated: use p.Addr() and manually create the client
    59  func (p *Plugin) Client() *plugins.Client {
    60  	p.mu.RLock()
    61  	defer p.mu.RUnlock()
    62  
    63  	return p.pClient
    64  }
    65  
    66  // SetPClient set the plugin client.
    67  // Deprecated: Hardcoded plugin client is deprecated
    68  func (p *Plugin) SetPClient(client *plugins.Client) {
    69  	p.mu.Lock()
    70  	defer p.mu.Unlock()
    71  
    72  	p.pClient = client
    73  }
    74  
    75  // IsV1 returns true for V1 plugins and false otherwise.
    76  func (p *Plugin) IsV1() bool {
    77  	return false
    78  }
    79  
    80  // Name returns the plugin name.
    81  func (p *Plugin) Name() string {
    82  	return p.PluginObj.Name
    83  }
    84  
    85  // FilterByCap query the plugin for a given capability.
    86  func (p *Plugin) FilterByCap(capability string) (*Plugin, error) {
    87  	capability = strings.ToLower(capability)
    88  	for _, typ := range p.PluginObj.Config.Interface.Types {
    89  		if typ.Capability == capability && typ.Prefix == "docker" {
    90  			return p, nil
    91  		}
    92  	}
    93  	return nil, ErrInadequateCapability{capability}
    94  }
    95  
    96  // InitEmptySettings initializes empty settings for a plugin.
    97  func (p *Plugin) InitEmptySettings() {
    98  	p.PluginObj.Settings.Mounts = make([]types.PluginMount, len(p.PluginObj.Config.Mounts))
    99  	copy(p.PluginObj.Settings.Mounts, p.PluginObj.Config.Mounts)
   100  	p.PluginObj.Settings.Devices = make([]types.PluginDevice, len(p.PluginObj.Config.Linux.Devices))
   101  	copy(p.PluginObj.Settings.Devices, p.PluginObj.Config.Linux.Devices)
   102  	p.PluginObj.Settings.Env = make([]string, 0, len(p.PluginObj.Config.Env))
   103  	for _, env := range p.PluginObj.Config.Env {
   104  		if env.Value != nil {
   105  			p.PluginObj.Settings.Env = append(p.PluginObj.Settings.Env, fmt.Sprintf("%s=%s", env.Name, *env.Value))
   106  		}
   107  	}
   108  	p.PluginObj.Settings.Args = make([]string, len(p.PluginObj.Config.Args.Value))
   109  	copy(p.PluginObj.Settings.Args, p.PluginObj.Config.Args.Value)
   110  }
   111  
   112  // Set is used to pass arguments to the plugin.
   113  func (p *Plugin) Set(args []string) error {
   114  	p.mu.Lock()
   115  	defer p.mu.Unlock()
   116  
   117  	if p.PluginObj.Enabled {
   118  		return fmt.Errorf("cannot set on an active plugin, disable plugin before setting")
   119  	}
   120  
   121  	sets, err := newSettables(args)
   122  	if err != nil {
   123  		return err
   124  	}
   125  
   126  	// TODO(vieux): lots of code duplication here, needs to be refactored.
   127  
   128  next:
   129  	for _, s := range sets {
   130  		// range over all the envs in the config
   131  		for _, env := range p.PluginObj.Config.Env {
   132  			// found the env in the config
   133  			if env.Name == s.name {
   134  				// is it settable ?
   135  				if ok, err := s.isSettable(allowedSettableFieldsEnv, env.Settable); err != nil {
   136  					return err
   137  				} else if !ok {
   138  					return fmt.Errorf("%q is not settable", s.prettyName())
   139  				}
   140  				// is it, so lets update the settings in memory
   141  				updateSettingsEnv(&p.PluginObj.Settings.Env, &s)
   142  				continue next
   143  			}
   144  		}
   145  
   146  		// range over all the mounts in the config
   147  		for _, mount := range p.PluginObj.Config.Mounts {
   148  			// found the mount in the config
   149  			if mount.Name == s.name {
   150  				// is it settable ?
   151  				if ok, err := s.isSettable(allowedSettableFieldsMounts, mount.Settable); err != nil {
   152  					return err
   153  				} else if !ok {
   154  					return fmt.Errorf("%q is not settable", s.prettyName())
   155  				}
   156  
   157  				// it is, so lets update the settings in memory
   158  				if mount.Source == nil {
   159  					return fmt.Errorf("Plugin config has no mount source")
   160  				}
   161  				*mount.Source = s.value
   162  				continue next
   163  			}
   164  		}
   165  
   166  		// range over all the devices in the config
   167  		for _, device := range p.PluginObj.Config.Linux.Devices {
   168  			// found the device in the config
   169  			if device.Name == s.name {
   170  				// is it settable ?
   171  				if ok, err := s.isSettable(allowedSettableFieldsDevices, device.Settable); err != nil {
   172  					return err
   173  				} else if !ok {
   174  					return fmt.Errorf("%q is not settable", s.prettyName())
   175  				}
   176  
   177  				// it is, so lets update the settings in memory
   178  				if device.Path == nil {
   179  					return fmt.Errorf("Plugin config has no device path")
   180  				}
   181  				*device.Path = s.value
   182  				continue next
   183  			}
   184  		}
   185  
   186  		// found the name in the config
   187  		if p.PluginObj.Config.Args.Name == s.name {
   188  			// is it settable ?
   189  			if ok, err := s.isSettable(allowedSettableFieldsArgs, p.PluginObj.Config.Args.Settable); err != nil {
   190  				return err
   191  			} else if !ok {
   192  				return fmt.Errorf("%q is not settable", s.prettyName())
   193  			}
   194  
   195  			// it is, so lets update the settings in memory
   196  			p.PluginObj.Settings.Args = strings.Split(s.value, " ")
   197  			continue next
   198  		}
   199  
   200  		return fmt.Errorf("setting %q not found in the plugin configuration", s.name)
   201  	}
   202  
   203  	return nil
   204  }
   205  
   206  // IsEnabled returns the active state of the plugin.
   207  func (p *Plugin) IsEnabled() bool {
   208  	p.mu.RLock()
   209  	defer p.mu.RUnlock()
   210  
   211  	return p.PluginObj.Enabled
   212  }
   213  
   214  // GetID returns the plugin's ID.
   215  func (p *Plugin) GetID() string {
   216  	p.mu.RLock()
   217  	defer p.mu.RUnlock()
   218  
   219  	return p.PluginObj.ID
   220  }
   221  
   222  // GetSocket returns the plugin socket.
   223  func (p *Plugin) GetSocket() string {
   224  	p.mu.RLock()
   225  	defer p.mu.RUnlock()
   226  
   227  	return p.PluginObj.Config.Interface.Socket
   228  }
   229  
   230  // GetTypes returns the interface types of a plugin.
   231  func (p *Plugin) GetTypes() []types.PluginInterfaceType {
   232  	p.mu.RLock()
   233  	defer p.mu.RUnlock()
   234  
   235  	return p.PluginObj.Config.Interface.Types
   236  }
   237  
   238  // GetRefCount returns the reference count.
   239  func (p *Plugin) GetRefCount() int {
   240  	p.mu.RLock()
   241  	defer p.mu.RUnlock()
   242  
   243  	return p.refCount
   244  }
   245  
   246  // AddRefCount adds to reference count.
   247  func (p *Plugin) AddRefCount(count int) {
   248  	p.mu.Lock()
   249  	defer p.mu.Unlock()
   250  
   251  	p.refCount += count
   252  }
   253  
   254  // Acquire increments the plugin's reference count
   255  // This should be followed up by `Release()` when the plugin is no longer in use.
   256  func (p *Plugin) Acquire() {
   257  	p.AddRefCount(plugingetter.Acquire)
   258  }
   259  
   260  // Release decrements the plugin's reference count
   261  // This should only be called when the plugin is no longer in use, e.g. with
   262  // via `Acquire()` or getter.Get("name", "type", plugingetter.Acquire)
   263  func (p *Plugin) Release() {
   264  	p.AddRefCount(plugingetter.Release)
   265  }
   266  
   267  // SetSpecOptModifier sets the function to use to modify the generated
   268  // runtime spec.
   269  func (p *Plugin) SetSpecOptModifier(f func(*specs.Spec)) {
   270  	p.mu.Lock()
   271  	p.modifyRuntimeSpec = f
   272  	p.mu.Unlock()
   273  }
   274  
   275  // Timeout gets the currently configured connection timeout.
   276  // This should be used when dialing the plugin.
   277  func (p *Plugin) Timeout() time.Duration {
   278  	p.mu.RLock()
   279  	t := p.timeout
   280  	p.mu.RUnlock()
   281  	return t
   282  }
   283  
   284  // SetTimeout sets the timeout to use for dialing.
   285  func (p *Plugin) SetTimeout(t time.Duration) {
   286  	p.mu.Lock()
   287  	p.timeout = t
   288  	p.mu.Unlock()
   289  }
   290  
   291  // Addr returns the net.Addr to use to connect to the plugin socket
   292  func (p *Plugin) Addr() net.Addr {
   293  	p.mu.RLock()
   294  	addr := p.addr
   295  	p.mu.RUnlock()
   296  	return addr
   297  }
   298  
   299  // SetAddr sets the plugin address which can be used for dialing the plugin.
   300  func (p *Plugin) SetAddr(addr net.Addr) {
   301  	p.mu.Lock()
   302  	p.addr = addr
   303  	p.mu.Unlock()
   304  }
   305  
   306  // Protocol is the protocol that should be used for interacting with the plugin.
   307  func (p *Plugin) Protocol() string {
   308  	if p.PluginObj.Config.Interface.ProtocolScheme != "" {
   309  		return p.PluginObj.Config.Interface.ProtocolScheme
   310  	}
   311  	return plugins.ProtocolSchemeHTTPV1
   312  }