diff --git a/tests/storage/linstor/conftest.py b/tests/storage/linstor/conftest.py index f898e9c2e..db26e7a6a 100644 --- a/tests/storage/linstor/conftest.py +++ b/tests/storage/linstor/conftest.py @@ -113,9 +113,10 @@ def pool_with_linstor( hostA2: Host, lvm_disks: None, pool_with_saved_yum_state: Pool, - _linstor_config: LinstorConfig + _linstor_config: LinstorConfig, ) -> Generator[Pool, None, None]: import concurrent.futures + pool = pool_with_saved_yum_state def ensure_linstor_not_installed(host: Host) -> None: diff --git a/tests/storage/linstor/test_linstor_sr.py b/tests/storage/linstor/test_linstor_sr.py index 454d65d85..f7c68c56f 100644 --- a/tests/storage/linstor/test_linstor_sr.py +++ b/tests/storage/linstor/test_linstor_sr.py @@ -1,8 +1,10 @@ import pytest +import concurrent.futures import json import logging import shlex +import threading import time from lib.commands import SSHCommandFailed @@ -251,6 +253,54 @@ def test_linstor_missing(self, linstor_sr: SR, host: Host) -> None: if not linstor_installed: host.yum_install([LINSTOR_PACKAGE]) + @pytest.mark.reboot + @pytest.mark.small_vm + def test_linstor_sr_pool_update(self, linstor_sr: SR, vm_on_linstor_sr: VM) -> None: + """ + Perform update on the Linstor SR pool hosts while ensuring VM availability. + 1. Identify all hosts in the SR pool and order them with the master first. + 2. Update all hosts if updates are available from xcp-ng-linstor-testing. + 3. Reboot updated hosts. + 4. Sequentially ensure that the VM can start on all hosts. + """ + sr = linstor_sr + vm = vm_on_linstor_sr + updates_applied = [] + updates_lock = threading.Lock() + + # Sort hosts so that pool master is first (optional) + hosts = sorted(sr.pool.hosts, key=lambda h: h != sr.pool.master) + + # RPU is disabled for pools with XOSTOR SRs. + # LINSTOR expects that we always use satellites and controllers with the same version on all hosts. + def update_host(host: Host) -> None: + logging.info("Updating host %s", host.hostname_or_ip) + host.yum_clean_metadata() + output = host.yum_update(enablerepos=["xcp-ng-linstor-testing"]) + if "No packages marked for update" not in output: + with updates_lock: + updates_applied.append(host) + else: + logging.info("No updates available for host %s", host.hostname_or_ip) + + with concurrent.futures.ThreadPoolExecutor() as executor: + executor.map(update_host, hosts) + + # Reboot updated hosts + def reboot_updated(host: Host) -> None: + host.reboot(verify=True) + + if updates_applied: + with concurrent.futures.ThreadPoolExecutor() as executor: + executor.map(reboot_updated, updates_applied) + wait_for(sr.all_pbds_attached, "Wait for PBD attached") + + # Ensure VM is able to boot on all the hosts + for h in hosts: + vm.start(on=h.uuid) + vm.wait_for_os_booted() + vm.shutdown(verify=True) + # *** End of tests with reboots # --- Test diskless resources --------------------------------------------------