diff --git a/lib/vm.py b/lib/vm.py index c334500ba..69fd6135c 100644 --- a/lib/vm.py +++ b/lib/vm.py @@ -4,6 +4,7 @@ import logging import os +import re import subprocess import tempfile import uuid @@ -12,6 +13,7 @@ import lib.efi as efi from lib.basevm import BaseVM from lib.common import ( + KiB, PackageManagerEnum, expand_scope_relative_nodeid, parse_xe_dict, @@ -27,7 +29,7 @@ from lib.vdi import VDI from lib.vif import VIF -from typing import TYPE_CHECKING, Iterable, List, Literal, overload +from typing import TYPE_CHECKING, Iterable, List, Literal, assert_never, overload if TYPE_CHECKING: from lib.host import Host @@ -523,6 +525,36 @@ def detect_package_manager(self) -> PackageManagerEnum: return PackageManagerEnum.ZYPPER return PackageManagerEnum.UNKNOWN + def grow_root_partition(self) -> int | None: + pkg_manager = self.detect_package_manager() + match pkg_manager: + case PackageManagerEnum.APK: + self.ssh('apk add util-linux e2fsprogs-extra') + case PackageManagerEnum.APT_GET: + self.ssh('apt-get update && apt-get install -y -qq util-linux e2fsprogs') + case PackageManagerEnum.DNF: + self.ssh('dnf install -y util-linux e2fsprogs') + case PackageManagerEnum.YUM: + self.ssh('yum install -y util-linux e2fsprogs') + case PackageManagerEnum.ZYPPER: + self.ssh('zypper --non-interactive install util-linux e2fsprogs') + case PackageManagerEnum.UNKNOWN: + return None + case _: + assert_never(pkg_manager) + mount_output = self.ssh('mount').strip() + root_match = re.search(r'/dev/(\w+?)(p?)(\d+) on / type (\w+)', mount_output) + assert root_match is not None + disk, p, partition, fs_type = root_match.groups() + if not fs_type.startswith('ext'): + logging.debug(f"Unsupported filesystem: {fs_type}") + return None + self.ssh(f'echo ", +" | sfdisk --no-reread --force -N {partition} /dev/{disk}') + self.ssh(f'partx -u -n {partition}:{partition} /dev/{disk}') + self.ssh(f'resize2fs /dev/{disk}{p}{partition}') + df_output = self.ssh('df /') + return int(df_output.splitlines()[-1].split()[3]) * KiB + def insert_cd(self, vdi_name: str) -> None: logging.info("Insert CD %r in VM %s", vdi_name, self.uuid) self.host.xe('vm-cd-insert', {'uuid': self.uuid, 'cd-name': vdi_name}) diff --git a/tests/storage/storage.py b/tests/storage/storage.py index bddd157f4..8d07acd8f 100644 --- a/tests/storage/storage.py +++ b/tests/storage/storage.py @@ -250,17 +250,9 @@ def xva_export_import(source_vm: VM, compression: XVACompression, temp_large_dir vm.wait_for_vm_running_and_ssh_up() install_randstream(vm) - if vm.detect_package_manager() == PackageManagerEnum.APK: - # growpart is not available in alpine 3.12 - # vm.ssh('apk add cloud-utils-growpart e2fsprogs-extra') - vm.ssh('apk add gawk util-linux e2fsprogs-extra') - vm.ssh('wget https://raw.githubusercontent.com/canonical/cloud-utils/main/bin/growpart -O /usr/bin/growpart') - vm.ssh('chmod +x /usr/bin/growpart') - # TODO: maybe use `findmnt -no SOURCE /` from util-linux to get the blockdevice mounted on / - growpart_returncode = vm.ssh_with_result('growpart /dev/xvda 3').returncode - assert growpart_returncode in [0, 1] # growpart returns 1 if the size is already the expected one - vm.ssh('resize2fs /dev/xvda3') - stream_size = min(volume_size // 2, config.write_volume_cap) + root_partition_size = vm.grow_root_partition() + if root_partition_size is not None: + stream_size = min(root_partition_size // 2, config.write_volume_cap) else: stream_size = 500 * MiB