github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/plugin/v2/plugin.go (about)

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