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