Skip to content

INTEROP-9265: Add ACM operator upgrade step for OPP product upgrades - #82641

Open
amp-rh wants to merge 2 commits into
openshift:mainfrom
amp-rh:interop-9265-acm-operator-upgrade
Open

INTEROP-9265: Add ACM operator upgrade step for OPP product upgrades#82641
amp-rh wants to merge 2 commits into
openshift:mainfrom
amp-rh:interop-9265-acm-operator-upgrade

Conversation

@amp-rh

@amp-rh amp-rh commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Add step registry entry at interop/opp/product-upgrade/acm/ that upgrades ACM via OLM subscription channel change and validates the operator reaches Succeeded phase.

What it does:

  • Identifies current ACM version via CSV
  • Patches the Subscription to the target channel (or resolves next available)
  • Waits for the new CSV to reach Succeeded phase
  • Validates MCE (MultiCluster Engine) co-upgrade completion
  • Confirms hub health (MCH phase, policy propagator, managed clusters)

This step gates downstream product upgrades (ACS, ODF, Quay) in the OPP coordinated product upgrade workflow (INTEROP-8941).

Jira

Files

  • ci-operator/step-registry/interop/opp/product-upgrade/OWNERS
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/OWNERS
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-ref.yaml
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-ref.metadata.json

Test plan

  • ci/prow/ci-operator-registry passes (step ref validation)
  • ci/prow/step-registry-shellcheck passes
  • ci/prow/owners passes (OWNERS file validation)
  • Prow rehearsal confirms step loads without error

Summary by CodeRabbit

Adds a new ACM operator upgrade step to the CI step-registry interop interop/opp/product-upgrade so OPP-coordinated product upgrades can reliably advance ACM/OLM in a controlled, validated way.

  • Introduces interop-opp-product-upgrade-acm step definition (command, 45m execution timeout, env vars, resource requests, and documented exit codes).
  • Adds an interop-opp-product-upgrade-acm-commands.sh upgrade script that:
    • Detects the current ACM Subscription CSV/version/channel.
    • Resolves the target channel from ACM_TARGET_CHANNEL, or auto-selects the next higher semver-based channel from the catalog.
    • Patches the Subscription to switch channels, waits for an InstallPlan, and auto-approves it when spec.approval=Manual.
    • Polls for the upgrade CSV to reach Succeeded (with support for m|s|h|minutes timeout formats and a default of 30m).
    • Validates post-upgrade co-upgrade and health by checking MultiClusterEngine CSV completion, MultiClusterHub phase, governance-policy-propagator readiness, and managed cluster availability counts.
    • Collects extensive diagnostics to an artifact on failure (Subscription/CSVs/InstallPlans/pods/MCE CSVs) and writes an acm-upgrade-summary.txt; also optionally records upgraded version/channel into SHARED_DIR for downstream gating of ACS/ODF/Quay upgrades.
  • Updates OWNERS configuration for the OPP product-upgrade and the ACM subdirectory to define approvers/reviewers via YAML anchors.

Add step registry entry at interop/opp/product-upgrade/acm/ that
upgrades ACM via OLM subscription channel change and validates the
operator reaches Succeeded phase. Includes MCE co-upgrade validation
and hub health checks (MCH phase, policy propagator, managed clusters).

This step gates downstream product upgrades (ACS, ODF, Quay) in the
OPP coordinated product upgrade workflow (INTEROP-8941).
@openshift-ci-robot

openshift-ci-robot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@amp-rh: This pull request references INTEROP-9265 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

Add step registry entry at interop/opp/product-upgrade/acm/ that upgrades ACM via OLM subscription channel change and validates the operator reaches Succeeded phase.

What it does:

  • Identifies current ACM version via CSV
  • Patches the Subscription to the target channel (or resolves next available)
  • Waits for the new CSV to reach Succeeded phase
  • Validates MCE (MultiCluster Engine) co-upgrade completion
  • Confirms hub health (MCH phase, policy propagator, managed clusters)

This step gates downstream product upgrades (ACS, ODF, Quay) in the OPP coordinated product upgrade workflow (INTEROP-8941).

Jira

Files

  • ci-operator/step-registry/interop/opp/product-upgrade/OWNERS
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/OWNERS
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-ref.yaml
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-ref.metadata.json

Test plan

  • ci/prow/ci-operator-registry passes (step ref validation)
  • ci/prow/step-registry-shellcheck passes
  • ci/prow/owners passes (OWNERS file validation)
  • Prow rehearsal confirms step loads without error

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 29, 2026
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: e4e1929d-66d3-4d3c-adf7-3d2e427afda4

📥 Commits

Reviewing files that changed from the base of the PR and between e828887 and ce974b9.

📒 Files selected for processing (1)
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh

Walkthrough

Adds a CI step-registry entry that upgrades the ACM operator through an OLM subscription channel change, approves InstallPlans, waits for completion, validates MCE and hub health, and collects diagnostics and summary artifacts.

Changes

ACM operator upgrade

Layer / File(s) Summary
Step contract and ownership
ci-operator/step-registry/interop/opp/product-upgrade/...
Defines ACM step metadata, runtime settings, environment variables, documentation, and approver/reviewer ownership.
Upgrade orchestration
ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh
Discovers channels and versions, patches the subscription, approves manual InstallPlans, polls CSV completion, and captures failure diagnostics.
Post-upgrade validation
ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh
Validates MCE, MultiClusterHub, governance pod readiness, managed cluster availability, and writes upgrade results.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant OLM
  participant ACM
  participant Cluster
  CI->>OLM: Resolve and patch ACM subscription channel
  OLM-->>CI: Create InstallPlan
  CI->>OLM: Approve manual InstallPlan
  OLM->>ACM: Install upgraded CSV
  CI->>ACM: Wait for CSV Succeeded
  CI->>Cluster: Validate MCE and hub health
  Cluster-->>CI: Return health status
Loading

Suggested reviewers: shakyav, chaclark1974

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding an ACM operator upgrade step for OPP product upgrades.
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.
Stable And Deterministic Test Names ✅ Passed No Ginkgo/BDD test titles were added or changed; the PR only touches OWNERS, YAML, JSON, and a shell script.
Test Structure And Quality ✅ Passed No Ginkgo test code was changed in this PR; only a step-registry bash script and metadata/OWNERS files were added or updated.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the PR only changes OWNERS, shell, and step-registry YAML/metadata, so MicroShift compatibility isn’t implicated.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; this PR only adds step-registry shell/YAML/metadata/OWNERS assets, so SNO test compatibility is not applicable.
Topology-Aware Scheduling Compatibility ✅ Passed PR only adds step-registry OWNERS, YAML, metadata, and a bash upgrade script; no pod scheduling constraints, affinities, replicas, or node selectors were introduced.
Ote Binary Stdout Contract ✅ Passed No OTE binary code was changed; the PR only adds step-registry config and a shell script, so there are no process-level stdout writes to flag.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Only step-registry YAML/shell files were added; no Ginkgo tests, IPv4-only IP handling, or external/public connectivity were found.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret/token comparisons found in the added ACM step files.
Container-Privileges ✅ Passed No privileged container fields were found in the added ACM step manifests; the new ref.yaml only defines step metadata/env/resources, and keyword scans returned no hits.
No-Sensitive-Data-In-Logs ✅ Passed Only cluster-resource metadata/status and counts are logged; I գտfound no passwords, tokens, API keys, PII, session IDs, or raw pod logs.
✨ 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.

@openshift-ci
openshift-ci Bot requested review from chaclark1974 and shakyav July 29, 2026 18:24
@openshift-ci

openshift-ci Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: amp-rh

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 29, 2026
@openshift-merge-bot openshift-merge-bot Bot added the rehearsals-ack Signifies that rehearsal jobs have been acknowledged label Jul 29, 2026
@redhat-chai-bot

Copy link
Copy Markdown
Contributor

Code Review: ACM Operator Upgrade Step

Overall this is a well-structured step with clean function decomposition, proper artifact collection, defensive error handling in diagnostics, and thorough post-upgrade validation (MCE + hub health). The ref YAML documentation with exit codes is excellent. A few issues and suggestions below.


Bug: set -e + inherit_errexit makes empty-value checks unreachable

The script sets set -euo pipefail and shopt -s inherit_errexit. With inherit_errexit, command substitutions inherit set -e, so if oc get inside a helper function returns non-zero (e.g. subscription doesn't exist yet, transient API error), the subshell exits immediately, which then triggers set -e in the calling scope — before the subsequent empty-string check is ever reached.

Affected call sites (non-exhaustive):

# Main section — if oc get fails, script exits before the -z check:
current_csv="$(get_current_csv)"
if [[ -z "${current_csv}" ]]; then  # ← never reached on oc failure
    echo >&2 "ERROR: No ACM subscription found or no currentCSV set"
    exit 3
fi

# wait_for_csv_succeeded — transient API blip kills the polling loop:
new_csv="$(get_current_csv)"
if [[ -z "${new_csv}" ]]; then  # ← never reached
    sleep 10
    continue
fi

This pattern repeats for get_current_channel, get_csv_phase, and get_installed_version.

Suggested fix — add || true at call sites that expect empty output as a valid result:

current_csv="$(get_current_csv || true)"
if [[ -z "${current_csv}" ]]; then
    ...
fi

Or equivalently, add || true inside the helper functions after oc get ... 2>/dev/null || true. This is the more robust approach since it fixes every caller at once.


Bug: Inconsistent jsonpath for InstallPlan reference

The script uses two different jsonpaths for the same field:

# Line ~298 ("same channel" check) — correct, current API field:
-o jsonpath='{.status.installPlanRef.name}'

# Line ~316 (post-channel-patch polling loop) — deprecated field:
-o jsonpath='{.status.installplan.name}'

Per the OLM SubscriptionStatus type definition, .status.installplan (JSON tag of the Install field) is explicitly marked DEPRECATED in favor of .status.installPlanRef. Both fields are currently populated by OLM for backward compatibility, but only installPlanRef includes the full object reference (with namespace and resourceVersion).

Fix: Use .status.installPlanRef.name consistently in both locations.


Suggestion: parse_timeout should warn on unrecognized formats

parse_timeout returns 0 seconds for any input it can't parse (e.g. 30min, abc). This would cause wait_for_csv_succeeded to timeout immediately with no indication that the timeout value was invalid.

parse_timeout() {
    local input="$1"
    # ... existing cases ...
    else
        echo >&2 "WARNING: Unrecognized timeout format '${input}', defaulting to 30m"
        minutes=30
    fi
    echo "$(( minutes * 60 + seconds ))"
}

Suggestion: Write upgrade result to SHARED_DIR for downstream steps

The PR description says this step "gates downstream product upgrades (ACS, ODF, Quay) in the OPP coordinated product upgrade workflow." Downstream steps may need to know the post-upgrade ACM version and channel. Consider writing the result to SHARED_DIR:

echo "${new_version}" > "${SHARED_DIR}/acm-upgraded-version"
echo "${target_channel}" > "${SHARED_DIR}/acm-upgraded-channel"

This follows the standard inter-step communication pattern in the step registry and keeps the 1MB flat-file constraint.


Minor: validate_hub_health pipefail edge case

cluster_count="$(oc get managedclusters --no-headers 2>/dev/null | wc -l || echo 0)"

If oc get fails (API unreachable, CRD not found), wc -l outputs 0 from empty input, but pipefail makes the pipeline fail, triggering || echo 0. The command substitution captures output from both wc -l and echo 0, resulting in "0\n0". Since this is only used for informational logging and validate_hub_health always returns 0 regardless, the impact is cosmetic (double 0 in the log). A cleaner pattern:

cluster_count="$(oc get managedclusters --no-headers 2>/dev/null | wc -l)" || cluster_count=0

Positive notes

  • shopt -s inherit_errexit is a nice strictness addition (though it creates the interaction noted above).
  • The collect_diagnostics trap with || true on every oc call is solid — it won't interfere with the original exit code.
  • The resolve_target_channel version comparison logic correctly finds the minimum-next-version across unsorted channel lists.
  • MCE co-upgrade validation with displayName + label fallback is a good defensive pattern.
  • The ref YAML env documentation and exit code table are well-structured.

Thanks for a solid contribution. The set -e / inherit_errexit interaction is the most important item — it could cause silent failures in production runs.

@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: 5

🧹 Nitpick comments (1)
ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh (1)

79-97: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Empty spec.sourceNamespace degrades into a misleading error.

If the Subscription omits sourceNamespace, the packagemanifest query runs against the current context namespace and returns nothing, surfacing as "No channels found" rather than the real cause. Default it to openshift-marketplace and validate package_name too.

🤖 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
`@ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh`
around lines 79 - 97, Update the subscription lookup flow to default an empty
catalog_namespace from spec.sourceNamespace to openshift-marketplace before
querying packagemanifest. Also validate package_name immediately after
retrieving it and return a clear error when it is empty, before executing the
channels lookup; preserve the existing no-channels handling for valid package
manifests.
🤖 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
`@ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh`:
- Around line 303-312: Update the same-channel logic in the target_channel check
to verify that the referenced InstallPlan represents a pending upgrade, rather
than treating any installPlanRef.name as pending. Inspect the referenced
InstallPlan’s spec.clusterServiceVersionNames and status.phase, or compare the
subscription’s currentCSV and installedCSV, and exit 0 only when no upgrade is
actually available; preserve the existing upgrade flow when one is pending.
- Around line 36-40: Update get_current_csv and the corresponding subscription
lookups around the callers near lines 290-297 to explicitly handle oc failures.
Ensure command substitution failures are caught without triggering set -e, then
return an empty result so the existing “No ACM subscription found” handling
executes and exits with status 3.
- Around line 180-193: Update parse_timeout to reject inputs that match none of
its supported formats instead of echoing 0. After the existing parsing branches,
return a nonzero status and emit a clear error for invalid values such as
“1h30m” or “45min”; preserve the current seconds conversion for valid minute,
second, hour, and numeric inputs.
- Around line 143-178: Update wait_for_csv_succeeded to ignore the pre-upgrade
CSV by requiring get_current_csv to differ from the previously installed
current_csv before accepting a Succeeded phase. Preserve the existing timeout,
failure handling, and polling behavior, and only return success after the
replacement CSV reports Succeeded.
- Around line 323-351: Update the InstallPlan lookup in the retry loop to read
`.status.installPlanRef.name`, matching the earlier subscription lookup. Scope
the fallback `oc get installplan` query to InstallPlans whose owner reference
name matches `${ACM_SUBSCRIPTION_NAME}` before selecting the newest result, so
the approval logic only targets the ACM Subscription’s InstallPlan.

---

Nitpick comments:
In
`@ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh`:
- Around line 79-97: Update the subscription lookup flow to default an empty
catalog_namespace from spec.sourceNamespace to openshift-marketplace before
querying packagemanifest. Also validate package_name immediately after
retrieving it and return a clear error when it is empty, before executing the
channels lookup; preserve the existing no-channels handling for valid package
manifests.
🪄 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: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: e4f7e528-1fa1-4acd-9866-6113eb749e67

📥 Commits

Reviewing files that changed from the base of the PR and between e38f568 and e828887.

📒 Files selected for processing (5)
  • ci-operator/step-registry/interop/opp/product-upgrade/OWNERS
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/OWNERS
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-ref.metadata.json
  • ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-ref.yaml

Comment on lines +143 to +178
wait_for_csv_succeeded() {
local timeout_seconds
timeout_seconds="$(parse_timeout "${ACM_UPGRADE_TIMEOUT}")"
local start_time elapsed new_csv phase
start_time="$(date +%s)"

while true; do
elapsed="$(( $(date +%s) - start_time ))"
if (( elapsed > timeout_seconds )); then
echo >&2 "ERROR: Timeout (${ACM_UPGRADE_TIMEOUT}) waiting for CSV upgrade"
return 2
fi

new_csv="$(get_current_csv)"
if [[ -z "${new_csv}" ]]; then
sleep 10
continue
fi

phase="$(get_csv_phase "${new_csv}")"
echo " CSV: ${new_csv} Phase: ${phase} (${elapsed}s elapsed)"

case "${phase}" in
Succeeded)
return 0
;;
Failed)
echo >&2 "ERROR: CSV ${new_csv} entered Failed phase"
return 1
;;
*)
sleep 15
;;
esac
done
}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

wait_for_csv_succeeded can return immediately on the pre-upgrade CSV.

Right after the channel patch, status.currentCSV still holds ${current_csv}, which is already Succeeded, so the loop can exit on the first iteration and the step reports a successful upgrade that never happened. Gate on the CSV name changing (or on spec.version differing) before accepting Succeeded.

🐛 Suggested fix
 wait_for_csv_succeeded() {
+    local previous_csv="$1"
     local timeout_seconds
@@
         new_csv="$(get_current_csv)"
-        if [[ -z "${new_csv}" ]]; then
+        if [[ -z "${new_csv}" || "${new_csv}" == "${previous_csv}" ]]; then
             sleep 10
             continue
         fi
🤖 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
`@ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh`
around lines 143 - 178, Update wait_for_csv_succeeded to ignore the pre-upgrade
CSV by requiring get_current_csv to differ from the previously installed
current_csv before accepting a Succeeded phase. Preserve the existing timeout,
failure handling, and polling behavior, and only return success after the
replacement CSV reports Succeeded.

Comment on lines +180 to +193
parse_timeout() {
local input="$1"
local minutes=0 seconds=0
if [[ "${input}" =~ ^([0-9]+)m$ ]]; then
minutes="${BASH_REMATCH[1]}"
elif [[ "${input}" =~ ^([0-9]+)s$ ]]; then
seconds="${BASH_REMATCH[1]}"
elif [[ "${input}" =~ ^([0-9]+)h$ ]]; then
minutes="$(( BASH_REMATCH[1] * 60 ))"
elif [[ "${input}" =~ ^([0-9]+)$ ]]; then
minutes="${input}"
fi
echo "$(( minutes * 60 + seconds ))"
}

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

parse_timeout silently yields 0 on unparsable input.

An unexpected ACM_UPGRADE_TIMEOUT (e.g. 1h30m, 45min) falls through all branches and returns 0, causing an immediate timeout on the first loop iteration. Fail loudly instead.

♻️ Suggested change
     elif [[ "${input}" =~ ^([0-9]+)$ ]]; then
         minutes="${input}"
+    else
+        echo >&2 "ERROR: Unsupported timeout format: ${input}"
+        return 3
     fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
parse_timeout() {
local input="$1"
local minutes=0 seconds=0
if [[ "${input}" =~ ^([0-9]+)m$ ]]; then
minutes="${BASH_REMATCH[1]}"
elif [[ "${input}" =~ ^([0-9]+)s$ ]]; then
seconds="${BASH_REMATCH[1]}"
elif [[ "${input}" =~ ^([0-9]+)h$ ]]; then
minutes="$(( BASH_REMATCH[1] * 60 ))"
elif [[ "${input}" =~ ^([0-9]+)$ ]]; then
minutes="${input}"
fi
echo "$(( minutes * 60 + seconds ))"
}
parse_timeout() {
local input="$1"
local minutes=0 seconds=0
if [[ "${input}" =~ ^([0-9]+)m$ ]]; then
minutes="${BASH_REMATCH[1]}"
elif [[ "${input}" =~ ^([0-9]+)s$ ]]; then
seconds="${BASH_REMATCH[1]}"
elif [[ "${input}" =~ ^([0-9]+)h$ ]]; then
minutes="$(( BASH_REMATCH[1] * 60 ))"
elif [[ "${input}" =~ ^([0-9]+)$ ]]; then
minutes="${input}"
else
echo >&2 "ERROR: Unsupported timeout format: ${input}"
return 3
fi
echo "$(( minutes * 60 + seconds ))"
}
🤖 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
`@ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh`
around lines 180 - 193, Update parse_timeout to reject inputs that match none of
its supported formats instead of echoing 0. After the existing parsing branches,
return a nonzero status and emit a clear error for invalid values such as
“1h30m” or “45min”; preserve the current seconds conversion for valid minute,
second, hour, and numeric inputs.

Comment on lines +303 to +312
if [[ "${target_channel}" == "${current_channel}" ]]; then
echo "Already on target channel ${target_channel}; checking if upgrade is available..."
install_plan="$(oc get subscription "${ACM_SUBSCRIPTION_NAME}" \
-n "${ACM_SUBSCRIPTION_NAMESPACE}" \
-o jsonpath='{.status.installPlanRef.name}' 2>/dev/null || true)"
if [[ -z "${install_plan}" ]]; then
echo "No pending upgrade on current channel; nothing to do"
exit 0
fi
fi

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

"Pending upgrade" detection is unreliable.

status.installPlanRef.name remains populated for the already-applied InstallPlan, so this branch almost never takes the exit 0 path; instead it falls through to a no-op channel patch and then to wait_for_csv_succeeded, which reports success without upgrading. Check the referenced InstallPlan's spec.clusterServiceVersionNames / status.phase (or compare status.currentCSV with status.installedCSV) instead of mere presence.

🤖 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
`@ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh`
around lines 303 - 312, Update the same-channel logic in the target_channel
check to verify that the referenced InstallPlan represents a pending upgrade,
rather than treating any installPlanRef.name as pending. Inspect the referenced
InstallPlan’s spec.clusterServiceVersionNames and status.phase, or compare the
subscription’s currentCSV and installedCSV, and exit 0 only when no upgrade is
actually available; preserve the existing upgrade flow when one is pending.

Comment on lines +323 to +351
install_plan=""
for _ in $(seq 1 12); do
install_plan="$(oc get subscription "${ACM_SUBSCRIPTION_NAME}" \
-n "${ACM_SUBSCRIPTION_NAMESPACE}" \
-o jsonpath='{.status.installplan.name}' 2>/dev/null || true)"
if [[ -z "${install_plan}" ]]; then
install_plan="$(oc get installplan -n "${ACM_SUBSCRIPTION_NAMESPACE}" \
--sort-by=.metadata.creationTimestamp \
-o jsonpath='{.items[-1:].metadata.name}' 2>/dev/null || true)"
fi
if [[ -n "${install_plan}" ]]; then
break
fi
sleep 10
done

if [[ -n "${install_plan}" ]]; then
echo "InstallPlan: ${install_plan}"
local_approval="$(oc get installplan "${install_plan}" \
-n "${ACM_SUBSCRIPTION_NAMESPACE}" \
-o jsonpath='{.spec.approval}' 2>/dev/null || true)"
if [[ "${local_approval}" == "Manual" ]]; then
echo "Approving manual InstallPlan..."
oc patch installplan "${install_plan}" \
-n "${ACM_SUBSCRIPTION_NAMESPACE}" \
--type merge \
-p '{"spec":{"approved":true}}'
fi
fi

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# How other steps resolve a Subscription's InstallPlan
rg -n --glob 'ci-operator/step-registry/**/*.sh' -e 'installPlanRef' -e 'status\.installplan' -C2 | head -60

Repository: openshift/release

Length of output: 155


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh"

printf '--- file exists and line count ---\n'
wc -l "$file" || true

printf '--- relevant sections ---\n'
sed -n '280,360p' "$file" | nl -ba -v280

printf '--- all installplan references in file ---\n'
rg -n -i 'installplan|installPlan|subscription|ACM_SUBSCRIPTION' "$file" -C2

printf '--- repo-wide manual approvals of InstallPlans ---\n'
rg -n --glob '*.sh' 'oc patch installplan|approved.*true|approval|installPlanRef|installplan\.name|installPlan\.name' -C3 | head -200

Repository: openshift/release

Length of output: 246


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check whether git is available ==="
git --version || true

echo "=== Locate target file(s) ==="
git ls-files 'ci-operator/step-registry/**/*-commands.sh' | rg 'interop-opp-product-upgrade-acm-commands\.sh|acm.*product-upgrade|product-upgrade-acm' || true

echo "=== Run targeted search if target file path is known ==="
if [ -f ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh ]; then
  sed -n '280,360p' ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh | nl -ba -v280
fi

Repository: openshift/release

Length of output: 443


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh"

tmp="$(mktemp)"
line=1
while IFS= read -r lineno content; do
  case "$content" in
    *installplan*|*installPlan*|*installPlanRef*|*subscription*|*ACM_SUBSCRIPTION*)
      start=$((lineno-2)); [ "$start" -lt 1 ] && start=1
      end=$((lineno+3)); echo "--- lines $start-$end around installplan/subscription refs ---"
      sed -n "${start},${end}p" "$file" - | awk -v S="$start" '{printf "%d\t%s\n", S+$0-1, $0}'
      ;;
  esac
done < <(cat -n "$file" | awk '{gsub(/^\s+[0-9]+\t/, "", $0); print NR"\t"$0}')

printf '\n--- repo-wide InstallPlan approval/owner refs ---\n'
rg -n --glob '*.sh' 'oc patch installplan|approved.*true|approval|installPlanRef|status\.installplan\.name|metadata\.ownerReferences|ownerReferences' -C2 | head -240

printf '\n--- behavioral probe for the owner-agnostic fallback and duplicate field expression ---\n'
python3 - <<'PY'
installplan_name_expr = ".installplan.name"
installPlanRef_expr = ".installPlanRef.name"
fallback_all_namespaces = "Newest InstallPlan in namespace regardless of owner"
print("Field expression:", installplan_name_expr)
print("Consistent expression elsewhere:", installPlanRef_expr)
print("Falls back to:", fallback_all_namespaces)
PY

Repository: openshift/release

Length of output: 208


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh"

echo "--- targeted lines 290-360 ---"
awk '{printf "%d\t%s\n", NR, $0}' "$file" | sed -n '290,360p'

echo
echo "--- all matches in file ---"
grep -InEi 'installplan|installPlan|installPlanRef|subscription|ACM_SUBSCRIPTION' "$file" || true

echo
echo "--- repo-wide InstallPlan/owner references in SH files ---"
rg -n --glob '*.sh' 'oc patch installplan|approved.*true|approval|installPlanRef|status\.installplan\.name|metadata\.ownerReferences|ownerReferences' -C2 | head -240 || true

Repository: openshift/release

Length of output: 5727


Use installPlanRef and scope the InstallPlan fallback to the ACM Subscription.

Lines 323-331 still read .status.installplan.name, while the same value is read as .status.installPlanRef.name at line 305. The fallback also selects the newest InstallPlan in the namespace; in namespaces with multiple operators, patch that InstallPlan can approve an unrelated manual InstallPlan. Filter the fallback by metadata.ownerReferences[?(@.name=="${ACM_SUBSCRIPTION_NAME}")] before taking the latest one.

🤖 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
`@ci-operator/step-registry/interop/opp/product-upgrade/acm/interop-opp-product-upgrade-acm-commands.sh`
around lines 323 - 351, Update the InstallPlan lookup in the retry loop to read
`.status.installPlanRef.name`, matching the earlier subscription lookup. Scope
the fallback `oc get installplan` query to InstallPlans whose owner reference
name matches `${ACM_SUBSCRIPTION_NAME}` before selecting the newest result, so
the approval logic only targets the ACM Subscription’s InstallPlan.

…t default

- Add || true to all oc get helpers to prevent inherit_errexit from
  killing callers before empty-string checks can run
- Use consistent .status.installPlanRef.name (not deprecated .installplan)
- Add fallback default (30m) for unrecognized timeout formats in parse_timeout
- Write acm-upgraded-version and acm-upgraded-channel to SHARED_DIR for
  downstream step consumption
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

[REHEARSALNOTIFIER]
@amp-rh: no rehearsable tests are affected by this change

Note: If this PR includes changes to step registry files (ci-operator/step-registry/) and you expected jobs to be found, try rebasing your PR onto the base branch. This helps pj-rehearse accurately detect changes when the base branch has moved forward.

Interacting with pj-rehearse

Comment: /pj-rehearse to run up to 5 rehearsals
Comment: /pj-rehearse skip to opt-out of rehearsals
Comment: /pj-rehearse {test-name}, with each test separated by a space, to run one or more specific rehearsals
Comment: /pj-rehearse more to run up to 10 rehearsals
Comment: /pj-rehearse max to run up to 25 rehearsals
Comment: /pj-rehearse auto-ack to run up to 5 rehearsals, and add the rehearsals-ack label on success
Comment: /pj-rehearse list to get an up-to-date list of affected jobs
Comment: /pj-rehearse abort to abort all active rehearsals
Comment: /pj-rehearse network-access-allowed to allow rehearsals of tests that have the restrict_network_access field set to false. This must be executed by an openshift org member who is not the PR author

Once you are satisfied with the results of the rehearsals, comment: /pj-rehearse ack to unblock merge. When the rehearsals-ack label is present on your PR, merge will no longer be blocked by rehearsals.
If you would like the rehearsals-ack label removed, comment: /pj-rehearse reject to re-block merging.

@openshift-ci

openshift-ci Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@amp-rh: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/step-registry-metadata ce974b9 link true /test step-registry-metadata

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. rehearsals-ack Signifies that rehearsal jobs have been acknowledged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants