Add volume API/CLI

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff
2015-08-26 13:37:52 -04:00
parent 7ef08f39ed
commit b3b7eb2723
49 changed files with 1455 additions and 394 deletions
+1
View File
@@ -20,6 +20,7 @@ type DockerSuite struct {
func (s *DockerSuite) TearDownTest(c *check.C) {
deleteAllContainers()
deleteAllImages()
deleteAllVolumes()
}
func init() {
@@ -0,0 +1,85 @@
package main
import (
"encoding/json"
"net/http"
"path"
"github.com/docker/docker/api/types"
"github.com/go-check/check"
)
func (s *DockerSuite) TestVolumesApiList(c *check.C) {
dockerCmd(c, "run", "-d", "-v", "/foo", "busybox")
status, b, err := sockRequest("GET", "/volumes", nil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
var volumes types.VolumesListResponse
c.Assert(json.Unmarshal(b, &volumes), check.IsNil)
c.Assert(len(volumes.Volumes), check.Equals, 1, check.Commentf("\n%v", volumes.Volumes))
}
func (s *DockerSuite) TestVolumesApiCreate(c *check.C) {
config := types.VolumeCreateRequest{
Name: "test",
}
status, b, err := sockRequest("POST", "/volumes", config)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusCreated, check.Commentf(string(b)))
var vol types.Volume
err = json.Unmarshal(b, &vol)
c.Assert(err, check.IsNil)
c.Assert(path.Base(path.Dir(vol.Mountpoint)), check.Equals, config.Name)
}
func (s *DockerSuite) TestVolumesApiRemove(c *check.C) {
dockerCmd(c, "run", "-d", "-v", "/foo", "--name=test", "busybox")
status, b, err := sockRequest("GET", "/volumes", nil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusOK)
var volumes types.VolumesListResponse
c.Assert(json.Unmarshal(b, &volumes), check.IsNil)
c.Assert(len(volumes.Volumes), check.Equals, 1, check.Commentf("\n%v", volumes.Volumes))
v := volumes.Volumes[0]
status, _, err = sockRequest("DELETE", "/volumes/"+v.Name, nil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusConflict, check.Commentf("Should not be able to remove a volume that is in use"))
dockerCmd(c, "rm", "-f", "test")
status, data, err := sockRequest("DELETE", "/volumes/"+v.Name, nil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusNoContent, check.Commentf(string(data)))
}
func (s *DockerSuite) TestVolumesApiInspect(c *check.C) {
config := types.VolumeCreateRequest{
Name: "test",
}
status, b, err := sockRequest("POST", "/volumes", config)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusCreated, check.Commentf(string(b)))
status, b, err = sockRequest("GET", "/volumes", nil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusOK, check.Commentf(string(b)))
var volumes types.VolumesListResponse
c.Assert(json.Unmarshal(b, &volumes), check.IsNil)
c.Assert(len(volumes.Volumes), check.Equals, 1, check.Commentf("\n%v", volumes.Volumes))
var vol types.Volume
status, b, err = sockRequest("GET", "/volumes/"+config.Name, nil)
c.Assert(err, check.IsNil)
c.Assert(status, check.Equals, http.StatusOK, check.Commentf(string(b)))
c.Assert(json.Unmarshal(b, &vol), check.IsNil)
c.Assert(vol.Name, check.Equals, config.Name)
}
+24
View File
@@ -71,6 +71,7 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithVolumesRefs(c *check.C) {
if err := s.d.Restart(); err != nil {
c.Fatal(err)
}
if _, err := s.d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox", "top"); err != nil {
c.Fatal(err)
}
@@ -1660,5 +1661,28 @@ func (s *DockerDaemonSuite) TestDaemonRestartWithPausedContainer(c *check.C) {
c.Fatal(err)
}
}
}
func (s *DockerDaemonSuite) TestDaemonRestartRmVolumeInUse(c *check.C) {
c.Assert(s.d.StartWithBusybox(), check.IsNil)
out, err := s.d.Cmd("create", "-v", "test:/foo", "busybox")
c.Assert(err, check.IsNil, check.Commentf(out))
c.Assert(s.d.Restart(), check.IsNil)
out, err = s.d.Cmd("volume", "rm", "test")
c.Assert(err, check.Not(check.IsNil), check.Commentf("should not be able to remove in use volume after daemon restart"))
c.Assert(strings.Contains(out, "in use"), check.Equals, true)
}
func (s *DockerDaemonSuite) TestDaemonRestartLocalVolumes(c *check.C) {
c.Assert(s.d.Start(), check.IsNil)
_, err := s.d.Cmd("volume", "create", "--name", "test")
c.Assert(err, check.IsNil)
c.Assert(s.d.Restart(), check.IsNil)
_, err = s.d.Cmd("volume", "inspect", "test")
c.Assert(err, check.IsNil)
}
+1 -1
View File
@@ -238,7 +238,7 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
}
expected := 39
expected := 40
if isLocalDaemon {
expected++ // for the daemon command
}
+10
View File
@@ -2781,3 +2781,13 @@ func (s *DockerSuite) TestRunCreateContainerFailedCleanUp(c *check.C) {
containerID, err := inspectField(name, "Id")
c.Assert(containerID, check.Equals, "", check.Commentf("Expected not to have this container: %s!", containerID))
}
func (s *DockerSuite) TestRunNamedVolume(c *check.C) {
dockerCmd(c, "run", "--name=test", "-v", "testing:/foo", "busybox", "sh", "-c", "echo hello > /foo/bar")
out, _ := dockerCmd(c, "run", "--volumes-from", "test", "busybox", "sh", "-c", "cat /foo/bar")
c.Assert(strings.TrimSpace(out), check.Equals, "hello")
out, _ = dockerCmd(c, "run", "-v", "testing:/foo", "busybox", "sh", "-c", "cat /foo/bar")
c.Assert(strings.TrimSpace(out), check.Equals, "hello")
}
@@ -119,11 +119,6 @@ func (s *DockerExternalVolumeSuite) SetUpSuite(c *check.C) {
http.Error(w, err.Error(), 500)
}
p := hostVolumePath(pr.name)
if err := os.RemoveAll(p); err != nil {
http.Error(w, err.Error(), 500)
}
w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
fmt.Fprintln(w, `{}`)
})
@@ -152,7 +147,7 @@ func (s *DockerExternalVolumeSuite) TestStartExternalNamedVolumeDriver(c *check.
out, err := s.d.Cmd("run", "--rm", "--name", "test-data", "-v", "external-volume-test:/tmp/external-volume-test", "--volume-driver", "test-external-volume-driver", "busybox:latest", "cat", "/tmp/external-volume-test/test")
if err != nil {
c.Fatal(err)
c.Fatal(out, err)
}
if !strings.Contains(out, s.server.URL) {
@@ -202,20 +197,17 @@ func (s DockerExternalVolumeSuite) TestStartExternalVolumeDriverVolumesFrom(c *c
c.Fatal(err)
}
if _, err := s.d.Cmd("run", "-d", "--name", "vol-test1", "-v", "/foo", "--volume-driver", "test-external-volume-driver", "busybox:latest"); err != nil {
c.Fatal(err)
}
out, err := s.d.Cmd("run", "-d", "--name", "vol-test1", "-v", "/foo", "--volume-driver", "test-external-volume-driver", "busybox:latest")
c.Assert(err, check.IsNil, check.Commentf(out))
if _, err := s.d.Cmd("run", "--rm", "--volumes-from", "vol-test1", "--name", "vol-test2", "busybox", "ls", "/tmp"); err != nil {
c.Fatal(err)
}
out, err = s.d.Cmd("run", "--rm", "--volumes-from", "vol-test1", "--name", "vol-test2", "busybox", "ls", "/tmp")
c.Assert(err, check.IsNil, check.Commentf(out))
if _, err := s.d.Cmd("rm", "-f", "vol-test1"); err != nil {
c.Fatal(err)
}
out, err = s.d.Cmd("rm", "-fv", "vol-test1")
c.Assert(err, check.IsNil, check.Commentf(out))
c.Assert(s.ec.activations, check.Equals, 1)
c.Assert(s.ec.creations, check.Equals, 2)
c.Assert(s.ec.creations, check.Equals, 1)
c.Assert(s.ec.removals, check.Equals, 1)
c.Assert(s.ec.mounts, check.Equals, 2)
c.Assert(s.ec.unmounts, check.Equals, 2)
@@ -226,12 +218,12 @@ func (s DockerExternalVolumeSuite) TestStartExternalVolumeDriverDeleteContainer(
c.Fatal(err)
}
if _, err := s.d.Cmd("run", "-d", "--name", "vol-test1", "-v", "/foo", "--volume-driver", "test-external-volume-driver", "busybox:latest"); err != nil {
c.Fatal(err)
if out, err := s.d.Cmd("run", "-d", "--name", "vol-test1", "-v", "/foo", "--volume-driver", "test-external-volume-driver", "busybox:latest"); err != nil {
c.Fatal(out, err)
}
if _, err := s.d.Cmd("rm", "-fv", "vol-test1"); err != nil {
c.Fatal(err)
if out, err := s.d.Cmd("rm", "-fv", "vol-test1"); err != nil {
c.Fatal(out, err)
}
c.Assert(s.ec.activations, check.Equals, 1)
+90
View File
@@ -0,0 +1,90 @@
package main
import (
"os/exec"
"strings"
"github.com/go-check/check"
)
func (s *DockerSuite) TestVolumeCliCreate(c *check.C) {
dockerCmd(c, "volume", "create")
_, err := runCommand(exec.Command(dockerBinary, "volume", "create", "-d", "nosuchdriver"))
c.Assert(err, check.Not(check.IsNil))
out, _ := dockerCmd(c, "volume", "create", "--name=test")
name := strings.TrimSpace(out)
c.Assert(name, check.Equals, "test")
}
func (s *DockerSuite) TestVolumeCliInspect(c *check.C) {
c.Assert(
exec.Command(dockerBinary, "volume", "inspect", "doesntexist").Run(),
check.Not(check.IsNil),
check.Commentf("volume inspect should error on non-existant volume"),
)
out, _ := dockerCmd(c, "volume", "create")
name := strings.TrimSpace(out)
out, _ = dockerCmd(c, "volume", "inspect", "--format='{{ .Name }}'", name)
c.Assert(strings.TrimSpace(out), check.Equals, name)
dockerCmd(c, "volume", "create", "--name", "test")
out, _ = dockerCmd(c, "volume", "inspect", "--format='{{ .Name }}'", "test")
c.Assert(strings.TrimSpace(out), check.Equals, "test")
}
func (s *DockerSuite) TestVolumeCliLs(c *check.C) {
out, _ := dockerCmd(c, "volume", "create")
id := strings.TrimSpace(out)
dockerCmd(c, "volume", "create", "--name", "test")
dockerCmd(c, "run", "-v", "/foo", "busybox", "ls", "/")
out, _ = dockerCmd(c, "volume", "ls")
outArr := strings.Split(strings.TrimSpace(out), "\n")
c.Assert(len(outArr), check.Equals, 4, check.Commentf("\n%s", out))
// Since there is no guarentee of ordering of volumes, we just make sure the names are in the output
c.Assert(strings.Contains(out, id+"\n"), check.Equals, true)
c.Assert(strings.Contains(out, "test\n"), check.Equals, true)
}
func (s *DockerSuite) TestVolumeCliRm(c *check.C) {
out, _ := dockerCmd(c, "volume", "create")
id := strings.TrimSpace(out)
dockerCmd(c, "volume", "create", "--name", "test")
dockerCmd(c, "volume", "rm", id)
dockerCmd(c, "volume", "rm", "test")
out, _ = dockerCmd(c, "volume", "ls")
outArr := strings.Split(strings.TrimSpace(out), "\n")
c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
volumeID := "testing"
dockerCmd(c, "run", "-v", volumeID+":/foo", "--name=test", "busybox", "sh", "-c", "echo hello > /foo/bar")
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "volume", "rm", "testing"))
c.Assert(
err,
check.Not(check.IsNil),
check.Commentf("Should not be able to remove volume that is in use by a container\n%s", out))
out, _ = dockerCmd(c, "run", "--volumes-from=test", "--name=test2", "busybox", "sh", "-c", "cat /foo/bar")
c.Assert(strings.TrimSpace(out), check.Equals, "hello")
dockerCmd(c, "rm", "-fv", "test2")
dockerCmd(c, "volume", "inspect", volumeID)
dockerCmd(c, "rm", "-f", "test")
out, _ = dockerCmd(c, "run", "--name=test2", "-v", volumeID+":/foo", "busybox", "sh", "-c", "cat /foo/bar")
c.Assert(strings.TrimSpace(out), check.Equals, "hello", check.Commentf("volume data was removed"))
dockerCmd(c, "rm", "test2")
dockerCmd(c, "volume", "rm", volumeID)
c.Assert(
exec.Command("volume", "rm", "doesntexist").Run(),
check.Not(check.IsNil),
check.Commentf("volume rm should fail with non-existant volume"),
)
}
+34
View File
@@ -445,6 +445,40 @@ func deleteAllContainers() error {
return nil
}
func deleteAllVolumes() error {
volumes, err := getAllVolumes()
if err != nil {
return err
}
var errors []string
for _, v := range volumes {
status, b, err := sockRequest("DELETE", "/volumes/"+v.Name, nil)
if err != nil {
errors = append(errors, err.Error())
continue
}
if status != http.StatusNoContent {
errors = append(errors, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b)))
}
}
if len(errors) > 0 {
return fmt.Errorf(strings.Join(errors, "\n"))
}
return nil
}
func getAllVolumes() ([]*types.Volume, error) {
var volumes types.VolumesListResponse
_, b, err := sockRequest("GET", "/volumes", nil)
if err != nil {
return nil, err
}
if err := json.Unmarshal(b, &volumes); err != nil {
return nil, err
}
return volumes.Volumes, nil
}
var protectedImages = map[string]struct{}{}
func init() {