backend_linux.go 5.4 KB

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