github.com/yesnault/moby@v1.13.1/plugin/v2/plugin.go (about)

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