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