300 lines
12 KiB
Python
Executable File
300 lines
12 KiB
Python
Executable File
#!/usr/bin/python3 -cimport os, sys; os.execv(os.path.dirname(sys.argv[1]) + "/../common/pywrap", sys.argv)
|
|
|
|
# This file is part of Cockpit.
|
|
#
|
|
# Copyright (C) 2015 Red Hat, Inc.
|
|
#
|
|
# Cockpit is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU Lesser General Public License as published by
|
|
# the Free Software Foundation; either version 2.1 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Cockpit is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import unittest
|
|
|
|
from storagelib import StorageCase
|
|
from testlib import skipImage, test_main
|
|
|
|
|
|
class TestStorageResize(StorageCase):
|
|
|
|
# LUKS uses memory hard PBKDF, 1 GiB is not enough; see https://bugzilla.redhat.com/show_bug.cgi?id=1881829
|
|
provision = {
|
|
"0": {"memory_mb": 1536}
|
|
}
|
|
|
|
def checkResize(self, fsys, crypto, can_shrink, can_grow, shrink_needs_unmount=None, grow_needs_unmount=None):
|
|
m = self.machine
|
|
b = self.browser
|
|
|
|
fsys_row = 1
|
|
fsys_tab = 2
|
|
|
|
need_passphrase = crypto and self.default_crypto_type == "luks2"
|
|
|
|
self.login_and_go("/storage")
|
|
m.add_disk("500M", serial="DISK1")
|
|
b.wait_in_text("#drives", "DISK1")
|
|
|
|
m.execute("vgcreate TEST /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_DISK1")
|
|
m.execute("lvcreate TEST -n vol -L 320m") # minimum xfs size is ~300MB
|
|
b.wait_in_text("#devices", "TEST")
|
|
b.click('#devices .sidepanel-row:contains("TEST")')
|
|
b.wait_visible("#storage-detail")
|
|
self.content_row_wait_in_col(1, 1, "vol")
|
|
|
|
self.content_row_action(1, "Format")
|
|
self.dialog_wait_open()
|
|
self.dialog_wait_apply_enabled()
|
|
self.dialog_set_val("name", "FSYS")
|
|
self.dialog_set_val("type", fsys)
|
|
self.dialog_set_val("mount_point", "/run/foo")
|
|
if crypto:
|
|
self.dialog_set_val("crypto", self.default_crypto_type)
|
|
self.dialog_set_val("passphrase", "vainu-reku-toma-rolle-kaja")
|
|
self.dialog_set_val("passphrase2", "vainu-reku-toma-rolle-kaja")
|
|
self.dialog_apply()
|
|
self.dialog_wait_close()
|
|
self.content_tab_wait_in_info(fsys_row, fsys_tab, "Name", "FSYS")
|
|
self.content_tab_wait_in_info(fsys_row, fsys_tab, "Mount point", "/run/foo")
|
|
|
|
if can_grow:
|
|
self.content_tab_action(1, 1, "Grow")
|
|
self.dialog_wait_open()
|
|
self.dialog_wait_apply_enabled()
|
|
if grow_needs_unmount:
|
|
b.wait_in_text("#dialog", "unmount, grow")
|
|
self.dialog_set_val("size", 400)
|
|
if need_passphrase:
|
|
self.dialog_set_val("passphrase", "vainu-reku-toma-rolle-kaja")
|
|
self.dialog_apply()
|
|
self.dialog_wait_close()
|
|
self.content_tab_wait_in_info(1, 1, "Size", "398 MB")
|
|
if grow_needs_unmount:
|
|
self.content_row_action(fsys_row, "Mount")
|
|
self.confirm()
|
|
with b.wait_timeout(30):
|
|
self.wait_mounted(fsys_row, fsys_tab)
|
|
size = int(m.execute("df -k --output=size /run/foo | tail -1").strip())
|
|
self.assertGreater(size, 300000)
|
|
else:
|
|
self.wait_content_tab_action_disabled(1, 1, "Grow")
|
|
|
|
if can_shrink:
|
|
self.content_tab_action(1, 1, "Shrink")
|
|
self.dialog_wait_open()
|
|
self.dialog_wait_apply_enabled()
|
|
if shrink_needs_unmount:
|
|
b.wait_in_text("#dialog", "unmount, shrink")
|
|
self.dialog_set_val("size", 200)
|
|
if need_passphrase:
|
|
self.dialog_set_val("passphrase", "vainu-reku-toma-rolle-kaja")
|
|
self.dialog_apply()
|
|
self.dialog_wait_close()
|
|
self.content_tab_wait_in_info(1, 1, "Size", "201 MB")
|
|
if shrink_needs_unmount:
|
|
self.content_row_action(fsys_row, "Mount")
|
|
self.confirm()
|
|
self.wait_mounted(fsys_row, fsys_tab)
|
|
size = int(m.execute("df -k --output=size /run/foo | tail -1").strip())
|
|
self.assertLess(size, 300000)
|
|
else:
|
|
self.wait_content_tab_action_disabled(1, 1, "Shrink")
|
|
|
|
def testResizeExt4(self):
|
|
self.checkResize("ext4", False,
|
|
can_shrink=True, shrink_needs_unmount=True,
|
|
can_grow=True, grow_needs_unmount=False)
|
|
|
|
def testResizeXfs(self):
|
|
self.checkResize("xfs", False,
|
|
can_shrink=False,
|
|
can_grow=True, grow_needs_unmount=False)
|
|
|
|
@skipImage("NTFS not supported on RHEL", "rhel-*", "centos-*")
|
|
def testResizeNtfs(self):
|
|
self.checkResize("ntfs", False,
|
|
can_shrink=True, shrink_needs_unmount=True,
|
|
can_grow=True, grow_needs_unmount=True)
|
|
|
|
@skipImage("TODO: arch does not mount the LUKS partition after growing", "arch")
|
|
def testResizeLuks(self):
|
|
self.checkResize("ext4", True,
|
|
can_shrink=True, shrink_needs_unmount=True,
|
|
can_grow=True, grow_needs_unmount=False)
|
|
|
|
def shrink_extfs(self, fs_dev, size):
|
|
# fsadm can automatically unmount and check the fs when doing
|
|
# a resize, but in that case it will try to remount it
|
|
# afterwards. This remounting will mostly fail because
|
|
# UDisks2 has removed the mount point directory in the mean
|
|
# time. But sometimes it will succeed. So we take control
|
|
# and unmount the fs explicitly. But then we also need to
|
|
# check it explicitly.
|
|
#
|
|
self.machine.execute(f"(! findmnt -S '{fs_dev}' || umount '{fs_dev}') && fsadm -y check '{fs_dev}' && fsadm -y resize '{fs_dev}' '{size}'")
|
|
|
|
def testGrowShrinkHelp(self):
|
|
m = self.machine
|
|
b = self.browser
|
|
|
|
if self.storaged_version < [2, 7, 6]:
|
|
# No Filesystem.Size property
|
|
raise unittest.SkipTest("UDisks2 too old")
|
|
|
|
self.login_and_go("/storage")
|
|
m.add_disk("500M", serial="DISK1")
|
|
b.wait_in_text("#drives", "DISK1")
|
|
|
|
m.execute("vgcreate TEST /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_DISK1")
|
|
m.execute("lvcreate TEST -n vol -L 200m")
|
|
b.wait_in_text("#devices", "TEST")
|
|
b.click('#devices .sidepanel-row:contains("TEST")')
|
|
b.wait_visible("#storage-detail")
|
|
self.content_row_wait_in_col(1, 1, "vol")
|
|
|
|
mountpoint = "/run/foo"
|
|
self.content_row_action(1, "Format")
|
|
self.dialog_wait_open()
|
|
self.dialog_set_val("name", "FSYS")
|
|
self.dialog_set_val("type", "ext4")
|
|
self.dialog_set_val("mount_point", mountpoint)
|
|
self.dialog_apply()
|
|
self.dialog_wait_close()
|
|
self.content_tab_wait_in_info(1, 2, "Name", "FSYS")
|
|
self.content_tab_wait_in_info(1, 2, "Mount point", mountpoint)
|
|
|
|
vol_tab = self.content_tab_expand(1, 1)
|
|
|
|
# Grow the logical volume and let Cockpit grow the filesystem
|
|
|
|
m.execute("lvresize TEST/vol -L+100M")
|
|
b.wait_visible(vol_tab + " button:contains(Grow content)")
|
|
self.content_tab_action(1, 1, "Grow content")
|
|
b.wait_not_present(vol_tab + " button:contains(Grow content)")
|
|
size = int(m.execute(f"df -k --output=size {mountpoint} | tail -1").strip())
|
|
self.assertGreater(size, 250000)
|
|
|
|
# Shrink the filesystem and let Cockpit shrink the logical volume
|
|
|
|
fs_dev = m.execute("lsblk -pnl /dev/TEST/vol -o NAME | tail -1").strip()
|
|
self.shrink_extfs(fs_dev, "200M")
|
|
|
|
self.content_row_action(1, "Mount")
|
|
self.confirm()
|
|
self.wait_mounted(1, 2)
|
|
self.content_tab_action(1, 1, "Shrink volume")
|
|
b.wait_not_present(vol_tab + " button:contains(Shrink volume)")
|
|
size = int(m.execute("lvs TEST/vol -o lv_size --noheading --units b --nosuffix"))
|
|
self.assertLess(size, 250000000)
|
|
|
|
def testGrowShrinkEncryptedHelp(self):
|
|
m = self.machine
|
|
b = self.browser
|
|
|
|
if self.storaged_version < [2, 8, 0]:
|
|
# No Encrypted.MetadataSize property
|
|
raise unittest.SkipTest("UDisks2 too old")
|
|
|
|
self.login_and_go("/storage")
|
|
m.add_disk("500M", serial="DISK1")
|
|
b.wait_in_text("#drives", "DISK1")
|
|
|
|
m.execute("vgcreate TEST /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_DISK1")
|
|
m.execute("lvcreate TEST -n vol -L 200m")
|
|
b.wait_in_text("#devices", "TEST")
|
|
b.click('#devices .sidepanel-row:contains("TEST")')
|
|
b.wait_visible("#storage-detail")
|
|
self.content_row_wait_in_col(1, 1, "vol")
|
|
|
|
mountpoint = "/run/foo"
|
|
self.content_row_action(1, "Format")
|
|
self.dialog_wait_open()
|
|
self.dialog_set_val("name", "FSYS")
|
|
self.dialog_set_val("type", "ext4")
|
|
self.dialog_set_val("crypto", self.default_crypto_type)
|
|
self.dialog_set_val("passphrase", "vainu-reku-toma-rolle-kaja")
|
|
self.dialog_set_val("passphrase2", "vainu-reku-toma-rolle-kaja")
|
|
self.dialog_set_val("mount_point", mountpoint)
|
|
self.dialog_apply()
|
|
self.dialog_wait_close()
|
|
self.content_tab_wait_in_info(1, 2, "Name", "FSYS")
|
|
self.content_tab_wait_in_info(1, 2, "Mount point", mountpoint)
|
|
|
|
vol_tab = self.content_tab_expand(1, 1)
|
|
|
|
# Grow the logical volume and let Cockpit grow the LUKS container and the filesystem
|
|
|
|
m.execute("lvresize TEST/vol -L+100M")
|
|
|
|
def confirm_with_passphrase():
|
|
if self.default_crypto_type == "luks1":
|
|
return
|
|
self.dialog_wait_open()
|
|
self.dialog_wait_apply_enabled()
|
|
self.dialog_set_val("passphrase", "vainu-reku-toma-rolle-kaja")
|
|
self.dialog_apply()
|
|
self.dialog_wait_close()
|
|
|
|
b.wait_visible(vol_tab + " button:contains(Grow content)")
|
|
self.content_tab_action(1, 1, "Grow content")
|
|
confirm_with_passphrase()
|
|
b.wait_not_present(vol_tab + " button:contains(Grow content)")
|
|
size = int(m.execute(f"df -k --output=size {mountpoint} | tail -1").strip())
|
|
self.assertGreater(size, 250000)
|
|
|
|
# Shrink the filesystem and let Cockpit shrink the LUKS container and logical volume
|
|
|
|
fs_dev = m.execute("lsblk -pnl /dev/TEST/vol -o NAME | tail -1").strip()
|
|
self.shrink_extfs(fs_dev, "200M")
|
|
self.content_row_action(1, "Mount")
|
|
self.confirm()
|
|
self.wait_mounted(1, 2)
|
|
|
|
vol_tab = self.content_tab_expand(1, 1)
|
|
b.wait_visible(vol_tab + " button:contains(Shrink volume)")
|
|
self.content_tab_action(1, 1, "Shrink volume")
|
|
confirm_with_passphrase()
|
|
b.wait_not_present(vol_tab + " button:contains(Shrink volume)")
|
|
size = int(m.execute("lvs TEST/vol -o lv_size --noheading --units b --nosuffix"))
|
|
self.assertLess(size, 250000000)
|
|
|
|
# Grow the logical volume and the LUKS container and let Cockpit grow the filesystem
|
|
|
|
m.execute("lvresize TEST/vol -L+100M")
|
|
m.execute(f"echo vainu-reku-toma-rolle-kaja | cryptsetup resize {fs_dev}")
|
|
|
|
b.wait_visible(vol_tab + " button:contains(Grow content)")
|
|
self.content_tab_action(1, 1, "Grow content")
|
|
confirm_with_passphrase()
|
|
b.wait_not_present(vol_tab + " button:contains(Grow content)")
|
|
size = int(m.execute(f"df -k --output=size {mountpoint} | tail -1").strip())
|
|
self.assertGreater(size, 250000)
|
|
|
|
# Shrink the filesystem and the LUKS container and let Cockpit shrink the logical volume
|
|
|
|
self.shrink_extfs(fs_dev, "198M")
|
|
m.execute(f"echo vainu-reku-toma-rolle-kaja | cryptsetup resize '{fs_dev}' 200M")
|
|
self.content_row_action(1, "Mount")
|
|
self.confirm()
|
|
self.wait_mounted(1, 2)
|
|
|
|
vol_tab = self.content_tab_expand(1, 1)
|
|
b.wait_visible(vol_tab + " button:contains(Shrink volume)")
|
|
self.content_tab_action(1, 1, "Shrink volume")
|
|
confirm_with_passphrase()
|
|
b.wait_not_present(vol_tab + " button:contains(Shrink volume)")
|
|
size = int(m.execute("lvs TEST/vol -o lv_size --noheading --units b --nosuffix"))
|
|
self.assertLess(size, 250000000)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
test_main()
|