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