github.com/goern/docker@v1.9.0-rc1/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  	if err != nil {
   106  		c.Fatalf("error initializing graph driver: %v", err)
   107  	}
   108  	driver := graphdriver.NewNaiveDiffDriver(vfsProto, nil, nil)
   109  
   110  	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
   111  		s.ec.activations++
   112  		respond(w, `{"Implements": ["GraphDriver"]}`)
   113  	})
   114  
   115  	mux.HandleFunc("/GraphDriver.Init", func(w http.ResponseWriter, r *http.Request) {
   116  		s.ec.init++
   117  		respond(w, "{}")
   118  	})
   119  
   120  	mux.HandleFunc("/GraphDriver.Create", func(w http.ResponseWriter, r *http.Request) {
   121  		s.ec.creations++
   122  
   123  		var req graphDriverRequest
   124  		if err := decReq(r.Body, &req, w); err != nil {
   125  			return
   126  		}
   127  		if err := driver.Create(req.ID, req.Parent); err != nil {
   128  			respond(w, err)
   129  			return
   130  		}
   131  		respond(w, "{}")
   132  	})
   133  
   134  	mux.HandleFunc("/GraphDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
   135  		s.ec.removals++
   136  
   137  		var req graphDriverRequest
   138  		if err := decReq(r.Body, &req, w); err != nil {
   139  			return
   140  		}
   141  
   142  		if err := driver.Remove(req.ID); err != nil {
   143  			respond(w, err)
   144  			return
   145  		}
   146  		respond(w, "{}")
   147  	})
   148  
   149  	mux.HandleFunc("/GraphDriver.Get", func(w http.ResponseWriter, r *http.Request) {
   150  		s.ec.gets++
   151  
   152  		var req graphDriverRequest
   153  		if err := decReq(r.Body, &req, w); err != nil {
   154  			return
   155  		}
   156  
   157  		dir, err := driver.Get(req.ID, req.MountLabel)
   158  		if err != nil {
   159  			respond(w, err)
   160  			return
   161  		}
   162  		respond(w, &graphDriverResponse{Dir: dir})
   163  	})
   164  
   165  	mux.HandleFunc("/GraphDriver.Put", func(w http.ResponseWriter, r *http.Request) {
   166  		s.ec.puts++
   167  
   168  		var req graphDriverRequest
   169  		if err := decReq(r.Body, &req, w); err != nil {
   170  			return
   171  		}
   172  
   173  		if err := driver.Put(req.ID); err != nil {
   174  			respond(w, err)
   175  			return
   176  		}
   177  		respond(w, "{}")
   178  	})
   179  
   180  	mux.HandleFunc("/GraphDriver.Exists", func(w http.ResponseWriter, r *http.Request) {
   181  		s.ec.exists++
   182  
   183  		var req graphDriverRequest
   184  		if err := decReq(r.Body, &req, w); err != nil {
   185  			return
   186  		}
   187  		respond(w, &graphDriverResponse{Exists: driver.Exists(req.ID)})
   188  	})
   189  
   190  	mux.HandleFunc("/GraphDriver.Status", func(w http.ResponseWriter, r *http.Request) {
   191  		s.ec.stats++
   192  		respond(w, &graphDriverResponse{Status: driver.Status()})
   193  	})
   194  
   195  	mux.HandleFunc("/GraphDriver.Cleanup", func(w http.ResponseWriter, r *http.Request) {
   196  		s.ec.cleanups++
   197  		err := driver.Cleanup()
   198  		if err != nil {
   199  			respond(w, err)
   200  			return
   201  		}
   202  		respond(w, `{}`)
   203  	})
   204  
   205  	mux.HandleFunc("/GraphDriver.GetMetadata", func(w http.ResponseWriter, r *http.Request) {
   206  		s.ec.metadata++
   207  
   208  		var req graphDriverRequest
   209  		if err := decReq(r.Body, &req, w); err != nil {
   210  			return
   211  		}
   212  
   213  		data, err := driver.GetMetadata(req.ID)
   214  		if err != nil {
   215  			respond(w, err)
   216  			return
   217  		}
   218  		respond(w, &graphDriverResponse{Metadata: data})
   219  	})
   220  
   221  	mux.HandleFunc("/GraphDriver.Diff", func(w http.ResponseWriter, r *http.Request) {
   222  		s.ec.diff++
   223  
   224  		var req graphDriverRequest
   225  		if err := decReq(r.Body, &req, w); err != nil {
   226  			return
   227  		}
   228  
   229  		diff, err := driver.Diff(req.ID, req.Parent)
   230  		if err != nil {
   231  			respond(w, err)
   232  			return
   233  		}
   234  		io.Copy(w, diff)
   235  	})
   236  
   237  	mux.HandleFunc("/GraphDriver.Changes", func(w http.ResponseWriter, r *http.Request) {
   238  		s.ec.changes++
   239  		var req graphDriverRequest
   240  		if err := decReq(r.Body, &req, w); err != nil {
   241  			return
   242  		}
   243  
   244  		changes, err := driver.Changes(req.ID, req.Parent)
   245  		if err != nil {
   246  			respond(w, err)
   247  			return
   248  		}
   249  		respond(w, &graphDriverResponse{Changes: changes})
   250  	})
   251  
   252  	mux.HandleFunc("/GraphDriver.ApplyDiff", func(w http.ResponseWriter, r *http.Request) {
   253  		s.ec.applydiff++
   254  		var diff archive.Reader = r.Body
   255  		defer r.Body.Close()
   256  
   257  		id := r.URL.Query().Get("id")
   258  		parent := r.URL.Query().Get("parent")
   259  
   260  		if id == "" {
   261  			http.Error(w, fmt.Sprintf("missing id"), 409)
   262  		}
   263  
   264  		size, err := driver.ApplyDiff(id, parent, diff)
   265  		if err != nil {
   266  			respond(w, err)
   267  			return
   268  		}
   269  		respond(w, &graphDriverResponse{Size: size})
   270  	})
   271  
   272  	mux.HandleFunc("/GraphDriver.DiffSize", func(w http.ResponseWriter, r *http.Request) {
   273  		s.ec.diffsize++
   274  
   275  		var req graphDriverRequest
   276  		if err := decReq(r.Body, &req, w); err != nil {
   277  			return
   278  		}
   279  
   280  		size, err := driver.DiffSize(req.ID, req.Parent)
   281  		if err != nil {
   282  			respond(w, err)
   283  			return
   284  		}
   285  		respond(w, &graphDriverResponse{Size: size})
   286  	})
   287  
   288  	if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil {
   289  		c.Fatal(err)
   290  	}
   291  
   292  	if err := ioutil.WriteFile("/etc/docker/plugins/test-external-graph-driver.spec", []byte(s.server.URL), 0644); err != nil {
   293  		c.Fatal(err)
   294  	}
   295  }
   296  
   297  func (s *DockerExternalGraphdriverSuite) TearDownSuite(c *check.C) {
   298  	s.server.Close()
   299  
   300  	if err := os.RemoveAll("/etc/docker/plugins"); err != nil {
   301  		c.Fatal(err)
   302  	}
   303  }
   304  
   305  func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriver(c *check.C) {
   306  	if err := s.d.StartWithBusybox("-s", "test-external-graph-driver"); err != nil {
   307  		b, _ := ioutil.ReadFile(s.d.LogfileName())
   308  		c.Assert(err, check.IsNil, check.Commentf("\n%s", string(b)))
   309  	}
   310  
   311  	out, err := s.d.Cmd("run", "-d", "--name=graphtest", "busybox", "sh", "-c", "echo hello > /hello")
   312  	c.Assert(err, check.IsNil, check.Commentf(out))
   313  
   314  	err = s.d.Restart("-s", "test-external-graph-driver")
   315  
   316  	out, err = s.d.Cmd("inspect", "--format='{{.GraphDriver.Name}}'", "graphtest")
   317  	c.Assert(err, check.IsNil, check.Commentf(out))
   318  	c.Assert(strings.TrimSpace(out), check.Equals, "test-external-graph-driver")
   319  
   320  	out, err = s.d.Cmd("diff", "graphtest")
   321  	c.Assert(err, check.IsNil, check.Commentf(out))
   322  	c.Assert(strings.Contains(out, "A /hello"), check.Equals, true)
   323  
   324  	out, err = s.d.Cmd("rm", "-f", "graphtest")
   325  	c.Assert(err, check.IsNil, check.Commentf(out))
   326  
   327  	out, err = s.d.Cmd("info")
   328  	c.Assert(err, check.IsNil, check.Commentf(out))
   329  
   330  	err = s.d.Stop()
   331  	c.Assert(err, check.IsNil)
   332  
   333  	c.Assert(s.ec.activations, check.Equals, 2)
   334  	c.Assert(s.ec.init, check.Equals, 2)
   335  	c.Assert(s.ec.creations >= 1, check.Equals, true)
   336  	c.Assert(s.ec.removals >= 1, check.Equals, true)
   337  	c.Assert(s.ec.gets >= 1, check.Equals, true)
   338  	c.Assert(s.ec.puts >= 1, check.Equals, true)
   339  	c.Assert(s.ec.stats, check.Equals, 3)
   340  	c.Assert(s.ec.cleanups, check.Equals, 2)
   341  	c.Assert(s.ec.exists >= 1, check.Equals, true)
   342  	c.Assert(s.ec.applydiff >= 1, check.Equals, true)
   343  	c.Assert(s.ec.changes, check.Equals, 1)
   344  	c.Assert(s.ec.diffsize, check.Equals, 0)
   345  	c.Assert(s.ec.diff, check.Equals, 0)
   346  	c.Assert(s.ec.metadata, check.Equals, 1)
   347  }
   348  
   349  func (s *DockerExternalGraphdriverSuite) TestExternalGraphDriverPull(c *check.C) {
   350  	testRequires(c, Network)
   351  	c.Assert(s.d.Start(), check.IsNil)
   352  
   353  	out, err := s.d.Cmd("pull", "busybox:latest")
   354  	c.Assert(err, check.IsNil, check.Commentf(out))
   355  
   356  	out, err = s.d.Cmd("run", "-d", "busybox", "top")
   357  	c.Assert(err, check.IsNil, check.Commentf(out))
   358  }