Add tests for partitioned disk images
The setup for this is a bit complex, so it really ends up testing things twice.
This commit is contained in:
parent
d69f01d4a8
commit
fb4e6f2588
@ -14,6 +14,7 @@ RUN dnf -y install \
|
|||||||
python3-nose \
|
python3-nose \
|
||||||
python3-pocketlint \
|
python3-pocketlint \
|
||||||
python3-pylint \
|
python3-pylint \
|
||||||
|
python3-pyparted \
|
||||||
python3-pytoml \
|
python3-pytoml \
|
||||||
python3-semantic_version \
|
python3-semantic_version \
|
||||||
python3-sphinx \
|
python3-sphinx \
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import glob
|
||||||
import os
|
import os
|
||||||
|
import parted
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
@ -23,6 +25,7 @@ from pylorax.executils import runcmd
|
|||||||
from pylorax.imgutils import mkcpio, mktar, mksquashfs, mksparse, mkqcow2, loop_attach, loop_detach
|
from pylorax.imgutils import mkcpio, mktar, mksquashfs, mksparse, mkqcow2, loop_attach, loop_detach
|
||||||
from pylorax.imgutils import get_loop_name, LoopDev, dm_attach, dm_detach, DMDev, Mount
|
from pylorax.imgutils import get_loop_name, LoopDev, dm_attach, dm_detach, DMDev, Mount
|
||||||
from pylorax.imgutils import mkdosimg, mkext4img, mkbtrfsimg, mkhfsimg, default_image_name
|
from pylorax.imgutils import mkdosimg, mkext4img, mkbtrfsimg, mkhfsimg, default_image_name
|
||||||
|
from pylorax.imgutils import mount, umount, kpartx_disk_img, PartitionMount, mkfsimage_from_disk
|
||||||
from pylorax.sysutils import joinpaths
|
from pylorax.sysutils import joinpaths
|
||||||
|
|
||||||
def mkfakerootdir(rootdir):
|
def mkfakerootdir(rootdir):
|
||||||
@ -42,6 +45,76 @@ def mkfakerootdir(rootdir):
|
|||||||
os.makedirs(joinpaths(rootdir, os.path.dirname(f)))
|
os.makedirs(joinpaths(rootdir, os.path.dirname(f)))
|
||||||
open(joinpaths(rootdir, f), "w").write("I AM FAKE FILE %s" % f.upper())
|
open(joinpaths(rootdir, f), "w").write("I AM FAKE FILE %s" % f.upper())
|
||||||
|
|
||||||
|
def mkfakebootdir(bootdir):
|
||||||
|
"""Populate a fake /boot directory with a kernel and initrd
|
||||||
|
|
||||||
|
:param bootdir: An existing directory to create files/dirs under
|
||||||
|
:type bootdir: str
|
||||||
|
"""
|
||||||
|
open(joinpaths(bootdir, "vmlinuz-4.18.13-200.fc28.x86_64"), "w").write("I AM A FAKE KERNEL")
|
||||||
|
open(joinpaths(bootdir, "initramfs-4.18.13-200.fc28.x86_64.img"), "w").write("I AM A FAKE INITRD")
|
||||||
|
|
||||||
|
def mkfakediskimg(disk_img):
|
||||||
|
"""Create a fake partitioned disk image
|
||||||
|
|
||||||
|
:param disk_img: Full path to a partitioned disk image
|
||||||
|
:type disk_img: str
|
||||||
|
:returns: True if it was successful, False if something went wrong
|
||||||
|
|
||||||
|
Include /boot, swap, and / partitions with fake kernel and /etc/passwd
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
mksparse(disk_img, 42 * 1024**2)
|
||||||
|
# Make a /boot, / and swap partitions on it
|
||||||
|
dev = parted.getDevice(disk_img)
|
||||||
|
disk = parted.freshDisk(dev, "gpt")
|
||||||
|
|
||||||
|
# (start, length, flags, name)
|
||||||
|
for start, length, flags, name in [
|
||||||
|
( 1024**2, 1024**2, None, "boot"),
|
||||||
|
(2*1024**2, 2*1024**2, parted.PARTITION_SWAP, "swap"),
|
||||||
|
(4*1024**2, 38*1024**2, None, "root")]:
|
||||||
|
geo = parted.Geometry(device=dev, start=start//dev.sectorSize, length=length//dev.sectorSize)
|
||||||
|
part = parted.Partition(disk=disk, type=parted.PARTITION_NORMAL, geometry=geo)
|
||||||
|
part.getPedPartition().set_name(name)
|
||||||
|
disk.addPartition(partition=part)
|
||||||
|
if flags:
|
||||||
|
part.setFlag(flags)
|
||||||
|
disk.commit()
|
||||||
|
os.sync()
|
||||||
|
except parted.PartedException:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Mount the disk's partitions
|
||||||
|
loop_devs = kpartx_disk_img(disk_img)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Format the partitions
|
||||||
|
runcmd(["mkfs.ext4", "/dev/mapper/" + loop_devs[0][0]])
|
||||||
|
runcmd(["mkswap", "/dev/mapper/" + loop_devs[1][0]])
|
||||||
|
runcmd(["mkfs.ext4", "/dev/mapper/" + loop_devs[2][0]])
|
||||||
|
|
||||||
|
# Mount the boot partition and make a fake kernel and initrd
|
||||||
|
boot_mnt = mount("/dev/mapper/" + loop_devs[0][0])
|
||||||
|
try:
|
||||||
|
mkfakebootdir(boot_mnt)
|
||||||
|
finally:
|
||||||
|
umount(boot_mnt)
|
||||||
|
|
||||||
|
# Mount the / partition and make a fake / filesystem with /etc/passwd
|
||||||
|
root_mnt = mount("/dev/mapper/" + loop_devs[2][0])
|
||||||
|
try:
|
||||||
|
mkfakerootdir(root_mnt)
|
||||||
|
finally:
|
||||||
|
umount(root_mnt)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
# Remove the disk's mounted partitions
|
||||||
|
runcmd(["kpartx", "-d", "-s", disk_img])
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
class ImgUtilsTest(unittest.TestCase):
|
class ImgUtilsTest(unittest.TestCase):
|
||||||
def mkcpio_test(self):
|
def mkcpio_test(self):
|
||||||
"""Test mkcpio function"""
|
"""Test mkcpio function"""
|
||||||
@ -179,7 +252,8 @@ class ImgUtilsTest(unittest.TestCase):
|
|||||||
with tempfile.TemporaryDirectory(prefix="lorax.test.") as work_dir:
|
with tempfile.TemporaryDirectory(prefix="lorax.test.") as work_dir:
|
||||||
with tempfile.NamedTemporaryFile(prefix="lorax.test.disk.") as disk_img:
|
with tempfile.NamedTemporaryFile(prefix="lorax.test.disk.") as disk_img:
|
||||||
mkfakerootdir(work_dir)
|
mkfakerootdir(work_dir)
|
||||||
mkext4img(work_dir, disk_img.name)
|
graft = {"/etc/yum.repos.d/": "./tests/pylorax/repos/single.repo"}
|
||||||
|
mkext4img(work_dir, disk_img.name, graft=graft)
|
||||||
self.assertTrue(os.path.exists(disk_img.name))
|
self.assertTrue(os.path.exists(disk_img.name))
|
||||||
file_details = get_file_magic(disk_img.name)
|
file_details = get_file_magic(disk_img.name)
|
||||||
self.assertTrue("ext2 filesystem" in file_details, file_details)
|
self.assertTrue("ext2 filesystem" in file_details, file_details)
|
||||||
@ -212,3 +286,42 @@ class ImgUtilsTest(unittest.TestCase):
|
|||||||
filename = default_image_name(compression, "foobar")
|
filename = default_image_name(compression, "foobar")
|
||||||
self.assertTrue(filename.endswith(suffix))
|
self.assertTrue(filename.endswith(suffix))
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.geteuid() == 0 and not os.path.exists("/.in-container"), "requires root privileges, and no containers")
|
||||||
|
def partition_mount_test(self):
|
||||||
|
"""Test PartitionMount context manager (requires loop)"""
|
||||||
|
with tempfile.NamedTemporaryFile(prefix="lorax.test.disk.") as disk_img:
|
||||||
|
self.assertTrue(mkfakediskimg(disk_img.name))
|
||||||
|
# Make sure it can mount the / with /etc/passwd
|
||||||
|
with PartitionMount(disk_img.name) as img_mount:
|
||||||
|
self.assertTrue(img_mount is not None)
|
||||||
|
self.assertTrue(os.path.isdir(img_mount.mount_dir))
|
||||||
|
self.assertTrue(os.path.exists(joinpaths(img_mount.mount_dir, "/etc/passwd")))
|
||||||
|
|
||||||
|
# Make sure submount works
|
||||||
|
with PartitionMount(disk_img.name, submount="/a-sub-mount/") as img_mount:
|
||||||
|
self.assertTrue(img_mount is not None)
|
||||||
|
self.assertTrue(os.path.isdir(img_mount.mount_dir))
|
||||||
|
self.assertTrue(os.path.exists(joinpaths(img_mount.mount_dir, "/etc/passwd")))
|
||||||
|
|
||||||
|
# Make sure it can mount the /boot partition with a custom mount_ok function
|
||||||
|
def mount_ok(mount_dir):
|
||||||
|
kernels = glob.glob(joinpaths(mount_dir, "vmlinuz-*"))
|
||||||
|
return len(kernels) > 0
|
||||||
|
|
||||||
|
with PartitionMount(disk_img.name, mount_ok=mount_ok) as img_mount:
|
||||||
|
self.assertTrue(img_mount is not None)
|
||||||
|
self.assertTrue(os.path.isdir(img_mount.mount_dir))
|
||||||
|
self.assertFalse(os.path.exists(joinpaths(img_mount.mount_dir, "/etc/passwd")))
|
||||||
|
self.assertTrue(os.path.exists(joinpaths(img_mount.mount_dir, "vmlinuz-4.18.13-200.fc28.x86_64")))
|
||||||
|
self.assertTrue(os.path.exists(joinpaths(img_mount.mount_dir, "initramfs-4.18.13-200.fc28.x86_64.img")))
|
||||||
|
|
||||||
|
@unittest.skipUnless(os.geteuid() == 0 and not os.path.exists("/.in-container"), "requires root privileges, and no containers")
|
||||||
|
def mkfsimage_from_disk_test(self):
|
||||||
|
"""Test creating a fsimage from the / partition of a disk image"""
|
||||||
|
with tempfile.NamedTemporaryFile(prefix="lorax.test.disk.") as disk_img:
|
||||||
|
self.assertTrue(mkfakediskimg(disk_img.name))
|
||||||
|
with tempfile.NamedTemporaryFile(prefix="lorax.test.disk.") as fs_img:
|
||||||
|
mkfsimage_from_disk(disk_img.name, fs_img.name)
|
||||||
|
self.assertTrue(os.path.exists(fs_img.name))
|
||||||
|
file_details = get_file_magic(fs_img.name)
|
||||||
|
self.assertTrue("ext2 filesystem" in file_details, file_details)
|
||||||
|
Loading…
Reference in New Issue
Block a user