github.com/damirazo/docker@v1.9.0/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 if err != nil { 106 c.Fatalf("error initializing graph driver: %v", err) 107 } 108 driver := graphdriver.NewNaiveDiffDriver(vfsProto, nil, nil) 109 110 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 111 s.ec.activations++ 112 respond(w, `{"Implements": ["GraphDriver"]}`) 113 }) 114 115 mux.HandleFunc("/GraphDriver.Init", func(w http.ResponseWriter, r *http.Request) { 116 s.ec.init++ 117 respond(w, "{}") 118 }) 119 120 mux.HandleFunc("/GraphDriver.Create", func(w http.ResponseWriter, r *http.Request) { 121 s.ec.creations++ 122 123 var req graphDriverRequest 124 if err := decReq(r.Body, &req, w); err != nil { 125 return 126 } 127 if err := driver.Create(req.ID, req.Parent); err != nil { 128 respond(w, err) 129 return 130 } 131 respond(w, "{}") 132 }) 133 134 mux.HandleFunc("/GraphDriver.Remove", func(w http.ResponseWriter, r *http.Request) { 135 s.ec.removals++ 136 137 var req graphDriverRequest 138 if err := decReq(r.Body, &req, w); err != nil { 139 return 140 } 141 142 if err := driver.Remove(req.ID); err != nil { 143 respond(w, err) 144 return 145 } 146 respond(w, "{}") 147 }) 148 149 mux.HandleFunc("/GraphDriver.Get", func(w http.ResponseWriter, r *http.Request) { 150 s.ec.gets++ 151 152 var req graphDriverRequest 153 if err := decReq(r.Body, &req, w); err != nil { 154 return 155 } 156 157 dir, err := driver.Get(req.ID, req.MountLabel) 158 if err != nil { 159 respond(w, err) 160 return 161 } 162 respond(w, &graphDriverResponse{Dir: dir}) 163 }) 164 165 mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) { 166 s.ec.puts++ 167 168 var req graphDriverRequest 169 if err := decReq(r.Body, &req, w); err != nil { 170 return 171 } 172 173 if err := driver.Put(req.ID); err != nil { 174 respond(w, err) 175 return 176 } 177 respond(w, "{}") 178 }) 179 180 mux.HandleFunc("/GraphDriver.Exists", func(w http.ResponseWriter, r *http.Request) { 181 s.ec.exists++ 182 183 var req graphDriverRequest 184 if err := decReq(r.Body, &req, w); err != nil { 185 return 186 } 187 respond(w, &graphDriverResponse{Exists: driver.Exists(req.ID)}) 188 }) 189 190 mux.HandleFunc("/GraphDriver.Status", func(w http.ResponseWriter, r *http.Request) { 191 s.ec.stats++ 192 respond(w, &graphDriverResponse{Status: driver.Status()}) 193 }) 194 195 mux.HandleFunc("/GraphDriver.Cleanup", func(w http.ResponseWriter, r *http.Request) { 196 s.ec.cleanups++ 197 err := driver.Cleanup() 198 if err != nil { 199 respond(w, err) 200 return 201 } 202 respond(w, `{}`) 203 }) 204 205 mux.HandleFunc("/GraphDriver.GetMetadata", func(w http.ResponseWriter, r *http.Request) { 206 s.ec.metadata++ 207 208 var req graphDriverRequest 209 if err := decReq(r.Body, &req, w); err != nil { 210 return 211 } 212 213 data, err := driver.GetMetadata(req.ID) 214 if err != nil { 215 respond(w, err) 216 return 217 } 218 respond(w, &graphDriverResponse{Metadata: data}) 219 }) 220 221 mux.HandleFunc("/GraphDriver.Diff", func(w http.ResponseWriter, r *http.Request) { 222 s.ec.diff++ 223 224 var req graphDriverRequest 225 if err := decReq(r.Body, &req, w); err != nil { 226 return 227 } 228 229 diff, err := driver.Diff(req.ID, req.Parent) 230 if err != nil { 231 respond(w, err) 232 return 233 } 234 io.Copy(w, diff) 235 }) 236 237 mux.HandleFunc("/GraphDriver.Changes", func(w http.ResponseWriter, r *http.Request) { 238 s.ec.changes++ 239 var req graphDriverRequest 240 if err := decReq(r.Body, &req, w); err != nil { 241 return 242 } 243 244 changes, err := driver.Changes(req.ID, req.Parent) 245 if err != nil { 246 respond(w, err) 247 return 248 } 249 respond(w, &graphDriverResponse{Changes: changes}) 250 }) 251 252 mux.HandleFunc("/GraphDriver.ApplyDiff", func(w http.ResponseWriter, r *http.Request) { 253 s.ec.applydiff++ 254 var diff archive.Reader = r.Body 255 defer r.Body.Close() 256 257 id := r.URL.Query().Get("id") 258 parent := r.URL.Query().Get("parent") 259 260 if id == "" { 261 http.Error(w, fmt.Sprintf("missing id"), 409) 262 } 263 264 size, err := driver.ApplyDiff(id, parent, diff) 265 if err != nil { 266 respond(w, err) 267 return 268 } 269 respond(w, &graphDriverResponse{Size: size}) 270 }) 271 272 mux.HandleFunc("/GraphDriver.DiffSize", func(w http.ResponseWriter, r *http.Request) { 273 s.ec.diffsize++ 274 275 var req graphDriverRequest 276 if err := decReq(r.Body, &req, w); err != nil { 277 return 278 } 279 280 size, err := driver.DiffSize(req.ID, req.Parent) 281 if err != nil { 282 respond(w, err) 283 return 284 } 285 respond(w, &graphDriverResponse{Size: size}) 286 }) 287 288 if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil { 289 c.Fatal(err) 290 } 291 292 if err := ioutil.WriteFile("/etc/docker/plugins/test-external-graph-driver.spec", []byte(s.server.URL), 0644); err != nil { 293 c.Fatal(err) 294 } 295 } 296 297 func (s *DockerExternalGraphdriverSuite) TearDownSuite(c *check.C) { 298 s.server.Close() 299 300 if err := os.RemoveAll("/etc/docker/plugins"); err != nil { 301 c.Fatal(err) 302 } 303 } 304 305 func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriver(c *check.C) { 306 if err := s.d.StartWithBusybox("-s", "test-external-graph-driver"); err != nil { 307 b, _ := ioutil.ReadFile(s.d.LogfileName()) 308 c.Assert(err, check.IsNil, check.Commentf("\n%s", string(b))) 309 } 310 311 out, err := s.d.Cmd("run", "-d", "--name=graphtest", "busybox", "sh", "-c", "echo hello > /hello") 312 c.Assert(err, check.IsNil, check.Commentf(out)) 313 314 err = s.d.Restart("-s", "test-external-graph-driver") 315 316 out, err = s.d.Cmd("inspect", "--format='{{.GraphDriver.Name}}'", "graphtest") 317 c.Assert(err, check.IsNil, check.Commentf(out)) 318 c.Assert(strings.TrimSpace(out), check.Equals, "test-external-graph-driver") 319 320 out, err = s.d.Cmd("diff", "graphtest") 321 c.Assert(err, check.IsNil, check.Commentf(out)) 322 c.Assert(strings.Contains(out, "A /hello"), check.Equals, true) 323 324 out, err = s.d.Cmd("rm", "-f", "graphtest") 325 c.Assert(err, check.IsNil, check.Commentf(out)) 326 327 out, err = s.d.Cmd("info") 328 c.Assert(err, check.IsNil, check.Commentf(out)) 329 330 err = s.d.Stop() 331 c.Assert(err, check.IsNil) 332 333 c.Assert(s.ec.activations, check.Equals, 2) 334 c.Assert(s.ec.init, check.Equals, 2) 335 c.Assert(s.ec.creations >= 1, check.Equals, true) 336 c.Assert(s.ec.removals >= 1, check.Equals, true) 337 c.Assert(s.ec.gets >= 1, check.Equals, true) 338 c.Assert(s.ec.puts >= 1, check.Equals, true) 339 c.Assert(s.ec.stats, check.Equals, 3) 340 c.Assert(s.ec.cleanups, check.Equals, 2) 341 c.Assert(s.ec.exists >= 1, check.Equals, true) 342 c.Assert(s.ec.applydiff >= 1, check.Equals, true) 343 c.Assert(s.ec.changes, check.Equals, 1) 344 c.Assert(s.ec.diffsize, check.Equals, 0) 345 c.Assert(s.ec.diff, check.Equals, 0) 346 c.Assert(s.ec.metadata, check.Equals, 1) 347 } 348 349 func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriverPull(c *check.C) { 350 testRequires(c, Network) 351 c.Assert(s.d.Start(), check.IsNil) 352 353 out, err := s.d.Cmd("pull", "busybox:latest") 354 c.Assert(err, check.IsNil, check.Commentf(out)) 355 356 out, err = s.d.Cmd("run", "-d", "busybox", "top") 357 c.Assert(err, check.IsNil, check.Commentf(out)) 358 }