1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #62 from shykes/devmapper-unit-tests

Devmapper unit tests
This commit is contained in:
Michael Crosby 2013-11-21 16:54:50 -08:00
commit 437bdeee59
9 changed files with 856 additions and 144 deletions

View file

@ -6,13 +6,10 @@ import (
"github.com/dotcloud/docker/utils"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"sync"
"syscall"
"time"
)
@ -105,7 +102,7 @@ func (devices *DeviceSet) hasImage(name string) bool {
dirname := devices.loopbackDir()
filename := path.Join(dirname, name)
_, err := os.Stat(filename)
_, err := osStat(filename)
return err == nil
}
@ -117,16 +114,16 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
dirname := devices.loopbackDir()
filename := path.Join(dirname, name)
if err := os.MkdirAll(dirname, 0700); err != nil && !os.IsExist(err) {
if err := osMkdirAll(dirname, 0700); err != nil && !osIsExist(err) {
return "", err
}
if _, err := os.Stat(filename); err != nil {
if !os.IsNotExist(err) {
if _, err := osStat(filename); err != nil {
if !osIsNotExist(err) {
return "", err
}
utils.Debugf("Creating loopback file %s for device-manage use", filename)
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600)
file, err := osOpenFile(filename, osORdWr|osOCreate, 0600)
if err != nil {
return "", err
}
@ -174,7 +171,7 @@ func (devices *DeviceSet) saveMetadata() error {
if err := tmpFile.Close(); err != nil {
return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err)
}
if err := os.Rename(tmpFile.Name(), devices.jsonFile()); err != nil {
if err := osRename(tmpFile.Name(), devices.jsonFile()); err != nil {
return fmt.Errorf("Error committing metadata file", err)
}
@ -225,9 +222,9 @@ func (devices *DeviceSet) activateDeviceIfNeeded(hash string) error {
func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
devname := info.DevName()
err := exec.Command("mkfs.ext4", "-E", "discard,lazy_itable_init=0,lazy_journal_init=0", devname).Run()
err := execRun("mkfs.ext4", "-E", "discard,lazy_itable_init=0,lazy_journal_init=0", devname)
if err != nil {
err = exec.Command("mkfs.ext4", "-E", "discard,lazy_itable_init=0", devname).Run()
err = execRun("mkfs.ext4", "-E", "discard,lazy_itable_init=0", devname)
}
if err != nil {
utils.Debugf("\n--->Err: %s\n", err)
@ -252,7 +249,7 @@ func (devices *DeviceSet) loadMetaData() error {
devices.NewTransactionId = devices.TransactionId
jsonData, err := ioutil.ReadFile(devices.jsonFile())
if err != nil && !os.IsNotExist(err) {
if err != nil && !osIsNotExist(err) {
utils.Debugf("\n--->Err: %s\n", err)
return err
}
@ -337,14 +334,13 @@ func (devices *DeviceSet) setupBaseImage() error {
}
func setCloseOnExec(name string) {
fileInfos, _ := ioutil.ReadDir("/proc/self/fd")
if fileInfos != nil {
if fileInfos, _ := ioutil.ReadDir("/proc/self/fd"); fileInfos != nil {
for _, i := range fileInfos {
link, _ := os.Readlink(filepath.Join("/proc/self/fd", i.Name()))
link, _ := osReadlink(filepath.Join("/proc/self/fd", i.Name()))
if link == name {
fd, err := strconv.Atoi(i.Name())
if err == nil {
syscall.CloseOnExec(fd)
sysCloseOnExec(fd)
}
}
}
@ -372,7 +368,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
datafilename := path.Join(dirname, "data")
metadatafilename := path.Join(dirname, "metadata")
datafile, err := os.OpenFile(datafilename, os.O_RDWR, 0)
datafile, err := osOpenFile(datafilename, osORdWr, 0)
if datafile == nil {
return err
}
@ -387,19 +383,19 @@ func (devices *DeviceSet) ResizePool(size int64) error {
return fmt.Errorf("Can't shrink file")
}
dataloopback := FindLoopDeviceFor(datafile)
dataloopback := FindLoopDeviceFor(&osFile{File: datafile})
if dataloopback == nil {
return fmt.Errorf("Unable to find loopback mount for: %s", datafilename)
}
defer dataloopback.Close()
metadatafile, err := os.OpenFile(metadatafilename, os.O_RDWR, 0)
metadatafile, err := osOpenFile(metadatafilename, osORdWr, 0)
if metadatafile == nil {
return err
}
defer metadatafile.Close()
metadataloopback := FindLoopDeviceFor(metadatafile)
metadataloopback := FindLoopDeviceFor(&osFile{File: metadatafile})
if metadataloopback == nil {
return fmt.Errorf("Unable to find loopback mount for: %s", metadatafilename)
}
@ -464,11 +460,11 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
// Set the device prefix from the device id and inode of the docker root dir
st, err := os.Stat(devices.root)
st, err := osStat(devices.root)
if err != nil {
return fmt.Errorf("Error looking up dir %s: %s", devices.root, err)
}
sysSt := st.Sys().(*syscall.Stat_t)
sysSt := toSysStatT(st.Sys())
// "reg-" stands for "regular file".
// In the future we might use "dev-" for "device file", etc.
// docker-maj,min[-inode] stands for:
@ -708,15 +704,16 @@ func (devices *DeviceSet) byHash(hash string) (devname string, err error) {
}
func (devices *DeviceSet) Shutdown() error {
utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
devices.Lock()
utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
defer devices.Unlock()
utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
for path, count := range devices.activeMounts {
for i := count; i > 0; i-- {
if err := syscall.Unmount(path, 0); err != nil {
if err := sysUnmount(path, 0); err != nil {
utils.Debugf("Shutdown unmounting %s, error: %s\n", path, err)
}
}
@ -752,15 +749,15 @@ func (devices *DeviceSet) MountDevice(hash, path string, readOnly bool) error {
info := devices.Devices[hash]
var flags uintptr = syscall.MS_MGC_VAL
var flags uintptr = sysMsMgcVal
if readOnly {
flags = flags | syscall.MS_RDONLY
flags = flags | sysMsRdOnly
}
err := syscall.Mount(info.DevName(), path, "ext4", flags, "discard")
if err != nil && err == syscall.EINVAL {
err = syscall.Mount(info.DevName(), path, "ext4", flags, "")
err := sysMount(info.DevName(), path, "ext4", flags, "discard")
if err != nil && err == sysEInval {
err = sysMount(info.DevName(), path, "ext4", flags, "")
}
if err != nil {
return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
@ -779,7 +776,7 @@ func (devices *DeviceSet) UnmountDevice(hash, path string, deactivate bool) erro
defer devices.Unlock()
utils.Debugf("[devmapper] Unmount(%s)", path)
if err := syscall.Unmount(path, 0); err != nil {
if err := sysUnmount(path, 0); err != nil {
utils.Debugf("\n--->Err: %s\n", err)
return err
}

View file

@ -4,9 +4,7 @@ import (
"errors"
"fmt"
"github.com/dotcloud/docker/utils"
"os"
"runtime"
"syscall"
)
type DevmapperLogger interface {
@ -49,7 +47,6 @@ var (
ErrTaskAddTarget = errors.New("dm_task_add_target failed")
ErrTaskSetSector = errors.New("dm_task_set_sector failed")
ErrTaskGetInfo = errors.New("dm_task_get_info failed")
ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version failed")
ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
ErrNilCookie = errors.New("cookie ptr can't be nil")
ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
@ -86,7 +83,7 @@ type (
func (t *Task) destroy() {
if t != nil {
DmTaskDestory(t.unmanaged)
DmTaskDestroy(t.unmanaged)
runtime.SetFinalizer(t, nil)
}
}
@ -180,16 +177,16 @@ func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
start, length, targetType, params
}
func AttachLoopDevice(filename string) (*os.File, error) {
func AttachLoopDevice(filename string) (*osFile, error) {
var fd int
res := DmAttachLoopDevice(filename, &fd)
if res == "" {
return nil, ErrAttachLoopbackDevice
}
return os.NewFile(uintptr(fd), res), nil
return &osFile{File: osNewFile(uintptr(fd), res)}, nil
}
func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
func getLoopbackBackingFile(file *osFile) (uint64, uint64, error) {
dev, inode, err := dmGetLoopbackBackingFile(file.Fd())
if err != 0 {
return 0, 0, ErrGetLoopbackBackingFile
@ -197,7 +194,7 @@ func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
return dev, inode, nil
}
func LoopbackSetCapacity(file *os.File) error {
func LoopbackSetCapacity(file *osFile) error {
err := dmLoopbackSetCapacity(file.Fd())
if err != 0 {
return ErrLoopbackSetCapacity
@ -205,20 +202,20 @@ func LoopbackSetCapacity(file *os.File) error {
return nil
}
func FindLoopDeviceFor(file *os.File) *os.File {
func FindLoopDeviceFor(file *osFile) *osFile {
stat, err := file.Stat()
if err != nil {
return nil
}
targetInode := stat.Sys().(*syscall.Stat_t).Ino
targetDevice := stat.Sys().(*syscall.Stat_t).Dev
targetInode := stat.Sys().(*sysStatT).Ino
targetDevice := stat.Sys().(*sysStatT).Dev
for i := 0; true; i++ {
path := fmt.Sprintf("/dev/loop%d", i)
file, err := os.OpenFile(path, os.O_RDWR, 0)
file, err := osOpenFile(path, osORdWr, 0)
if err != nil {
if os.IsNotExist(err) {
if osIsNotExist(err) {
return nil
}
@ -227,9 +224,9 @@ func FindLoopDeviceFor(file *os.File) *os.File {
continue
}
dev, inode, err := getLoopbackBackingFile(file)
dev, inode, err := getLoopbackBackingFile(&osFile{File: file})
if err == nil && dev == targetDevice && inode == targetInode {
return file
return &osFile{File: file}
}
file.Close()
@ -289,7 +286,7 @@ func RemoveDevice(name string) error {
return nil
}
func GetBlockDeviceSize(file *os.File) (uint64, error) {
func GetBlockDeviceSize(file *osFile) (uint64, error) {
size, errno := DmGetBlockSize(file.Fd())
if size == -1 || errno != 0 {
return 0, ErrGetBlockSize
@ -298,7 +295,7 @@ func GetBlockDeviceSize(file *os.File) (uint64, error) {
}
// This is the programmatic example of "dmsetup create"
func createPool(poolName string, dataFile *os.File, metadataFile *os.File) error {
func createPool(poolName string, dataFile, metadataFile *osFile) error {
task, err := createTask(DeviceCreate, poolName)
if task == nil {
return err
@ -328,7 +325,7 @@ func createPool(poolName string, dataFile *os.File, metadataFile *os.File) error
return nil
}
func reloadPool(poolName string, dataFile *os.File, metadataFile *os.File) error {
func reloadPool(poolName string, dataFile, metadataFile *osFile) error {
task, err := createTask(DeviceReload, poolName)
if task == nil {
return err
@ -394,8 +391,8 @@ func getStatus(name string) (uint64, uint64, string, string, error) {
return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
}
_, start, length, target_type, params := task.GetNextTarget(0)
return start, length, target_type, params, nil
_, start, length, targetType, params := task.GetNextTarget(0)
return start, length, targetType, params, nil
}
func setTransactionId(poolName string, oldId uint64, newId uint64) error {

View file

@ -0,0 +1,106 @@
package devmapper
// Definition of struct dm_task and sub structures (from lvm2)
//
// struct dm_ioctl {
// /*
// * The version number is made up of three parts:
// * major - no backward or forward compatibility,
// * minor - only backwards compatible,
// * patch - both backwards and forwards compatible.
// *
// * All clients of the ioctl interface should fill in the
// * version number of the interface that they were
// * compiled with.
// *
// * All recognised ioctl commands (ie. those that don't
// * return -ENOTTY) fill out this field, even if the
// * command failed.
// */
// uint32_t version[3]; /* in/out */
// uint32_t data_size; /* total size of data passed in
// * including this struct */
// uint32_t data_start; /* offset to start of data
// * relative to start of this struct */
// uint32_t target_count; /* in/out */
// int32_t open_count; /* out */
// uint32_t flags; /* in/out */
// /*
// * event_nr holds either the event number (input and output) or the
// * udev cookie value (input only).
// * The DM_DEV_WAIT ioctl takes an event number as input.
// * The DM_SUSPEND, DM_DEV_REMOVE and DM_DEV_RENAME ioctls
// * use the field as a cookie to return in the DM_COOKIE
// * variable with the uevents they issue.
// * For output, the ioctls return the event number, not the cookie.
// */
// uint32_t event_nr; /* in/out */
// uint32_t padding;
// uint64_t dev; /* in/out */
// char name[DM_NAME_LEN]; /* device name */
// char uuid[DM_UUID_LEN]; /* unique identifier for
// * the block device */
// char data[7]; /* padding or data */
// };
// struct target {
// uint64_t start;
// uint64_t length;
// char *type;
// char *params;
// struct target *next;
// };
// typedef enum {
// DM_ADD_NODE_ON_RESUME, /* add /dev/mapper node with dmsetup resume */
// DM_ADD_NODE_ON_CREATE /* add /dev/mapper node with dmsetup create */
// } dm_add_node_t;
// struct dm_task {
// int type;
// char *dev_name;
// char *mangled_dev_name;
// struct target *head, *tail;
// int read_only;
// uint32_t event_nr;
// int major;
// int minor;
// int allow_default_major_fallback;
// uid_t uid;
// gid_t gid;
// mode_t mode;
// uint32_t read_ahead;
// uint32_t read_ahead_flags;
// union {
// struct dm_ioctl *v4;
// } dmi;
// char *newname;
// char *message;
// char *geometry;
// uint64_t sector;
// int no_flush;
// int no_open_count;
// int skip_lockfs;
// int query_inactive_table;
// int suppress_identical_reload;
// dm_add_node_t add_node;
// uint64_t existing_table_size;
// int cookie_set;
// int new_uuid;
// int secure_data;
// int retry_remove;
// int enable_checks;
// int expected_errno;
// char *uuid;
// char *mangled_uuid;
// };
//

View file

@ -1,11 +1,11 @@
package devmapper
import (
"syscall"
"testing"
)
func TestTaskCreate(t *testing.T) {
t.Skip("FIXME: not a unit test")
// Test success
taskCreate(t, DeviceInfo)
@ -18,6 +18,7 @@ func TestTaskCreate(t *testing.T) {
}
func TestTaskRun(t *testing.T) {
t.Skip("FIXME: not a unit test")
task := taskCreate(t, DeviceInfo)
// Test success
@ -46,6 +47,7 @@ func TestTaskRun(t *testing.T) {
}
func TestTaskSetName(t *testing.T) {
t.Skip("FIXME: not a unit test")
task := taskCreate(t, DeviceInfo)
// Test success
@ -63,6 +65,7 @@ func TestTaskSetName(t *testing.T) {
}
func TestTaskSetMessage(t *testing.T) {
t.Skip("FIXME: not a unit test")
task := taskCreate(t, DeviceInfo)
// Test success
@ -80,6 +83,7 @@ func TestTaskSetMessage(t *testing.T) {
}
func TestTaskSetSector(t *testing.T) {
t.Skip("FIXME: not a unit test")
task := taskCreate(t, DeviceInfo)
// Test success
@ -97,6 +101,7 @@ func TestTaskSetSector(t *testing.T) {
}
func TestTaskSetCookie(t *testing.T) {
t.Skip("FIXME: not a unit test")
var (
cookie uint = 0
task = taskCreate(t, DeviceInfo)
@ -121,6 +126,7 @@ func TestTaskSetCookie(t *testing.T) {
}
func TestTaskSetAddNode(t *testing.T) {
t.Skip("FIXME: not a unit test")
task := taskCreate(t, DeviceInfo)
// Test success
@ -142,6 +148,7 @@ func TestTaskSetAddNode(t *testing.T) {
}
func TestTaskSetRo(t *testing.T) {
t.Skip("FIXME: not a unit test")
task := taskCreate(t, DeviceInfo)
// Test success
@ -159,6 +166,7 @@ func TestTaskSetRo(t *testing.T) {
}
func TestTaskAddTarget(t *testing.T) {
t.Skip("FIXME: not a unit test")
task := taskCreate(t, DeviceInfo)
// Test success
@ -247,10 +255,6 @@ func dmTaskAddTargetFail(task *CDmTask,
return -1
}
func dmTaskGetDriverVersionFail(task *CDmTask, version *string) int {
return -1
}
func dmTaskGetInfoFail(task *CDmTask, info *Info) int {
return -1
}
@ -264,14 +268,10 @@ func dmAttachLoopDeviceFail(filename string, fd *int) string {
return ""
}
func sysGetBlockSizeFail(fd uintptr, size *uint64) syscall.Errno {
func sysGetBlockSizeFail(fd uintptr, size *uint64) sysErrno {
return 1
}
func dmGetBlockSizeFail(fd uintptr) int64 {
return -1
}
func dmUdevWaitFail(cookie uint) int {
return -1
}

View file

@ -140,7 +140,6 @@ static void log_with_errno_init()
import "C"
import (
"syscall"
"unsafe"
)
@ -149,26 +148,26 @@ type (
)
var (
DmTaskDestory = dmTaskDestroyFct
DmTaskCreate = dmTaskCreateFct
DmTaskRun = dmTaskRunFct
DmTaskSetName = dmTaskSetNameFct
DmTaskSetMessage = dmTaskSetMessageFct
DmTaskSetSector = dmTaskSetSectorFct
DmTaskSetCookie = dmTaskSetCookieFct
DmTaskSetAddNode = dmTaskSetAddNodeFct
DmTaskSetRo = dmTaskSetRoFct
DmTaskAddTarget = dmTaskAddTargetFct
DmTaskGetInfo = dmTaskGetInfoFct
DmGetNextTarget = dmGetNextTargetFct
DmGetBlockSize = dmGetBlockSizeFct
DmAttachLoopDevice = dmAttachLoopDeviceFct
DmUdevWait = dmUdevWaitFct
DmGetBlockSize = dmGetBlockSizeFct
DmGetLibraryVersion = dmGetLibraryVersionFct
DmGetNextTarget = dmGetNextTargetFct
DmLogInitVerbose = dmLogInitVerboseFct
DmSetDevDir = dmSetDevDirFct
DmGetLibraryVersion = dmGetLibraryVersionFct
LogWithErrnoInit = logWithErrnoInitFct
DmTaskAddTarget = dmTaskAddTargetFct
DmTaskCreate = dmTaskCreateFct
DmTaskDestroy = dmTaskDestroyFct
DmTaskGetInfo = dmTaskGetInfoFct
DmTaskRun = dmTaskRunFct
DmTaskSetAddNode = dmTaskSetAddNodeFct
DmTaskSetCookie = dmTaskSetCookieFct
DmTaskSetMessage = dmTaskSetMessageFct
DmTaskSetName = dmTaskSetNameFct
DmTaskSetRo = dmTaskSetRoFct
DmTaskSetSector = dmTaskSetSectorFct
DmUdevWait = dmUdevWaitFct
GetBlockSize = getBlockSizeFct
LogWithErrnoInit = logWithErrnoInitFct
)
func free(p *C.char) {
@ -239,23 +238,22 @@ func dmTaskAddTargetFct(task *CDmTask,
C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
}
func dmGetLoopbackBackingFile(fd uintptr) (uint64, uint64, syscall.Errno) {
func dmGetLoopbackBackingFile(fd uintptr) (uint64, uint64, sysErrno) {
var lo64 C.struct_loop_info64
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.LOOP_GET_STATUS64,
_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_GET_STATUS64,
uintptr(unsafe.Pointer(&lo64)))
return uint64(lo64.lo_device), uint64(lo64.lo_inode), err
return uint64(lo64.lo_device), uint64(lo64.lo_inode), sysErrno(err)
}
func dmLoopbackSetCapacity(fd uintptr) syscall.Errno {
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.LOOP_SET_CAPACITY, 0)
return err
func dmLoopbackSetCapacity(fd uintptr) sysErrno {
_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_SET_CAPACITY, 0)
return sysErrno(err)
}
func dmGetBlockSizeFct(fd uintptr) (int64, syscall.Errno) {
func dmGetBlockSizeFct(fd uintptr) (int64, sysErrno) {
var size int64
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64,
uintptr(unsafe.Pointer(&size)))
return size, err
_, _, err := sysSyscall(sysSysIoctl, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size)))
return size, sysErrno(err)
}
func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
@ -275,9 +273,7 @@ func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
}
func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64,
target, params *string) uintptr {
func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
var (
Cstart, Clength C.uint64_t
CtargetType, Cparams *C.char
@ -288,6 +284,7 @@ func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64,
*target = C.GoString(CtargetType)
*params = C.GoString(Cparams)
}()
nextp := C.dm_get_next_target((*C.struct_dm_task)(task),
unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
return uintptr(nextp)
@ -307,10 +304,9 @@ func dmAttachLoopDeviceFct(filename string, fd *int) string {
return C.GoString(ret)
}
func getBlockSizeFct(fd uintptr, size *uint64) syscall.Errno {
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64,
uintptr(unsafe.Pointer(&size)))
return err
func getBlockSizeFct(fd uintptr, size *uint64) sysErrno {
_, _, err := sysSyscall(sysSysIoctl, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size)))
return sysErrno(err)
}
func dmUdevWaitFct(cookie uint) int {

View file

@ -4,7 +4,6 @@ import (
"fmt"
"github.com/dotcloud/docker/graphdriver"
"io/ioutil"
"os"
"path"
)
@ -22,7 +21,7 @@ type Driver struct {
home string
}
func Init(home string) (graphdriver.Driver, error) {
var Init = func(home string) (graphdriver.Driver, error) {
deviceSet, err := NewDeviceSet(home, true)
if err != nil {
return nil, err
@ -57,7 +56,7 @@ func (d *Driver) Cleanup() error {
return d.DeviceSet.Shutdown()
}
func (d *Driver) Create(id string, parent string) error {
func (d *Driver) Create(id, parent string) error {
if err := d.DeviceSet.AddDevice(id, parent); err != nil {
return err
}
@ -67,7 +66,7 @@ func (d *Driver) Create(id string, parent string) error {
return err
}
if err := os.MkdirAll(path.Join(mp, "rootfs"), 0755); err != nil && !os.IsExist(err) {
if err := osMkdirAll(path.Join(mp, "rootfs"), 0755); err != nil && !osIsExist(err) {
return err
}
@ -98,7 +97,7 @@ func (d *Driver) Get(id string) (string, error) {
func (d *Driver) mount(id, mountPoint string) error {
// Create the target directories if they don't exist
if err := os.MkdirAll(mountPoint, 0755); err != nil && !os.IsExist(err) {
if err := osMkdirAll(mountPoint, 0755); err != nil && !osIsExist(err) {
return err
}
// If mountpoint is already mounted, do nothing

View file

@ -1,9 +1,13 @@
package devmapper
import (
"fmt"
"github.com/dotcloud/docker/graphdriver"
"io/ioutil"
"os"
"path"
"runtime"
"strings"
"syscall"
"testing"
)
@ -12,7 +16,105 @@ func init() {
DefaultDataLoopbackSize = 300 * 1024 * 1024
DefaultMetaDataLoopbackSize = 200 * 1024 * 1024
DefaultBaseFsSize = 300 * 1024 * 1024
}
// denyAllDevmapper mocks all calls to libdevmapper in the unit tests, and denies them by default
func denyAllDevmapper() {
// Hijack all calls to libdevmapper with default panics.
// Authorized calls are selectively hijacked in each tests.
DmTaskCreate = func(t int) *CDmTask {
panic("DmTaskCreate: this method should not be called here")
}
DmTaskRun = func(task *CDmTask) int {
panic("DmTaskRun: this method should not be called here")
}
DmTaskSetName = func(task *CDmTask, name string) int {
panic("DmTaskSetName: this method should not be called here")
}
DmTaskSetMessage = func(task *CDmTask, message string) int {
panic("DmTaskSetMessage: this method should not be called here")
}
DmTaskSetSector = func(task *CDmTask, sector uint64) int {
panic("DmTaskSetSector: this method should not be called here")
}
DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
panic("DmTaskSetCookie: this method should not be called here")
}
DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
panic("DmTaskSetAddNode: this method should not be called here")
}
DmTaskSetRo = func(task *CDmTask) int {
panic("DmTaskSetRo: this method should not be called here")
}
DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
panic("DmTaskAddTarget: this method should not be called here")
}
DmTaskGetInfo = func(task *CDmTask, info *Info) int {
panic("DmTaskGetInfo: this method should not be called here")
}
DmGetNextTarget = func(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
panic("DmGetNextTarget: this method should not be called here")
}
DmAttachLoopDevice = func(filename string, fd *int) string {
panic("DmAttachLoopDevice: this method should not be called here")
}
DmGetBlockSize = func(fd uintptr) (int64, sysErrno) {
panic("DmGetBlockSize: this method should not be called here")
}
DmUdevWait = func(cookie uint) int {
panic("DmUdevWait: this method should not be called here")
}
DmSetDevDir = func(dir string) int {
panic("DmSetDevDir: this method should not be called here")
}
DmGetLibraryVersion = func(version *string) int {
panic("DmGetLibraryVersion: this method should not be called here")
}
DmLogInitVerbose = func(level int) {
panic("DmLogInitVerbose: this method should not be called here")
}
DmTaskDestroy = func(task *CDmTask) {
panic("DmTaskDestroy: this method should not be called here")
}
GetBlockSize = func(fd uintptr, size *uint64) sysErrno {
panic("GetBlockSize: this method should not be called here")
}
LogWithErrnoInit = func() {
panic("LogWithErrnoInit: this method should not be called here")
}
}
func denyAllSyscall() {
sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
panic("sysMount: this method should not be called here")
}
sysUnmount = func(target string, flags int) (err error) {
panic("sysUnmount: this method should not be called here")
}
sysCloseOnExec = func(fd int) {
panic("sysCloseOnExec: this method should not be called here")
}
sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
panic("sysSyscall: this method should not be called here")
}
// Not a syscall, but forbidding it here anyway
Mounted = func(mnt string) (bool, error) {
panic("devmapper.Mounted: this method should not be called here")
}
// osOpenFile = os.OpenFile
// osNewFile = os.NewFile
// osCreate = os.Create
// osStat = os.Stat
// osIsNotExist = os.IsNotExist
// osIsExist = os.IsExist
// osMkdirAll = os.MkdirAll
// osRemoveAll = os.RemoveAll
// osRename = os.Rename
// osReadlink = os.Readlink
// execRun = func(name string, args ...string) error {
// return exec.Command(name, args...).Run()
// }
}
func mkTestDirectory(t *testing.T) string {
@ -34,72 +136,521 @@ func newDriver(t *testing.T) *Driver {
func cleanup(d *Driver) {
d.Cleanup()
os.RemoveAll(d.home)
osRemoveAll(d.home)
}
type Set map[string]bool
func (r Set) Assert(t *testing.T, names ...string) {
for _, key := range names {
if _, exists := r[key]; !exists {
t.Fatalf("Key not set: %s", key)
}
delete(r, key)
}
if len(r) != 0 {
t.Fatalf("Unexpected keys: %v", r)
}
}
func TestInit(t *testing.T) {
home := mkTestDirectory(t)
defer os.RemoveAll(home)
driver, err := Init(home)
if err != nil {
t.Fatal(err)
}
defer func() {
if err := driver.Cleanup(); err != nil {
var (
calls = make(Set)
devicesAttached = make(Set)
taskMessages = make(Set)
taskTypes = make(Set)
home = mkTestDirectory(t)
)
defer osRemoveAll(home)
func() {
denyAllDevmapper()
DmSetDevDir = func(dir string) int {
calls["DmSetDevDir"] = true
expectedDir := "/dev"
if dir != expectedDir {
t.Fatalf("Wrong libdevmapper call\nExpected: DmSetDevDir(%v)\nReceived: DmSetDevDir(%v)\n", expectedDir, dir)
}
return 0
}
LogWithErrnoInit = func() {
calls["DmLogWithErrnoInit"] = true
}
var task1 CDmTask
DmTaskCreate = func(taskType int) *CDmTask {
calls["DmTaskCreate"] = true
taskTypes[fmt.Sprintf("%d", taskType)] = true
return &task1
}
DmTaskSetName = func(task *CDmTask, name string) int {
calls["DmTaskSetName"] = true
expectedTask := &task1
if task != expectedTask {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetName(%v)\nReceived: DmTaskSetName(%v)\n", expectedTask, task)
}
// FIXME: use Set.AssertRegexp()
if !strings.HasPrefix(name, "docker-") && !strings.HasPrefix(name, "/dev/mapper/docker-") ||
!strings.HasSuffix(name, "-pool") && !strings.HasSuffix(name, "-base") {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetName(%v)\nReceived: DmTaskSetName(%v)\n", "docker-...-pool", name)
}
return 1
}
DmTaskRun = func(task *CDmTask) int {
calls["DmTaskRun"] = true
expectedTask := &task1
if task != expectedTask {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskRun(%v)\nReceived: DmTaskRun(%v)\n", expectedTask, task)
}
return 1
}
DmTaskGetInfo = func(task *CDmTask, info *Info) int {
calls["DmTaskGetInfo"] = true
expectedTask := &task1
if task != expectedTask {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskGetInfo(%v)\nReceived: DmTaskGetInfo(%v)\n", expectedTask, task)
}
// This will crash if info is not dereferenceable
info.Exists = 0
return 1
}
DmTaskSetSector = func(task *CDmTask, sector uint64) int {
calls["DmTaskSetSector"] = true
expectedTask := &task1
if task != expectedTask {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetSector(%v)\nReceived: DmTaskSetSector(%v)\n", expectedTask, task)
}
if expectedSector := uint64(0); sector != expectedSector {
t.Fatalf("Wrong libdevmapper call to DmTaskSetSector\nExpected: %v\nReceived: %v\n", expectedSector, sector)
}
return 1
}
DmTaskSetMessage = func(task *CDmTask, message string) int {
calls["DmTaskSetMessage"] = true
expectedTask := &task1
if task != expectedTask {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetSector(%v)\nReceived: DmTaskSetSector(%v)\n", expectedTask, task)
}
taskMessages[message] = true
return 1
}
var (
fakeDataLoop = "/dev/loop42"
fakeMetadataLoop = "/dev/loop43"
fakeDataLoopFd = 42
fakeMetadataLoopFd = 43
)
var attachCount int
DmAttachLoopDevice = func(filename string, fd *int) string {
calls["DmAttachLoopDevice"] = true
if _, exists := devicesAttached[filename]; exists {
t.Fatalf("Already attached %s", filename)
}
devicesAttached[filename] = true
// This will crash if fd is not dereferenceable
if attachCount == 0 {
attachCount++
*fd = fakeDataLoopFd
return fakeDataLoop
} else {
*fd = fakeMetadataLoopFd
return fakeMetadataLoop
}
}
DmTaskDestroy = func(task *CDmTask) {
calls["DmTaskDestroy"] = true
expectedTask := &task1
if task != expectedTask {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
}
}
fakeBlockSize := int64(4242 * 512)
DmGetBlockSize = func(fd uintptr) (int64, sysErrno) {
calls["DmGetBlockSize"] = true
if expectedFd := uintptr(42); fd != expectedFd {
t.Fatalf("Wrong libdevmapper call\nExpected: DmGetBlockSize(%v)\nReceived: DmGetBlockSize(%v)\n", expectedFd, fd)
}
return fakeBlockSize, 0
}
DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
calls["DmTaskSetTarget"] = true
expectedTask := &task1
if task != expectedTask {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
}
if start != 0 {
t.Fatalf("Wrong start: %d != %d", start, 0)
}
if ttype != "thin" && ttype != "thin-pool" {
t.Fatalf("Wrong ttype: %s", ttype)
}
// Quick smoke test
if params == "" {
t.Fatalf("Params should not be empty")
}
return 1
}
fakeCookie := uint(4321)
DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
calls["DmTaskSetCookie"] = true
expectedTask := &task1
if task != expectedTask {
t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
}
if flags != 0 {
t.Fatalf("Cookie flags should be 0 (not %x)", flags)
}
*cookie = fakeCookie
return 1
}
DmUdevWait = func(cookie uint) int {
calls["DmUdevWait"] = true
if cookie != fakeCookie {
t.Fatalf("Wrong cookie: %d != %d", cookie, fakeCookie)
}
return 1
}
DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
if addNode != AddNodeOnCreate {
t.Fatalf("Wrong AddNoteType: %v (expected %v)", addNode, AddNodeOnCreate)
}
calls["DmTaskSetAddNode"] = true
return 1
}
execRun = func(name string, args ...string) error {
calls["execRun"] = true
if name != "mkfs.ext4" {
t.Fatalf("Expected %s to be executed, not %s", "mkfs.ext4", name)
}
return nil
}
driver, err := Init(home)
if err != nil {
t.Fatal(err)
}
defer func() {
if err := driver.Cleanup(); err != nil {
t.Fatal(err)
}
}()
}()
// Put all tests in a funciton to make sure the garbage collection will
// occur.
id := "foo"
if err := driver.Create(id, ""); err != nil {
t.Fatal(err)
// Call GC to cleanup runtime.Finalizers
runtime.GC()
calls.Assert(t,
"DmSetDevDir",
"DmLogWithErrnoInit",
"DmTaskSetName",
"DmTaskRun",
"DmTaskGetInfo",
"DmAttachLoopDevice",
"DmTaskDestroy",
"execRun",
"DmTaskCreate",
"DmGetBlockSize",
"DmTaskSetTarget",
"DmTaskSetCookie",
"DmUdevWait",
"DmTaskSetSector",
"DmTaskSetMessage",
"DmTaskSetAddNode",
)
devicesAttached.Assert(t, path.Join(home, "devicemapper", "data"), path.Join(home, "devicemapper", "metadata"))
taskTypes.Assert(t, "0", "6", "17")
taskMessages.Assert(t, "create_thin 0", "set_transaction_id 0 1")
}
func fakeInit() func(home string) (graphdriver.Driver, error) {
oldInit := Init
Init = func(home string) (graphdriver.Driver, error) {
return &Driver{
home: home,
}, nil
}
dir, err := driver.Get(id)
if err != nil {
t.Fatal(err)
return oldInit
}
func restoreInit(init func(home string) (graphdriver.Driver, error)) {
Init = init
}
func mockAllDevmapper(calls Set) {
DmSetDevDir = func(dir string) int {
calls["DmSetDevDir"] = true
return 0
}
if st, err := os.Stat(dir); err != nil {
t.Fatal(err)
} else if !st.IsDir() {
t.Fatalf("Get(%V) did not return a directory", id)
LogWithErrnoInit = func() {
calls["DmLogWithErrnoInit"] = true
}
DmTaskCreate = func(taskType int) *CDmTask {
calls["DmTaskCreate"] = true
return &CDmTask{}
}
DmTaskSetName = func(task *CDmTask, name string) int {
calls["DmTaskSetName"] = true
return 1
}
DmTaskRun = func(task *CDmTask) int {
calls["DmTaskRun"] = true
return 1
}
DmTaskGetInfo = func(task *CDmTask, info *Info) int {
calls["DmTaskGetInfo"] = true
return 1
}
DmTaskSetSector = func(task *CDmTask, sector uint64) int {
calls["DmTaskSetSector"] = true
return 1
}
DmTaskSetMessage = func(task *CDmTask, message string) int {
calls["DmTaskSetMessage"] = true
return 1
}
DmAttachLoopDevice = func(filename string, fd *int) string {
calls["DmAttachLoopDevice"] = true
return "/dev/loop42"
}
DmTaskDestroy = func(task *CDmTask) {
calls["DmTaskDestroy"] = true
}
DmGetBlockSize = func(fd uintptr) (int64, sysErrno) {
calls["DmGetBlockSize"] = true
return int64(4242 * 512), 0
}
DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
calls["DmTaskSetTarget"] = true
return 1
}
DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
calls["DmTaskSetCookie"] = true
return 1
}
DmUdevWait = func(cookie uint) int {
calls["DmUdevWait"] = true
return 1
}
DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
calls["DmTaskSetAddNode"] = true
return 1
}
execRun = func(name string, args ...string) error {
calls["execRun"] = true
return nil
}
}
func TestDriverName(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
denyAllDevmapper()
defer denyAllDevmapper()
oldInit := fakeInit()
defer restoreInit(oldInit)
d := newDriver(t)
if d.String() != "devicemapper" {
t.Fatalf("Expected driver name to be devicemapper got %s", d.String())
}
}
func TestDriverCreate(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
denyAllDevmapper()
denyAllSyscall()
defer denyAllSyscall()
defer denyAllDevmapper()
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
calls := make(Set)
mockAllDevmapper(calls)
sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
calls["sysMount"] = true
// FIXME: compare the exact source and target strings (inodes + devname)
if expectedSource := "/dev/mapper/docker-"; !strings.HasPrefix(source, expectedSource) {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedSource, source)
}
if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
}
if expectedFstype := "ext4"; fstype != expectedFstype {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFstype, fstype)
}
if expectedFlags := uintptr(3236757504); flags != expectedFlags {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
}
return nil
}
Mounted = func(mnt string) (bool, error) {
calls["Mounted"] = true
if !strings.HasPrefix(mnt, "/tmp/docker-test-devmapper-") || !strings.HasSuffix(mnt, "/mnt/1") {
t.Fatalf("Wrong mounted call\nExpected: Mounted(%v)\nReceived: Mounted(%v)\n", "/tmp/docker-test-devmapper-.../mnt/1", mnt)
}
return false, nil
}
func() {
d := newDriver(t)
calls.Assert(t,
"DmSetDevDir",
"DmLogWithErrnoInit",
"DmTaskSetName",
"DmTaskRun",
"DmTaskGetInfo",
"DmAttachLoopDevice",
"execRun",
"DmTaskCreate",
"DmGetBlockSize",
"DmTaskSetTarget",
"DmTaskSetCookie",
"DmUdevWait",
"DmTaskSetSector",
"DmTaskSetMessage",
"DmTaskSetAddNode",
)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
calls.Assert(t,
"DmTaskCreate",
"DmTaskGetInfo",
"sysMount",
"Mounted",
"DmTaskRun",
"DmTaskSetTarget",
"DmTaskSetSector",
"DmTaskSetCookie",
"DmUdevWait",
"DmTaskSetName",
"DmTaskSetMessage",
"DmTaskSetAddNode",
)
}()
runtime.GC()
calls.Assert(t,
"DmTaskDestroy",
)
}
func TestDriverRemove(t *testing.T) {
d := newDriver(t)
defer cleanup(d)
denyAllDevmapper()
denyAllSyscall()
defer denyAllSyscall()
defer denyAllDevmapper()
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
calls := make(Set)
mockAllDevmapper(calls)
sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
calls["sysMount"] = true
// FIXME: compare the exact source and target strings (inodes + devname)
if expectedSource := "/dev/mapper/docker-"; !strings.HasPrefix(source, expectedSource) {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedSource, source)
}
if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
}
if expectedFstype := "ext4"; fstype != expectedFstype {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFstype, fstype)
}
if expectedFlags := uintptr(3236757504); flags != expectedFlags {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
}
return nil
}
sysUnmount = func(target string, flags int) (err error) {
calls["sysUnmount"] = true
// FIXME: compare the exact source and target strings (inodes + devname)
if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
}
if expectedFlags := 0; flags != expectedFlags {
t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
}
return nil
}
Mounted = func(mnt string) (bool, error) {
calls["Mounted"] = true
return false, nil
}
if err := d.Remove("1"); err != nil {
t.Fatal(err)
}
func() {
d := newDriver(t)
calls.Assert(t,
"DmSetDevDir",
"DmLogWithErrnoInit",
"DmTaskSetName",
"DmTaskRun",
"DmTaskGetInfo",
"DmAttachLoopDevice",
"execRun",
"DmTaskCreate",
"DmGetBlockSize",
"DmTaskSetTarget",
"DmTaskSetCookie",
"DmUdevWait",
"DmTaskSetSector",
"DmTaskSetMessage",
"DmTaskSetAddNode",
)
if err := d.Create("1", ""); err != nil {
t.Fatal(err)
}
calls.Assert(t,
"DmTaskCreate",
"DmTaskGetInfo",
"sysMount",
"Mounted",
"DmTaskRun",
"DmTaskSetTarget",
"DmTaskSetSector",
"DmTaskSetCookie",
"DmUdevWait",
"DmTaskSetName",
"DmTaskSetMessage",
"DmTaskSetAddNode",
)
Mounted = func(mnt string) (bool, error) {
calls["Mounted"] = true
return true, nil
}
if err := d.Remove("1"); err != nil {
t.Fatal(err)
}
calls.Assert(t,
"DmTaskRun",
"DmTaskSetSector",
"DmTaskSetName",
"DmTaskSetMessage",
"DmTaskCreate",
"DmTaskGetInfo",
"Mounted",
"sysUnmount",
)
}()
runtime.GC()
calls.Assert(t,
"DmTaskDestroy",
)
}
func TestCleanup(t *testing.T) {
t.Skip("FIXME: not a unit test")
t.Skip("Unimplemented")
d := newDriver(t)
defer os.RemoveAll(d.home)
defer osRemoveAll(d.home)
mountPoints := make([]string, 2)
@ -161,6 +712,7 @@ func TestCleanup(t *testing.T) {
}
func TestNotMounted(t *testing.T) {
t.Skip("FIXME: not a unit test")
t.Skip("Not implemented")
d := newDriver(t)
defer cleanup(d)
@ -179,6 +731,7 @@ func TestNotMounted(t *testing.T) {
}
func TestMounted(t *testing.T) {
t.Skip("FIXME: not a unit test")
d := newDriver(t)
defer cleanup(d)
@ -199,6 +752,7 @@ func TestMounted(t *testing.T) {
}
func TestInitCleanedDriver(t *testing.T) {
t.Skip("FIXME: not a unit test")
d := newDriver(t)
if err := d.Create("1", ""); err != nil {
@ -225,6 +779,7 @@ func TestInitCleanedDriver(t *testing.T) {
}
func TestMountMountedDriver(t *testing.T) {
t.Skip("FIXME: not a unit test")
d := newDriver(t)
defer cleanup(d)
@ -243,6 +798,7 @@ func TestMountMountedDriver(t *testing.T) {
}
func TestGetReturnsValidDevice(t *testing.T) {
t.Skip("FIXME: not a unit test")
d := newDriver(t)
defer cleanup(d)
@ -268,6 +824,7 @@ func TestGetReturnsValidDevice(t *testing.T) {
}
func TestDriverGetSize(t *testing.T) {
t.Skip("FIXME: not a unit test")
t.Skipf("Size is currently not implemented")
d := newDriver(t)
@ -284,7 +841,7 @@ func TestDriverGetSize(t *testing.T) {
size := int64(1024)
f, err := os.Create(path.Join(mountPoint, "test_file"))
f, err := osCreate(path.Join(mountPoint, "test_file"))
if err != nil {
t.Fatal(err)
}
@ -301,3 +858,15 @@ func TestDriverGetSize(t *testing.T) {
// t.Fatalf("Expected size %d got %d", size, diffSize)
// }
}
func assertMap(t *testing.T, m map[string]bool, keys ...string) {
for _, key := range keys {
if _, exists := m[key]; !exists {
t.Fatalf("Key not set: %s", key)
}
delete(m, key)
}
if len(m) != 0 {
t.Fatalf("Unexpected keys: %v", m)
}
}

View file

@ -1,27 +1,25 @@
package devmapper
import (
"os"
"path/filepath"
"syscall"
)
// FIXME: this is copy-pasted from the aufs driver.
// It should be moved into the core.
func Mounted(mountpoint string) (bool, error) {
mntpoint, err := os.Stat(mountpoint)
var Mounted = func(mountpoint string) (bool, error) {
mntpoint, err := osStat(mountpoint)
if err != nil {
if os.IsNotExist(err) {
if osIsNotExist(err) {
return false, nil
}
return false, err
}
parent, err := os.Stat(filepath.Join(mountpoint, ".."))
parent, err := osStat(filepath.Join(mountpoint, ".."))
if err != nil {
return false, err
}
mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
parentSt := parent.Sys().(*syscall.Stat_t)
mntpointSt := toSysStatT(mntpoint.Sys())
parentSt := toSysStatT(parent.Sys())
return mntpointSt.Dev != parentSt.Dev, nil
}

View file

@ -0,0 +1,50 @@
package devmapper
import (
"os"
"os/exec"
"syscall"
)
type (
sysStatT syscall.Stat_t
sysErrno syscall.Errno
osFile struct{ *os.File }
)
var (
sysMount = syscall.Mount
sysUnmount = syscall.Unmount
sysCloseOnExec = syscall.CloseOnExec
sysSyscall = syscall.Syscall
osOpenFile = os.OpenFile
osNewFile = os.NewFile
osCreate = os.Create
osStat = os.Stat
osIsNotExist = os.IsNotExist
osIsExist = os.IsExist
osMkdirAll = os.MkdirAll
osRemoveAll = os.RemoveAll
osRename = os.Rename
osReadlink = os.Readlink
execRun = func(name string, args ...string) error {
return exec.Command(name, args...).Run()
}
)
const (
sysMsMgcVal = syscall.MS_MGC_VAL
sysMsRdOnly = syscall.MS_RDONLY
sysEInval = syscall.EINVAL
sysSysIoctl = syscall.SYS_IOCTL
osORdWr = os.O_RDWR
osOCreate = os.O_CREATE
)
func toSysStatT(i interface{}) *sysStatT {
return (*sysStatT)(i.(*syscall.Stat_t))
}