You've already forked fsextender
mirror of
https://github.com/rekby/fsextender.git
synced 2025-09-19 01:14:30 +03:00
1464 lines
39 KiB
Go
1464 lines
39 KiB
Go
package fsextender
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/ogier/pflag"
|
|
"github.com/rekby/pretty"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
const GB = 1024 * 1024 * 1024
|
|
const TB = 1024 * 1024 * 1024 * 1024
|
|
const TMP_DIR = "/tmp"
|
|
const TMP_MOUNT_DIR = "/tmp/fsextender-test-mount-dir"
|
|
const LVM_VG_NAME = "test-fsextender-lvm-vg"
|
|
const LVM_LV_NAME = "test-fsextender-lvm-lv"
|
|
|
|
const GPT_SIZE = 16896 // Size of GPT header + gpt entries
|
|
const TMP_DISK_SIZE = 100 * GB
|
|
const MSDOS_START_BYTE = 32256
|
|
const MSDOS_LAST_BYTE = 107374182399
|
|
const GPT_START_BYTE = 512 + GPT_SIZE
|
|
const GPT_LAST_BYTE = TMP_DISK_SIZE - GPT_SIZE - 1
|
|
|
|
var PART_TABLES = []string{"msdos", "gpt"}
|
|
|
|
type testPartition struct {
|
|
Number uint64
|
|
Start uint64
|
|
Last uint64
|
|
}
|
|
|
|
func resetProgramState() {
|
|
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
|
|
majorMinorDeviceTypeCache = make(map[[2]int]storageItem)
|
|
diskNewPartitionNumLastGeneratedNum = make(map[[2]int]uint32)
|
|
}
|
|
|
|
// Call main program
|
|
func call(args ...string) {
|
|
if os.Getuid() == 0 {
|
|
// for test coverage run test as root
|
|
oldArgs := os.Args
|
|
os.Args = append([]string{os.Args[0]}, args...)
|
|
// Clean old environment
|
|
resetProgramState()
|
|
|
|
Main()
|
|
os.Args = oldArgs
|
|
} else {
|
|
sudo("./fsextender", args...)
|
|
}
|
|
}
|
|
|
|
// Create loop-back test device with partition table, standard size
|
|
func createTmpDevice(partTable string) (path string, err error) {
|
|
return createTmpDeviceSize(partTable, TMP_DISK_SIZE)
|
|
}
|
|
|
|
// Create loop-back test device with partition table
|
|
func createTmpDeviceSize(partTable string, size int64) (path string, err error) {
|
|
var f *os.File
|
|
f, err = ioutil.TempFile(TMP_DIR, "fsextender-loop-")
|
|
if err != nil {
|
|
return
|
|
}
|
|
fname := f.Name()
|
|
|
|
// Large sparse size = 100GB
|
|
_, err = f.WriteAt([]byte{0}, size)
|
|
f.Close()
|
|
if err != nil {
|
|
os.Remove(fname)
|
|
return
|
|
}
|
|
|
|
res, errString, err := sudo("losetup", "-f", "--show", fname)
|
|
path = strings.TrimSpace(res)
|
|
if path == "" {
|
|
err = fmt.Errorf("Can't create loop device: %v\n%v\n%v\n", fname, err, errString)
|
|
os.Remove(fname)
|
|
return
|
|
}
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
_, _, err = sudo("parted", "-s", path, "mklabel", partTable)
|
|
if err != nil {
|
|
err = fmt.Errorf("Can't create part table: %v (%v)\n", path, err)
|
|
deleteTmpDevice(path)
|
|
path = ""
|
|
return
|
|
}
|
|
return path, nil
|
|
}
|
|
|
|
func deleteTmpDevice(path string) {
|
|
filePath, _, _ := sudo("losetup", path)
|
|
start := strings.Index(filePath, "(")
|
|
finish := strings.Index(filePath, ")")
|
|
filePath = filePath[start+1 : finish]
|
|
|
|
// remove partitions
|
|
for _, part := range readPartitions(path) {
|
|
sudo("parted", "-s", path, "rm", strconv.Itoa(int(part.Number)))
|
|
}
|
|
|
|
sudo("sudo", "losetup", "-d", path)
|
|
os.Remove(filePath)
|
|
|
|
// Wait for umount device
|
|
for {
|
|
_, errString, _ := sudo("losetup", path)
|
|
if errString != "" {
|
|
break
|
|
}
|
|
time.Sleep(time.Second / 10) // time to kernel remove device
|
|
}
|
|
}
|
|
|
|
func extendTmpDevice(path string, size int64) (disk string, err error) {
|
|
filePath, _, _ := sudo("losetup", path)
|
|
start := strings.Index(filePath, "(")
|
|
finish := strings.Index(filePath, ")")
|
|
filePath = filePath[start+1 : finish]
|
|
|
|
sudo("sudo", "losetup", "-d", path)
|
|
fDisk, err := os.OpenFile(filePath, os.O_WRONLY, 0)
|
|
if err != nil {
|
|
os.Remove(filePath)
|
|
return "", errors.New("Error open file of disk: " + err.Error())
|
|
}
|
|
err = fDisk.Truncate(size)
|
|
if err != nil {
|
|
os.Remove(filePath)
|
|
return "", errors.New("Error truncate file of disk: " + err.Error())
|
|
}
|
|
fDisk.Close()
|
|
|
|
res, errString, err := sudo("losetup", "-f", "--show", filePath)
|
|
disk = strings.TrimSpace(res)
|
|
if path == "" {
|
|
err = fmt.Errorf("Can't create loop device: %v\n%v\n%v\n", filePath, err, errString)
|
|
os.Remove(filePath)
|
|
return "", err
|
|
}
|
|
return disk, nil
|
|
}
|
|
|
|
// Return volume of filesystem in 1-Gb blocks
|
|
func df(path string) uint64 {
|
|
res, _, _ := cmd("df", "-BG", path)
|
|
resLines := strings.Split(res, "\n")
|
|
blocksStart := strings.Index(resLines[0], "1G-blocks")
|
|
blocksEnd := blocksStart + len("1G-blocks")
|
|
blocksString := strings.TrimSpace(resLines[1][blocksStart:blocksEnd])
|
|
blocksString = strings.TrimSuffix(blocksString, "G")
|
|
blocks, _ := parseUint(blocksString)
|
|
return blocks
|
|
}
|
|
|
|
func readPartitions(path string) (res []testPartition) {
|
|
partedRes, _, _ := cmd("sudo", "parted", "-s", path, "unit", "b", "print")
|
|
lines := strings.Split(partedRes, "\n")
|
|
var numStart, numFinish, startStart, startFinish, endStart, endFinish int
|
|
var startParse = false
|
|
for _, line := range lines {
|
|
if strings.TrimSpace(line) == "" {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(line, "Number") {
|
|
numStart = 0
|
|
numFinish = strings.Index(line, "Start")
|
|
startStart = strings.Index(line, "Start")
|
|
startFinish = strings.Index(line, "End")
|
|
endStart = strings.Index(line, "End")
|
|
endFinish = strings.Index(line, "Size")
|
|
startParse = true
|
|
continue
|
|
}
|
|
if !startParse {
|
|
continue
|
|
}
|
|
var partition testPartition
|
|
partition.Number, _ = parseUint(strings.TrimSpace(line[numStart:numFinish]))
|
|
if partition.Number == 0 {
|
|
continue
|
|
}
|
|
partition.Start, _ = parseUint(strings.TrimSuffix(strings.TrimSpace(line[startStart:startFinish]), "B"))
|
|
partition.Last, _ = parseUint(strings.TrimSuffix(strings.TrimSpace(line[endStart:endFinish]), "B"))
|
|
|
|
res = append(res, partition)
|
|
}
|
|
return
|
|
}
|
|
|
|
func s(n uint64) string {
|
|
return strconv.FormatUint(n, 10)
|
|
}
|
|
|
|
func sudo(command string, args ...string) (res string, errString string, err error) {
|
|
if os.Getuid() == 0 {
|
|
return cmd(command, args...)
|
|
} else {
|
|
args = append([]string{command}, args...)
|
|
return cmd("sudo", args...)
|
|
}
|
|
}
|
|
|
|
func TestExt4PartitionMSDOS(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
part := disk + "p1"
|
|
sudo("mkfs.ext4", part)
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sudo("mount", part, TMP_MOUNT_DIR)
|
|
defer sudo("umount", part)
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
res, _, _ := cmd("df", "-BG", part)
|
|
resLines := strings.Split(res, "\n")
|
|
blocksStart := strings.Index(resLines[0], "1G-blocks")
|
|
blocksEnd := blocksStart + len("1G-blocks")
|
|
blocksString := strings.TrimSpace(resLines[1][blocksStart:blocksEnd])
|
|
blocksString = strings.TrimSuffix(blocksString, "G")
|
|
blocks, _ := parseUint(blocksString)
|
|
if blocks != 99 {
|
|
t.Error(resLines[1])
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, MSDOS_START_BYTE, MSDOS_LAST_BYTE},
|
|
}
|
|
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestExt4PartitionGPT(t *testing.T) {
|
|
disk, err := createTmpDevice("gpt")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(GPT_START_BYTE), s(GPT_START_BYTE+GB)) // 1Gb
|
|
part := disk + "p1"
|
|
sudo("mkfs.ext4", part)
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sudo("mount", part, TMP_MOUNT_DIR)
|
|
defer sudo("umount", part)
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
res, _, _ := cmd("df", "-BG", part)
|
|
resLines := strings.Split(res, "\n")
|
|
blocksStart := strings.Index(resLines[0], "1G-blocks")
|
|
blocksEnd := blocksStart + len("1G-blocks")
|
|
blocksString := strings.TrimSpace(resLines[1][blocksStart:blocksEnd])
|
|
blocksString = strings.TrimSuffix(blocksString, "G")
|
|
blocks, _ := parseUint(blocksString)
|
|
if blocks != 99 {
|
|
t.Error(resLines[1])
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, GPT_START_BYTE, GPT_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
|
|
}
|
|
|
|
func TestXfsPartitionMSDOS(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
part := disk + "p1"
|
|
sudo("mkfs.xfs", part)
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sudo("mount", part, TMP_MOUNT_DIR)
|
|
defer sudo("umount", part)
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
res, _, _ := cmd("df", "-BG", part)
|
|
resLines := strings.Split(res, "\n")
|
|
blocksStart := strings.Index(resLines[0], "1G-blocks")
|
|
blocksEnd := blocksStart + len("1G-blocks")
|
|
blocksString := strings.TrimSpace(resLines[1][blocksStart:blocksEnd])
|
|
blocksString = strings.TrimSuffix(blocksString, "G")
|
|
blocks, _ := parseUint(blocksString)
|
|
if blocks != 100 {
|
|
t.Error(resLines[1])
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, MSDOS_START_BYTE, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestXfsPartitionGPT(t *testing.T) {
|
|
disk, err := createTmpDevice("gpt")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(GPT_START_BYTE), s(GPT_START_BYTE+GB)) // 1Gb
|
|
part := disk + "p1"
|
|
sudo("mkfs.xfs", part)
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sudo("mount", part, TMP_MOUNT_DIR)
|
|
defer sudo("umount", part)
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
res, _, _ := cmd("df", "-BG", part)
|
|
resLines := strings.Split(res, "\n")
|
|
blocksStart := strings.Index(resLines[0], "1G-blocks")
|
|
blocksEnd := blocksStart + len("1G-blocks")
|
|
blocksString := strings.TrimSpace(resLines[1][blocksStart:blocksEnd])
|
|
blocksString = strings.TrimSuffix(blocksString, "G")
|
|
blocks, _ := parseUint(blocksString)
|
|
if blocks != 100 {
|
|
t.Errorf("%v[%v:%v]\n'%v'", resLines[1], blocksStart, blocksEnd, blocksString)
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, GPT_START_BYTE, GPT_LAST_BYTE},
|
|
}
|
|
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestXfsPartitionUnmounted(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
part := disk + "p1"
|
|
sudo("mkfs.xfs", part)
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
sudo("mount", part, TMP_MOUNT_DIR)
|
|
defer sudo("umount", part)
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
sudo("umount", TMP_MOUNT_DIR)
|
|
call(part, "--do")
|
|
sudo("mount", part, TMP_MOUNT_DIR)
|
|
res, _, _ := cmd("df", "-BG", part)
|
|
resLines := strings.Split(res, "\n")
|
|
blocksStart := strings.Index(resLines[0], "1G-blocks")
|
|
blocksEnd := blocksStart + len("1G-blocks")
|
|
blocksString := strings.TrimSpace(resLines[1][blocksStart:blocksEnd])
|
|
blocksString = strings.TrimSuffix(blocksString, "G")
|
|
blocks, _ := parseUint(blocksString)
|
|
if blocks != 100 {
|
|
t.Error(resLines[1])
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, MSDOS_START_BYTE, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartitionMSDOS(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
if 100 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size")
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, 32256, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartitionGPT(t *testing.T) {
|
|
disk, err := createTmpDevice("gpt")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(GPT_START_BYTE), s(GPT_START_BYTE+GB)) // 1Gb
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
if 100 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size")
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, GPT_START_BYTE, GPT_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartitionADD_PV(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(GB-1)) // 1Gb
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(GB), s(MSDOS_LAST_BYTE)) // Free PV
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("pvcreate", disk+"p2") // create free pv
|
|
defer sudo("pvremove", disk+"p2")
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
if 100 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, 32256, GB - 1},
|
|
{2, GB, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartition_ResizePV(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
|
|
// Resize partition under PV and save old save of PV
|
|
sudo("parted", "-s", disk, "rm", "1")
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_LAST_BYTE))
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
sudo("blockdev", "--rereadpt", disk)
|
|
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
if 100 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, 32256, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartitionInMiddleDiskMSDOS(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(5*GB), s(6*GB))
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
if 100 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{2, MSDOS_START_BYTE, 5*GB - 1},
|
|
{1, 5 * GB, MSDOS_LAST_BYTE},
|
|
}
|
|
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
pretty.Println(readPartitions(disk))
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartitionInMiddleDiskGPT(t *testing.T) {
|
|
disk, err := createTmpDevice("gpt")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(5*GB), s(6*GB))
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
if 100 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{2, GPT_START_BYTE, 5*GB - 1},
|
|
{1, 5 * GB, GPT_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
pretty.Println(readPartitions(disk))
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartitionIn2MiddleDiskMSDOS(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(5*GB), s(6*GB-1))
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
// No create lvm on second partition. Partition for split free space
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(10*GB), s(11*GB-1))
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
if 99 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{3, MSDOS_START_BYTE, 5*GB - 1},
|
|
{1, 5 * GB, 10*GB - 1},
|
|
{2, 10 * GB, 11*GB - 1},
|
|
{4, 11 * GB, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
pretty.Println(readPartitions(disk))
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartitionIn2MiddleDiskGPT(t *testing.T) {
|
|
disk, err := createTmpDevice("gpt")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(5*GB), s(6*GB-1))
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
// No create lvm on second partition. Partition for split free space
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(10*GB), s(11*GB-1))
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call(TMP_MOUNT_DIR, "--do")
|
|
if 99 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{3, GPT_START_BYTE, 5*GB - 1},
|
|
{1, 5 * GB, 10*GB - 1},
|
|
{2, 10 * GB, 11*GB - 1},
|
|
{4, 11 * GB, GPT_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
pretty.Println(readPartitions(disk))
|
|
pretty.Println(needPartitions)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartitionWithoutFS(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB-1)) // 1Gb
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
call(lvmLV, "--do")
|
|
|
|
needPartitions := []testPartition{
|
|
{1, 32256, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
lvmLVSize := lvmLVGetSize(LVM_VG_NAME + "/" + LVM_LV_NAME)
|
|
PartitionSize := uint64(MSDOS_LAST_BYTE - MSDOS_START_BYTE + 1)
|
|
MinSize := PartitionSize - 100*1024*1024
|
|
if lvmLVSize < MinSize || lvmLVSize > PartitionSize {
|
|
t.Error("LVM Size:", formatSize(lvmLVSize), lvmLVSize)
|
|
}
|
|
}
|
|
|
|
func TestRecursiveHierarchy(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_LAST_BYTE))
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
// Create pv in LVM
|
|
sudo("pvcreate", lvmLV)
|
|
defer sudo("lvremove", lvmLV)
|
|
|
|
// Extend VG to PV in the VM - create recursive dependency
|
|
sudo("vgextend", LVM_VG_NAME, lvmLV)
|
|
defer sudo("vgreduce", LVM_VG_NAME, lvmLV)
|
|
|
|
resetProgramState()
|
|
_, err = extendScanWays(lvmLV)
|
|
if err == nil {
|
|
t.Error("MUST detect hierarchy recursive error")
|
|
} else {
|
|
t.Log("Recursive error OK detected as:", err)
|
|
}
|
|
}
|
|
|
|
func TestLVMPartition_LimitFilterForAlreadyPlacedOneDevice(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
disk2, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk2)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call("--filter=LVM_ALREADY_PLACED", TMP_MOUNT_DIR, "--do")
|
|
if 100 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, 32256, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
if len(readPartitions(disk2)) != 0 {
|
|
t.Error(pretty.Sprintf("%v", readPartitions(disk2)))
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartition_LimitFilterForAlreadyPlacedTwoDevices(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
disk2, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk2)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
sudo("parted", "-s", disk2, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
sudo("parted", "-s", disk2, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
part2 := disk2 + "p1"
|
|
|
|
sudo("pvcreate", part)
|
|
sudo("pvcreate", part2)
|
|
defer sudo("pvremove", part)
|
|
defer sudo("pvremove", part2)
|
|
|
|
sudo("vgcreate", LVM_VG_NAME, part, part2)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call("--filter=LVM_ALREADY_PLACED", TMP_MOUNT_DIR, "--do")
|
|
if 200 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, 32256, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
// Same layout for disk 2
|
|
partDiff = pretty.Diff(readPartitions(disk2), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartition_LimitFilterOneDeviceWhilePlacedInTwo(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
disk2, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk2)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB-1)) // 1Gb
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
sudo("parted", "-s", disk2, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB-1)) // 1Gb
|
|
sudo("parted", "-s", disk2, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
part2 := disk2 + "p1"
|
|
|
|
sudo("pvcreate", part)
|
|
sudo("pvcreate", part2)
|
|
defer sudo("pvremove", part)
|
|
defer sudo("pvremove", part2)
|
|
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("vgextend", LVM_VG_NAME, part2)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call("--filter="+disk, TMP_MOUNT_DIR, "--do") // filter for one disk only
|
|
if 101 != df(TMP_MOUNT_DIR) { // 100 from first disk + 1 from pv existed in second disk
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, MSDOS_START_BYTE, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
needPartitions2 := []testPartition{
|
|
{1, MSDOS_START_BYTE, MSDOS_START_BYTE + GB - 1},
|
|
}
|
|
partDiff = pretty.Diff(readPartitions(disk2), needPartitions2)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestLVMPartition_LVMInOneDiskFilterIsNullAndtwoDisksForExtend(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
disk2, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk2)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(MSDOS_START_BYTE+GB)) // 1Gb
|
|
sudo("parted", "-s", disk, "set", "1", "lvm", "on")
|
|
|
|
part := disk + "p1"
|
|
sudo("pvcreate", part)
|
|
defer sudo("pvremove", part)
|
|
sudo("vgcreate", LVM_VG_NAME, part)
|
|
defer sudo("vgremove", "-f", LVM_VG_NAME)
|
|
sudo("lvcreate", "-L", "500M", "-n", LVM_LV_NAME, LVM_VG_NAME)
|
|
lvmLV := filepath.Join("/dev", LVM_VG_NAME, LVM_LV_NAME)
|
|
defer sudo("lvremove", "-f", lvmLV)
|
|
|
|
sudo("mkfs.xfs", lvmLV)
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0700)
|
|
if err == nil {
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
} else {
|
|
t.Fatal(err)
|
|
}
|
|
sudo("mount", lvmLV, TMP_MOUNT_DIR)
|
|
defer sudo("umount", lvmLV)
|
|
|
|
sudo("chmod", "a+rwx", TMP_MOUNT_DIR)
|
|
err = ioutil.WriteFile(filepath.Join(TMP_MOUNT_DIR, "test"), []byte("OK"), 0666)
|
|
if err != nil {
|
|
t.Error("Can't write test file", err)
|
|
}
|
|
|
|
call("--filter=", TMP_MOUNT_DIR, "--do")
|
|
if 200 != df(TMP_MOUNT_DIR) {
|
|
t.Error("Filesystem size", df(TMP_MOUNT_DIR))
|
|
}
|
|
|
|
needPartitions := []testPartition{
|
|
{1, 32256, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
partDiff = pretty.Diff(readPartitions(disk2), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
|
|
testBytes, err := ioutil.ReadFile(filepath.Join(TMP_MOUNT_DIR, "test"))
|
|
if err != nil {
|
|
t.Error("Can't read test file", err)
|
|
}
|
|
if string(testBytes) != "OK" {
|
|
t.Error("Bad file content:", string(testBytes))
|
|
}
|
|
}
|
|
|
|
func TestIssue13_ReadExtendedPartitions(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "mkpart", "extended", "0%", "100%")
|
|
defer sudo("parted", "-s", disk, "rm", "1")
|
|
sudo("parted", "-s", disk, "mkpart", "logical", "1G", "2G")
|
|
defer sudo("parted", "-s", disk, "rm", "5")
|
|
part := disk + "p5"
|
|
sudo("mkfs.xfs", part)
|
|
|
|
// in issue failed by panic
|
|
call("--do", part)
|
|
}
|
|
|
|
// https://github.com/rekby/fsextender/issues/14
|
|
func TestIssue14_ExtractPartNumberFromLinks(t *testing.T) {
|
|
disk, err := createTmpDevice("msdos")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(MSDOS_START_BYTE), s(GB-1))
|
|
defer sudo("parted", "-s", disk, "rm", "1")
|
|
|
|
part := disk + "p1"
|
|
sudo("mkfs.xfs", disk+"p1")
|
|
sudo("xfs_admin", "-U", "78c1656c-a17f-11e5-b076-74e6e20dc9f0", part)
|
|
|
|
for i := 0; i < TRY_COUNT; i++ {
|
|
_, err = os.Stat("/dev/disk/by-uuid/78c1656c-a17f-11e5-b076-74e6e20dc9f0")
|
|
if os.IsNotExist(err) {
|
|
if i < TRY_COUNT-1 {
|
|
time.Sleep(time.Second)
|
|
}
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
if err != nil {
|
|
t.Fatal("Can't create symlink")
|
|
}
|
|
|
|
err = os.MkdirAll(TMP_MOUNT_DIR, 0600)
|
|
if err != nil {
|
|
t.Fatal("Can't create tmp mount dir")
|
|
}
|
|
defer os.Remove(TMP_MOUNT_DIR)
|
|
|
|
sudo("mount", "/dev/disk/by-uuid/78c1656c-a17f-11e5-b076-74e6e20dc9f0", TMP_MOUNT_DIR)
|
|
defer sudo("umount", TMP_MOUNT_DIR)
|
|
|
|
call("--do", TMP_MOUNT_DIR)
|
|
|
|
needPartitions := []testPartition{
|
|
{1, 32256, MSDOS_LAST_BYTE},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
}
|
|
|
|
func Test_Issue17_ExtendBlockDeviceAfterGTPCreated(t *testing.T) {
|
|
disk, err := createTmpDevice("gpt")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
if disk != "" {
|
|
deleteTmpDevice(disk)
|
|
}
|
|
}() // For get disk value when defer will be called
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(GPT_START_BYTE), s(GB-1))
|
|
defer func() {
|
|
if disk != "" {
|
|
sudo("parted", "-s", disk, "rm", "1")
|
|
}
|
|
}()
|
|
|
|
disk, err = extendTmpDevice(disk, 200*GB)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
call(disk+"p1", "--do")
|
|
|
|
needPartitions := []testPartition{
|
|
{1, GPT_START_BYTE, 200*GB - GPT_SIZE - 1},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
}
|
|
|
|
func TestIssue_18_MBR_ReadErrorBigDisk(t *testing.T) {
|
|
disk, err := createTmpDeviceSize("gpt", 8*TB)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer deleteTmpDevice(disk)
|
|
|
|
sudo("parted", "-s", disk, "unit", "b", "mkpart", "primary", s(GPT_START_BYTE), s(GB-1))
|
|
call(disk+"p1", "--do")
|
|
|
|
needPartitions := []testPartition{
|
|
{1, GPT_START_BYTE, 8*TB - GPT_SIZE - 1},
|
|
}
|
|
partDiff := pretty.Diff(readPartitions(disk), needPartitions)
|
|
if partDiff != nil {
|
|
t.Error(partDiff)
|
|
}
|
|
}
|