|
2 | 2 | import pytest
|
3 | 3 | import time
|
4 | 4 |
|
5 |
| -from .conftest import LINSTOR_PACKAGE |
| 5 | +from .conftest import GROUP_NAME, LINSTOR_PACKAGE |
6 | 6 | from lib.commands import SSHCommandFailed
|
7 | 7 | from lib.common import wait_for, vm_image
|
8 | 8 | from tests.storage import vdi_is_open
|
@@ -86,6 +86,29 @@ def test_snapshot(self, vm_on_linstor_sr):
|
86 | 86 | finally:
|
87 | 87 | vm.shutdown(verify=True)
|
88 | 88 |
|
| 89 | + @pytest.mark.small_vm |
| 90 | + def test_linstor_sr_expand_disk(self, linstor_sr, provisioning_type, storage_pool_name, |
| 91 | + pytestconfig, vm_with_reboot_check): |
| 92 | + """ |
| 93 | + This test demonstrates online expansion of a LINSTOR SR while a VM is actively running on it. |
| 94 | +
|
| 95 | + It identifies hosts within the same pool, detects free raw disks, and expands the LVM to grow the SR. |
| 96 | + A VM is started before the expansion, and its functionality is verified through a shutdown and restart |
| 97 | + after the expansion completes successfully. |
| 98 | + """ |
| 99 | + sr = linstor_sr |
| 100 | + sr_size = sr.pool.master.xe('sr-param-get', {'uuid': sr.uuid, 'param-name': 'physical-size'}) |
| 101 | + |
| 102 | + resized = _expand_lvm_on_hosts(sr, provisioning_type, storage_pool_name, pytestconfig) |
| 103 | + |
| 104 | + # Need to ensure that linstor is healthy/up-to-date before moving ahead. |
| 105 | + time.sleep(30) # Wait time for Linstor node communications to restore. |
| 106 | + sr.scan() |
| 107 | + new_sr_size = sr.pool.master.xe('sr-param-get', {'uuid': sr.uuid, 'param-name': 'physical-size'}) |
| 108 | + assert int(new_sr_size) > int(sr_size) and resized is True, \ |
| 109 | + f"Expected SR size to increase but got old size: {sr_size}, new size: {new_sr_size}" |
| 110 | + logging.info("SR expansion completed") |
| 111 | + |
89 | 112 | # *** tests with reboots (longer tests).
|
90 | 113 |
|
91 | 114 | @pytest.mark.reboot
|
@@ -133,6 +156,40 @@ def test_linstor_missing(self, linstor_sr, host):
|
133 | 156 |
|
134 | 157 | # *** End of tests with reboots
|
135 | 158 |
|
| 159 | +def _expand_lvm_on_hosts(sr, provisioning_type, storage_pool_name, pytestconfig): |
| 160 | + from lib.commands import SSHCommandFailed |
| 161 | + resized = False |
| 162 | + for h in sr.pool.hosts: |
| 163 | + logging.info(f"Checking for available disks on host: {h.hostname_or_ip}") |
| 164 | + available_disks = [d for d in h.available_disks() if h.raw_disk_is_available(d)] |
| 165 | + |
| 166 | + disks = [] |
| 167 | + expansion_sr_disk = pytestconfig.getoption("expansion_sr_disk") |
| 168 | + if expansion_sr_disk: |
| 169 | + assert len(expansion_sr_disk) == 1, "Only one --expansion-sr-disk should be provided" |
| 170 | + if expansion_sr_disk[0] == "auto": |
| 171 | + disks = available_disks |
| 172 | + else: |
| 173 | + assert expansion_sr_disk[0] in available_disks, "The specified expansion disk is unavailable" |
| 174 | + disks = expansion_sr_disk |
| 175 | + else: |
| 176 | + disks = available_disks |
| 177 | + |
| 178 | + for disk in disks: |
| 179 | + device = f"/dev/{disk}" |
| 180 | + try: |
| 181 | + h.ssh(['pvcreate', device]) |
| 182 | + h.ssh(['vgextend', GROUP_NAME, device]) |
| 183 | + if provisioning_type == "thin": |
| 184 | + h.ssh(['lvextend', '-l', '+100%FREE', storage_pool_name]) |
| 185 | + else: |
| 186 | + h.ssh(['systemctl', 'restart', 'linstor-satellite.service']) |
| 187 | + resized = True |
| 188 | + logging.info("LVM extended on host %s using device %s", h.hostname_or_ip, device) |
| 189 | + except SSHCommandFailed as e: |
| 190 | + raise RuntimeError(f"Disk expansion failed on {h.hostname_or_ip}: {e}") |
| 191 | + return resized |
| 192 | + |
136 | 193 | # --- Test diskless resources --------------------------------------------------
|
137 | 194 |
|
138 | 195 | def _get_diskful_hosts(host, controller_option, volume_name):
|
|
0 commit comments