Skip to content

feat: add prepare and cleanup steps for rhaiis project#106

Open
MML-coder wants to merge 7 commits into
openshift-psap:mainfrom
MML-coder:rhaiis-prepare-steps
Open

feat: add prepare and cleanup steps for rhaiis project#106
MML-coder wants to merge 7 commits into
openshift-psap:mainfrom
MML-coder:rhaiis-prepare-steps

Conversation

@MML-coder

@MML-coder MML-coder commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Rewrite prepare_rhaiis.py with a 9-step prepare sequence:
    • Cluster-level: NFD, GPU operator, KServe (via RHOAI) — skips if CSV already exists to avoid triggering upgrades
    • Per-run: namespace with forge labels, SA, SCC (anyuid), vault-based image pull secret, model PVC
  • Add config.d/platform.yaml with operator specs, DSC config, SCC/PVC/vault settings
  • Add vault definition psap-rhaiis-image-pull for container registry credentials
  • Update ci.py with preflight CRD validation for KServe
  • Enhanced cleanup: also deletes InferenceServices and ServingRuntimes
  • Default image_pull_secret: rhaiis-image-pull — no longer needs FournosJob override

Cluster-side prerequisite

The vault secret vault-psap-rhaiis-image-pull must exist in psap-secrets on psap-automation with the fournos.dev/vault-entry=true label. See Fournos README "Adding a project vault secret" section.

Test plan

  • Full pipeline rhaiis-mlflow-full-tfsnx succeeded on forge-smoke-testing
  • Operators skipped (already installed) — prepare completed in ~22s
  • SCC policy applied, image pull secret created from vault, PVC created
  • Preflight passed (KServe CRDs found)
  • Test phase completed (~41m), post-cleanup + export succeeded

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added a CRD-based preflight gate that blocks execution when required cluster capabilities are missing.
    • Expanded orchestration to bootstrap key platform components and prepare namespace resources, including optional model storage provisioning.
  • Bug Fixes

    • Setup and cleanup now report clear success/failure outcomes.
    • Added support for pulling private images using credentials sourced from Vault configuration.
  • Chores

    • Added new platform and secret configuration for the workflow.
    • Removed a redundant CI entrypoint module.

The completed pipellne https://mlflow.apps.psap-automation.ibm.rhperfscale.org/#/experiments/233/runs/34cd9812b0a84004a6b2cfd58d23b436/artifacts?workspace=default

On the forge-smoke-testing, all operators were already installed, so the prepare step validated their presence by checking for existing CSVs and skipped installation:

  1. Operator nfd already installed in openshift-nfd, skipping
  2. Operator gpu-operator-certified already installed in nvidia-gpu-operator, skipping
  3. Operator rhcl-operator already installed in redhat-ods-operator, skipping
  4. Operator rhods-operator already installed in redhat-ods-operator, skipping

MML-coder added 5 commits July 1, 2026 14:09
Rewrite prepare_rhaiis.py with a 9-step prepare sequence:
- Cluster-level: NFD, GPU operator, KServe (via RHOAI) installation
- Per-run: namespace, SA, SCC policy, vault-based image pull secret, PVC

Add config.d/platform.yaml with operator specs, DSC config, and
prepare settings (SCC, PVC storage class, vault references).

Add vault definition for rhaiis image pull credentials
(psap-rhaiis-image-pull) following existing Fournos vault pattern.

Update ci.py with @agent_review_on_failure decorators and preflight
CRD validation for KServe InferenceService/ServingRuntime.

Update cleanup to also delete InferenceServices and ServingRuntimes.
The decorator requires agentic config (model_key etc) that rhaiis
does not use. Remove it to unblock the prepare step.
Avoids triggering operator upgrades on clusters where operators are
already installed and working. Checks for existing CSV by package
name before calling cluster_deploy_operator.
@openshift-ci

openshift-ci Bot commented Jul 1, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign kpouget for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 362bd97a-a905-4be2-8eff-98ffd19b381e

📥 Commits

Reviewing files that changed from the base of the PR and between 8ee72fe and fe63ae3.

📒 Files selected for processing (2)
  • projects/core/ci_entrypoint/run_ci.py
  • projects/rhaiis/orchestration/prepare_rhaiis.py
💤 Files with no reviewable changes (1)
  • projects/core/ci_entrypoint/run_ci.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • projects/rhaiis/orchestration/prepare_rhaiis.py

📝 Walkthrough

Walkthrough

Adds a CRD preflight gate, new platform and Vault configuration, and a rewritten RHAIIS orchestration flow that prepares operators and per-run namespace, secret, SCC, and PVC resources, then cleans up KServe and benchmark resources.

Changes

RHAIIS platform preparation

Layer / File(s) Summary
CRD preflight check
projects/rhaiis/orchestration/ci.py
Adds REQUIRED_CRDS and rewrites preflight() to verify CRD existence via oc_resource_exists, returning 1 on missing CRDs or 0 on success.
Platform config and vault definitions
projects/rhaiis/orchestration/config.d/platform.yaml, projects/rhaiis/orchestration/config.d/rhaiis.yaml, projects/rhaiis/orchestration/config.yaml, vaults/psap-rhaiis-image-pull.yaml, projects/rhaiis/orchestration/runtime_config.py
Adds operators, datasciencecluster, prepare, and cleanup sections; new Vault secret entry; updated image_pull_secret value; new get_platform_config() helper.
prepare()/cleanup() entry points and imports
projects/rhaiis/orchestration/prepare_rhaiis.py
Reorganizes imports; rewrites prepare() and cleanup() to orchestrate operator/namespace/secret/PVC setup and expanded resource deletion, returning status codes.
Operator subscription helpers
projects/rhaiis/orchestration/prepare_rhaiis.py
Adds operator spec derivation, CSV existence checks, and subscription install helper logic used by the operator preparation functions.
NFD, GPU operator, and KServe preparation
projects/rhaiis/orchestration/prepare_rhaiis.py
Adds prepare_nfd(), prepare_gpu_operator(), and prepare_kserve() to install subscriptions, wait on CRDs, and apply a DataScienceCluster.
Namespace, SA, SCC, secret, and PVC provisioning
projects/rhaiis/orchestration/prepare_rhaiis.py
Adds namespace, service account, SCC, image pull secret, and model PVC provisioning helpers plus the base64 encoding helper.

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

Possibly related PRs

Suggested labels: lgtm

🚥 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 clearly matches the main change: adding prepare and cleanup support for the rhaiis project.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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 `@projects/rhaiis/orchestration/config.d/platform.yaml`:
- Around line 31-34: The SCC is currently bound to a hardcoded service account
that may never be created because `rhaiis.deploy.service_account_name` can be
empty and `ensure_service_account()` skips creation in that case. Update
`prepare.scc.service_account` to use the same source of truth as the deploy
service account, or give `rhaiis.deploy.service_account_name` a non-empty
default so both `prepare.scc` and `ensure_service_account()` reference a real,
consistent service account.

In `@projects/rhaiis/orchestration/prepare_rhaiis.py`:
- Around line 71-80: The _operator_csv_exists helper is treating any matching
CSV name as installed, which can skip operator installation before the CSV is
ready. Update _operator_csv_exists in prepare_rhaiis.py to inspect CSV status
and only return true when the matching CSV is in Succeeded phase, then make the
operator-installation check around the current package/CSV handling use that
readiness check instead of name matching alone.
- Around line 93-101: The call to cluster_deploy_operator.run in
prepare_rhaiis.py passes an unsupported artifact_dirname_suffix keyword, which
will raise TypeError before operator installation starts. Remove that argument
from the run invocation and keep the remaining parameters aligned with the
actual cluster_deploy_operator.run signature, using the existing package,
namespace, and operator_spec fields.
- Around line 216-217: The success log in prepare_rhaiis.py is unconditional
because the `oc("adm", "policy", "add-scc-to-user", ...)` call uses
`check=False`, so failures can still be reported as applied. Update the
`prepare_rhaiis` flow around the SCC binding call to either let the command
raise on failure or explicitly inspect the return status and only emit
`logger.info("Applied SCC %s to SA %s in %s", ...)` when the `oc adm policy`
operation succeeds.
- Around line 291-298: The `prepare_rhaiis` flow currently skips PVC creation
and still returns success when `deploy_cfg.storage_pvc` is set but
`model_pvc.storage_class` is missing, leaving the deployment without its
required volume. Update the PVC handling in `prepare_rhaiis` so that a
configured model PVC is treated as required: if the PVC is expected but cannot
be provisioned because `storage_class` is absent, raise an error or fail the
prepare step instead of logging a warning and returning. Keep the early-exit
only for cases where no model PVC was requested.
- Around line 240-248: The image pull secret lookup in prepare_rhaiis.py
currently logs and returns when vault content is missing, which allows prepare
to succeed even though deploy_cfg.image_pull_secret was requested. Update the
secret-creation flow around the vault.get_vault_content_path check to treat
missing Vault content or an absent dockerconfig_path as a hard failure for the
configured image pull secret, and make the prepare_rhaiis path raise/abort
instead of returning silently. Use the existing vault_name, vault_content, and
deploy_cfg.image_pull_secret handling in this function to locate the change.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: a733fb85-6249-44b6-af25-ed6f83154feb

📥 Commits

Reviewing files that changed from the base of the PR and between 48ac14c and 8ee72fe.

📒 Files selected for processing (7)
  • projects/rhaiis/orchestration/ci.py
  • projects/rhaiis/orchestration/config.d/platform.yaml
  • projects/rhaiis/orchestration/config.d/rhaiis.yaml
  • projects/rhaiis/orchestration/config.yaml
  • projects/rhaiis/orchestration/prepare_rhaiis.py
  • projects/rhaiis/orchestration/runtime_config.py
  • vaults/psap-rhaiis-image-pull.yaml

Comment on lines +31 to +34
prepare:
scc:
policy: anyuid
service_account: sa

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n "def ensure_service_account" -A 20 projects/rhaiis/orchestration/prepare_rhaiis.py

Repository: openshift-psap/forge

Length of output: 1016


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the SCC application logic
sed -n '208,250p' projects/rhaiis/orchestration/prepare_rhaiis.py

# Find where service_account_name is defined/consumed
rg -n "service_account_name|scc:" projects/rhaiis -g '*.yaml' -g '*.py'

# Read the relevant config file section
sed -n '1,120p' projects/rhaiis/orchestration/config.d/platform.yaml

Repository: openshift-psap/forge

Length of output: 3905


Align the SCC service account with the deploy SA
In projects/rhaiis/orchestration/config.d/platform.yaml, prepare.scc.service_account is hardcoded to sa, but rhaiis.deploy.service_account_name defaults to empty and ensure_service_account() skips creation when it’s unset. Use one shared source of truth, or set a non-empty default, so the SCC isn’t applied to a service account that never exists.

🤖 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 `@projects/rhaiis/orchestration/config.d/platform.yaml` around lines 31 - 34,
The SCC is currently bound to a hardcoded service account that may never be
created because `rhaiis.deploy.service_account_name` can be empty and
`ensure_service_account()` skips creation in that case. Update
`prepare.scc.service_account` to use the same source of truth as the deploy
service account, or give `rhaiis.deploy.service_account_name` a non-empty
default so both `prepare.scc` and `ensure_service_account()` reference a real,
consistent service account.

Comment on lines +71 to +80
def _operator_csv_exists(namespace: str, package: str) -> bool:
result = oc(
"get", "csv", "-n", namespace,
"-o", "jsonpath={.items[*].metadata.name}",
check=False, log_stdout=False,
)
if result.returncode != 0:
oc("create", "namespace", ns)
logger.info(f"Created namespace {ns}")
else:
logger.info(f"Namespace {ns} already exists")
return False
csv_names = result.stdout.strip().split()
return any(package in name for name in csv_names)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Only skip operator installation when the matching CSV is actually Succeeded.

A CSV can exist while still Pending, Installing, or Failed. Lines 87-89 currently treat any name match as installed, bypassing the helper that waits for readiness.

Proposed fix
-def _operator_csv_exists(namespace: str, package: str) -> bool:
+def _operator_csv_succeeded(namespace: str, package: str) -> bool:
     result = oc(
         "get", "csv", "-n", namespace,
-        "-o", "jsonpath={.items[*].metadata.name}",
+        "-o", 'jsonpath={range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}',
         check=False, log_stdout=False,
     )
     if result.returncode != 0:
         return False
-    csv_names = result.stdout.strip().split()
-    return any(package in name for name in csv_names)
+    for line in result.stdout.strip().splitlines():
+        name, _, phase = line.partition("\t")
+        if package in name and phase == "Succeeded":
+            return True
+    return False
@@
-    if _operator_csv_exists(namespace, package):
+    if _operator_csv_succeeded(namespace, package):

Also applies to: 87-89

🤖 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 `@projects/rhaiis/orchestration/prepare_rhaiis.py` around lines 71 - 80, The
_operator_csv_exists helper is treating any matching CSV name as installed,
which can skip operator installation before the CSV is ready. Update
_operator_csv_exists in prepare_rhaiis.py to inspect CSV status and only return
true when the matching CSV is in Succeeded phase, then make the
operator-installation check around the current package/CSV handling use that
readiness check instead of name matching alone.

Comment on lines +93 to +101
cluster_deploy_operator.run(
package_name=package,
target_namespace=namespace,
source_name=operator_spec["source"],
channel=operator_spec["channel"],
source_namespace=operator_spec.get("source_namespace", "openshift-marketplace"),
display_name=operator_spec.get("display_name", package),
artifact_dirname_suffix=f"_{package}",
)

@coderabbitai coderabbitai Bot Jul 1, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Remove the unsupported artifact_dirname_suffix argument.

Line 100 passes artifact_dirname_suffix, but the provided cluster_deploy_operator.run() signature does not accept that keyword, so the first missing operator install will raise TypeError before any subscription is created.

Proposed fix
     cluster_deploy_operator.run(
         package_name=package,
         target_namespace=namespace,
         source_name=operator_spec["source"],
         channel=operator_spec["channel"],
         source_namespace=operator_spec.get("source_namespace", "openshift-marketplace"),
         display_name=operator_spec.get("display_name", package),
-        artifact_dirname_suffix=f"_{package}",
     )
📝 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
cluster_deploy_operator.run(
package_name=package,
target_namespace=namespace,
source_name=operator_spec["source"],
channel=operator_spec["channel"],
source_namespace=operator_spec.get("source_namespace", "openshift-marketplace"),
display_name=operator_spec.get("display_name", package),
artifact_dirname_suffix=f"_{package}",
)
cluster_deploy_operator.run(
package_name=package,
target_namespace=namespace,
source_name=operator_spec["source"],
channel=operator_spec["channel"],
source_namespace=operator_spec.get("source_namespace", "openshift-marketplace"),
display_name=operator_spec.get("display_name", package),
)
🤖 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 `@projects/rhaiis/orchestration/prepare_rhaiis.py` around lines 93 - 101, The
call to cluster_deploy_operator.run in prepare_rhaiis.py passes an unsupported
artifact_dirname_suffix keyword, which will raise TypeError before operator
installation starts. Remove that argument from the run invocation and keep the
remaining parameters aligned with the actual cluster_deploy_operator.run
signature, using the existing package, namespace, and operator_spec fields.

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.

@coderabbitai, this is supported, these parameters are dynamically appended to the function signature
see there:

projects/core/dsl/task.py:514:        "artifact_dirname_suffix", inspect.Parameter.KEYWORD_ONLY, default=None, annotation=str
projects/core/dsl/task.py:520:        "artifact_dirname_prefix", inspect.Parameter.KEYWORD_ONLY, default=None, annotation=str

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '480,540p' projects/core/dsl/task.py

Length of output: 4301


🏁 Script executed:

#!/bin/bash
sed -n '1,30p' projects/cluster/toolbox/cluster_deploy_operator/main.py

Length of output: 656


Confirmed — run() is decorated with @entrypoint, which dynamically appends artifact_dirname_suffix/artifact_dirname_prefix as keyword-only parameters to the signature (per projects/core/dsl/task.py Lines 514-520). So the call is valid, and my original comment was mistaken. Thanks for the clarification!


🧬 Code Graph Analysis Results

projects/rhaiis/orchestration/prepare_rhaiis.py

Lines 84-102 (calls cluster_deploy_operator.run with artifact_dirname_suffix=...)

def _ensure_operator_subscription(operator_spec: dict[str, str]) -> None:
    package = operator_spec["package"]
    namespace = operator_spec["namespace"]

    if _operator_csv_exists(namespace, package):
        logger.info("Operator %s already installed in %s, skipping", package, namespace)
        return

    from projects.cluster.toolbox.cluster_deploy_operator import main as cluster_deploy_operator

    cluster_deploy_operator.run(
        package_name=package,
        target_namespace=namespace,
        source_name=operator_spec["source"],
        channel=operator_spec["channel"],
        source_namespace=operator_spec.get("source_namespace", "openshift-marketplace"),
        display_name=operator_spec.get("display_name", package),
        artifact_dirname_suffix=f"_{package}",
    )

projects/cluster/toolbox/cluster_deploy_operator/main.py

Lines 27-53 (shows run(...) signature as defined; does not list artifact_dirname_suffix explicitly)

def run(
    package_name: str,
    target_namespace: str,
    source_name: str,
    channel: str,
    *,
    source_namespace: str = "openshift-marketplace",
    installplan_approval: str = "Automatic",
    display_name: str = "",
    install_mode: str = "auto",
) -> int:
    """
    Deploy an OLM operator and wait for its CSV to succeed.

    Args:
        package_name: Operator package/subscription name
        target_namespace: Namespace where the operator will be installed
        source_name: CatalogSource name providing the operator
        channel: Subscription channel to use
        source_namespace: CatalogSource namespace
        installplan_approval: InstallPlan approval mode
        display_name: Optional human-friendly name used in logs
        install_mode: Install mode - "auto" (default), "namespace-scoped", or "cluster-wide"
    """

    execute_tasks(locals())
    return 0

Comment on lines +216 to +217
oc("adm", "policy", "add-scc-to-user", policy, "-z", sa, "-n", namespace, check=False)
logger.info("Applied SCC %s to SA %s in %s", policy, sa, namespace)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not report SCC application success after a failed oc adm policy command.

Line 216 disables checking, then Line 217 logs success unconditionally. If RBAC/SCC binding fails, prepare still returns success and workloads can later fail admission.

Proposed fix
-    oc("adm", "policy", "add-scc-to-user", policy, "-z", sa, "-n", namespace, check=False)
+    oc("adm", "policy", "add-scc-to-user", policy, "-z", sa, "-n", namespace)
     logger.info("Applied SCC %s to SA %s in %s", policy, sa, namespace)
📝 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
oc("adm", "policy", "add-scc-to-user", policy, "-z", sa, "-n", namespace, check=False)
logger.info("Applied SCC %s to SA %s in %s", policy, sa, namespace)
oc("adm", "policy", "add-scc-to-user", policy, "-z", sa, "-n", namespace)
logger.info("Applied SCC %s to SA %s in %s", policy, sa, namespace)
🤖 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 `@projects/rhaiis/orchestration/prepare_rhaiis.py` around lines 216 - 217, The
success log in prepare_rhaiis.py is unconditional because the `oc("adm",
"policy", "add-scc-to-user", ...)` call uses `check=False`, so failures can
still be reported as applied. Update the `prepare_rhaiis` flow around the SCC
binding call to either let the command raise on failure or explicitly inspect
the return status and only emit `logger.info("Applied SCC %s to SA %s in %s",
...)` when the `oc adm policy` operation succeeds.

Comment on lines +240 to +248
try:
dockerconfig_path = vault.get_vault_content_path(vault_name, vault_content)
except Exception:
logger.warning("Vault %s not available — cannot create image pull secret", vault_name)
return

if not dockerconfig_path or not dockerconfig_path.exists():
logger.warning("Vault content %s/%s not found", vault_name, vault_content)
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Fail prepare when the configured image pull secret cannot be created.

If deploy_cfg.image_pull_secret is set and the secret is absent, missing Vault content is not optional; returning here makes prepare succeed while later image pulls fail.

Proposed fix
     try:
         dockerconfig_path = vault.get_vault_content_path(vault_name, vault_content)
-    except Exception:
-        logger.warning("Vault %s not available — cannot create image pull secret", vault_name)
-        return
+    except Exception as exc:
+        raise RuntimeError(
+            f"Vault {vault_name} not available — cannot create image pull secret {secret_name}"
+        ) from exc
 
     if not dockerconfig_path or not dockerconfig_path.exists():
-        logger.warning("Vault content %s/%s not found", vault_name, vault_content)
-        return
+        raise FileNotFoundError(f"Vault content {vault_name}/{vault_content} not found")
📝 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
try:
dockerconfig_path = vault.get_vault_content_path(vault_name, vault_content)
except Exception:
logger.warning("Vault %s not available — cannot create image pull secret", vault_name)
return
if not dockerconfig_path or not dockerconfig_path.exists():
logger.warning("Vault content %s/%s not found", vault_name, vault_content)
return
try:
dockerconfig_path = vault.get_vault_content_path(vault_name, vault_content)
except Exception as exc:
raise RuntimeError(
f"Vault {vault_name} not available — cannot create image pull secret {secret_name}"
) from exc
if not dockerconfig_path or not dockerconfig_path.exists():
raise FileNotFoundError(f"Vault content {vault_name}/{vault_content} not found")
🤖 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 `@projects/rhaiis/orchestration/prepare_rhaiis.py` around lines 240 - 248, The
image pull secret lookup in prepare_rhaiis.py currently logs and returns when
vault content is missing, which allows prepare to succeed even though
deploy_cfg.image_pull_secret was requested. Update the secret-creation flow
around the vault.get_vault_content_path check to treat missing Vault content or
an absent dockerconfig_path as a hard failure for the configured image pull
secret, and make the prepare_rhaiis path raise/abort instead of returning
silently. Use the existing vault_name, vault_content, and
deploy_cfg.image_pull_secret handling in this function to locate the change.

Comment on lines +291 to +298
pvc_cfg = prepare_cfg.get("model_pvc", {})
storage_class = pvc_cfg.get("storage_class", "")
size = pvc_cfg.get("size", "300Gi")
access_mode = pvc_cfg.get("access_mode", "ReadWriteOnce")

if not storage_class:
logger.warning("No storage_class configured for model PVC, skipping creation")
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Fail prepare when a configured model PVC cannot be provisioned.

When deploy_cfg.storage_pvc is set and the PVC does not already exist, missing model_pvc.storage_class leaves the run without its required volume while prepare still exits 0.

Proposed fix
     if not storage_class:
-        logger.warning("No storage_class configured for model PVC, skipping creation")
-        return
+        raise ValueError(
+            "platform.prepare.model_pvc.storage_class is required when rhaiis.deploy.storage_pvc is configured"
+        )
📝 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
pvc_cfg = prepare_cfg.get("model_pvc", {})
storage_class = pvc_cfg.get("storage_class", "")
size = pvc_cfg.get("size", "300Gi")
access_mode = pvc_cfg.get("access_mode", "ReadWriteOnce")
if not storage_class:
logger.warning("No storage_class configured for model PVC, skipping creation")
return
pvc_cfg = prepare_cfg.get("model_pvc", {})
storage_class = pvc_cfg.get("storage_class", "")
size = pvc_cfg.get("size", "300Gi")
access_mode = pvc_cfg.get("access_mode", "ReadWriteOnce")
if not storage_class:
raise ValueError(
"platform.prepare.model_pvc.storage_class is required when rhaiis.deploy.storage_pvc is configured"
)
🤖 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 `@projects/rhaiis/orchestration/prepare_rhaiis.py` around lines 291 - 298, The
`prepare_rhaiis` flow currently skips PVC creation and still returns success
when `deploy_cfg.storage_pvc` is set but `model_pvc.storage_class` is missing,
leaving the deployment without its required volume. Update the PVC handling in
`prepare_rhaiis` so that a configured model PVC is treated as required: if the
PVC is expected but cannot be provisioned because `storage_class` is absent,
raise an error or fail the prepare step instead of logging a warning and
returning. Keep the early-exit only for cases where no model PVC was requested.

Comment on lines +91 to +94
REQUIRED_CRDS = [
"inferenceservices.serving.kserve.io",
"servingruntimes.serving.kserve.io",
]

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.

this should be in the config file (it's easier to control the list from there)

from projects.core.dsl.utils.k8s import oc_resource_exists

logger.info("Starting preflight checks")
missing = [crd for crd in REQUIRED_CRDS if not oc_resource_exists("crd", crd)]

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.

will be updated with config.project.get_config("somewhere.required_crds") instead of REQUIRED_CRDS

vaults:
- psap-forge-notifications
- psap-forge-mlflow-export
- psap-rhaiis-image-pull

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.

did you define the vault in the OCPCI vault already?

return 0


def cleanup() -> int:

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.

the cleanup should delete all the components that have been installed, to bring the cluster back to a fresh state
More or less at least. See in llm-d, for time sake I don't uninstall the GPU operator and a few other core operators

logger.info("SCC policy not configured, skipping")
return

oc("adm", "policy", "add-scc-to-user", policy, "-z", sa, "-n", namespace, check=False)

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.

check=False

@MML-coder @Harshith-umesh I'd like to draw your attention on this (aside from the slack comment)
this check=False will swallow an error. If the command fails because the KUBECONFIG isn't kubeadmin or alike, the automation will silently continue, just with an ignored error message lost in the logs, and the test won't fail until an image anyuid image tries to run

(+ @acalhounRH for awareness, as this is a important aspect for the reliability of the overall test harnesses development)

Comment on lines +229 to +230
if not secret_name:
return

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.

you can log here that no secret is configured

Comment on lines +245 to +249
try:
dockerconfig_path = vault.get_vault_content_path(vault_name, vault_content)
except Exception:
logger.warning("Vault %s not available — cannot create image pull secret", vault_name)
return

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.

don't swallow the error.
If the vault is optional, log a message telling that the optional vault is not available
if it's mandatory, fail here

(same for the lines below)

Comment on lines +272 to +277
src_dir = env.ARTIFACT_DIR / "src"
src_dir.mkdir(parents=True, exist_ok=True)
oc_apply(src_dir / "image-pull-secret.yaml", manifest)
logger.info(
"Created image pull secret %s in %s from vault %s", secret_name, namespace, vault_name
)

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.

@MML-coder @Harshith-umesh ,
please use oc create secret generic --from-file=...
(will be discussed further on slack)

Comment on lines +298 to +301
pvc_cfg = prepare_cfg.get("model_pvc", {})
storage_class = pvc_cfg.get("storage_class", "")
size = pvc_cfg.get("size", "300Gi")
access_mode = pvc_cfg.get("access_mode", "ReadWriteOnce")

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.

please remove the hardcoded default. The values must be in the configuration.

Comment on lines +303 to +305
if not storage_class:
logger.warning("No storage_class configured for model PVC, skipping creation")
return

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.

remove this guard, make it more explicit, eg with a enabled field.
If enabled, do it and all the fields exist, if not enabled, skip.

This ^^^ is true in the general cases, but here: please don't bail out if there's no storage class. There's a default storage class mechanism in OCP/K8s, so if this field is empty, the default PVC will be picked up by the cluster

Comment on lines +314 to +316
"app.kubernetes.io/managed-by": "forge",
"forge.openshift.io/project": "rhaiis",
"forge.openshift.io/preserve": "true",

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.

this should be defined in the config file

)
vault_content = prepare_cfg.get("image_pull_secret", {}).get(
"vault_content", ".dockerconfigjson"
)

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.

please remove the hardcoded default values

Comment on lines +192 to +195
labels={
"app.kubernetes.io/managed-by": "forge",
"forge.openshift.io/project": "rhaiis",
},

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.

please move this to the config file

Comment on lines +26 to +30
ensure_test_namespace(ns)
ensure_service_account(ns, deploy_cfg)
ensure_scc_policy(ns, prepare_cfg)
ensure_image_pull_secret(ns, deploy_cfg, prepare_cfg)
ensure_model_pvc(ns, deploy_cfg, prepare_cfg)

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.

those could be:

  • either included in the preflight checks (in a check-only mode)
  • or moved to the beginning of the test step, so that all the tests ensure that the cluster has that well prepared. Makes it easier to test on a cluster not prepared by Forge

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants