mirror of https://github.com/docker/docs.git
docker volume rm
Signed-off-by: Victor Vieux <vieux@docker.com>
This commit is contained in:
parent
ce7c0a6dfa
commit
440a379860
|
@ -104,7 +104,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/samalba/dockerclient",
|
||||
"Rev": "77b723e2c0d07a21cc9483dc6108f95bd403b576"
|
||||
"Rev": "14849c8f5ab609e834348fccad25e32877952fa7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
||||
|
|
|
@ -757,3 +757,9 @@ func (client *DockerClient) ListVolumes() ([]*Volume, error) {
|
|||
}
|
||||
return volumesList.Volumes, nil
|
||||
}
|
||||
|
||||
func (client *DockerClient) RemoveVolume(name string) error {
|
||||
uri := fmt.Sprintf("/%s/volumes/%s", APIVersion, name)
|
||||
_, err := client.doRequest("DELETE", uri, nil, nil)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -46,4 +46,5 @@ type Client interface {
|
|||
ImportImage(source string, repository string, tag string, tar io.Reader) (io.ReadCloser, error)
|
||||
BuildImage(image *BuildImage) (io.ReadCloser, error)
|
||||
ListVolumes() ([]*Volume, error)
|
||||
RemoveVolume(name string) error
|
||||
}
|
||||
|
|
|
@ -175,3 +175,8 @@ func (client *MockClient) ListVolumes() ([]*dockerclient.Volume, error) {
|
|||
args := client.Mock.Called()
|
||||
return args.Get(0).([]*dockerclient.Volume), args.Error(1)
|
||||
}
|
||||
|
||||
func (client *MockClient) RemoveVolume(name string) error {
|
||||
args := client.Mock.Called(name)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
|
|
@ -149,3 +149,7 @@ func (client *NopClient) BuildImage(image *dockerclient.BuildImage) (io.ReadClos
|
|||
func (client *NopClient) ListVolumes() ([]*dockerclient.Volume, error) {
|
||||
return nil, ErrNoEngine
|
||||
}
|
||||
|
||||
func (client *NopClient) RemoveVolume(name string) error {
|
||||
return ErrNoEngine
|
||||
}
|
||||
|
|
|
@ -401,12 +401,13 @@ func deleteContainers(c *context, w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
name := mux.Vars(r)["name"]
|
||||
force := boolValue(r, "force")
|
||||
volumes := boolValue(r, "v")
|
||||
container := c.cluster.Container(name)
|
||||
if container == nil {
|
||||
httpError(w, fmt.Sprintf("Container %s not found", name), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if err := c.cluster.RemoveContainer(container, force); err != nil {
|
||||
if err := c.cluster.RemoveContainer(container, force, volumes); err != nil {
|
||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
@ -572,6 +573,27 @@ func deleteImages(c *context, w http.ResponseWriter, r *http.Request) {
|
|||
json.NewEncoder(NewWriteFlusher(w)).Encode(out)
|
||||
}
|
||||
|
||||
// DELETE /volumes/{names:.*}
|
||||
func deleteVolumes(c *context, w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var name = mux.Vars(r)["name"]
|
||||
|
||||
found, err := c.cluster.RemoveVolumes(name)
|
||||
if err != nil {
|
||||
httpError(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !found {
|
||||
httpError(w, fmt.Sprintf("No such volume %s", name), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// GET /_ping
|
||||
func ping(c *context, w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte{'O', 'K'})
|
||||
|
|
|
@ -73,6 +73,7 @@ var routes = map[string]map[string]handler{
|
|||
"/containers/{name:.*}/exec": postContainersExec,
|
||||
"/exec/{execid:.*}/start": proxyHijack,
|
||||
"/exec/{execid:.*}/resize": proxyContainer,
|
||||
// "/volumes": postVolumes,
|
||||
},
|
||||
"PUT": {
|
||||
"/containers/{name:.*}/archive": proxyContainer,
|
||||
|
@ -80,6 +81,7 @@ var routes = map[string]map[string]handler{
|
|||
"DELETE": {
|
||||
"/containers/{name:.*}": deleteContainers,
|
||||
"/images/{name:.*}": deleteImages,
|
||||
"/volumes/{name:.*}": deleteVolumes,
|
||||
},
|
||||
"OPTIONS": {
|
||||
"": optionsHandler,
|
||||
|
|
|
@ -12,7 +12,7 @@ type Cluster interface {
|
|||
CreateContainer(config *ContainerConfig, name string) (*Container, error)
|
||||
|
||||
// Remove a container
|
||||
RemoveContainer(container *Container, force bool) error
|
||||
RemoveContainer(container *Container, force, volumes bool) error
|
||||
|
||||
// Return all images
|
||||
Images(all bool) []*Image
|
||||
|
@ -37,6 +37,9 @@ type Cluster interface {
|
|||
// Return one volume from the cluster
|
||||
Volume(name string) *Volume
|
||||
|
||||
// Remove volumes from the cluster
|
||||
RemoveVolumes(name string) (bool, error)
|
||||
|
||||
// Pull images
|
||||
// `callback` can be called multiple time
|
||||
// `where` is where it is being pulled
|
||||
|
|
|
@ -36,6 +36,7 @@ func NewEngine(addr string, overcommitRatio float64) *Engine {
|
|||
Labels: make(map[string]string),
|
||||
stopCh: make(chan struct{}),
|
||||
containers: make(map[string]*Container),
|
||||
volumes: make(map[string]*Volume),
|
||||
healthy: true,
|
||||
overcommitRatio: int64(overcommitRatio * 100),
|
||||
}
|
||||
|
@ -57,7 +58,7 @@ type Engine struct {
|
|||
stopCh chan struct{}
|
||||
containers map[string]*Container
|
||||
images []*Image
|
||||
volumes []*Volume
|
||||
volumes map[string]*Volume
|
||||
client dockerclient.Client
|
||||
eventHandler EventHandler
|
||||
healthy bool
|
||||
|
@ -187,6 +188,21 @@ func (e *Engine) RemoveImage(image *Image, name string, force bool) ([]*dockercl
|
|||
return e.client.RemoveImage(name, force)
|
||||
}
|
||||
|
||||
// RemoveVolume deletes a volume from the engine.
|
||||
func (e *Engine) RemoveVolume(name string) error {
|
||||
if err := e.client.RemoveVolume(name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove the container from the state. Eventually, the state refresh loop
|
||||
// will rewrite this.
|
||||
e.Lock()
|
||||
defer e.Unlock()
|
||||
delete(e.volumes, name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RefreshImages refreshes the list of images on the engine.
|
||||
func (e *Engine) RefreshImages() error {
|
||||
images, err := e.client.ListImages(true)
|
||||
|
@ -209,9 +225,9 @@ func (e *Engine) RefreshVolumes() error {
|
|||
return err
|
||||
}
|
||||
e.Lock()
|
||||
e.volumes = nil
|
||||
e.volumes = make(map[string]*Volume)
|
||||
for _, volume := range volumes {
|
||||
e.volumes = append(e.volumes, &Volume{Volume: *volume, Engine: e})
|
||||
e.volumes[volume.Name] = &Volume{Volume: *volume, Engine: e}
|
||||
}
|
||||
e.Unlock()
|
||||
return nil
|
||||
|
@ -455,8 +471,8 @@ func (e *Engine) Create(config *ContainerConfig, name string, pullImage bool) (*
|
|||
}
|
||||
|
||||
// RemoveContainer a container from the engine.
|
||||
func (e *Engine) RemoveContainer(container *Container, force bool) error {
|
||||
if err := e.client.RemoveContainer(container.Id, force, true); err != nil {
|
||||
func (e *Engine) RemoveContainer(container *Container, force, volumes bool) error {
|
||||
if err := e.client.RemoveContainer(container.Id, force, volumes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -179,11 +179,11 @@ func (c *Cluster) CreateContainer(config *cluster.ContainerConfig, name string)
|
|||
}
|
||||
|
||||
// RemoveContainer to remove containers on mesos cluster
|
||||
func (c *Cluster) RemoveContainer(container *cluster.Container, force bool) error {
|
||||
func (c *Cluster) RemoveContainer(container *cluster.Container, force, volumes bool) error {
|
||||
c.scheduler.Lock()
|
||||
defer c.scheduler.Unlock()
|
||||
|
||||
return container.Engine.RemoveContainer(container, force)
|
||||
return container.Engine.RemoveContainer(container, force, volumes)
|
||||
}
|
||||
|
||||
// Images returns all the images in the cluster.
|
||||
|
@ -222,6 +222,11 @@ func (c *Cluster) RemoveImages(name string, force bool) ([]*dockerclient.ImageDe
|
|||
return nil, errNotSupported
|
||||
}
|
||||
|
||||
// RemoveVolumes removes volumes from the cluster
|
||||
func (c *Cluster) RemoveVolumes(name string) (bool, error) {
|
||||
return false, errNotSupported
|
||||
}
|
||||
|
||||
func formatContainer(container *cluster.Container) *cluster.Container {
|
||||
if container == nil {
|
||||
return nil
|
||||
|
|
|
@ -131,11 +131,11 @@ func (c *Cluster) createContainer(config *cluster.ContainerConfig, name string,
|
|||
|
||||
// RemoveContainer aka Remove a container from the cluster. Containers should
|
||||
// always be destroyed through the scheduler to guarantee atomicity.
|
||||
func (c *Cluster) RemoveContainer(container *cluster.Container, force bool) error {
|
||||
func (c *Cluster) RemoveContainer(container *cluster.Container, force, volumes bool) error {
|
||||
c.scheduler.Lock()
|
||||
defer c.scheduler.Unlock()
|
||||
|
||||
err := container.Engine.RemoveContainer(container, force)
|
||||
err := container.Engine.RemoveContainer(container, force, volumes)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -295,6 +295,31 @@ func (c *Cluster) RemoveImages(name string, force bool) ([]*dockerclient.ImageDe
|
|||
return out, err
|
||||
}
|
||||
|
||||
// RemoveVolumes removes all the volumes that match `name` from the cluster
|
||||
func (c *Cluster) RemoveVolumes(name string) (bool, error) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
found := false
|
||||
errs := []string{}
|
||||
var err error
|
||||
for _, e := range c.engines {
|
||||
for _, volume := range e.Volumes() {
|
||||
if volume.Name == name {
|
||||
if err := volume.Engine.RemoveVolume(name); err != nil {
|
||||
errs = append(errs, fmt.Sprintf("%s: %s", volume.Engine.Name, err.Error()))
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
err = errors.New(strings.Join(errs, "\n"))
|
||||
}
|
||||
return found, err
|
||||
}
|
||||
|
||||
// Pull is exported
|
||||
func (c *Cluster) Pull(name string, authConfig *dockerclient.AuthConfig, callback func(where, status string, err error)) {
|
||||
var wg sync.WaitGroup
|
||||
|
|
|
@ -40,4 +40,41 @@ function teardown() {
|
|||
run docker_swarm volume inspect ${output}
|
||||
[ "${#lines[@]}" -eq 7 ]
|
||||
[[ "${output}" == *"\"Driver\": \"local\""* ]]
|
||||
}
|
||||
|
||||
@test "docker volume create" {
|
||||
skip
|
||||
start_docker 2
|
||||
swarm_manage
|
||||
|
||||
docker_swarm volume create --name=test_volume
|
||||
run docker_swarm volume
|
||||
[ "${#lines[@]}" -eq 3 ]
|
||||
}
|
||||
|
||||
@test "docker volume rm" {
|
||||
start_docker_with_busybox 2
|
||||
swarm_manage
|
||||
|
||||
run docker_swarm volume rm test_volume
|
||||
[ "$status" -ne 0 ]
|
||||
|
||||
docker_swarm run -d --name=test_container -v=/tmp busybox true
|
||||
|
||||
run docker_swarm volume ls -q
|
||||
volume=${output}
|
||||
[ "${#lines[@]}" -eq 1 ]
|
||||
|
||||
run docker_swarm volume rm $volume
|
||||
[ "$status" -ne 0 ]
|
||||
|
||||
docker_swarm rm test_container
|
||||
|
||||
run docker_swarm volume rm $volume
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${#lines[@]}" -eq 1 ]
|
||||
|
||||
run docker_swarm volume
|
||||
echo $output
|
||||
[ "${#lines[@]}" -eq 1 ]
|
||||
}
|
Loading…
Reference in New Issue