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