mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
1716d497a4
This change will allow us to run SELinux in a container with BTRFS back end. We continue to work on fixing the kernel/BTRFS but this change will allow SELinux Security separation on BTRFS. It basically relabels the content on container creation. Just relabling -init directory in BTRFS use case. Everything looks like it works. I don't believe tar/achive stores the SELinux labels, so we are good as far as docker commit. Tested Speed on startup with BTRFS on top of loopback directory. BTRFS not on loopback should get even better perfomance on startup time. The more inodes inside of the container image will increase the relabel time. This patch will give people who care more about security the option of runnin BTRFS with SELinux. Those who don't want to take the slow down can disable SELinux either in individual containers or for all containers by continuing to disable SELinux in the daemon. Without relabel: > time docker run --security-opt label:disable fedora echo test test real 0m0.918s user 0m0.009s sys 0m0.026s With Relabel test real 0m1.942s user 0m0.007s sys 0m0.030s Signed-off-by: Dan Walsh <dwalsh@redhat.com> Signed-off-by: Dan Walsh <dwalsh@redhat.com>
816 lines
15 KiB
Go
816 lines
15 KiB
Go
// +build linux
|
|
|
|
package aufs
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/daemon/graphdriver"
|
|
"github.com/docker/docker/pkg/archive"
|
|
"github.com/docker/docker/pkg/reexec"
|
|
)
|
|
|
|
var (
|
|
tmpOuter = path.Join(os.TempDir(), "aufs-tests")
|
|
tmp = path.Join(tmpOuter, "aufs")
|
|
)
|
|
|
|
func init() {
|
|
reexec.Init()
|
|
}
|
|
|
|
func testInit(dir string, t *testing.T) graphdriver.Driver {
|
|
d, err := Init(dir, nil, nil, nil)
|
|
if err != nil {
|
|
if err == graphdriver.ErrNotSupported {
|
|
t.Skip(err)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
return d
|
|
}
|
|
|
|
func newDriver(t *testing.T) *Driver {
|
|
if err := os.MkdirAll(tmp, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
d := testInit(tmp, t)
|
|
return d.(*Driver)
|
|
}
|
|
|
|
func TestNewDriver(t *testing.T) {
|
|
if err := os.MkdirAll(tmp, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
d := testInit(tmp, t)
|
|
defer os.RemoveAll(tmp)
|
|
if d == nil {
|
|
t.Fatalf("Driver should not be nil")
|
|
}
|
|
}
|
|
|
|
func TestAufsString(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if d.String() != "aufs" {
|
|
t.Fatalf("Expected aufs got %s", d.String())
|
|
}
|
|
}
|
|
|
|
func TestCreateDirStructure(t *testing.T) {
|
|
newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
paths := []string{
|
|
"mnt",
|
|
"layers",
|
|
"diff",
|
|
}
|
|
|
|
for _, p := range paths {
|
|
if _, err := os.Stat(path.Join(tmp, p)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// We should be able to create two drivers with the same dir structure
|
|
func TestNewDriverFromExistingDir(t *testing.T) {
|
|
if err := os.MkdirAll(tmp, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
testInit(tmp, t)
|
|
testInit(tmp, t)
|
|
os.RemoveAll(tmp)
|
|
}
|
|
|
|
func TestCreateNewDir(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestCreateNewDirStructure(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
paths := []string{
|
|
"mnt",
|
|
"diff",
|
|
"layers",
|
|
}
|
|
|
|
for _, p := range paths {
|
|
if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRemoveImage(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Remove("1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
paths := []string{
|
|
"mnt",
|
|
"diff",
|
|
"layers",
|
|
}
|
|
|
|
for _, p := range paths {
|
|
if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
|
|
t.Fatalf("Error should not be nil because dirs with id 1 should be delted: %s", p)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetWithoutParent(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expected := path.Join(tmp, "diff", "1")
|
|
if diffPath != expected {
|
|
t.Fatalf("Expected path %s got %s", expected, diffPath)
|
|
}
|
|
}
|
|
|
|
func TestCleanupWithNoDirs(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestCleanupWithDir(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestMountedFalseResponse(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
response, err := d.mounted(d.active["1"])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if response != false {
|
|
t.Fatalf("Response if dir id 1 is mounted should be false")
|
|
}
|
|
}
|
|
|
|
func TestMountedTrueReponse(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("2", "1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := d.Get("2", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
response, err := d.mounted(d.active["2"])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if response != true {
|
|
t.Fatalf("Response if dir id 2 is mounted should be true")
|
|
}
|
|
}
|
|
|
|
func TestMountWithParent(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("2", "1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer func() {
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
mntPath, err := d.Get("2", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if mntPath == "" {
|
|
t.Fatal("mntPath should not be empty string")
|
|
}
|
|
|
|
expected := path.Join(tmp, "mnt", "2")
|
|
if mntPath != expected {
|
|
t.Fatalf("Expected %s got %s", expected, mntPath)
|
|
}
|
|
}
|
|
|
|
func TestRemoveMountedDir(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("2", "1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer func() {
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
mntPath, err := d.Get("2", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if mntPath == "" {
|
|
t.Fatal("mntPath should not be empty string")
|
|
}
|
|
|
|
mounted, err := d.mounted(d.active["2"])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !mounted {
|
|
t.Fatalf("Dir id 2 should be mounted")
|
|
}
|
|
|
|
if err := d.Remove("2"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestCreateWithInvalidParent(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "docker", ""); err == nil {
|
|
t.Fatalf("Error should not be nil with parent does not exist")
|
|
}
|
|
}
|
|
|
|
func TestGetDiff(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Add a file to the diff path with a fixed size
|
|
size := int64(1024)
|
|
|
|
f, err := os.Create(path.Join(diffPath, "test_file"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Truncate(size); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
a, err := d.Diff("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a == nil {
|
|
t.Fatalf("Archive should not be nil")
|
|
}
|
|
}
|
|
|
|
func TestChanges(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("2", "1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer func() {
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
mntPoint, err := d.Get("2", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a file to save in the mountpoint
|
|
f, err := os.Create(path.Join(mntPoint, "test.txt"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := f.WriteString("testline"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
changes, err := d.Changes("2", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(changes) != 1 {
|
|
t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
|
|
}
|
|
change := changes[0]
|
|
|
|
expectedPath := "/test.txt"
|
|
if change.Path != expectedPath {
|
|
t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
|
|
}
|
|
|
|
if change.Kind != archive.ChangeAdd {
|
|
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
|
|
}
|
|
|
|
if err := d.Create("3", "2", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mntPoint, err = d.Get("3", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a file to save in the mountpoint
|
|
f, err = os.Create(path.Join(mntPoint, "test2.txt"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := f.WriteString("testline"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
changes, err = d.Changes("3", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(changes) != 1 {
|
|
t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
|
|
}
|
|
change = changes[0]
|
|
|
|
expectedPath = "/test2.txt"
|
|
if change.Path != expectedPath {
|
|
t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
|
|
}
|
|
|
|
if change.Kind != archive.ChangeAdd {
|
|
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
|
|
}
|
|
}
|
|
|
|
func TestDiffSize(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Add a file to the diff path with a fixed size
|
|
size := int64(1024)
|
|
|
|
f, err := os.Create(path.Join(diffPath, "test_file"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Truncate(size); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := f.Stat()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
size = s.Size()
|
|
if err := f.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffSize, err := d.DiffSize("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if diffSize != size {
|
|
t.Fatalf("Expected size to be %d got %d", size, diffSize)
|
|
}
|
|
}
|
|
|
|
func TestChildDiffSize(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Add a file to the diff path with a fixed size
|
|
size := int64(1024)
|
|
|
|
f, err := os.Create(path.Join(diffPath, "test_file"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Truncate(size); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := f.Stat()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
size = s.Size()
|
|
if err := f.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffSize, err := d.DiffSize("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if diffSize != size {
|
|
t.Fatalf("Expected size to be %d got %d", size, diffSize)
|
|
}
|
|
|
|
if err := d.Create("2", "1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffSize, err = d.DiffSize("2", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// The diff size for the child should be zero
|
|
if diffSize != 0 {
|
|
t.Fatalf("Expected size to be %d got %d", 0, diffSize)
|
|
}
|
|
}
|
|
|
|
func TestExists(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if d.Exists("none") {
|
|
t.Fatal("id name should not exist in the driver")
|
|
}
|
|
|
|
if !d.Exists("1") {
|
|
t.Fatal("id 1 should exist in the driver")
|
|
}
|
|
}
|
|
|
|
func TestStatus(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
status := d.Status()
|
|
if status == nil || len(status) == 0 {
|
|
t.Fatal("Status should not be nil or empty")
|
|
}
|
|
rootDir := status[0]
|
|
dirs := status[2]
|
|
if rootDir[0] != "Root Dir" {
|
|
t.Fatalf("Expected Root Dir got %s", rootDir[0])
|
|
}
|
|
if rootDir[1] != d.rootPath() {
|
|
t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1])
|
|
}
|
|
if dirs[0] != "Dirs" {
|
|
t.Fatalf("Expected Dirs got %s", dirs[0])
|
|
}
|
|
if dirs[1] != "1" {
|
|
t.Fatalf("Expected 1 got %s", dirs[1])
|
|
}
|
|
}
|
|
|
|
func TestApplyDiff(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Add a file to the diff path with a fixed size
|
|
size := int64(1024)
|
|
|
|
f, err := os.Create(path.Join(diffPath, "test_file"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Truncate(size); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
diff, err := d.Diff("1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Create("2", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("3", "2", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.applyDiff("3", diff); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Ensure that the file is in the mount point for id 3
|
|
|
|
mountPoint, err := d.Get("3", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestHardlinks(t *testing.T) {
|
|
// Copy 2 layers that have linked files to new layers and check if hardlink are preserved
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
origFile := "test_file"
|
|
linkedFile := "linked_file"
|
|
|
|
if err := d.Create("source-1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mountPath, err := d.Get("source-1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
f, err := os.Create(path.Join(mountPath, origFile))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
layerTar1, err := d.Diff("source-1", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Create("source-2", "source-1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mountPath, err = d.Get("source-2", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := os.Link(path.Join(mountPath, origFile), path.Join(mountPath, linkedFile)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
layerTar2, err := d.Diff("source-2", "source-1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Create("target-1", "", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := d.ApplyDiff("target-1", "", layerTar1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Create("target-2", "target-1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := d.ApplyDiff("target-2", "target-1", layerTar2); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mountPath, err = d.Get("target-2", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
fi1, err := os.Lstat(path.Join(mountPath, origFile))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fi2, err := os.Lstat(path.Join(mountPath, linkedFile))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !os.SameFile(fi1, fi2) {
|
|
t.Fatal("Target files are not linked")
|
|
}
|
|
}
|
|
|
|
func hash(c string) string {
|
|
h := sha256.New()
|
|
fmt.Fprint(h, c)
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
func testMountMoreThan42Layers(t *testing.T, mountPath string) {
|
|
if err := os.MkdirAll(mountPath, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer os.RemoveAll(mountPath)
|
|
d := testInit(mountPath, t).(*Driver)
|
|
defer d.Cleanup()
|
|
var last string
|
|
var expected int
|
|
|
|
for i := 1; i < 127; i++ {
|
|
expected++
|
|
var (
|
|
parent = fmt.Sprintf("%d", i-1)
|
|
current = fmt.Sprintf("%d", i)
|
|
)
|
|
|
|
if parent == "0" {
|
|
parent = ""
|
|
} else {
|
|
parent = hash(parent)
|
|
}
|
|
current = hash(current)
|
|
|
|
if err := d.Create(current, parent, ""); err != nil {
|
|
t.Logf("Current layer %d", i)
|
|
t.Error(err)
|
|
}
|
|
point, err := d.Get(current, "")
|
|
if err != nil {
|
|
t.Logf("Current layer %d", i)
|
|
t.Error(err)
|
|
}
|
|
f, err := os.Create(path.Join(point, current))
|
|
if err != nil {
|
|
t.Logf("Current layer %d", i)
|
|
t.Error(err)
|
|
}
|
|
f.Close()
|
|
|
|
if i%10 == 0 {
|
|
if err := os.Remove(path.Join(point, parent)); err != nil {
|
|
t.Logf("Current layer %d", i)
|
|
t.Error(err)
|
|
}
|
|
expected--
|
|
}
|
|
last = current
|
|
}
|
|
|
|
// Perform the actual mount for the top most image
|
|
point, err := d.Get(last, "")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
files, err := ioutil.ReadDir(point)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if len(files) != expected {
|
|
t.Errorf("Expected %d got %d", expected, len(files))
|
|
}
|
|
}
|
|
|
|
func TestMountMoreThan42Layers(t *testing.T) {
|
|
os.RemoveAll(tmpOuter)
|
|
testMountMoreThan42Layers(t, tmp)
|
|
}
|
|
|
|
func TestMountMoreThan42LayersMatchingPathLength(t *testing.T) {
|
|
defer os.RemoveAll(tmpOuter)
|
|
zeroes := "0"
|
|
for {
|
|
// This finds a mount path so that when combined into aufs mount options
|
|
// 4096 byte boundary would be in between the paths or in permission
|
|
// section. For '/tmp' it will use '/tmp/aufs-tests/00000000/aufs'
|
|
mountPath := path.Join(tmpOuter, zeroes, "aufs")
|
|
pathLength := 77 + len(mountPath)
|
|
|
|
if mod := 4095 % pathLength; mod == 0 || mod > pathLength-2 {
|
|
t.Logf("Using path: %s", mountPath)
|
|
testMountMoreThan42Layers(t, mountPath)
|
|
return
|
|
}
|
|
zeroes += "0"
|
|
}
|
|
}
|