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