github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/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 _, set := range sets {
   130  		s := set
   131  
   132  		// range over all the envs in the config
   133  		for _, env := range p.PluginObj.Config.Env {
   134  			// found the env in the config
   135  			if env.Name == s.name {
   136  				// is it settable ?
   137  				if ok, err := s.isSettable(allowedSettableFieldsEnv, env.Settable); err != nil {
   138  					return err
   139  				} else if !ok {
   140  					return fmt.Errorf("%q is not settable", s.prettyName())
   141  				}
   142  				// is it, so lets update the settings in memory
   143  				updateSettingsEnv(&p.PluginObj.Settings.Env, &s)
   144  				continue next
   145  			}
   146  		}
   147  
   148  		// range over all the mounts in the config
   149  		for _, mount := range p.PluginObj.Config.Mounts {
   150  			// found the mount in the config
   151  			if mount.Name == s.name {
   152  				// is it settable ?
   153  				if ok, err := s.isSettable(allowedSettableFieldsMounts, mount.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  				if mount.Source == nil {
   161  					return fmt.Errorf("Plugin config has no mount source")
   162  				}
   163  				*mount.Source = s.value
   164  				continue next
   165  			}
   166  		}
   167  
   168  		// range over all the devices in the config
   169  		for _, device := range p.PluginObj.Config.Linux.Devices {
   170  			// found the device in the config
   171  			if device.Name == s.name {
   172  				// is it settable ?
   173  				if ok, err := s.isSettable(allowedSettableFieldsDevices, device.Settable); err != nil {
   174  					return err
   175  				} else if !ok {
   176  					return fmt.Errorf("%q is not settable", s.prettyName())
   177  				}
   178  
   179  				// it is, so lets update the settings in memory
   180  				if device.Path == nil {
   181  					return fmt.Errorf("Plugin config has no device path")
   182  				}
   183  				*device.Path = s.value
   184  				continue next
   185  			}
   186  		}
   187  
   188  		// found the name in the config
   189  		if p.PluginObj.Config.Args.Name == s.name {
   190  			// is it settable ?
   191  			if ok, err := s.isSettable(allowedSettableFieldsArgs, p.PluginObj.Config.Args.Settable); err != nil {
   192  				return err
   193  			} else if !ok {
   194  				return fmt.Errorf("%q is not settable", s.prettyName())
   195  			}
   196  
   197  			// it is, so lets update the settings in memory
   198  			p.PluginObj.Settings.Args = strings.Split(s.value, " ")
   199  			continue next
   200  		}
   201  
   202  		return fmt.Errorf("setting %q not found in the plugin configuration", s.name)
   203  	}
   204  
   205  	return nil
   206  }
   207  
   208  // IsEnabled returns the active state of the plugin.
   209  func (p *Plugin) IsEnabled() bool {
   210  	p.mu.RLock()
   211  	defer p.mu.RUnlock()
   212  
   213  	return p.PluginObj.Enabled
   214  }
   215  
   216  // GetID returns the plugin's ID.
   217  func (p *Plugin) GetID() string {
   218  	p.mu.RLock()
   219  	defer p.mu.RUnlock()
   220  
   221  	return p.PluginObj.ID
   222  }
   223  
   224  // GetSocket returns the plugin socket.
   225  func (p *Plugin) GetSocket() string {
   226  	p.mu.RLock()
   227  	defer p.mu.RUnlock()
   228  
   229  	return p.PluginObj.Config.Interface.Socket
   230  }
   231  
   232  // GetTypes returns the interface types of a plugin.
   233  func (p *Plugin) GetTypes() []types.PluginInterfaceType {
   234  	p.mu.RLock()
   235  	defer p.mu.RUnlock()
   236  
   237  	return p.PluginObj.Config.Interface.Types
   238  }
   239  
   240  // GetRefCount returns the reference count.
   241  func (p *Plugin) GetRefCount() int {
   242  	p.mu.RLock()
   243  	defer p.mu.RUnlock()
   244  
   245  	return p.refCount
   246  }
   247  
   248  // AddRefCount adds to reference count.
   249  func (p *Plugin) AddRefCount(count int) {
   250  	p.mu.Lock()
   251  	defer p.mu.Unlock()
   252  
   253  	p.refCount += count
   254  }
   255  
   256  // Acquire increments the plugin's reference count
   257  // This should be followed up by `Release()` when the plugin is no longer in use.
   258  func (p *Plugin) Acquire() {
   259  	p.AddRefCount(plugingetter.Acquire)
   260  }
   261  
   262  // Release decrements the plugin's reference count
   263  // This should only be called when the plugin is no longer in use, e.g. with
   264  // via `Acquire()` or getter.Get("name", "type", plugingetter.Acquire)
   265  func (p *Plugin) Release() {
   266  	p.AddRefCount(plugingetter.Release)
   267  }
   268  
   269  // SetSpecOptModifier sets the function to use to modify the generated
   270  // runtime spec.
   271  func (p *Plugin) SetSpecOptModifier(f func(*specs.Spec)) {
   272  	p.mu.Lock()
   273  	p.modifyRuntimeSpec = f
   274  	p.mu.Unlock()
   275  }
   276  
   277  // Timeout gets the currently configured connection timeout.
   278  // This should be used when dialing the plugin.
   279  func (p *Plugin) Timeout() time.Duration {
   280  	p.mu.RLock()
   281  	t := p.timeout
   282  	p.mu.RUnlock()
   283  	return t
   284  }
   285  
   286  // SetTimeout sets the timeout to use for dialing.
   287  func (p *Plugin) SetTimeout(t time.Duration) {
   288  	p.mu.Lock()
   289  	p.timeout = t
   290  	p.mu.Unlock()
   291  }
   292  
   293  // Addr returns the net.Addr to use to connect to the plugin socket
   294  func (p *Plugin) Addr() net.Addr {
   295  	p.mu.RLock()
   296  	addr := p.addr
   297  	p.mu.RUnlock()
   298  	return addr
   299  }
   300  
   301  // SetAddr sets the plugin address which can be used for dialing the plugin.
   302  func (p *Plugin) SetAddr(addr net.Addr) {
   303  	p.mu.Lock()
   304  	p.addr = addr
   305  	p.mu.Unlock()
   306  }
   307  
   308  // Protocol is the protocol that should be used for interacting with the plugin.
   309  func (p *Plugin) Protocol() string {
   310  	if p.PluginObj.Config.Interface.ProtocolScheme != "" {
   311  		return p.PluginObj.Config.Interface.ProtocolScheme
   312  	}
   313  	return plugins.ProtocolSchemeHTTPV1
   314  }