backend.go 5.4 KB

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