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