diff --git a/pkg/storagemigration/failcleanup.go b/pkg/storagemigration/failcleanup.go index 5e61045d71..5d24c157be 100644 --- a/pkg/storagemigration/failcleanup.go +++ b/pkg/storagemigration/failcleanup.go @@ -10,7 +10,6 @@ import ( // FailCleanup should be run after a failed migration. // It will remove any files left over from the migration process // and migrate containers back to aufs. -// func failCleanup(root string) error { logrus.WithField("storage_root", root).Warning("recovering from failed aufs to overlay migration") diff --git a/pkg/storagemigration/migrate.go b/pkg/storagemigration/migrate.go index 8a9c46974e..b37c77f440 100644 --- a/pkg/storagemigration/migrate.go +++ b/pkg/storagemigration/migrate.go @@ -128,7 +128,6 @@ func Migrate(root string) (err error) { if err != nil { return fmt.Errorf("Error migrating containers to overlay2: %v", err) } - return nil } @@ -336,10 +335,17 @@ func SwitchAllContainersStorageDriver(root, newStorageDriver string) error { logrus.Debugf("migrating %v container(s) to %s", len(containerIDs), newStorageDriver) for _, containerID := range containerIDs { err := switchContainerStorageDriver(root, containerID, newStorageDriver) - if err != nil { + switch err { + case nil: + logrus.WithField("container_id", containerID).Debugf("reconfigured storage-driver to %s", newStorageDriver) + case errNoConfigV2JSON: + if newStorageDriver == "overlay2" { + return fmt.Errorf("Error containerID %s: %v", containerID, err) + } + logrus.WithField("container_id", containerID).Errorf("has no config.v2.json %s", newStorageDriver) + default: return fmt.Errorf("Error rewriting container config for %s: %v", containerID, err) } - logrus.WithField("container_id", containerID).Debugf("reconfigured storage-driver to %s", newStorageDriver) } return nil } diff --git a/pkg/storagemigration/migrate_test.go b/pkg/storagemigration/migrate_test.go index f041f70352..9c11b0f580 100644 --- a/pkg/storagemigration/migrate_test.go +++ b/pkg/storagemigration/migrate_test.go @@ -41,6 +41,7 @@ func setup(t *testing.T) (*fs.Dir, *State, func()) { ), ), ) + state := &State{ Layers: []Layer{ { @@ -132,3 +133,37 @@ func TestFailCleanup(t *testing.T) { _, err = os.Stat(root.Join("aufs")) assert.NilError(t, err) } + +func TestFailCleanupContainer(t *testing.T) { + root, _, cleanup := setup(t) + defer cleanup() + + // delete config.v2.json to force SwitchAllContainersStorageDriver to fail + os.Remove(root.Join("containers", "bebe92422caf828ab21ae39974a0c003a29970ec09c6e5529bbb24f71eb9ca2ef", "config.v2.json")) + + err := Migrate(root.Path()) + if err == nil { + // won't err on rollback to aufs fail + assert.NilError(t, err) + } else { + // only errs on migration to overlay2 fail + assert.ErrorContains(t, err, "bebe92422caf828ab21ae39974a0c003a29970ec09c6e5529bbb24f71eb9ca2ef") + + // // config.v2.json should not exists + _, err = os.Stat(root.Join("containers", "bebe92422caf828ab21ae39974a0c003a29970ec09c6e5529bbb24f71eb9ca2ef", "config.v2.json")) + assert.ErrorType(t, err, os.IsNotExist) + + // migration logfile should exists + _, err = os.Stat(root.Join("migrate.log")) + assert.NilError(t, err) + + // overlay2 directory should not exists + _, err = os.Stat(root.Join("overlay2")) + println("err", root.Join("overlay2"), err) + assert.ErrorType(t, err, os.IsNotExist) + + // aufs directory should still exists + _, err = os.Stat(root.Join("aufs")) + assert.NilError(t, err) + } +} diff --git a/pkg/storagemigration/utils.go b/pkg/storagemigration/utils.go index 4ce0fe6690..bf3ff945d5 100644 --- a/pkg/storagemigration/utils.go +++ b/pkg/storagemigration/utils.go @@ -2,6 +2,7 @@ package storagemigration import ( "encoding/json" + "errors" "os" "path/filepath" @@ -11,6 +12,8 @@ import ( "golang.org/x/sys/unix" ) +var errNoConfigV2JSON = errors.New("config.v2.json not found for container") + // exists checks if a file (or if isDir is set to "true" a directory) exists func exists(path string, isDir bool) (bool, error) { fi, err := os.Stat(path) @@ -60,6 +63,10 @@ func replicate(sourceDir, targetDir string) error { // this is the only change needed to make it work after the migration func switchContainerStorageDriver(root, containerID, newStorageDriver string) error { containerConfigPath := filepath.Join(root, "containers", containerID, "config.v2.json") + if ok, _ := exists(containerConfigPath, false); !ok { + return errNoConfigV2JSON + } + f, err := os.OpenFile(containerConfigPath, os.O_RDWR, os.ModePerm) if err != nil { return err