Skip to content

Commit

Permalink
Restore volume refs after daemon restart
Browse files Browse the repository at this point in the history
Volume refs were not being restored on daemon restart.
This made it possible to remove a volume being used by other containers
after a daemon restart.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
  • Loading branch information
cpuguy83 committed Oct 8, 2014
1 parent 0d5daa4 commit 9acf7c7
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 7 deletions.
4 changes: 1 addition & 3 deletions daemon/daemon.go
Expand Up @@ -400,9 +400,7 @@ func (daemon *Daemon) restore() error {
}

for _, c := range registeredContainers {
for _, mnt := range c.VolumeMounts() {
daemon.volumes.Add(mnt.volume)
}
c.registerVolumes()
}

if !debug {
Expand Down
6 changes: 6 additions & 0 deletions daemon/volumes.go
Expand Up @@ -92,6 +92,12 @@ func (container *Container) VolumePaths() map[string]struct{} {
return paths
}

func (container *Container) registerVolumes() {
for _, mnt := range container.VolumeMounts() {
mnt.volume.AddContainer(container.ID)
}
}

func (container *Container) derefVolumes() {
for path := range container.VolumePaths() {
vol := container.daemon.volumes.Get(path)
Expand Down
34 changes: 34 additions & 0 deletions integration-cli/docker_cli_daemon_test.go
@@ -1,6 +1,8 @@
package main

import (
"encoding/json"
"os"
"strings"
"testing"
)
Expand Down Expand Up @@ -48,3 +50,35 @@ func TestDaemonRestartWithRunningContainersPorts(t *testing.T) {

logDone("daemon - running containers on daemon restart")
}

func TestDaemonRestartWithVolumesRefs(t *testing.T) {
d := NewDaemon(t)
if err := d.StartWithBusybox(); err != nil {
t.Fatal(err)
}
defer d.Stop()

if out, err := d.Cmd("run", "-d", "--name", "volrestarttest1", "-v", "/foo", "busybox"); err != nil {
t.Fatal(err, out)
}
if err := d.Restart(); err != nil {
t.Fatal(err)
}
if _, err := d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox"); err != nil {
t.Fatal(err)
}
if out, err := d.Cmd("rm", "-fv", "volrestarttest2"); err != nil {
t.Fatal(err, out)
}
v, err := d.Cmd("inspect", "--format", "{{ json .Volumes }}", "volrestarttest1")
if err != nil {
t.Fatal(err)
}
volumes := make(map[string]string)
json.Unmarshal([]byte(v), &volumes)
if _, err := os.Stat(volumes["/foo"]); err != nil {
t.Fatalf("Expected volume to exist: %s - %s", volumes["/foo"], err)
}

logDone("daemon - volume refs are restored")
}
29 changes: 25 additions & 4 deletions volumes/repository.go
Expand Up @@ -8,6 +8,7 @@ import (
"sync"

"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/log"
"github.com/docker/docker/utils"
)

Expand Down Expand Up @@ -83,11 +84,31 @@ func (r *Repository) restore() error {
return err
}

var ids []string
for _, v := range dir {
id := v.Name()
if r.driver.Exists(id) {
ids = append(ids, id)
path, err := r.driver.Get(id, "")
if err != nil {
log.Debugf("Could not find volume for %s: %v", id, err)
continue
}
vol := &Volume{
ID: id,
configPath: r.configPath + "/" + id,
containers: make(map[string]struct{}),
Path: path,
}
if err := vol.FromDisk(); err != nil {
if !os.IsNotExist(err) {
log.Debugf("Error restoring volume: %v", err)
continue
}
if err := vol.initialize(); err != nil {
log.Debugf("%s", err)
continue
}
}
if err := r.add(vol); err != nil {
log.Debugf("Error restoring volume: %v", err)
}
}
return nil
Expand Down Expand Up @@ -173,7 +194,7 @@ func (r *Repository) createNewVolumePath(id string) (string, error) {

path, err := r.driver.Get(id, "")
if err != nil {
return "", fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", r.driver, id, err)
return "", fmt.Errorf("Driver %s failed to get volume rootfs %s: %v", r.driver, id, err)
}

return path, nil
Expand Down

0 comments on commit 9acf7c7

Please sign in to comment.