Skip to content

feat(MTV-5654): add copy-offload populator throttling test - #550

Merged
myakove merged 27 commits into
RedHatQE:mainfrom
prabinovRedhat:feat/MTV-5654-populator-throttling
Jun 19, 2026
Merged

myakove merged 27 commits into
RedHatQE:mainfrom
prabinovRedhat:feat/MTV-5654-populator-throttling

Conversation

@prabinovRedhat

@prabinovRedhat prabinovRedhat commented Jun 9, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds MTV-5654 copy-offload (Case 1 + Case 3) coverage for per-ESXi-host populator throttling and sourceHost labels.

  • TestCopyoffloadPopulatorThrottlingMigration: 7-step flow (storagemap → networkmap → plan → migrate with peak monitoring → verify throttling → check xcopy → check VMs)
  • populator_inflight_forkliftcontroller fixture: class-scoped patch of ForkliftController.spec.controller_max_populator_inflight and deployment env to limit 2, with pre-test snapshot restore on teardown and xdist file lock
  • Verification utilities: peak in-flight populate pods during migration, PopulatorThrottled events (≥ disks − limit), single sourceHost label on all populate pods
  • wait_for_migration_complate(on_status_poll=...) and public get_migration_for_plan() for migration-scoped monitoring

Rebased on latest main (includes merge_storage_secret_extra integration).

Test plan

  • Local cluster run: uv run pytest -m copyoffload -k TestCopyoffloadPopulatorThrottlingMigration — 7/7 passed (~17 min)
  • Peak concurrency observed: 2/2 with 5 disks (1 boot + 4 add_disks)
  • 3 PopulatorThrottled events with (2/2 in-flight)
  • Fixture restore: CR/deployment limit 2 → 20 after class teardown

Notes

  • Cluster-mutating test: temporarily sets global populator in-flight limit to 2. Do not run in parallel with other copy-offload tests on the same cluster.
  • MTV-5654 Test 2/4 (multi-host) are out of scope for this PR.

Summary by CodeRabbit

  • New Features
    • Added end-to-end coverage for copy-offload populator throttling, including per-host inflight concurrency validation and expected throttling/event behavior.
    • Introduced shared testing utilities to temporarily control and verify populator inflight limits safely during throttling scenarios.
  • Tests
    • Added a new populator-throttling test scenario and multi-disk VM setup for copy-offload migrations.
    • Improved concurrent migration flows to wait for copy-offload plan populator secrets before validation.
  • Documentation
    • Updated contributor/testing guidance with a step-by-step throttling test pattern and added a copy-offload warning about cluster-wide throttle mutations.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 55a5b271-de54-4e4f-8e97-e1f5fa056dfd

📥 Commits

Reviewing files that changed from the base of the PR and between 6cb4755 and 3dad828.

📒 Files selected for processing (2)
  • AGENTS.md
  • utilities/forklift_controller_populator.py

Walkthrough

Implements MTV-696 end-to-end copy-offload populator throttling tests by adding constants, a new copyoffload_plan_secret module, a forklift_controller_populator utility module for cluster-wide limit management with cross-worker file locking, migration monitoring with per-host peak concurrency tracking, throttling verification, a new test class, and supporting documentation.

Changes

MTV-696 Populator Throttling Migration Test

Layer / File(s) Summary
Throttling constants and shared controller name
utilities/copyoffload_constants.py, conftest.py
Adds POPULATOR_INFLIGHT_LIMIT, SOURCE_HOST_LABEL, PVC_NAME_LABEL, POPULATOR_THROTTLED_EVENT_REASON, and FORKLIFT_CONTROLLER_NAME; replaces hardcoded "forklift-controller" string in the precopy_interval_forkliftcontroller fixture.
Plan secret polling helper module
utilities/copyoffload_plan_secret.py
New module with plan_uses_copyoffload(), _plan_secret_exists() (by label pair or name prefix), wait_for_plan_secret() (60s/2s TimeoutSampler), and exported wait_for_copyoffload_plan_secret() that only waits when the plan uses copy-offload.
MTV migration helpers refactored for secret wait and status callback
utilities/mtv_migration.py
Promotes _find_migration_for_plan to public get_migration_for_plan(); moves plan-secret wait from create_plan_resource into execute_migration; adds optional on_status_poll callback to wait_for_migration_complate(); switches timeout to py_config["plan_wait_timeout"].
ForkliftController populator limit utilities
utilities/forklift_controller_populator.py
New module: constants, secure cross-worker lock directory helpers (O_NOFOLLOW/UID/0700), deployment env-var readers, wait_for_populator_inflight_deployment(), and populator_inflight_limit() context manager that patches the ForkliftController CR, waits for propagation, yields, then restores.
Migration monitoring and throttling verification
utilities/copyoffload_migration.py
Adds _ACTIVE_POPULATOR_POD_PHASES, refactors _find_populate_pods() with require_pods flag, updates two XCOPY verification sites to use PVC_NAME_LABEL, adds _count_active_populator_pods_by_host(), _PopulatorConcurrencyTracker, execute_migration_monitoring_populator_inflight(), and the full verify_populator_throttling() verification chain.
Cross-worker fixture for populator limit coordination
tests/copyoffload/conftest.py
New class-scoped populator_inflight_forkliftcontroller fixture acquires a shared FileLock, waits for ForkliftController RUNNING state, reads original deployment limit, applies POPULATOR_INFLIGHT_LIMIT via context manager, and restores on teardown.
Test class, scenario config, and secret-wait integration
tests/copyoffload/test_copyoffload_migration.py, tests/tests_config/config.py
Adds TestCopyoffloadPopulatorThrottlingMigration (MTV-696) with full provisioning, monitoring, throttling/XCOPY verification, and VM/disk assertions; inserts plan-secret waits into two existing concurrent test flows; adds test_copyoffload_populator_throttling_migration scenario with thin-cloned VM and four 10GB disks.
User and developer documentation
README.md, AGENTS.md
README warns about cluster-wide throttling mutation and parallel execution restriction; AGENTS.md corrects import example, adds 7-step throttling pattern, and updates method-count guidance.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(70, 130, 180, 0.5)
    Note over Test,populator_inflight_limit: Fixture Setup
    Test->>populator_inflight_forkliftcontroller: class-scoped fixture entry
    populator_inflight_forkliftcontroller->>FileLock: acquire(timeout=POPULATOR_INFLIGHT_LOCK_TIMEOUT)
    populator_inflight_forkliftcontroller->>ForkliftController: wait for RUNNING state
    populator_inflight_forkliftcontroller->>get_deployment_populator_inflight_limit: read current MAX_POPULATOR_INFLIGHT
    populator_inflight_forkliftcontroller->>populator_inflight_limit: apply POPULATOR_INFLIGHT_LIMIT=2
    populator_inflight_limit->>ForkliftController: patch spec.controller_max_populator_inflight=2
    populator_inflight_limit->>wait_for_populator_inflight_deployment: poll until Deployment env-var matches
  end
  rect rgba(60, 179, 113, 0.5)
    Note over Test,verify_populator_throttling: Migration Execution and Verification
    Test->>execute_migration_monitoring_populator_inflight: plan, target_namespace
    execute_migration_monitoring_populator_inflight->>wait_for_copyoffload_plan_secret: wait for plan populator Secret
    execute_migration_monitoring_populator_inflight->>wait_for_migration_complate: on_status_poll=tracker.poll
    wait_for_migration_complate->_PopulatorConcurrencyTracker: poll per iteration
    _PopulatorConcurrencyTracker->>_count_active_populator_pods_by_host: count Running/Pending pods by SOURCE_HOST_LABEL
    execute_migration_monitoring_populator_inflight-->>Test: max_concurrent_by_host dict
    Test->>verify_populator_throttling: max_concurrent_by_host, max_populator_inflight=2
    verify_populator_throttling->>_verify_source_host_labels_on_pods: assert single SOURCE_HOST_LABEL per pod
    verify_populator_throttling->>_verify_throttled_events_on_pods: assert POPULATOR_THROTTLED_EVENT_REASON on PVCs
    verify_populator_throttling->>_verify_populator_inflight_observed: assert peak ≤ 2 and peak ≥ min(2, disk_count)
  end
  rect rgba(255, 165, 0, 0.5)
    Note over populator_inflight_limit,ForkliftController: Fixture Teardown
    populator_inflight_limit->>ForkliftController: restore original_deployment_limit
    populator_inflight_limit->>wait_for_populator_inflight_deployment: confirm Deployment restored
    FileLock->>FileLock: release
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

size/L, can-be-merged, approved-myakove, lgtm-myakove, lgtm-tshefi, lgtm-coderabbitai[bot], cherry-pick-v2.11, cherry-pick-v2.10

Suggested reviewers

  • myakove
  • krcmarik
  • solenoci
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(MTV-5654): add copy-offload populator throttling test' is directly related to the main changeset, which implements a comprehensive test framework for copy-offload populator throttling (MTV-696) including a new test class, fixtures, utilities, and verification helpers.
Docstring Coverage ✅ Passed Docstring coverage is 98.15% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@redhat-qe-bot

Copy link
Copy Markdown

Report bugs in Issues

Welcome! 🎉

This pull request will be automatically processed with the following features:

🔄 Automatic Actions

  • Reviewer Assignment: Reviewers are automatically assigned based on the OWNERS file in the repository root
  • Size Labeling: PR size labels (XS, S, M, L, XL, XXL) are automatically applied based on changes
  • Issue Creation: Disabled for this repository
  • Branch Labeling: Branch-specific labels are applied to track the target branch
  • Auto-verification: Auto-verified users have their PRs automatically marked as verified
  • Labels: All label categories are enabled (default configuration)

📋 Available Commands

PR Status Management

  • /wip - Mark PR as work in progress (adds WIP: prefix to title)
  • /wip cancel - Remove work in progress status
  • /hold - Block PR merging (approvers only)
  • /hold cancel - Unblock PR merging
  • /verified - Mark PR as verified
  • /verified cancel - Remove verification status
  • /reprocess - Trigger complete PR workflow reprocessing (useful if webhook failed or configuration changed)
  • /regenerate-welcome - Regenerate this welcome message

Review & Approval

  • /lgtm - Approve changes (looks good to me)
  • /approve - Approve PR (approvers only)
  • /automerge - Enable automatic merging when all requirements are met (maintainers and approvers only)
  • /assign-reviewers - Assign reviewers based on OWNERS file
  • /assign-reviewer @username - Assign specific reviewer
  • /check-can-merge - Check if PR meets merge requirements

Testing & Validation

  • /retest tox - Run Python test suite with tox
  • /retest build-container - Rebuild and test container image
  • /retest conventional-title - Validate commit message format
  • /retest all - Run all available tests

Container Operations

  • /build-and-push-container - Build and push container image (tagged with PR number)
    • Supports additional build arguments: /build-and-push-container --build-arg KEY=value

Cherry-pick Operations

  • /cherry-pick <branch> - Schedule cherry-pick to target branch when PR is merged
    • Multiple branches: /cherry-pick branch1 branch2 branch3

Label Management

  • /<label-name> - Add a label to the PR
  • /<label-name> cancel - Remove a label from the PR

✅ Merge Requirements

This PR will be automatically approved when the following conditions are met:

  1. Approval: /approve from at least one approver
  2. Status Checks: All required status checks must pass
  3. No Blockers: No wip, hold, has-conflicts labels and PR must be mergeable (no conflicts)
  4. Verified: PR must be marked as verified

📊 Review Process

Approvers and Reviewers

Approvers:

  • krcmarik
  • myakove
  • solenoci

Reviewers:

  • krcmarik
  • myakove
  • solenoci
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
  • automerge
AI Features
  • Conventional Title: Mode: fix (claude/claude-opus-4-6[1m])
  • Cherry-Pick Conflict Resolution: Enabled (claude/claude-opus-4-6[1m])
  • Test Oracle: Triggers: approved (cursor/gpt-5.4-xhigh-fast); /test-oracle can be used anytime

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is removed on new commits unless the push is detected as a clean rebase
  • Cherry-picking: Cherry-pick labels are processed when the PR is merged
  • Container Builds: Container images are automatically tagged with the PR number
  • Permission Levels: Some commands require approver permissions
  • Auto-verified Users: Certain users have automatic verification and merge privileges

For more information, please refer to the project documentation or contact the maintainers.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
utilities/mtv_migration.py (1)

367-404: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add Raises section to docstring.

The function raises MigrationPlanExecError on failure/timeout (lines 399-404), but the docstring omits the Raises section. Per coding guidelines, include Raises when exceptions are actually raised.

📝 Proposed fix
 def wait_for_migration_complate(
     plan: Plan,
     *,
     on_status_poll: Callable[[str], None] | None = None,
 ) -> None:
     """Wait for a Plan migration to reach Succeeded or Failed.
 
     Args:
         plan (Plan): The Plan resource to monitor.
         on_status_poll (Callable[[str], None] | None): Optional callback invoked on each poll
             with the current migration status string.
+
+    Raises:
+        MigrationPlanExecError: If the migration fails or times out.
     """
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@utilities/mtv_migration.py` around lines 367 - 404, Update the docstring for
wait_for_migration_complate to include a Raises section that documents
MigrationPlanExecError being raised when the plan migration fails or when a
timeout occurs (the except branch catching TimeoutExpiredError and
MigrationPlanExecError re-raises MigrationPlanExecError); reference the Plan
parameter and mention the function uses TimeoutSampler and
py_config.get("plan_wait_timeout") for timing so readers know the timeout
source.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@guides/copyoffload/how-to-run-copyoffload-tests.md`:
- Around line 424-432: Update the pytest example so it explicitly
disables/limits xdist parallelism to enforce isolation for
TestCopyoffloadPopulatorThrottlingMigration; modify the suggested command that
runs pytest -m copyoffload -k TestCopyoffloadPopulatorThrottlingMigration to
include an explicit xdist flag (e.g., add -n 0 or -n 1) so the test never runs
concurrently with other tests that rely on the default populator limit.

In `@tests/copyoffload/test_copyoffload_migration.py`:
- Around line 3514-3554: Add full Python type annotations to each new test
method in this class (including test_create_storagemap, test_create_networkmap,
test_create_plan, test_check_vms and the other methods mentioned around lines
3556-3609 and 3650-3675): annotate every fixture parameter with appropriate
built-in typing (e.g., dict, list, tuple, str, int, or specific types used by
your test fixtures) and add a return type of -> None on each function signature;
ensure you use only built-in typing names (dict, list, tuple) as required by the
repo policy and update any untyped fixture parameters in
get_storage_migration_map callers (and related helper calls) to match the new
annotated signatures so the test signatures are consistent with test_migrate_vms
and test_verify_populator_throttling.

---

Outside diff comments:
In `@utilities/mtv_migration.py`:
- Around line 367-404: Update the docstring for wait_for_migration_complate to
include a Raises section that documents MigrationPlanExecError being raised when
the plan migration fails or when a timeout occurs (the except branch catching
TimeoutExpiredError and MigrationPlanExecError re-raises
MigrationPlanExecError); reference the Plan parameter and mention the function
uses TimeoutSampler and py_config.get("plan_wait_timeout") for timing so readers
know the timeout source.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 07f2d88a-ce6c-48bf-98fc-e62666fe7f9a

📥 Commits

Reviewing files that changed from the base of the PR and between e74ee3b and eca7da6.

📒 Files selected for processing (8)
  • README.md
  • guides/copyoffload/how-to-run-copyoffload-tests.md
  • tests/copyoffload/conftest.py
  • tests/copyoffload/test_copyoffload_migration.py
  • tests/tests_config/config.py
  • utilities/copyoffload_constants.py
  • utilities/copyoffload_migration.py
  • utilities/mtv_migration.py

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 9, 2026
@prabinovRedhat

Copy link
Copy Markdown
Collaborator Author

cc: @tshefi

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
utilities/copyoffload_migration.py (1)

925-946: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

HIGH: Poll for PopulatorThrottled events instead of reading them once.

Event.list() is eventually consistent, so this one-shot read can miss throttling events that were emitted during the migration but have not been surfaced yet when verification runs. That makes the new copy-offload test flaky under cluster load.

A short retry window here is enough: keep collecting unique PVCs with PopulatorThrottled until you reach min_expected_throttled, then assert.

Suggested fix
-    throttled_pvc_names: list[str] = []
-    for pod in populate_pods:
-        labels: dict[str, str] = pod.instance.metadata.labels or {}
-        pvc_name: str = labels.get("pvcName", pod.name)
-        field_selector = f"involvedObject.name={pvc_name},involvedObject.kind=PersistentVolumeClaim"
-        for event in Event.list(
-            client=ocp_admin_client,
-            namespace=target_namespace,
-            field_selector=field_selector,
-            since_seconds=py_config["plan_wait_timeout"],
-        ):
-            if event.get("reason") == POPULATOR_THROTTLED_EVENT_REASON:
-                throttled_pvc_names.append(pvc_name)
-                LOGGER.info(f"PVC '{pvc_name}' has {POPULATOR_THROTTLED_EVENT_REASON} event")
-                break
+    def _collect_throttled_pvc_names() -> set[str]:
+        seen: set[str] = set()
+        for pod in populate_pods:
+            labels: dict[str, str] = pod.instance.metadata.labels or {}
+            pvc_name: str = labels.get("pvcName", pod.name)
+            field_selector = f"involvedObject.name={pvc_name},involvedObject.kind=PersistentVolumeClaim"
+            for event in Event.list(
+                client=ocp_admin_client,
+                namespace=target_namespace,
+                field_selector=field_selector,
+                since_seconds=py_config["plan_wait_timeout"],
+            ):
+                if event.get("reason") == POPULATOR_THROTTLED_EVENT_REASON:
+                    seen.add(pvc_name)
+                    break
+        return seen
+
+    throttled_pvc_names: set[str] = set()
+    for throttled_pvc_names in TimeoutSampler(wait_timeout=30, sleep=2, func=_collect_throttled_pvc_names):
+        if len(throttled_pvc_names) >= min_expected_throttled:
+            break

     if len(throttled_pvc_names) < min_expected_throttled:
         raise ValueError(
             f"Expected at least {min_expected_throttled} PVC(s) with {POPULATOR_THROTTLED_EVENT_REASON} "
             f"events for migration '{migration_uid}' ({len(populate_pods)} disks, "
             f"limit={max_populator_inflight}); found {len(throttled_pvc_names)}: {throttled_pvc_names}"
         )

As per coding guidelines, tests must be deterministic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@utilities/copyoffload_migration.py` around lines 925 - 946, The one-time read
of Event.list can miss eventual events; change the block that builds
throttled_pvc_names (iterating populate_pods) into a short retry/poll loop that
repeatedly queries Event.list for each pod (using the same field_selector and
since_seconds) until either a deadline (e.g. now + a small retry window) is
reached or throttled_pvc_names contains at least min_expected_throttled unique
PVC names. Use a set to dedupe PVCs (convert to list for existing callers),
check event.get("reason") == POPULATOR_THROTTLED_EVENT_REASON to add the pvc,
log when discovered, and sleep a small interval between iterations; after the
loop assert the same ValueError if the count is still below
min_expected_throttled. Ensure you update references to throttled_pvc_names,
populate_pods, Event.list, POPULATOR_THROTTLED_EVENT_REASON, and
min_expected_throttled when implementing the retry loop.

Source: Coding guidelines

tests/copyoffload/test_copyoffload_migration.py (1)

3581-3608: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

HIGH: Fail fast if the plan config loses copyoffload=True.

This class is specifically validating copy-offload throttling, so copyoffload is not optional here. prepared_plan.get("copyoffload", False) silently downgrades the run to a non-copy-offload migration if the config key is missing or renamed, and the suite then fails much later in throttling/XCOPY assertions with a misleading signal.

Proposed fix
         self.__class__.plan_resource = create_plan_resource(
             ocp_admin_client=ocp_admin_client,
             fixture_store=fixture_store,
             source_provider=source_provider,
             destination_provider=destination_provider,
             storage_map=self.storage_map,
             network_map=self.network_map,
             virtual_machines_list=prepared_plan["virtual_machines"],
             target_namespace=target_namespace,
             warm_migration=prepared_plan.get("warm_migration", False),
-            copyoffload=prepared_plan.get("copyoffload", False),
+            copyoffload=prepared_plan["copyoffload"],
         )

As per coding guidelines, "For configurations controlled by the codebase (py_config, plan, tests_params), never use defaults; always use direct access like py_config['storage_class'] not .get() with defaults."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/copyoffload/test_copyoffload_migration.py` around lines 3581 - 3608, In
test_create_plan, do not use prepared_plan.get("copyoffload", False); instead
access prepared_plan["copyoffload"] directly (or assert "copyoffload" in
prepared_plan before calling create_plan_resource) so a missing/renamed key
fails fast; update the create_plan_resource call in the test_create_plan
function to pass prepared_plan["copyoffload"] (or perform an explicit assertion
on prepared_plan) to ensure copyoffload must be present.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@tests/copyoffload/test_copyoffload_migration.py`:
- Around line 3581-3608: In test_create_plan, do not use
prepared_plan.get("copyoffload", False); instead access
prepared_plan["copyoffload"] directly (or assert "copyoffload" in prepared_plan
before calling create_plan_resource) so a missing/renamed key fails fast; update
the create_plan_resource call in the test_create_plan function to pass
prepared_plan["copyoffload"] (or perform an explicit assertion on prepared_plan)
to ensure copyoffload must be present.

In `@utilities/copyoffload_migration.py`:
- Around line 925-946: The one-time read of Event.list can miss eventual events;
change the block that builds throttled_pvc_names (iterating populate_pods) into
a short retry/poll loop that repeatedly queries Event.list for each pod (using
the same field_selector and since_seconds) until either a deadline (e.g. now + a
small retry window) is reached or throttled_pvc_names contains at least
min_expected_throttled unique PVC names. Use a set to dedupe PVCs (convert to
list for existing callers), check event.get("reason") ==
POPULATOR_THROTTLED_EVENT_REASON to add the pvc, log when discovered, and sleep
a small interval between iterations; after the loop assert the same ValueError
if the count is still below min_expected_throttled. Ensure you update references
to throttled_pvc_names, populate_pods, Event.list,
POPULATOR_THROTTLED_EVENT_REASON, and min_expected_throttled when implementing
the retry loop.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8af482da-8ef9-48c9-be17-94702420c189

📥 Commits

Reviewing files that changed from the base of the PR and between eca7da6 and b91d9f5.

📒 Files selected for processing (4)
  • README.md
  • tests/copyoffload/test_copyoffload_migration.py
  • utilities/copyoffload_constants.py
  • utilities/copyoffload_migration.py

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 10, 2026
@prabinovRedhat

Copy link
Copy Markdown
Collaborator Author

/verified

@tshefi

tshefi commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

/lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants