Переглянути джерело

Merge pull request #16162 from cpuguy83/16071_fix_lstat_errors

Ignore stat errors on volume rm.
Jess Frazelle 9 роки тому
батько
коміт
d333849459
3 змінених файлів з 102 додано та 6 видалено
  1. 1 1
      daemon/delete.go
  2. 20 5
      volume/local/local.go
  3. 81 0
      volume/local/local_test.go

+ 1 - 1
daemon/delete.go

@@ -155,7 +155,7 @@ func (daemon *Daemon) VolumeRm(name string) error {
 		if err == ErrVolumeInUse {
 			return fmt.Errorf("Conflict: %v", err)
 		}
-		return err
+		return fmt.Errorf("Error while removing volume %s: %v", name, err)
 	}
 	return nil
 }

+ 20 - 5
volume/local/local.go

@@ -126,6 +126,7 @@ func (r *Root) Create(name string, _ map[string]string) (volume.Volume, error) {
 func (r *Root) Remove(v volume.Volume) error {
 	r.m.Lock()
 	defer r.m.Unlock()
+
 	lv, ok := v.(*localVolume)
 	if !ok {
 		return errors.New("unknown volume type")
@@ -133,18 +134,32 @@ func (r *Root) Remove(v volume.Volume) error {
 
 	realPath, err := filepath.EvalSymlinks(lv.path)
 	if err != nil {
-		return err
+		if !os.IsNotExist(err) {
+			return err
+		}
+		realPath = filepath.Dir(lv.path)
 	}
+
 	if !r.scopedPath(realPath) {
-		return fmt.Errorf("Unable to remove a directory of out the Docker root: %s", realPath)
+		return fmt.Errorf("Unable to remove a directory of out the Docker root %s: %s", r.scope, realPath)
 	}
 
-	if err := os.RemoveAll(realPath); err != nil {
+	if err := removePath(realPath); err != nil {
 		return err
 	}
 
 	delete(r.volumes, lv.name)
-	return os.RemoveAll(filepath.Dir(lv.path))
+	return removePath(filepath.Dir(lv.path))
+}
+
+func removePath(path string) error {
+	if err := os.RemoveAll(path); err != nil {
+		if os.IsNotExist(err) {
+			return nil
+		}
+		return err
+	}
+	return nil
 }
 
 // Get looks up the volume for the given name and returns it if found
@@ -162,7 +177,7 @@ func (r *Root) Get(name string) (volume.Volume, error) {
 // is under Docker's root and the valid local paths.
 func (r *Root) scopedPath(realPath string) bool {
 	// Volumes path for Docker version >= 1.7
-	if strings.HasPrefix(realPath, filepath.Join(r.scope, volumesPathName)) {
+	if strings.HasPrefix(realPath, filepath.Join(r.scope, volumesPathName)) && realPath != filepath.Join(r.scope, volumesPathName) {
 		return true
 	}
 

+ 81 - 0
volume/local/local_test.go

@@ -0,0 +1,81 @@
+package local
+
+import (
+	"io/ioutil"
+	"os"
+	"testing"
+)
+
+func TestRemove(t *testing.T) {
+	rootDir, err := ioutil.TempDir("", "local-volume-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(rootDir)
+
+	r, err := New(rootDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	vol, err := r.Create("testing", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := r.Remove(vol); err != nil {
+		t.Fatal(err)
+	}
+
+	vol, err = r.Create("testing2", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := os.RemoveAll(vol.Path()); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := r.Remove(vol); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := os.Stat(vol.Path()); err != nil && !os.IsNotExist(err) {
+		t.Fatal("volume dir not removed")
+	}
+
+	if len(r.List()) != 0 {
+		t.Fatal("expected there to be no volumes")
+	}
+}
+
+func TestInitializeWithVolumes(t *testing.T) {
+	rootDir, err := ioutil.TempDir("", "local-volume-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(rootDir)
+
+	r, err := New(rootDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	vol, err := r.Create("testing", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	r, err = New(rootDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	v, err := r.Get(vol.Name())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if v.Path() != vol.Path() {
+		t.Fatal("expected to re-initialize root with existing volumes")
+	}
+}