1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
//go:build linux && !exclude_disk_quota && cgo
package quota // import "github.com/docker/docker/quota"
import (
"os"
"os/exec"
"testing"
"golang.org/x/sys/unix"
)
// CanTestQuota - checks if xfs prjquota can be tested
// returns a reason if not
func CanTestQuota() (string, bool) {
if os.Getuid() != 0 {
return "requires mounts", false
}
_, err := exec.LookPath("mkfs.xfs")
if err != nil {
return "mkfs.xfs not found in PATH", false
}
return "", true
}
// PrepareQuotaTestImage - prepares an xfs prjquota test image
// returns the path of the image on success
func PrepareQuotaTestImage(t *testing.T) (string, error) {
// imageSize is the size of the test-image. The minimum size allowed
// is 300MB.
//
// See https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/commit/?id=6e0ed3d19c54603f0f7d628ea04b550151d8a262
const imageSize = 300 * 1024 * 1024
mkfs, err := exec.LookPath("mkfs.xfs")
if err != nil {
return "", err
}
// create a sparse image
imageFile, err := os.CreateTemp("", "xfs-image")
if err != nil {
return "", err
}
imageFileName := imageFile.Name()
if _, err = imageFile.Seek(imageSize-1, 0); err != nil {
os.Remove(imageFileName)
return "", err
}
if _, err = imageFile.Write([]byte{0}); err != nil {
os.Remove(imageFileName)
return "", err
}
if err = imageFile.Close(); err != nil {
os.Remove(imageFileName)
return "", err
}
// The reason for disabling these options is sometimes people run with a newer userspace
// than kernelspace
out, err := exec.Command(mkfs, "-m", "crc=0,finobt=0", imageFileName).CombinedOutput()
if len(out) > 0 {
t.Log(string(out))
}
if err != nil {
os.Remove(imageFileName)
return "", err
}
return imageFileName, nil
}
// WrapMountTest - wraps a test function such that it has easy access to a mountPoint and testDir
// with guaranteed prjquota or guaranteed no prjquota support.
func WrapMountTest(imageFileName string, enableQuota bool, testFunc func(t *testing.T, mountPoint, backingFsDev, testDir string)) func(*testing.T) {
return func(t *testing.T) {
mountOptions := "loop"
if enableQuota {
mountOptions = mountOptions + ",prjquota"
}
mountPoint := t.TempDir()
out, err := exec.Command("mount", "-o", mountOptions, imageFileName, mountPoint).CombinedOutput()
if err != nil {
_, err := os.Stat("/proc/fs/xfs")
if os.IsNotExist(err) {
t.Skip("no /proc/fs/xfs")
}
}
if err != nil {
t.Fatalf("assertion failed: error is not nil: %v: mount failed: %s", err, out)
}
defer func() {
if err := unix.Unmount(mountPoint, 0); err != nil {
t.Fatalf("assertion failed: error is not nil: %v", err)
}
}()
backingFsDev, err := makeBackingFsDev(mountPoint)
if err != nil {
t.Fatalf("assertion failed: error is not nil: %v", err)
}
testDir, err := os.MkdirTemp(mountPoint, "per-test")
if err != nil {
t.Fatalf("assertion failed: error is not nil: %v", err)
}
defer os.RemoveAll(testDir)
testFunc(t, mountPoint, backingFsDev, testDir)
}
}
// WrapQuotaTest - wraps a test function such that is has easy and guaranteed access to a quota Control
// instance with a quota test dir under its control.
func WrapQuotaTest(testFunc func(t *testing.T, ctrl *Control, mountPoint, testDir, testSubDir string)) func(t *testing.T, mountPoint, backingFsDev, testDir string) {
return func(t *testing.T, mountPoint, backingFsDev, testDir string) {
ctrl, err := NewControl(testDir)
if err != nil {
t.Fatalf("assertion failed: error is not nil: %v", err)
}
testSubDir, err := os.MkdirTemp(testDir, "quota-test")
if err != nil {
t.Fatalf("assertion failed: error is not nil: %v", err)
}
testFunc(t, ctrl, mountPoint, testDir, testSubDir)
}
}
|