docker_cli_external_graphdriver_unix_test.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. // +build experimental
  2. // +build !windows
  3. package main
  4. import (
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "net/http"
  10. "net/http/httptest"
  11. "os"
  12. "strings"
  13. "github.com/docker/docker/daemon/graphdriver"
  14. "github.com/docker/docker/daemon/graphdriver/vfs"
  15. "github.com/docker/docker/pkg/archive"
  16. "github.com/go-check/check"
  17. )
  18. func init() {
  19. check.Suite(&DockerExternalGraphdriverSuite{
  20. ds: &DockerSuite{},
  21. })
  22. }
  23. type DockerExternalGraphdriverSuite struct {
  24. server *httptest.Server
  25. ds *DockerSuite
  26. d *Daemon
  27. ec *graphEventsCounter
  28. }
  29. type graphEventsCounter struct {
  30. activations int
  31. creations int
  32. removals int
  33. gets int
  34. puts int
  35. stats int
  36. cleanups int
  37. exists int
  38. init int
  39. metadata int
  40. diff int
  41. applydiff int
  42. changes int
  43. diffsize int
  44. }
  45. func (s *DockerExternalGraphdriverSuite) SetUpTest(c *check.C) {
  46. s.d = NewDaemon(c)
  47. s.ec = &graphEventsCounter{}
  48. }
  49. func (s *DockerExternalGraphdriverSuite) TearDownTest(c *check.C) {
  50. s.d.Stop()
  51. s.ds.TearDownTest(c)
  52. }
  53. func (s *DockerExternalGraphdriverSuite) SetUpSuite(c *check.C) {
  54. mux := http.NewServeMux()
  55. s.server = httptest.NewServer(mux)
  56. type graphDriverRequest struct {
  57. ID string `json:",omitempty"`
  58. Parent string `json:",omitempty"`
  59. MountLabel string `json:",omitempty"`
  60. }
  61. type graphDriverResponse struct {
  62. Err error `json:",omitempty"`
  63. Dir string `json:",omitempty"`
  64. Exists bool `json:",omitempty"`
  65. Status [][2]string `json:",omitempty"`
  66. Metadata map[string]string `json:",omitempty"`
  67. Changes []archive.Change `json:",omitempty"`
  68. Size int64 `json:",omitempty"`
  69. }
  70. respond := func(w http.ResponseWriter, data interface{}) {
  71. w.Header().Set("Content-Type", "appplication/vnd.docker.plugins.v1+json")
  72. switch t := data.(type) {
  73. case error:
  74. fmt.Fprintln(w, fmt.Sprintf(`{"Err": %s}`, t.Error()))
  75. case string:
  76. fmt.Fprintln(w, t)
  77. default:
  78. json.NewEncoder(w).Encode(&data)
  79. }
  80. }
  81. base, err := ioutil.TempDir("", "external-graph-test")
  82. c.Assert(err, check.IsNil)
  83. vfsProto, err := vfs.Init(base, []string{})
  84. if err != nil {
  85. c.Fatalf("error initializing graph driver: %v", err)
  86. }
  87. driver := graphdriver.NewNaiveDiffDriver(vfsProto)
  88. mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
  89. s.ec.activations++
  90. respond(w, `{"Implements": ["GraphDriver"]}`)
  91. })
  92. mux.HandleFunc("/GraphDriver.Init", func(w http.ResponseWriter, r *http.Request) {
  93. s.ec.init++
  94. respond(w, "{}")
  95. })
  96. mux.HandleFunc("/GraphDriver.Create", func(w http.ResponseWriter, r *http.Request) {
  97. s.ec.creations++
  98. var req graphDriverRequest
  99. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  100. http.Error(w, err.Error(), 500)
  101. return
  102. }
  103. if err := driver.Create(req.ID, req.Parent); err != nil {
  104. respond(w, err)
  105. return
  106. }
  107. respond(w, "{}")
  108. })
  109. mux.HandleFunc("/GraphDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
  110. s.ec.removals++
  111. var req graphDriverRequest
  112. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  113. http.Error(w, err.Error(), 500)
  114. return
  115. }
  116. if err := driver.Remove(req.ID); err != nil {
  117. respond(w, err)
  118. return
  119. }
  120. respond(w, "{}")
  121. })
  122. mux.HandleFunc("/GraphDriver.Get", func(w http.ResponseWriter, r *http.Request) {
  123. s.ec.gets++
  124. var req graphDriverRequest
  125. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  126. http.Error(w, err.Error(), 500)
  127. }
  128. dir, err := driver.Get(req.ID, req.MountLabel)
  129. if err != nil {
  130. respond(w, err)
  131. return
  132. }
  133. respond(w, &graphDriverResponse{Dir: dir})
  134. })
  135. mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) {
  136. s.ec.puts++
  137. var req graphDriverRequest
  138. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  139. http.Error(w, err.Error(), 500)
  140. return
  141. }
  142. if err := driver.Put(req.ID); err != nil {
  143. respond(w, err)
  144. return
  145. }
  146. respond(w, "{}")
  147. })
  148. mux.HandleFunc("/GraphDriver.Exists", func(w http.ResponseWriter, r *http.Request) {
  149. s.ec.exists++
  150. var req graphDriverRequest
  151. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  152. http.Error(w, err.Error(), 500)
  153. return
  154. }
  155. respond(w, &graphDriverResponse{Exists: driver.Exists(req.ID)})
  156. })
  157. mux.HandleFunc("/GraphDriver.Status", func(w http.ResponseWriter, r *http.Request) {
  158. s.ec.stats++
  159. respond(w, `{"Status":{}}`)
  160. })
  161. mux.HandleFunc("/GraphDriver.Cleanup", func(w http.ResponseWriter, r *http.Request) {
  162. s.ec.cleanups++
  163. err := driver.Cleanup()
  164. if err != nil {
  165. respond(w, err)
  166. return
  167. }
  168. respond(w, `{}`)
  169. })
  170. mux.HandleFunc("/GraphDriver.GetMetadata", func(w http.ResponseWriter, r *http.Request) {
  171. s.ec.metadata++
  172. var req graphDriverRequest
  173. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  174. http.Error(w, err.Error(), 500)
  175. return
  176. }
  177. data, err := driver.GetMetadata(req.ID)
  178. if err != nil {
  179. respond(w, err)
  180. return
  181. }
  182. respond(w, &graphDriverResponse{Metadata: data})
  183. })
  184. mux.HandleFunc("/GraphDriver.Diff", func(w http.ResponseWriter, r *http.Request) {
  185. s.ec.diff++
  186. var req graphDriverRequest
  187. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  188. http.Error(w, err.Error(), 500)
  189. return
  190. }
  191. diff, err := driver.Diff(req.ID, req.Parent)
  192. if err != nil {
  193. respond(w, err)
  194. return
  195. }
  196. io.Copy(w, diff)
  197. })
  198. mux.HandleFunc("/GraphDriver.Changes", func(w http.ResponseWriter, r *http.Request) {
  199. s.ec.changes++
  200. var req graphDriverRequest
  201. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  202. http.Error(w, err.Error(), 500)
  203. return
  204. }
  205. changes, err := driver.Changes(req.ID, req.Parent)
  206. if err != nil {
  207. respond(w, err)
  208. return
  209. }
  210. respond(w, &graphDriverResponse{Changes: changes})
  211. })
  212. mux.HandleFunc("/GraphDriver.ApplyDiff", func(w http.ResponseWriter, r *http.Request) {
  213. s.ec.applydiff++
  214. id := r.URL.Query().Get("id")
  215. parent := r.URL.Query().Get("parent")
  216. size, err := driver.ApplyDiff(id, parent, r.Body)
  217. if err != nil {
  218. respond(w, err)
  219. return
  220. }
  221. respond(w, &graphDriverResponse{Size: size})
  222. })
  223. mux.HandleFunc("/GraphDriver.DiffSize", func(w http.ResponseWriter, r *http.Request) {
  224. s.ec.diffsize++
  225. var req graphDriverRequest
  226. if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
  227. http.Error(w, err.Error(), 500)
  228. return
  229. }
  230. size, err := driver.DiffSize(req.ID, req.Parent)
  231. if err != nil {
  232. respond(w, err)
  233. return
  234. }
  235. respond(w, &graphDriverResponse{Size: size})
  236. })
  237. if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil {
  238. c.Fatal(err)
  239. }
  240. if err := ioutil.WriteFile("/etc/docker/plugins/test-external-graph-driver.spec", []byte(s.server.URL), 0644); err != nil {
  241. c.Fatal(err)
  242. }
  243. }
  244. func (s *DockerExternalGraphdriverSuite) TearDownSuite(c *check.C) {
  245. s.server.Close()
  246. if err := os.RemoveAll("/etc/docker/plugins"); err != nil {
  247. c.Fatal(err)
  248. }
  249. }
  250. func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriver(c *check.C) {
  251. c.Assert(s.d.StartWithBusybox("-s", "test-external-graph-driver"), check.IsNil)
  252. out, err := s.d.Cmd("run", "-d", "--name=graphtest", "busybox", "sh", "-c", "echo hello > /hello")
  253. c.Assert(err, check.IsNil, check.Commentf(out))
  254. err = s.d.Restart("-s", "test-external-graph-driver")
  255. out, err = s.d.Cmd("inspect", "--format='{{.GraphDriver.Name}}'", "graphtest")
  256. c.Assert(err, check.IsNil, check.Commentf(out))
  257. c.Assert(strings.TrimSpace(out), check.Equals, "test-external-graph-driver")
  258. out, err = s.d.Cmd("diff", "graphtest")
  259. c.Assert(err, check.IsNil, check.Commentf(out))
  260. c.Assert(strings.Contains(out, "A /hello"), check.Equals, true)
  261. out, err = s.d.Cmd("rm", "-f", "graphtest")
  262. c.Assert(err, check.IsNil, check.Commentf(out))
  263. out, err = s.d.Cmd("info")
  264. c.Assert(err, check.IsNil, check.Commentf(out))
  265. err = s.d.Stop()
  266. c.Assert(err, check.IsNil)
  267. c.Assert(s.ec.activations, check.Equals, 2)
  268. c.Assert(s.ec.init, check.Equals, 2)
  269. c.Assert(s.ec.creations >= 1, check.Equals, true)
  270. c.Assert(s.ec.removals >= 1, check.Equals, true)
  271. c.Assert(s.ec.gets >= 1, check.Equals, true)
  272. c.Assert(s.ec.puts >= 1, check.Equals, true)
  273. c.Assert(s.ec.stats, check.Equals, 1)
  274. c.Assert(s.ec.cleanups, check.Equals, 2)
  275. c.Assert(s.ec.exists >= 1, check.Equals, true)
  276. c.Assert(s.ec.applydiff >= 1, check.Equals, true)
  277. c.Assert(s.ec.changes, check.Equals, 1)
  278. c.Assert(s.ec.diffsize, check.Equals, 0)
  279. c.Assert(s.ec.diff, check.Equals, 0)
  280. c.Assert(s.ec.metadata, check.Equals, 1)
  281. }
  282. func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriverPull(c *check.C) {
  283. testRequires(c, Network)
  284. c.Assert(s.d.Start(), check.IsNil)
  285. out, err := s.d.Cmd("pull", "busybox:latest")
  286. c.Assert(err, check.IsNil, check.Commentf(out))
  287. out, err = s.d.Cmd("run", "-d", "busybox", "top")
  288. c.Assert(err, check.IsNil, check.Commentf(out))
  289. }