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