From b68e161e5b76b5f622cf4fc226df46cbe314ea1e Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Wed, 1 Apr 2015 14:12:15 -0400 Subject: [PATCH] graphdriver: prefer prior driver state Before this, a storage driver would be defaulted to based on the priority list, and only print a warning if there is state from other drivers. This meant a reordering of priority list would "break" users in an upgrade of docker, such that there images in the prior driver's state were now invisible. With this change, prior state is scanned, and if present that driver is preferred. As such, we can reorder the priority list, and after an upgrade, existing installs with prior drivers can have a contiguous experience, while fresh installs may default to a driver in the new priority list. Ref: https://github.com/docker/docker/pull/11962#issuecomment-88274858 Signed-off-by: Vincent Batts --- daemon/graphdriver/driver.go | 55 ++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/daemon/graphdriver/driver.go b/daemon/graphdriver/driver.go index 79e6b72dea..0260e532d9 100644 --- a/daemon/graphdriver/driver.go +++ b/daemon/graphdriver/driver.go @@ -146,10 +146,40 @@ func GetDriver(name, home string, options []string) (Driver, error) { func New(root string, options []string) (driver Driver, err error) { for _, name := range []string{os.Getenv("DOCKER_DRIVER"), DefaultDriver} { if name != "" { + logrus.Infof("[graphdriver] trying provided driver %q", name) // so the logs show specified driver return GetDriver(name, root, options) } } + // Guess for prior driver + priorDrivers := scanPriorDrivers(root) + for _, name := range priority { + if name == "vfs" { + // don't use vfs even if there is state present. + continue + } + for _, prior := range priorDrivers { + // of the state found from prior drivers, check in order of our priority + // which we would prefer + if prior == name { + driver, err = GetDriver(name, root, options) + if err != nil { + // unlike below, we will return error here, because there is prior + // state, and now it is no longer supported/prereq/compatible, so + // something changed and needs attention. Otherwise the daemon's + // images would just "disappear". + logrus.Errorf("[graphdriver] prior storage driver %q failed: %s", name, err) + return nil, err + } + if err := checkPriorDriver(name, root); err != nil { + return nil, err + } + logrus.Infof("[graphdriver] using prior storage driver %q", name) + return driver, nil + } + } + } + // Check for priority drivers first for _, name := range priority { driver, err = GetDriver(name, root, options) @@ -159,34 +189,47 @@ func New(root string, options []string) (driver Driver, err error) { } return nil, err } - checkPriorDriver(name, root) return driver, nil } // Check all registered drivers if no priority driver is found - for name, initFunc := range drivers { + for _, initFunc := range drivers { if driver, err = initFunc(root, options); err != nil { if err == ErrNotSupported || err == ErrPrerequisites || err == ErrIncompatibleFS { continue } return nil, err } - checkPriorDriver(name, root) return driver, nil } return nil, fmt.Errorf("No supported storage backend found") } -func checkPriorDriver(name, root string) { +// scanPriorDrivers returns an un-ordered scan of directories of prior storage drivers +func scanPriorDrivers(root string) []string { priorDrivers := []string{} - for prior := range drivers { + for driver := range drivers { + p := path.Join(root, driver) + if _, err := os.Stat(p); err == nil { + priorDrivers = append(priorDrivers, driver) + } + } + return priorDrivers +} + +func checkPriorDriver(name, root string) error { + priorDrivers := []string{} + for _, prior := range scanPriorDrivers(root) { if prior != name && prior != "vfs" { if _, err := os.Stat(path.Join(root, prior)); err == nil { priorDrivers = append(priorDrivers, prior) } } } + if len(priorDrivers) > 0 { - logrus.Warnf("Graphdriver %s selected. Your graphdriver directory %s already contains data managed by other graphdrivers: %s", name, root, strings.Join(priorDrivers, ",")) + + return errors.New(fmt.Sprintf("%q contains other graphdrivers: %s; Please cleanup or explicitly choose storage driver (-s )", root, strings.Join(priorDrivers, ","))) } + return nil }