github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/plugin/v2/plugin.go (about)

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