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  }