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 }