backend_linux.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // +build linux
  2. package plugin
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "net/http"
  10. "os"
  11. "path/filepath"
  12. "github.com/Sirupsen/logrus"
  13. "github.com/docker/docker/api/types"
  14. "github.com/docker/docker/pkg/archive"
  15. "github.com/docker/docker/pkg/chrootarchive"
  16. "github.com/docker/docker/pkg/stringid"
  17. "github.com/docker/docker/plugin/distribution"
  18. "github.com/docker/docker/plugin/v2"
  19. "github.com/docker/docker/reference"
  20. "golang.org/x/net/context"
  21. )
  22. // Disable deactivates a plugin, which implies that they cannot be used by containers.
  23. func (pm *Manager) Disable(name string) error {
  24. p, err := pm.pluginStore.GetByName(name)
  25. if err != nil {
  26. return err
  27. }
  28. if err := pm.disable(p); err != nil {
  29. return err
  30. }
  31. pm.pluginEventLogger(p.GetID(), name, "disable")
  32. return nil
  33. }
  34. // Enable activates a plugin, which implies that they are ready to be used by containers.
  35. func (pm *Manager) Enable(name string, config *types.PluginEnableConfig) error {
  36. p, err := pm.pluginStore.GetByName(name)
  37. if err != nil {
  38. return err
  39. }
  40. p.TimeoutInSecs = config.Timeout
  41. if err := pm.enable(p, false); err != nil {
  42. return err
  43. }
  44. pm.pluginEventLogger(p.GetID(), name, "enable")
  45. return nil
  46. }
  47. // Inspect examines a plugin config
  48. func (pm *Manager) Inspect(name string) (tp types.Plugin, err error) {
  49. p, err := pm.pluginStore.GetByName(name)
  50. if err != nil {
  51. return tp, err
  52. }
  53. return p.PluginObj, nil
  54. }
  55. func (pm *Manager) pull(ref reference.Named, metaHeader http.Header, authConfig *types.AuthConfig, pluginID string) (types.PluginPrivileges, error) {
  56. pd, err := distribution.Pull(ref, pm.registryService, metaHeader, authConfig)
  57. if err != nil {
  58. logrus.Debugf("error in distribution.Pull(): %v", err)
  59. return nil, err
  60. }
  61. if err := distribution.WritePullData(pd, filepath.Join(pm.libRoot, pluginID), true); err != nil {
  62. logrus.Debugf("error in distribution.WritePullData(): %v", err)
  63. return nil, err
  64. }
  65. tag := distribution.GetTag(ref)
  66. p := v2.NewPlugin(ref.Name(), pluginID, pm.runRoot, pm.libRoot, tag)
  67. if err := p.InitPlugin(); err != nil {
  68. return nil, err
  69. }
  70. pm.pluginStore.Add(p)
  71. pm.pluginEventLogger(pluginID, ref.String(), "pull")
  72. return p.ComputePrivileges(), nil
  73. }
  74. // Pull pulls a plugin and computes the privileges required to install it.
  75. func (pm *Manager) Pull(name string, metaHeader http.Header, authConfig *types.AuthConfig) (types.PluginPrivileges, error) {
  76. ref, err := distribution.GetRef(name)
  77. if err != nil {
  78. logrus.Debugf("error in distribution.GetRef: %v", err)
  79. return nil, err
  80. }
  81. name = ref.String()
  82. if p, _ := pm.pluginStore.GetByName(name); p != nil {
  83. logrus.Debug("plugin already exists")
  84. return nil, fmt.Errorf("%s exists", name)
  85. }
  86. pluginID := stringid.GenerateNonCryptoID()
  87. pluginDir := filepath.Join(pm.libRoot, pluginID)
  88. if err := os.MkdirAll(pluginDir, 0755); err != nil {
  89. logrus.Debugf("error in MkdirAll: %v", err)
  90. return nil, err
  91. }
  92. priv, err := pm.pull(ref, metaHeader, authConfig, pluginID)
  93. if err != nil {
  94. if err := os.RemoveAll(pluginDir); err != nil {
  95. logrus.Warnf("unable to remove %q from failed plugin pull: %v", pluginDir, err)
  96. }
  97. return nil, err
  98. }
  99. return priv, nil
  100. }
  101. // List displays the list of plugins and associated metadata.
  102. func (pm *Manager) List() ([]types.Plugin, error) {
  103. plugins := pm.pluginStore.GetAll()
  104. out := make([]types.Plugin, 0, len(plugins))
  105. for _, p := range plugins {
  106. out = append(out, p.PluginObj)
  107. }
  108. return out, nil
  109. }
  110. // Push pushes a plugin to the store.
  111. func (pm *Manager) Push(name string, metaHeader http.Header, authConfig *types.AuthConfig) error {
  112. p, err := pm.pluginStore.GetByName(name)
  113. if err != nil {
  114. return err
  115. }
  116. dest := filepath.Join(pm.libRoot, p.GetID())
  117. config, err := ioutil.ReadFile(filepath.Join(dest, "config.json"))
  118. if err != nil {
  119. return err
  120. }
  121. var dummy types.Plugin
  122. err = json.Unmarshal(config, &dummy)
  123. if err != nil {
  124. return err
  125. }
  126. rootfs, err := archive.Tar(filepath.Join(dest, "rootfs"), archive.Gzip)
  127. if err != nil {
  128. return err
  129. }
  130. defer rootfs.Close()
  131. _, err = distribution.Push(name, pm.registryService, metaHeader, authConfig, ioutil.NopCloser(bytes.NewReader(config)), rootfs)
  132. // XXX: Ignore returning digest for now.
  133. // Since digest needs to be written to the ProgressWriter.
  134. return err
  135. }
  136. // Remove deletes plugin's root directory.
  137. func (pm *Manager) Remove(name string, config *types.PluginRmConfig) error {
  138. p, err := pm.pluginStore.GetByName(name)
  139. if err != nil {
  140. return err
  141. }
  142. if !config.ForceRemove {
  143. p.RLock()
  144. if p.RefCount > 0 {
  145. p.RUnlock()
  146. return fmt.Errorf("plugin %s is in use", p.Name())
  147. }
  148. p.RUnlock()
  149. if p.IsEnabled() {
  150. return fmt.Errorf("plugin %s is enabled", p.Name())
  151. }
  152. }
  153. if p.IsEnabled() {
  154. if err := pm.disable(p); err != nil {
  155. logrus.Errorf("failed to disable plugin '%s': %s", p.Name(), err)
  156. }
  157. }
  158. pm.pluginStore.Remove(p)
  159. os.RemoveAll(filepath.Join(pm.libRoot, p.GetID()))
  160. pm.pluginEventLogger(p.GetID(), name, "remove")
  161. return nil
  162. }
  163. // Set sets plugin args
  164. func (pm *Manager) Set(name string, args []string) error {
  165. p, err := pm.pluginStore.GetByName(name)
  166. if err != nil {
  167. return err
  168. }
  169. return p.Set(args)
  170. }
  171. // CreateFromContext creates a plugin from the given pluginDir which contains
  172. // both the rootfs and the config.json and a repoName with optional tag.
  173. func (pm *Manager) CreateFromContext(ctx context.Context, tarCtx io.Reader, options *types.PluginCreateOptions) error {
  174. repoName := options.RepoName
  175. ref, err := distribution.GetRef(repoName)
  176. if err != nil {
  177. return err
  178. }
  179. name := ref.Name()
  180. tag := distribution.GetTag(ref)
  181. pluginID := stringid.GenerateNonCryptoID()
  182. p := v2.NewPlugin(name, pluginID, pm.runRoot, pm.libRoot, tag)
  183. if v, _ := pm.pluginStore.GetByName(p.Name()); v != nil {
  184. return fmt.Errorf("plugin %q already exists", p.Name())
  185. }
  186. pluginDir := filepath.Join(pm.libRoot, pluginID)
  187. if err := os.MkdirAll(pluginDir, 0755); err != nil {
  188. return err
  189. }
  190. // In case an error happens, remove the created directory.
  191. if err := pm.createFromContext(ctx, tarCtx, pluginDir, repoName, p); err != nil {
  192. if err := os.RemoveAll(pluginDir); err != nil {
  193. logrus.Warnf("unable to remove %q from failed plugin creation: %v", pluginDir, err)
  194. }
  195. return err
  196. }
  197. return nil
  198. }
  199. func (pm *Manager) createFromContext(ctx context.Context, tarCtx io.Reader, pluginDir, repoName string, p *v2.Plugin) error {
  200. if err := chrootarchive.Untar(tarCtx, pluginDir, nil); err != nil {
  201. return err
  202. }
  203. if err := p.InitPlugin(); err != nil {
  204. return err
  205. }
  206. if err := pm.pluginStore.Add(p); err != nil {
  207. return err
  208. }
  209. pm.pluginEventLogger(p.GetID(), repoName, "create")
  210. return nil
  211. }