-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #168 from balena-os/a2o-migrate
Aufs to overlay2 migration utility
- Loading branch information
Showing
17 changed files
with
1,071 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package storagemigration | ||
|
||
import ( | ||
"context" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/docker/docker/api/types" | ||
"github.com/docker/docker/api/types/container" | ||
|
||
"github.com/docker/docker/internal/test/daemon" | ||
|
||
"gotest.tools/assert" | ||
"gotest.tools/fs" | ||
"gotest.tools/skip" | ||
) | ||
|
||
func TestAufsToOverlay2Migration(t *testing.T) { | ||
skip.If(t, testEnv.DaemonInfo.OSType != "linux") | ||
skip.If(t, testEnv.DaemonInfo.Driver != "overlay2") | ||
defer setupTest(t)() | ||
|
||
var err error | ||
|
||
root := fs.NewDir(t, t.Name()) | ||
defer root.Remove() | ||
|
||
{ | ||
// aufs.tar.gz contains a snapshot of /var/lib/docker after | ||
// building testdata/Dockerfile using dockerd which uses aufs | ||
// as default storage driver | ||
tar := exec.Command("tar", "-xzf", filepath.Join("testdata", "aufs.tar.gz"), "-C", root.Path()) | ||
tar.Stdout = os.Stdout | ||
tar.Stderr = os.Stderr | ||
assert.NilError(t, tar.Run()) | ||
} | ||
|
||
// if testing.Verbose() { | ||
// logrus.SetLevel(logrus.DebugLevel) | ||
// } | ||
// err = storagemigration.Migrate(root.Path()) | ||
// assert.NilError(t, err) | ||
|
||
err = os.Setenv("BALENA_MIGRATE_OVERLAY", "1") | ||
assert.NilError(t, err) | ||
|
||
d := daemon.New(t) | ||
d.Root = root.Path() | ||
d.Start(t) | ||
defer d.Stop(t) | ||
|
||
ctx := context.Background() | ||
|
||
cl := d.NewClientT(t) | ||
|
||
ctr, err := cl.ContainerCreate(ctx, | ||
&container.Config{ | ||
Image: "a2o-test", | ||
}, | ||
nil, | ||
nil, | ||
"", | ||
) | ||
assert.NilError(t, err) | ||
|
||
err = cl.ContainerStart(ctx, ctr.ID, types.ContainerStartOptions{}) | ||
assert.NilError(t, err) | ||
|
||
// original f1 should be removed (.wh.) | ||
_, err = cl.ContainerStatPath(ctx, ctr.ID, "/tmp/f1") | ||
assert.ErrorContains(t, err, "No such container:path") | ||
// original d1 should be opaque (.wh..wh.opq) | ||
_, err = cl.ContainerStatPath(ctx, ctr.ID, "/tmp/d1/d1f2") | ||
assert.NilError(t, err) | ||
_, err = cl.ContainerStatPath(ctx, ctr.ID, "/tmp/hlkn") | ||
assert.NilError(t, err) | ||
_, err = cl.ContainerStatPath(ctx, ctr.ID, "/tmp/slkn") | ||
assert.NilError(t, err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package storagemigration | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"testing" | ||
|
||
"github.com/docker/docker/internal/test/environment" | ||
) | ||
|
||
var testEnv *environment.Execution | ||
|
||
func TestMain(m *testing.M) { | ||
var err error | ||
testEnv, err = environment.New() | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
err = environment.EnsureFrozenImagesLinux(testEnv) | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
testEnv.Print() | ||
os.Exit(m.Run()) | ||
} | ||
|
||
func setupTest(t *testing.T) func() { | ||
environment.ProtectAll(t, testEnv) | ||
return func() { testEnv.Clean(t) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
FROM busybox:1.33.0 | ||
RUN mkdir /tmp/d1 && touch /tmp/d1/d1f1 && touch /tmp/f1 && touch /tmp/f2 | ||
RUN rm -R /tmp/d1 && mkdir /tmp/d1 && touch /tmp/d1/d1f2 && rm /tmp/f1 | ||
RUN ln -s /tmp/d1/d1f2 /tmp/slkn | ||
RUN ln /tmp/d1/d1f2 /tmp/hlkn |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// TODO: do we need to handle .wh..wh.plnk layer hardlinks? | ||
package storagemigration | ||
|
||
import ( | ||
"bufio" | ||
"errors" | ||
"io/ioutil" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/sirupsen/logrus" | ||
|
||
"github.com/docker/docker/pkg/archive" | ||
) | ||
|
||
var ( | ||
// ErrAuFSRootNotExists indicates the aufs root directory wasn't found | ||
ErrAuFSRootNotExists = errors.New("Aufs root doesn't exists") | ||
) | ||
|
||
// CheckRootExists checks for the aufs storage root directory | ||
func CheckAufsRootExists(engineDir string) error { | ||
root := filepath.Join(engineDir, "aufs") | ||
logrus.WithField("aufs_root", root).Debug("checking if aufs root exists") | ||
ok, err := exists(root, true) | ||
if err != nil { | ||
return err | ||
} | ||
if !ok { | ||
return ErrAuFSRootNotExists | ||
} | ||
return nil | ||
} | ||
|
||
func IsWhiteout(filename string) bool { | ||
return strings.HasPrefix(filename, archive.WhiteoutPrefix) | ||
} | ||
|
||
func IsWhiteoutMeta(filename string) bool { | ||
return strings.HasPrefix(filename, archive.WhiteoutMetaPrefix) | ||
} | ||
|
||
func IsOpaqueParentDir(filename string) bool { | ||
return filename == archive.WhiteoutOpaqueDir | ||
} | ||
|
||
func StripWhiteoutPrefix(filename string) string { | ||
out := filename | ||
for IsWhiteout(out) && !IsWhiteoutMeta(out) { | ||
out = strings.TrimPrefix(out, archive.WhiteoutPrefix) | ||
} | ||
return out | ||
} | ||
|
||
// Return all the directories | ||
// | ||
// from daemon/graphdriver/aufs/dirs.go | ||
func LoadIDs(root string) ([]string, error) { | ||
dirs, err := ioutil.ReadDir(root) | ||
if err != nil { | ||
return nil, err | ||
} | ||
var out []string | ||
for _, d := range dirs { | ||
if d.IsDir() { | ||
out = append(out, d.Name()) | ||
} | ||
} | ||
return out, nil | ||
} | ||
|
||
// Read the layers file for the current id and return all the | ||
// layers represented by new lines in the file | ||
// | ||
// If there are no lines in the file then the id has no parent | ||
// and an empty slice is returned. | ||
// | ||
// from daemon/graphdriver/aufs/dirs.go | ||
func GetParentIDs(root, id string) ([]string, error) { | ||
f, err := os.Open(path.Join(root, "layers", id)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
|
||
var out []string | ||
s := bufio.NewScanner(f) | ||
|
||
for s.Scan() { | ||
if t := s.Text(); t != "" { | ||
out = append(out, s.Text()) | ||
} | ||
} | ||
return out, s.Err() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package storagemigration | ||
|
||
import "testing" | ||
|
||
func TestIsWhiteout(t *testing.T) { | ||
var tcs = map[string]bool{ | ||
".wh.foo.txt": true, | ||
"bar.txt": false, | ||
".wh..wh.plnk": true, | ||
".wh..wh..opq": true, | ||
} | ||
for file, expect := range tcs { | ||
if IsWhiteout(file) != expect { | ||
t.Fatalf("did not detect %v", file) | ||
} | ||
} | ||
} | ||
func TestIsWhiteoutMeta(t *testing.T) { | ||
var tcs = map[string]bool{ | ||
".wh.foo.txt": false, | ||
"bar.txt": false, | ||
".wh..wh.plnk": true, | ||
".wh..wh..opq": true, | ||
} | ||
for file, expect := range tcs { | ||
if IsWhiteoutMeta(file) != expect { | ||
t.Fatalf("did not detect %v", file) | ||
} | ||
} | ||
} | ||
|
||
func TestIsOpaque(t *testing.T) { | ||
var tcs = map[string]bool{ | ||
".wh.foo.txt": false, | ||
"bar.txt": false, | ||
".wh..wh.plnk": false, | ||
".wh..wh..opq": true, | ||
} | ||
for file, expect := range tcs { | ||
if IsOpaqueParentDir(file) != expect { | ||
t.Fatalf("did not detect %v", file) | ||
} | ||
} | ||
} | ||
|
||
func TestStripWhiteoutPrefix(t *testing.T) { | ||
var tcs = map[string]string{ | ||
".wh.foo.txt": "foo.txt", | ||
"bar.txt": "bar.txt", | ||
".wh..wh.plnk": ".wh..wh.plnk", | ||
".wh..wh..opq": ".wh..wh..opq", | ||
} | ||
for file, expect := range tcs { | ||
if result := StripWhiteoutPrefix(file); result != expect { | ||
t.Fatalf("stripping filename failed, got: %q wanted: %q", result, expect) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package storagemigration | ||
|
||
import ( | ||
"path/filepath" | ||
|
||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
// Commit finalises the migration by deleting aufs storage root and images. | ||
func Commit(root string) error { | ||
logrus.WithField("storage_root", root).Debug("committing changes") | ||
|
||
// remove aufs layer data | ||
err := removeDirIfExists(aufsRoot(root)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// remove images | ||
aufsImageDir := filepath.Join(root, "image", "aufs") | ||
err = removeDirIfExists(aufsImageDir) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.