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 }