1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Move responsibility of ls/inspect to volume driver

Makes `docker volume ls` and `docker volume inspect` ask the volume
drivers rather than only using what is cached locally.

Previously in order to use a volume from an external driver, one would
either have to use `docker volume create` or have a container that is
already using that volume for it to be visible to the other volume
API's.

For keeping uniqueness of volume names in the daemon, names are bound to
a driver on a first come first serve basis. If two drivers have a volume
with the same name, the first one is chosen, and a warning is logged
about the second one.

Adds 2 new methods to the plugin API, `List` and `Get`.
If a plugin does not implement these endpoints, a user will not be able
to find the specified volumes as well requests go through the drivers.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff 2015-09-23 16:29:14 -04:00
parent 6c30931b06
commit d3eca4451d
30 changed files with 700 additions and 285 deletions

View file

@ -32,6 +32,8 @@ type eventCounter struct {
mounts int
unmounts int
paths int
lists int
gets int
}
type DockerExternalVolumeSuite struct {
@ -64,6 +66,12 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
Err string `json:",omitempty"`
}
type vol struct {
Name string
Mountpoint string
}
var volList []vol
read := func(b io.ReadCloser) (pluginRequest, error) {
defer b.Close()
var pr pluginRequest
@ -93,29 +101,61 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
mux.HandleFunc("/VolumeDriver.Create", func(w http.ResponseWriter, r *http.Request) {
s.ec.creations++
_, err := read(r.Body)
if err != nil {
send(w, err)
return
}
send(w, nil)
})
mux.HandleFunc("/VolumeDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
s.ec.removals++
pr, err := read(r.Body)
if err != nil {
send(w, err)
return
}
volList = append(volList, vol{Name: pr.Name})
send(w, nil)
})
mux.HandleFunc("/VolumeDriver.List", func(w http.ResponseWriter, r *http.Request) {
s.ec.lists++
send(w, map[string][]vol{"Volumes": volList})
})
mux.HandleFunc("/VolumeDriver.Get", func(w http.ResponseWriter, r *http.Request) {
s.ec.gets++
pr, err := read(r.Body)
if err != nil {
send(w, err)
return
}
for _, v := range volList {
if v.Name == pr.Name {
v.Mountpoint = hostVolumePath(pr.Name)
send(w, map[string]vol{"Volume": v})
return
}
}
send(w, `{"Err": "no such volume"}`)
})
mux.HandleFunc("/VolumeDriver.Remove", func(w http.ResponseWriter, r *http.Request) {
s.ec.removals++
pr, err := read(r.Body)
if err != nil {
send(w, err)
return
}
if err := os.RemoveAll(hostVolumePath(pr.Name)); err != nil {
send(w, &pluginResp{Err: err.Error()})
return
}
for i, v := range volList {
if v.Name == pr.Name {
if err := os.RemoveAll(hostVolumePath(v.Name)); err != nil {
send(w, fmt.Sprintf(`{"Err": "%v"}`, err))
return
}
volList = append(volList[:i], volList[i+1:]...)
break
}
}
send(w, nil)
})
@ -128,8 +168,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
return
}
p := hostVolumePath(pr.Name)
fmt.Fprintln(w, fmt.Sprintf("{\"Mountpoint\": \"%s\"}", p))
send(w, &pluginResp{Mountpoint: p})
})
mux.HandleFunc("/VolumeDriver.Mount", func(w http.ResponseWriter, r *http.Request) {
@ -164,7 +203,7 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
return
}
fmt.Fprintln(w, nil)
send(w, nil)
})
err := os.MkdirAll("/etc/docker/plugins", 0755)
@ -287,8 +326,8 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverNamedCheckBindLocalV
// Make sure a request to use a down driver doesn't block other requests
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverLookupNotBlocked(c *check.C) {
specPath := "/etc/docker/plugins/down-driver.spec"
err := ioutil.WriteFile("/etc/docker/plugins/down-driver.spec", []byte("tcp://127.0.0.7:9999"), 0644)
c.Assert(err, checker.IsNil)
err := ioutil.WriteFile(specPath, []byte("tcp://127.0.0.7:9999"), 0644)
c.Assert(err, check.IsNil)
defer os.RemoveAll(specPath)
chCmd1 := make(chan struct{})
@ -316,10 +355,11 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverLookupNotBlocked(c *
case err := <-chCmd2:
c.Assert(err, checker.IsNil)
case <-time.After(5 * time.Second):
c.Fatal("volume creates are blocked by previous create requests when previous driver is down")
cmd2.Process.Kill()
c.Fatal("volume creates are blocked by previous create requests when previous driver is down")
}
}
func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverRetryNotImmediatelyExists(c *check.C) {
err := s.d.StartWithBusybox()
c.Assert(err, checker.IsNil)
@ -371,3 +411,24 @@ func (s *DockerExternalVolumeSuite) TestExternalVolumeDriverBindExternalVolume(c
c.Assert(mounts[0].Name, checker.Equals, "foo")
c.Assert(mounts[0].Driver, checker.Equals, "test-external-volume-driver")
}
func (s *DockerExternalVolumeSuite) TestStartExternalVolumeDriverList(c *check.C) {
dockerCmd(c, "volume", "create", "-d", "test-external-volume-driver", "--name", "abc")
out, _ := dockerCmd(c, "volume", "ls")
ls := strings.Split(strings.TrimSpace(out), "\n")
c.Assert(len(ls), check.Equals, 2, check.Commentf("\n%s", out))
vol := strings.Fields(ls[len(ls)-1])
c.Assert(len(vol), check.Equals, 2, check.Commentf("%v", vol))
c.Assert(vol[0], check.Equals, "test-external-volume-driver")
c.Assert(vol[1], check.Equals, "abc")
c.Assert(s.ec.lists, check.Equals, 1)
}
func (s *DockerExternalVolumeSuite) TestStartExternalVolumeDriverGet(c *check.C) {
out, _, err := dockerCmdWithError("volume", "inspect", "dummy")
c.Assert(err, check.NotNil, check.Commentf(out))
c.Assert(s.ec.gets, check.Equals, 1)
c.Assert(out, checker.Contains, "No such volume")
}