plugin.go 7.2 KB

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