github.com/kim0/docker@v0.6.2-0.20161130212042-4addda3f07e7/integration-cli/docker_cli_external_graphdriver_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "strings" 14 15 "github.com/docker/docker/daemon/graphdriver" 16 "github.com/docker/docker/daemon/graphdriver/vfs" 17 "github.com/docker/docker/pkg/archive" 18 "github.com/docker/docker/pkg/plugins" 19 "github.com/go-check/check" 20 ) 21 22 func init() { 23 check.Suite(&DockerExternalGraphdriverSuite{ 24 ds: &DockerSuite{}, 25 }) 26 } 27 28 type DockerExternalGraphdriverSuite struct { 29 server *httptest.Server 30 jserver *httptest.Server 31 ds *DockerSuite 32 d *Daemon 33 ec map[string]*graphEventsCounter 34 } 35 36 type graphEventsCounter struct { 37 activations int 38 creations int 39 removals int 40 gets int 41 puts int 42 stats int 43 cleanups int 44 exists int 45 init int 46 metadata int 47 diff int 48 applydiff int 49 changes int 50 diffsize int 51 } 52 53 func (s *DockerExternalGraphdriverSuite) SetUpTest(c *check.C) { 54 s.d = NewDaemon(c) 55 } 56 57 func (s *DockerExternalGraphdriverSuite) TearDownTest(c *check.C) { 58 s.d.Stop() 59 s.ds.TearDownTest(c) 60 } 61 62 func (s *DockerExternalGraphdriverSuite) SetUpSuite(c *check.C) { 63 s.ec = make(map[string]*graphEventsCounter) 64 s.setUpPluginViaSpecFile(c) 65 s.setUpPluginViaJSONFile(c) 66 } 67 68 func (s *DockerExternalGraphdriverSuite) setUpPluginViaSpecFile(c *check.C) { 69 mux := http.NewServeMux() 70 s.server = httptest.NewServer(mux) 71 72 s.setUpPlugin(c, "test-external-graph-driver", "spec", mux, []byte(s.server.URL)) 73 } 74 75 func (s *DockerExternalGraphdriverSuite) setUpPluginViaJSONFile(c *check.C) { 76 mux := http.NewServeMux() 77 s.jserver = httptest.NewServer(mux) 78 79 p := plugins.NewLocalPlugin("json-external-graph-driver", s.jserver.URL) 80 b, err := json.Marshal(p) 81 c.Assert(err, check.IsNil) 82 83 s.setUpPlugin(c, "json-external-graph-driver", "json", mux, b) 84 } 85 86 func (s *DockerExternalGraphdriverSuite) setUpPlugin(c *check.C, name string, ext string, mux *http.ServeMux, b []byte) { 87 type graphDriverRequest struct { 88 ID string `json:",omitempty"` 89 Parent string `json:",omitempty"` 90 MountLabel string `json:",omitempty"` 91 ReadOnly bool `json:",omitempty"` 92 } 93 94 type graphDriverResponse struct { 95 Err error `json:",omitempty"` 96 Dir string `json:",omitempty"` 97 Exists bool `json:",omitempty"` 98 Status [][2]string `json:",omitempty"` 99 Metadata map[string]string `json:",omitempty"` 100 Changes []archive.Change `json:",omitempty"` 101 Size int64 `json:",omitempty"` 102 } 103 104 respond := func(w http.ResponseWriter, data interface{}) { 105 w.Header().Set("Content-Type", "appplication/vnd.docker.plugins.v1+json") 106 switch t := data.(type) { 107 case error: 108 fmt.Fprintln(w, fmt.Sprintf(`{"Err": %q}`, t.Error())) 109 case string: 110 fmt.Fprintln(w, t) 111 default: 112 json.NewEncoder(w).Encode(&data) 113 } 114 } 115 116 decReq := func(b io.ReadCloser, out interface{}, w http.ResponseWriter) error { 117 defer b.Close() 118 if err := json.NewDecoder(b).Decode(&out); err != nil { 119 http.Error(w, fmt.Sprintf("error decoding json: %s", err.Error()), 500) 120 } 121 return nil 122 } 123 124 base, err := ioutil.TempDir("", name) 125 c.Assert(err, check.IsNil) 126 vfsProto, err := vfs.Init(base, []string{}, nil, nil) 127 c.Assert(err, check.IsNil, check.Commentf("error initializing graph driver")) 128 driver := graphdriver.NewNaiveDiffDriver(vfsProto, nil, nil) 129 130 s.ec[ext] = &graphEventsCounter{} 131 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 132 s.ec[ext].activations++ 133 respond(w, `{"Implements": ["GraphDriver"]}`) 134 }) 135 136 mux.HandleFunc("/GraphDriver.Init", func(w http.ResponseWriter, r *http.Request) { 137 s.ec[ext].init++ 138 respond(w, "{}") 139 }) 140 141 mux.HandleFunc("/GraphDriver.CreateReadWrite", func(w http.ResponseWriter, r *http.Request) { 142 s.ec[ext].creations++ 143 144 var req graphDriverRequest 145 if err := decReq(r.Body, &req, w); err != nil { 146 return 147 } 148 if err := driver.CreateReadWrite(req.ID, req.Parent, "", nil); err != nil { 149 respond(w, err) 150 return 151 } 152 respond(w, "{}") 153 }) 154 155 mux.HandleFunc("/GraphDriver.Create", func(w http.ResponseWriter, r *http.Request) { 156 s.ec[ext].creations++ 157 158 var req graphDriverRequest 159 if err := decReq(r.Body, &req, w); err != nil { 160 return 161 } 162 if err := driver.Create(req.ID, req.Parent, "", nil); err != nil { 163 respond(w, err) 164 return 165 } 166 respond(w, "{}") 167 }) 168 169 mux.HandleFunc("/GraphDriver.Remove", func(w http.ResponseWriter, r *http.Request) { 170 s.ec[ext].removals++ 171 172 var req graphDriverRequest 173 if err := decReq(r.Body, &req, w); err != nil { 174 return 175 } 176 177 if err := driver.Remove(req.ID); err != nil { 178 respond(w, err) 179 return 180 } 181 respond(w, "{}") 182 }) 183 184 mux.HandleFunc("/GraphDriver.Get", func(w http.ResponseWriter, r *http.Request) { 185 s.ec[ext].gets++ 186 187 var req graphDriverRequest 188 if err := decReq(r.Body, &req, w); err != nil { 189 return 190 } 191 192 dir, err := driver.Get(req.ID, req.MountLabel) 193 if err != nil { 194 respond(w, err) 195 return 196 } 197 respond(w, &graphDriverResponse{Dir: dir}) 198 }) 199 200 mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) { 201 s.ec[ext].puts++ 202 203 var req graphDriverRequest 204 if err := decReq(r.Body, &req, w); err != nil { 205 return 206 } 207 208 if err := driver.Put(req.ID); err != nil { 209 respond(w, err) 210 return 211 } 212 respond(w, "{}") 213 }) 214 215 mux.HandleFunc("/GraphDriver.Exists", func(w http.ResponseWriter, r *http.Request) { 216 s.ec[ext].exists++ 217 218 var req graphDriverRequest 219 if err := decReq(r.Body, &req, w); err != nil { 220 return 221 } 222 respond(w, &graphDriverResponse{Exists: driver.Exists(req.ID)}) 223 }) 224 225 mux.HandleFunc("/GraphDriver.Status", func(w http.ResponseWriter, r *http.Request) { 226 s.ec[ext].stats++ 227 respond(w, &graphDriverResponse{Status: driver.Status()}) 228 }) 229 230 mux.HandleFunc("/GraphDriver.Cleanup", func(w http.ResponseWriter, r *http.Request) { 231 s.ec[ext].cleanups++ 232 err := driver.Cleanup() 233 if err != nil { 234 respond(w, err) 235 return 236 } 237 respond(w, `{}`) 238 }) 239 240 mux.HandleFunc("/GraphDriver.GetMetadata", func(w http.ResponseWriter, r *http.Request) { 241 s.ec[ext].metadata++ 242 243 var req graphDriverRequest 244 if err := decReq(r.Body, &req, w); err != nil { 245 return 246 } 247 248 data, err := driver.GetMetadata(req.ID) 249 if err != nil { 250 respond(w, err) 251 return 252 } 253 respond(w, &graphDriverResponse{Metadata: data}) 254 }) 255 256 mux.HandleFunc("/GraphDriver.Diff", func(w http.ResponseWriter, r *http.Request) { 257 s.ec[ext].diff++ 258 259 var req graphDriverRequest 260 if err := decReq(r.Body, &req, w); err != nil { 261 return 262 } 263 264 diff, err := driver.Diff(req.ID, req.Parent) 265 if err != nil { 266 respond(w, err) 267 return 268 } 269 io.Copy(w, diff) 270 }) 271 272 mux.HandleFunc("/GraphDriver.Changes", func(w http.ResponseWriter, r *http.Request) { 273 s.ec[ext].changes++ 274 var req graphDriverRequest 275 if err := decReq(r.Body, &req, w); err != nil { 276 return 277 } 278 279 changes, err := driver.Changes(req.ID, req.Parent) 280 if err != nil { 281 respond(w, err) 282 return 283 } 284 respond(w, &graphDriverResponse{Changes: changes}) 285 }) 286 287 mux.HandleFunc("/GraphDriver.ApplyDiff", func(w http.ResponseWriter, r *http.Request) { 288 s.ec[ext].applydiff++ 289 diff := r.Body 290 defer r.Body.Close() 291 292 id := r.URL.Query().Get("id") 293 parent := r.URL.Query().Get("parent") 294 295 if id == "" { 296 http.Error(w, fmt.Sprintf("missing id"), 409) 297 } 298 299 size, err := driver.ApplyDiff(id, parent, diff) 300 if err != nil { 301 respond(w, err) 302 return 303 } 304 respond(w, &graphDriverResponse{Size: size}) 305 }) 306 307 mux.HandleFunc("/GraphDriver.DiffSize", func(w http.ResponseWriter, r *http.Request) { 308 s.ec[ext].diffsize++ 309 310 var req graphDriverRequest 311 if err := decReq(r.Body, &req, w); err != nil { 312 return 313 } 314 315 size, err := driver.DiffSize(req.ID, req.Parent) 316 if err != nil { 317 respond(w, err) 318 return 319 } 320 respond(w, &graphDriverResponse{Size: size}) 321 }) 322 323 err = os.MkdirAll("/etc/docker/plugins", 0755) 324 c.Assert(err, check.IsNil, check.Commentf("error creating /etc/docker/plugins")) 325 326 specFile := "/etc/docker/plugins/" + name + "." + ext 327 err = ioutil.WriteFile(specFile, b, 0644) 328 c.Assert(err, check.IsNil, check.Commentf("error writing to %s", specFile)) 329 } 330 331 func (s *DockerExternalGraphdriverSuite) TearDownSuite(c *check.C) { 332 s.server.Close() 333 s.jserver.Close() 334 335 err := os.RemoveAll("/etc/docker/plugins") 336 c.Assert(err, check.IsNil, check.Commentf("error removing /etc/docker/plugins")) 337 } 338 339 func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriver(c *check.C) { 340 testRequires(c, ExperimentalDaemon) 341 342 s.testExternalGraphDriver("test-external-graph-driver", "spec", c) 343 s.testExternalGraphDriver("json-external-graph-driver", "json", c) 344 } 345 346 func (s *DockerExternalGraphdriverSuite) testExternalGraphDriver(name string, ext string, c *check.C) { 347 if err := s.d.StartWithBusybox("-s", name); err != nil { 348 b, _ := ioutil.ReadFile(s.d.LogFileName()) 349 c.Assert(err, check.IsNil, check.Commentf("\n%s", string(b))) 350 } 351 352 out, err := s.d.Cmd("run", "--name=graphtest", "busybox", "sh", "-c", "echo hello > /hello") 353 c.Assert(err, check.IsNil, check.Commentf(out)) 354 355 err = s.d.Restart("-s", name) 356 357 out, err = s.d.Cmd("inspect", "--format={{.GraphDriver.Name}}", "graphtest") 358 c.Assert(err, check.IsNil, check.Commentf(out)) 359 c.Assert(strings.TrimSpace(out), check.Equals, name) 360 361 out, err = s.d.Cmd("diff", "graphtest") 362 c.Assert(err, check.IsNil, check.Commentf(out)) 363 c.Assert(strings.Contains(out, "A /hello"), check.Equals, true, check.Commentf("diff output: %s", out)) 364 365 out, err = s.d.Cmd("rm", "-f", "graphtest") 366 c.Assert(err, check.IsNil, check.Commentf(out)) 367 368 out, err = s.d.Cmd("info") 369 c.Assert(err, check.IsNil, check.Commentf(out)) 370 371 err = s.d.Stop() 372 c.Assert(err, check.IsNil) 373 374 // Don't check s.ec.exists, because the daemon no longer calls the 375 // Exists function. 376 c.Assert(s.ec[ext].activations, check.Equals, 2) 377 c.Assert(s.ec[ext].init, check.Equals, 2) 378 c.Assert(s.ec[ext].creations >= 1, check.Equals, true) 379 c.Assert(s.ec[ext].removals >= 1, check.Equals, true) 380 c.Assert(s.ec[ext].gets >= 1, check.Equals, true) 381 c.Assert(s.ec[ext].puts >= 1, check.Equals, true) 382 c.Assert(s.ec[ext].stats, check.Equals, 5) 383 c.Assert(s.ec[ext].cleanups, check.Equals, 2) 384 c.Assert(s.ec[ext].applydiff >= 1, check.Equals, true) 385 c.Assert(s.ec[ext].changes, check.Equals, 1) 386 c.Assert(s.ec[ext].diffsize, check.Equals, 0) 387 c.Assert(s.ec[ext].diff, check.Equals, 0) 388 c.Assert(s.ec[ext].metadata, check.Equals, 1) 389 } 390 391 func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriverPull(c *check.C) { 392 testRequires(c, Network, ExperimentalDaemon) 393 394 c.Assert(s.d.Start(), check.IsNil) 395 396 out, err := s.d.Cmd("pull", "busybox:latest") 397 c.Assert(err, check.IsNil, check.Commentf(out)) 398 399 out, err = s.d.Cmd("run", "-d", "busybox", "top") 400 c.Assert(err, check.IsNil, check.Commentf(out)) 401 }