Skip to content

Conversation

@shellymiron
Copy link
Collaborator

@shellymiron shellymiron commented Jan 13, 2026

Add Multi-Vendor Copy-Offload Support

Summary

Extended copy-offload testing from 2 to 9 storage vendors, aligned with forklift vsphere-xcopy-volume-populator.

Supported Vendors

  • ✅ NetApp ONTAP - Tested
  • ✅ Hitachi Vantara
  • ✅ HPE Primera/3PAR
  • ✅ Pure Storage FlashArray
  • ✅ Dell PowerFlex
  • ✅ Dell PowerMax
  • ✅ Dell PowerStore
  • ✅ Infinidat InfiniBox
  • ✅ IBM FlashSystem

Changes

conftest.py

  • Extended copyoffload_storage_secret fixture with vendor-specific field mapping
  • Automatic Secret creation with correct env vars for each vendor
  • Validation with clear error messages

.providers.json.example

  • Added configuration examples for all 9 vendors
  • Documented required fields and how to obtain values

tests/test_copyoffload_migration.py

  • Updated docstrings with vendor information

Vendor-Specific Fields

Vendor Required Fields
NetApp ONTAP ontap_svm
Hitachi Vantara vantara_storage_id, vantara_storage_port, vantara_hostgroup_id_list
Pure Storage pure_cluster_prefix
Dell PowerFlex powerflex_system_id
Dell PowerMax powermax_symmetrix_id
Others Basic credentials only

Testing

✅ NetApp ONTAP validated
⚠️ Other vendors: Implementation aligned with forklift code, awaiting validation

Backward Compatibility

✅ Existing configurations work unchanged


Implementation verified against forklift populator source code.

This PR description was generated with assistance from Cursor AI.

Summary by CodeRabbit

  • New Features

    • Extended copy-offload configuration to support multiple storage vendors: Pure Storage FlashArray, Dell PowerFlex, Dell PowerMax, Hitachi Vantara, PowerStore, InfiniBox, and FlashSystem.
  • Documentation

    • Enhanced configuration examples and guidance for vendor-specific setup requirements.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 13, 2026

Walkthrough

Configuration schema expanded to support multiple storage vendors (NetApp ONTAP, Hitachi Vantara, Pure Storage, Dell PowerFlex/PowerMax, and others) with vendor-specific fields. Core validation and credential-handling logic refactored to dynamically map vendor-to-field relationships instead of hardcoded ontap-specific handling. Test documentation updated to reflect broader vendor support.

Changes

Cohort / File(s) Summary
Configuration Schema
.providers.json.example
Added vendor-specific fields for copyoffload: ontap_svm, vantara_storage_id/vantara_storage_port/vantara_hostgroup_id_list, pure_cluster_prefix, powerflex_system_id, powermax_symmetrix_id, esxi_clone_method/esxi_host/esxi_user/esxi_password, and rdm_lun_uuid. Expanded storage_vendor_product documentation with supported vendor list.
Credential Validation & Population
conftest.py
Replaced hardcoded ontap-specific credential handling with generic vendor_specific_fields dictionary mapping each vendor to required configuration keys. Updated vendor validation to check against supported vendor list and emit warnings for unknown vendors. Implemented dynamic field population loop that fetches vendor-specific credentials via get_copyoffload_credential and raises ValueError if required fields are missing.
Test Documentation & Guidance
tests/test_copyoffload_migration.py
Replaced explicit .providers.json example blocks with general reference guidance. Removed hardcoded ontap-specific comments. Added post-migration disk count verification in test_copyoffload_multi_disk_migration. Expanded vendor coverage notes to include multiple storage vendors.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: extending copy-offload testing support to 9 new storage vendors, which is the primary objective of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

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

📋 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)

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 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. LGTM Count: Minimum 0 /lgtm from reviewers
  3. Status Checks: All required status checks must pass
  4. No Blockers: No WIP, hold, or conflict labels
  5. Verified: PR must be marked as verified (if verification is enabled)

📊 Review Process

Approvers and Reviewers

Approvers:

  • myakove

Reviewers:

  • krcmarik
  • myakove
  • rnetser
Available Labels
  • hold
  • verified
  • wip
  • lgtm
  • approve
  • automerge

💡 Tips

  • WIP Status: Use /wip when your PR is not ready for review
  • Verification: The verified label is automatically removed on each new commit
  • 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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @conftest.py:
- Around line 943-953: Extract the local supported_vendors list into a
module-level constant (e.g., SUPPORTED_VENDORS) and replace the inline list in
the fixture with that constant; also update the vendor_specific_fields
dictionary keys (or its creation) to reference SUPPORTED_VENDORS so the vendor
set is defined once and reused (ensure the constant name is exported/available
at top of conftest.py and update any uses of supported_vendors to
SUPPORTED_VENDORS).
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d06e8c and 8e87463.

📒 Files selected for processing (3)
  • .providers.json.example
  • conftest.py
  • tests/test_copyoffload_migration.py
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use built-in Python typing (dict, list, tuple, etc.) for type annotations in Python code
Use openshift-python-wrapper for all OpenShift/Kubernetes cluster interactions; import resource classes from ocp_resources.* and utilities from ocp_utilities.*
Never import directly from kubernetes package at runtime; never instantiate DynamicClient directly - use ocp_utilities.infra.get_client() instead
Import DynamicClient from kubernetes.dynamic only within TYPE_CHECKING blocks or as string annotations for type hints
Every OpenShift resource must be created using create_and_store_resource() function from utilities/resources.py only
Keep functions small and focused - maximum ~50 lines per function with single responsibility; extract helpers with underscore prefix for sub-tasks
Keep code simple and readable; avoid over-engineering
Run ruff check and ruff format for linting and formatting of Python code
Run mypy with strict configuration for type checking of Python code

Files:

  • conftest.py
  • tests/test_copyoffload_migration.py
conftest.py

📄 CodeRabbit inference engine (CLAUDE.md)

conftest.py: conftest.py files ONLY contain pytest fixtures and pytest hooks; move standalone helper functions to utilities/ directory
Use @pytest.fixture with appropriate scope (session for shared resources, function for test-specific resources)

Files:

  • conftest.py
{conftest.py,tests/**/*.py}

📄 CodeRabbit inference engine (CLAUDE.md)

Track all created resources in fixture_store['teardown'] dictionary for automatic cleanup

Files:

  • conftest.py
  • tests/test_copyoffload_migration.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Never use default values or .get() with fallbacks for configurations defined in the codebase (py_config, plan, tests_params); use direct dictionary access to fail fast on missing keys
Use .get() with explicit validation for external/provider configurations to provide context-rich error messages
Use indirect=True in @pytest.mark.parametrize decorator when passing parameters to fixtures
Apply pytest markers (tier0, warm, remote, copyoffload) to categorize tests; markers must be defined in pytest.ini

Files:

  • tests/test_copyoffload_migration.py
tests/test_*_migration.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/test_*_migration.py: Test structure must follow standard pattern: parametrize with config, use standard fixtures, create migration maps, execute migration
New test files should follow naming convention test_<feature>_migration.py and be placed in tests/ directory

Files:

  • tests/test_copyoffload_migration.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: shellymiron
Repo: RedHatQE/mtv-api-tests PR: 239
File: README.md:270-331
Timestamp: 2026-01-12T16:24:31.016Z
Learning: Repository RedHatQE/mtv-api-tests: The OpenShift Job templates in README.md and docs/how-to-run-copyoffload-tests.md are intentionally duplicated with identical sections because the files are meant to be different but share common Job template structure; do not suggest consolidating them into a single YAML manifest.
📚 Learning: 2026-01-12T16:24:31.016Z
Learnt from: shellymiron
Repo: RedHatQE/mtv-api-tests PR: 239
File: README.md:270-331
Timestamp: 2026-01-12T16:24:31.016Z
Learning: Repository RedHatQE/mtv-api-tests: The OpenShift Job templates in README.md and docs/how-to-run-copyoffload-tests.md are intentionally duplicated with identical sections because the files are meant to be different but share common Job template structure; do not suggest consolidating them into a single YAML manifest.

Applied to files:

  • tests/test_copyoffload_migration.py
🧬 Code graph analysis (1)
conftest.py (1)
utilities/copyoffload_migration.py (1)
  • get_copyoffload_credential (21-38)
🪛 Ruff (0.14.10)
conftest.py

955-958: Avoid specifying long messages outside the exception class

(TRY003)


961-962: Logging statement uses f-string

(G004)


997-997: Logging statement uses f-string

(G004)


999-1003: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (7)
tests/test_copyoffload_migration.py (3)

74-98: LGTM! Clear vendor documentation added.

The expanded docstring accurately documents vendor-specific required fields and aligns with the vendor_specific_fields mapping in conftest.py. The reference to .providers.json.example for detailed configuration is helpful.


231-238: LGTM!

Docstring updates are consistent with the thin migration test and provide appropriate vendor guidance.


366-372: LGTM!

Consistent vendor documentation updates across all copy-offload test functions.

.providers.json.example (1)

28-78: LGTM! Comprehensive vendor configuration documentation.

The documentation clearly lists all 9 supported vendors with their required fields and provides actionable instructions on how to obtain vendor-specific values (e.g., Pure Storage cluster prefix from storagecluster CR, PowerFlex system ID from ConfigMap). This will significantly reduce configuration errors for users.

conftest.py (3)

954-963: LGTM! Good balance of validation and forward compatibility.

The approach of raising an error for missing vendor but only warning for unknown vendors is sensible - it allows new vendors to be tested before being formally added to the list while still alerting users to potential misconfiguration.

LOW: Static analysis flagged the long exception message (TRY003). This is a minor style consideration; the descriptive message is appropriate here for configuration errors.


972-989: LGTM! Clean and extensible vendor configuration mapping.

The tuple structure (config_key, secret_key, required) is self-documenting and the mapping is easily extensible for new vendors. The reference to forklift populator source code provides good traceability.


991-1003: LGTM! Correct dynamic field population logic.

The iteration correctly handles the vendor-specific fields: adding values to secret data when found, and raising a clear error with remediation guidance when a required field is missing. The check if storage_vendor in vendor_specific_fields properly skips unknown vendors (which already received a warning above).

LOW: Static analysis flagged f-string logging at line 997 (G004). Consider using %s style if strict linting is enforced, but this is a minor style preference.

Comment on lines +943 to +953
supported_vendors = [
"ontap",
"vantara",
"primera3par",
"pureFlashArray",
"powerflex",
"powermax",
"powerstore",
"infinibox",
"flashsystem",
]
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

MEDIUM: Consider extracting supported_vendors to a module-level constant.

The vendor list is effectively duplicated since vendor_specific_fields dictionary keys contain the same values. Extracting to a constant enables reuse and ensures consistency if vendors are added/removed.

♻️ Suggested refactor
+# Module-level constant (add near top of file after imports)
+SUPPORTED_COPYOFFLOAD_VENDORS = frozenset([
+    "ontap",
+    "vantara", 
+    "primera3par",
+    "pureFlashArray",
+    "powerflex",
+    "powermax",
+    "powerstore",
+    "infinibox",
+    "flashsystem",
+])

Then in the fixture:

-    supported_vendors = [
-        "ontap",
-        "vantara",
-        "primera3par",
-        "pureFlashArray",
-        "powerflex",
-        "powermax",
-        "powerstore",
-        "infinibox",
-        "flashsystem",
-    ]
+    # Use module-level constant
     if not storage_vendor:
         raise ValueError(
             f"storage_vendor_product is required in copyoffload configuration. "
-            f"Valid values: {', '.join(supported_vendors)}"
+            f"Valid values: {', '.join(sorted(SUPPORTED_COPYOFFLOAD_VENDORS))}"
         )
-    if storage_vendor not in supported_vendors:
+    if storage_vendor not in SUPPORTED_COPYOFFLOAD_VENDORS:
🤖 Prompt for AI Agents
In @conftest.py around lines 943 - 953, Extract the local supported_vendors list
into a module-level constant (e.g., SUPPORTED_VENDORS) and replace the inline
list in the fixture with that constant; also update the vendor_specific_fields
dictionary keys (or its creation) to reference SUPPORTED_VENDORS so the vendor
set is defined once and reused (ensure the constant name is exported/available
at top of conftest.py and update any uses of supported_vendors to
SUPPORTED_VENDORS).

Comment on lines +993 to +1003
for config_key, secret_key, required in vendor_specific_fields[storage_vendor]:
value = get_copyoffload_credential(config_key, copyoffload_cfg)
if value:
secret_data[secret_key] = value
LOGGER.info(f"✓ Added vendor-specific field: {secret_key}")
elif required:
raise ValueError(
f"Required vendor-specific field '{config_key}' not found for vendor '{storage_vendor}'. "
f"Add it to .providers.json copyoffload section or set environment variable: "
f"COPYOFFLOAD_{config_key.upper()}"
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and examine the get_copyoffload_credential function
rg -A 20 "def get_copyoffload_credential" utilities/

Repository: RedHatQE/mtv-api-tests

Length of output: 1573


🏁 Script executed:

#!/bin/bash
# Search for tests of get_copyoffload_credential
rg -r "get_copyoffload_credential" tests/

Repository: RedHatQE/mtv-api-tests

Length of output: 961


🏁 Script executed:

#!/bin/bash
# Find actual usages of get_copyoffload_credential in code
rg "get_copyoffload_credential\(" --type py

Repository: RedHatQE/mtv-api-tests

Length of output: 586


🏁 Script executed:

#!/bin/bash
# Find vendor_specific_fields definition
rg -B 5 -A 15 "vendor_specific_fields\s*=" conftest.py

Repository: RedHatQE/mtv-api-tests

Length of output: 1056


🏁 Script executed:

#!/bin/bash
# Search for test files that test get_copyoffload_credential or copyoffload_storage_secret
find tests -name "*copyoffload*" -o -name "*test_conftest*"

Repository: RedHatQE/mtv-api-tests

Length of output: 101


🏁 Script executed:

#!/bin/bash
# Examine the test file
cat tests/test_copyoffload_migration.py

Repository: RedHatQE/mtv-api-tests

Length of output: 26895


Document environment variable naming convention for vendor-specific fields in get_copyoffload_credential function.

The function correctly implements env var naming as COPYOFFLOAD_{credential_name.upper()}, converting vantara_hostgroup_id_listCOPYOFFLOAD_VANTARA_HOSTGROUP_ID_LIST. However, the docstring in utilities/copyoffload_migration.py only documents that "environment variables take precedence" but does not explain HOW env var names are constructed from credential names. Additionally, the test docstrings document basic env vars (e.g., COPYOFFLOAD_STORAGE_HOSTNAME, COPYOFFLOAD_ONTAP_SVM) but omit Vantara-specific ones like COPYOFFLOAD_VANTARA_HOSTGROUP_ID_LIST.

Why: Users setting up Vantara storage need to know the exact env var names to override config file values, especially since field names with underscores (e.g., vantara_hostgroup_id_list) map to uppercase env vars with underscores preserved.

Fix: Update get_copyoffload_credential docstring to explicitly state: "Environment variable names are constructed as COPYOFFLOAD_{credential_name.upper()} (e.g., 'storage_hostname' → 'COPYOFFLOAD_STORAGE_HOSTNAME')." Update test docstrings to list all vendor-specific env vars supported.

🧰 Tools
🪛 Ruff (0.14.10)

997-997: Logging statement uses f-string

(G004)


999-1003: Avoid specifying long messages outside the exception class

(TRY003)

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.

2 participants