Skip empty directories on prior graphdriver detection

When starting the daemon, the `/var/lib/docker` directory
is scanned for existing directories, so that the previously
selected graphdriver will automatically be used.

In some situations, empty directories are present (those
directories can be created during feature detection of
graph-drivers), in which case the daemon refuses to start.

This patch improves detection, and skips empty directories,
so that leftover directories don't cause the daemon to
fail.

Before this change:

    $ mkdir /var/lib/docker /var/lib/docker/aufs /var/lib/docker/overlay2
    $ dockerd
    ...
    Error starting daemon: error initializing graphdriver: /var/lib/docker contains several valid graphdrivers: overlay2, aufs; Please cleanup or explicitly choose storage driver (-s <DRIVER>)

With this patch applied:

    $ mkdir /var/lib/docker /var/lib/docker/aufs /var/lib/docker/overlay2
    $ dockerd
    ...
    INFO[2017-11-16T17:26:43.207739140Z] Docker daemon                                 commit=ab90bc296 graphdriver(s)=overlay2 version=dev
    INFO[2017-11-16T17:26:43.208033095Z] Daemon has completed initialization

And on restart (prior graphdriver is still picked up):

    $ dockerd
    ...
    INFO[2017-11-16T17:27:52.260361465Z] [graphdriver] using prior storage driver: overlay2

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Upstream-commit: 1262c57714e694193be6bbcbed83e859dc246c2f
Component: engine
This commit is contained in:
Sebastiaan van Stijn
2017-11-16 18:22:22 +01:00
parent c051f4a135
commit a653d42fdb
2 changed files with 57 additions and 1 deletions

View File

@ -283,8 +283,27 @@ func scanPriorDrivers(root string) map[string]bool {
for driver := range drivers {
p := filepath.Join(root, driver)
if _, err := os.Stat(p); err == nil && driver != "vfs" {
driversMap[driver] = true
if !isEmptyDir(p) {
driversMap[driver] = true
}
}
}
return driversMap
}
// isEmptyDir checks if a directory is empty. It is used to check if prior
// storage-driver directories exist. If an error occurs, it also assumes the
// directory is not empty (which preserves the behavior _before_ this check
// was added)
func isEmptyDir(name string) bool {
f, err := os.Open(name)
if err != nil {
return false
}
defer f.Close()
if _, err = f.Readdirnames(1); err == io.EOF {
return true
}
return false
}

View File

@ -0,0 +1,37 @@
package graphdriver
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestIsEmptyDir(t *testing.T) {
tmp, err := ioutil.TempDir("", "test-is-empty-dir")
require.NoError(t, err)
defer os.RemoveAll(tmp)
d := filepath.Join(tmp, "empty-dir")
err = os.Mkdir(d, 0755)
require.NoError(t, err)
empty := isEmptyDir(d)
assert.True(t, empty)
d = filepath.Join(tmp, "dir-with-subdir")
err = os.MkdirAll(filepath.Join(d, "subdir"), 0755)
require.NoError(t, err)
empty = isEmptyDir(d)
assert.False(t, empty)
d = filepath.Join(tmp, "dir-with-empty-file")
err = os.Mkdir(d, 0755)
require.NoError(t, err)
_, err = ioutil.TempFile(d, "file")
require.NoError(t, err)
empty = isEmptyDir(d)
assert.False(t, empty)
}