From 6efef21d2bec2160538a024ebb71d55de2ef5b2e Mon Sep 17 00:00:00 2001 From: Claudiu Belu Date: Tue, 6 Oct 2026 19:21:09 +0000 Subject: [PATCH] integration: Adds tests for Windows minion pool lifecycle Add WindowsMinionPoolLifecycleTests, which runs the destination pool lifecycle tests (CRUD, allocate / deallocate) against a Windows pool, covering Windows minions as used for OSMorphing (e.g.: the WinRM healthcheck) without needing a real Windows instance. The pool environment comes from the new optional destination.windows_minion_pool_environment of the providers YAML; the tests are skipped if it is not set. Windows guests are slow to boot, so the allocation timeout of the lifecycle tests becomes configurable, and _create_pool takes an os_type. --- coriolis/tests/integration/README.md | 5 +- coriolis/tests/integration/base.py | 16 ++++--- coriolis/tests/integration/harness.py | 6 +++ .../tests/integration/providers.yaml.sample | 4 ++ .../tests/integration/test_minion_pools.py | 48 ++++++++++++++++++- 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/coriolis/tests/integration/README.md b/coriolis/tests/integration/README.md index 6ec090f5c..ba828c53e 100644 --- a/coriolis/tests/integration/README.md +++ b/coriolis/tests/integration/README.md @@ -119,7 +119,10 @@ pointing at the built-in test provider. 4. Uses `destination.environment` as `destination_environment` and `destination.storage_mappings` as `storage_mappings` for each transfer, and `destination.minion_pool_environment` as the `environment_options` when - creating a destination minion pool. + creating a destination minion pool. The optional + `destination.windows_minion_pool_environment` is used the same way for + Windows destination minion pools; the Windows minion pool lifecycle tests + are skipped if it is not set. ### Running diff --git a/coriolis/tests/integration/base.py b/coriolis/tests/integration/base.py index 7ba36b648..30d138608 100644 --- a/coriolis/tests/integration/base.py +++ b/coriolis/tests/integration/base.py @@ -87,6 +87,7 @@ def setUpClass(cls): cls._imp_env_options = cls._harness.imp_env_options cls._storage_mappings = cls._harness.imp_storage_mappings cls._imp_pool_env = cls._harness.imp_minion_pool_environment + cls._imp_windows_pool_env = cls._harness.imp_windows_minion_pool_environment cls._exp_pool_env = cls._harness.exp_minion_pool_environment cls._client = cls.get_client() @@ -185,6 +186,7 @@ def _create_pool( skip_allocation=True, wait_for_allocation=False, platform=constants.PROVIDER_PLATFORM_DESTINATION, + os_type=constants.OS_TYPE_LINUX, minimum_minions=_DEFAULT_POOL_MINIMUM_MINIONS, maximum_minions=_DEFAULT_POOL_MAXIMUM_MINIONS, minion_max_idle_time=_DEFAULT_POOL_MINION_MAX_IDLE_TIME, @@ -192,16 +194,18 @@ def _create_pool( class_cleanup=True, ): """Create a pool, deleted at class teardown if *class_cleanup*.""" - env_options = ( - cls._imp_pool_env - if platform == constants.PROVIDER_PLATFORM_DESTINATION - else cls._exp_pool_env - ) + if platform != constants.PROVIDER_PLATFORM_DESTINATION: + env_options = cls._exp_pool_env + elif os_type == constants.OS_TYPE_WINDOWS: + env_options = cls._imp_windows_pool_env + else: + env_options = cls._imp_pool_env + pool = cls._client.minion_pools.create( name=name, endpoint=endpoint_id, platform=platform, - os_type=constants.OS_TYPE_LINUX, + os_type=os_type, environment_options=env_options, minimum_minions=minimum_minions, maximum_minions=maximum_minions, diff --git a/coriolis/tests/integration/harness.py b/coriolis/tests/integration/harness.py index f6c5ab268..1a8ed31de 100644 --- a/coriolis/tests/integration/harness.py +++ b/coriolis/tests/integration/harness.py @@ -125,6 +125,9 @@ def _load_providers_config(): "minion_pool_environment": ( dest_config.get("minion_pool_environment") or {} ), + "windows_minion_pool_environment": ( + dest_config.get("windows_minion_pool_environment") or {} + ), }, } @@ -415,6 +418,9 @@ def __init__(self): self.imp_minion_pool_environment = providers_config["destination"][ "minion_pool_environment" ] + self.imp_windows_minion_pool_environment = providers_config["destination"][ + "windows_minion_pool_environment" + ] self._wsgi_server = None self._wsgi_server_thread = None diff --git a/coriolis/tests/integration/providers.yaml.sample b/coriolis/tests/integration/providers.yaml.sample index b09bbc1c2..b10fbec05 100644 --- a/coriolis/tests/integration/providers.yaml.sample +++ b/coriolis/tests/integration/providers.yaml.sample @@ -41,3 +41,7 @@ destination: # environment options forwarded to destination minion pools. minion_pool_environment: {} + + # environment options forwarded to Windows destination minion pools. Optional: + # the Windows minion pool lifecycle tests are skipped if this is empty. + windows_minion_pool_environment: {} diff --git a/coriolis/tests/integration/test_minion_pools.py b/coriolis/tests/integration/test_minion_pools.py index 79a66c039..ff171b40f 100644 --- a/coriolis/tests/integration/test_minion_pools.py +++ b/coriolis/tests/integration/test_minion_pools.py @@ -11,6 +11,7 @@ """ import time +import unittest from oslo_config import cfg @@ -24,6 +25,7 @@ class MinionPoolLifecycleTestMixin: _MINION_PLATFORM = None + _POOL_ALLOCATION_TIMEOUT = 600 def _wait_for_machine_status(self, pool_id, status, timeout=120): """Poll the DB until the pool's single machine reaches *status*.""" @@ -86,7 +88,11 @@ def test_allocate_deallocate(self): # Allocate self._client.minion_pools.allocate_minion_pool(pool.id) - final = self._wait_for_pool(pool.id, base.MINION_ALLOCATED_TERMINAL) + final = self._wait_for_pool( + pool.id, + base.MINION_ALLOCATED_TERMINAL, + timeout=self._POOL_ALLOCATION_TIMEOUT, + ) self.assertEqual( constants.MINION_POOL_STATUS_ALLOCATED, final.status, @@ -176,6 +182,46 @@ def test_cron_triggered_refresh(self): ) +class WindowsMinionPoolLifecycleTests( + MinionPoolLifecycleTestMixin, base.DestinationMinionPoolTestBase +): + """Lifecycle of a Windows destination pool, e.g.: the WinRM healthcheck. + + Covers Windows minions, as used for OSMorphing. Skipped unless providers.yaml + has a ``destination.windows_minion_pool_environment``. + """ + + _MINION_PLATFORM = constants.PROVIDER_PLATFORM_DESTINATION + # Windows guests are slow to boot: + _POOL_ALLOCATION_TIMEOUT = 1200 + + @classmethod + def setUpClass(cls): + h = base.harness._IntegrationHarness.get() + if not h.imp_windows_minion_pool_environment: + raise unittest.SkipTest( + "No 'destination.windows_minion_pool_environment' configured in " + "CORIOLIS_PROVIDERS_YAML; skipping Windows minion pool tests" + ) + + super().setUpClass() + + def setUp(self): + super().setUp() + + self._endpoint = self._create_endpoint( + name="pool-dst-windows", + endpoint_type=self._imp_platform, + connection_info=self._imp_conn_info, + ) + self._pool_env = self._imp_windows_pool_env + + def _create_pool(self, endpoint_id, **kwargs): + return super()._create_pool( + endpoint_id, os_type=constants.OS_TYPE_WINDOWS, **kwargs + ) + + class SourceMinionPoolLifecycleTests( MinionPoolLifecycleTestMixin, base.SourceMinionPoolTestBase ):