Merge pull request #405 from samuelkarp/btrfs-test-setup
snapshot: automate btrfs test setup
This commit is contained in:
		| @@ -1,26 +1,32 @@ | |||||||
| package snapshot | package snapshot | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"bytes" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"os/exec" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/docker/containerd" | 	"github.com/docker/containerd" | ||||||
|  | 	btrfs "github.com/stevvooe/go-btrfs" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	mib = 1024 * 1024 | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestBtrfs(t *testing.T) { | func TestBtrfs(t *testing.T) { | ||||||
| 	// SORRY(stevvooe): This is where I mount a btrfs loopback. We can probably | 	device := setupBtrfsLoopbackDevice(t) | ||||||
| 	// set this up as part of the test. | 	defer removeBtrfsLoopbackDevice(t, device) | ||||||
| 	root, err := ioutil.TempDir("/tmp/snapshots", "TestBtrfsPrepare-") | 	root, err := ioutil.TempDir(device.mountPoint, "TestBtrfsPrepare-") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	defer os.RemoveAll(root) | 	defer os.RemoveAll(root) | ||||||
| 	// TODO(stevvooe): Cleanup subvolumes |  | ||||||
|  |  | ||||||
| 	sm, err := NewBtrfs("/dev/loop0", root) | 	sm, err := NewBtrfs(device.deviceName, root) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| @@ -47,6 +53,11 @@ func TestBtrfs(t *testing.T) { | |||||||
| 	if err := containerd.MountAll(mounts...); err != nil { | 	if err := containerd.MountAll(mounts...); err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  | 	defer func(mounts []containerd.Mount) { | ||||||
|  | 		for _, mount := range mounts { | ||||||
|  | 			unmount(t, mount.Target) | ||||||
|  | 		} | ||||||
|  | 	}(mounts) | ||||||
|  |  | ||||||
| 	// write in some data | 	// write in some data | ||||||
| 	if err := ioutil.WriteFile(filepath.Join(mounts[0].Target, "foo"), []byte("content"), 0777); err != nil { | 	if err := ioutil.WriteFile(filepath.Join(mounts[0].Target, "foo"), []byte("content"), 0777); err != nil { | ||||||
| @@ -62,6 +73,13 @@ func TestBtrfs(t *testing.T) { | |||||||
| 	if err := sm.Commit(filepath.Join(root, "snapshots/committed"), filepath.Join(root, "test")); err != nil { | 	if err := sm.Commit(filepath.Join(root, "snapshots/committed"), filepath.Join(root, "test")); err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  | 	defer func() { | ||||||
|  | 		t.Log("Delete snapshot 1") | ||||||
|  | 		err := btrfs.SubvolDelete(filepath.Join(root, "snapshots/committed")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Error("snapshot delete failed", err) | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
| 	mounts, err = sm.Prepare(filepath.Join(root, "test2"), filepath.Join(root, "snapshots/committed")) | 	mounts, err = sm.Prepare(filepath.Join(root, "test2"), filepath.Join(root, "snapshots/committed")) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -75,6 +93,11 @@ func TestBtrfs(t *testing.T) { | |||||||
| 	if err := containerd.MountAll(mounts...); err != nil { | 	if err := containerd.MountAll(mounts...); err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  | 	defer func(mounts []containerd.Mount) { | ||||||
|  | 		for _, mount := range mounts { | ||||||
|  | 			unmount(t, mount.Target) | ||||||
|  | 		} | ||||||
|  | 	}(mounts) | ||||||
|  |  | ||||||
| 	// TODO(stevvooe): Verify contents of "foo" | 	// TODO(stevvooe): Verify contents of "foo" | ||||||
| 	if err := ioutil.WriteFile(filepath.Join(mounts[0].Target, "bar"), []byte("content"), 0777); err != nil { | 	if err := ioutil.WriteFile(filepath.Join(mounts[0].Target, "bar"), []byte("content"), 0777); err != nil { | ||||||
| @@ -84,4 +107,120 @@ func TestBtrfs(t *testing.T) { | |||||||
| 	if err := sm.Commit(filepath.Join(root, "snapshots/committed2"), filepath.Join(root, "test2")); err != nil { | 	if err := sm.Commit(filepath.Join(root, "snapshots/committed2"), filepath.Join(root, "test2")); err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  | 	defer func() { | ||||||
|  | 		t.Log("Delete snapshot 2") | ||||||
|  | 		err := btrfs.SubvolDelete(filepath.Join(root, "snapshots/committed2")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Error("snapshot delete failed", err) | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type testDevice struct { | ||||||
|  | 	mountPoint string | ||||||
|  | 	fileName   string | ||||||
|  | 	deviceName string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // setupBtrfsLoopbackDevice creates a file, mounts it as a loopback device, and | ||||||
|  | // formats it as btrfs.  The device should be cleaned up by calling | ||||||
|  | // removeBtrfsLoopbackDevice. | ||||||
|  | func setupBtrfsLoopbackDevice(t *testing.T) *testDevice { | ||||||
|  | 	// create temporary directory for mount point | ||||||
|  | 	mountPoint, err := ioutil.TempDir("", "containerd-btrfs-test") | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("Could not create mount point for btrfs test", err) | ||||||
|  | 	} | ||||||
|  | 	t.Log("Temporary mount point created", mountPoint) | ||||||
|  |  | ||||||
|  | 	// create temporary file for the disk image | ||||||
|  | 	file, err := ioutil.TempFile("", "containerd-btrfs-test") | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("Could not create temporary file for btrfs test", err) | ||||||
|  | 	} | ||||||
|  | 	t.Log("Temporary file created", file.Name()) | ||||||
|  |  | ||||||
|  | 	// initialize file with 100 MiB | ||||||
|  | 	zero := [mib]byte{} | ||||||
|  | 	for i := 0; i < 100; i++ { | ||||||
|  | 		_, err = file.Write(zero[:]) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatal("Could not write to btrfs file", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	file.Close() | ||||||
|  |  | ||||||
|  | 	// create device | ||||||
|  | 	losetup := exec.Command("losetup", "--find", "--show", file.Name()) | ||||||
|  | 	var stdout, stderr bytes.Buffer | ||||||
|  | 	losetup.Stdout = &stdout | ||||||
|  | 	losetup.Stderr = &stderr | ||||||
|  | 	err = losetup.Run() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Log(stderr.String()) | ||||||
|  | 		t.Fatal("Could not run losetup", err) | ||||||
|  | 	} | ||||||
|  | 	deviceName := strings.TrimSpace(stdout.String()) | ||||||
|  | 	t.Log("Created loop device", deviceName) | ||||||
|  |  | ||||||
|  | 	// format | ||||||
|  | 	t.Log("Creating btrfs filesystem") | ||||||
|  | 	mkfs := exec.Command("mkfs.btrfs", deviceName) | ||||||
|  | 	err = mkfs.Run() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("Could not run mkfs.btrfs", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// mount | ||||||
|  | 	t.Logf("Mounting %s at %s", deviceName, mountPoint) | ||||||
|  | 	mount := exec.Command("mount", deviceName, mountPoint) | ||||||
|  | 	err = mount.Run() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal("Could not mount", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &testDevice{ | ||||||
|  | 		mountPoint: mountPoint, | ||||||
|  | 		fileName:   file.Name(), | ||||||
|  | 		deviceName: deviceName, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // removeBtrfsLoopbackDevice unmounts the loopback device and deletes the | ||||||
|  | // file holding the disk image. | ||||||
|  | func removeBtrfsLoopbackDevice(t *testing.T, device *testDevice) { | ||||||
|  | 	// unmount | ||||||
|  | 	unmount(t, device.mountPoint) | ||||||
|  |  | ||||||
|  | 	// detach device | ||||||
|  | 	t.Log("Removing loop device") | ||||||
|  | 	losetup := exec.Command("losetup", "--detach", device.deviceName) | ||||||
|  | 	err := losetup.Run() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error("Could not remove loop device", device.deviceName, err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// remove file | ||||||
|  | 	t.Log("Removing temporary file") | ||||||
|  | 	err = os.Remove(device.fileName) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// remove mount point | ||||||
|  | 	t.Log("Removing temporary mount point") | ||||||
|  | 	err = os.RemoveAll(device.mountPoint) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func unmount(t *testing.T, mountPoint string) { | ||||||
|  | 	t.Log("unmount", mountPoint) | ||||||
|  | 	umount := exec.Command("umount", mountPoint) | ||||||
|  | 	err := umount.Run() | ||||||
|  | 	if err != nil { | ||||||
|  |  | ||||||
|  | 		t.Error("Could not umount", mountPoint, err) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Stephen Day
					Stephen Day