mounts: accept more mount options
Before we could only ask OSBuild to mount a device as readonly. But devices can have more mount options than this. Supporting more options is necessary for the new version of image-info that is using OSBuild's internals in order to mount the image it wants to work on. Otherwise, for instance, some umasks aren't applied properly and we can get differences in rpm-verify results, thus corrupting the DB. Mount is now accepting: * readonly * uid * gid * umask * shortname
This commit is contained in:
parent
c0fb5cf90c
commit
8f08433804
3 changed files with 122 additions and 46 deletions
|
|
@ -46,14 +46,11 @@ def make_dev_tmpfs(tmpdir):
|
|||
subprocess.run(["umount", "--lazy", dev_path], check=True)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not TestBase.can_bind_mount(), reason="root only")
|
||||
def test_mount_ro(tmpdir):
|
||||
index = meta.Index(os.curdir)
|
||||
|
||||
def create_image(tmpdir):
|
||||
# create a file to contain an image
|
||||
tree = os.path.join(tmpdir, "tree")
|
||||
os.makedirs(tree)
|
||||
size = 1024 * 1024
|
||||
size = 2 * 1024 * 1024
|
||||
file = os.path.join(tree, "image.img")
|
||||
with open(file, "wb") as f:
|
||||
f.truncate(size)
|
||||
|
|
@ -67,56 +64,106 @@ def test_mount_ro(tmpdir):
|
|||
},
|
||||
"options": {
|
||||
"label": "TEST",
|
||||
"uuid": "FEEDFACE-CAFE-4004-FEED-C0DEC0FFEE11"
|
||||
"volid": "7B7795E7",
|
||||
"fat-size": 32
|
||||
}
|
||||
}
|
||||
|
||||
with make_arguments(mkfsopts):
|
||||
subprocess.run(
|
||||
[os.path.join(os.curdir, "stages", "org.osbuild.mkfs.ext4")],
|
||||
[os.path.join(os.curdir, "stages", "org.osbuild.mkfs.fat")],
|
||||
check=True,
|
||||
stdout=sys.stdout,
|
||||
stderr=sys.stderr)
|
||||
return tree, size
|
||||
|
||||
with tempfile.TemporaryDirectory() as mountpoint:
|
||||
|
||||
def mount(mgr, devpath, tree, size, mountpoint, options):
|
||||
index = meta.Index(os.curdir)
|
||||
# Device manager to open the loopback device
|
||||
devmgr = devices.DeviceManager(mgr, devpath, tree)
|
||||
# get a Device for the loopback
|
||||
dev = devices.Device(
|
||||
"loop",
|
||||
index.get_module_info(
|
||||
"Device",
|
||||
"org.osbuild.loopback"
|
||||
),
|
||||
None,
|
||||
{
|
||||
"filename": "image.img",
|
||||
"start": 0,
|
||||
"size": size // 512 # size is in sectors / blocks
|
||||
}
|
||||
)
|
||||
# open the device and get its loopback path
|
||||
lpath = os.path.join(
|
||||
devpath,
|
||||
devmgr.open(dev)["path"]
|
||||
)
|
||||
# mount the loopback
|
||||
mounts.MountManager(
|
||||
devmgr,
|
||||
mountpoint
|
||||
).mount(
|
||||
mounts.Mount(
|
||||
lpath,
|
||||
index.get_module_info("Mount", "org.osbuild.fat"),
|
||||
dev,
|
||||
"/",
|
||||
options
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skipif(not TestBase.can_bind_mount(), reason="root only")
|
||||
def test_without_options(tmpdir):
|
||||
tree, size = create_image(tmpdir)
|
||||
options = {}
|
||||
|
||||
with tempfile.TemporaryDirectory(dir=tmpdir) as mountpoint:
|
||||
with host.ServiceManager() as mgr:
|
||||
with make_dev_tmpfs(tmpdir) as devpath:
|
||||
# Device manager to open the loopback device
|
||||
devmgr = devices.DeviceManager(mgr, devpath, tree)
|
||||
# get a Device for the loopback
|
||||
dev = devices.Device(
|
||||
"loop",
|
||||
index.get_module_info(
|
||||
"Device",
|
||||
"org.osbuild.loopback"
|
||||
),
|
||||
None,
|
||||
{
|
||||
"filename": "image.img",
|
||||
"start": 0,
|
||||
"size": size // 512 # size is in sectors / blocks
|
||||
}
|
||||
)
|
||||
# open the device and get its loopback path
|
||||
lpath = os.path.join(
|
||||
devpath,
|
||||
devmgr.open(dev)["path"]
|
||||
)
|
||||
# mount the loopback
|
||||
mounts.MountManager(
|
||||
devmgr,
|
||||
mountpoint
|
||||
).mount(
|
||||
mounts.Mount(
|
||||
lpath,
|
||||
index.get_module_info("Mount", "org.osbuild.ext4"),
|
||||
dev,
|
||||
"/",
|
||||
{"readonly": True}
|
||||
)
|
||||
)
|
||||
mount(mgr, devpath, tree, size, mountpoint, options)
|
||||
with open(os.path.join(mountpoint, "test"), "w", encoding="utf-8") as f:
|
||||
f.write("should work")
|
||||
os.remove(os.path.join(mountpoint, "test"))
|
||||
|
||||
# try to write in it, and failure to do so is a success
|
||||
|
||||
@pytest.mark.skipif(not TestBase.can_bind_mount(), reason="root only")
|
||||
def test_all_options(tmpdir):
|
||||
tree, size = create_image(tmpdir)
|
||||
options = {
|
||||
"readonly": True,
|
||||
"uid": 0,
|
||||
"gid": 0,
|
||||
"umask": "077",
|
||||
"shortname": "winnt"
|
||||
}
|
||||
print(options)
|
||||
|
||||
with tempfile.TemporaryDirectory(dir=tmpdir) as mountpoint:
|
||||
with host.ServiceManager() as mgr:
|
||||
with make_dev_tmpfs(tmpdir) as devpath:
|
||||
mount(mgr, devpath, tree, size, mountpoint, options)
|
||||
|
||||
# Check FS is read only
|
||||
with pytest.raises(OSError) as err:
|
||||
with open(os.path.join(mountpoint, "test"), "w", encoding="utf-8") as f:
|
||||
f.write("should not work")
|
||||
assert err.value.errno == errno.EROFS # Check that FS is read only
|
||||
assert err.value.errno == errno.EROFS
|
||||
|
||||
# Check the other options
|
||||
st = os.lstat(mountpoint)
|
||||
assert st.st_mode == 0o040700
|
||||
assert st.st_uid == 0
|
||||
assert st.st_gid == 0
|
||||
|
||||
shortname_tested = False
|
||||
proc = subprocess.run("mount", capture_output=True, check=True)
|
||||
for line in proc.stdout.splitlines():
|
||||
strline = line.decode("utf-8")
|
||||
if mountpoint in strline:
|
||||
assert "winnt" in strline
|
||||
shortname_tested = True
|
||||
assert shortname_tested
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue