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