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