Fix Readme
Abstract
Apply this hotfix after completing the watsonx Orchestrate installation for Version 5.3.1 Patch 2, or after applying 5.3.1 patch2 as per documentation https://www.ibm.com/docs/en/software-hub/5.3.x?topic=upgrading-applying-patches.
Content
oc get wo -n $PROJECT_CPD_INST_OPERANDS
This output will show the watsonx Orchestrate version as 5.3.1
oc get wo -n $PROJECT_CPD_INST_OPERANDS -o yaml | grep version:
This output shows the watsonx Orchestrate CR version as 7.1.1. Without the patch, the version will be 7.0.0.
These two outputs together define the criteria for applying this hotfix. The first command shows the watsonx Orchestrate version as 5.3.1, whereas the second command shows the watsonx Orchestrate CR version as 7.1.1, which represents the patch version.
export PROJECT_CPD_INST_OPERATORS=<enter your IBM Software Hub operator project>
export PROJECT_CPD_INST_OPERANDS=<enter your IBM Software Hub operand project>Install skopeo: https://github.com/containers/skopeo/blob/main/install.md
export LOCAL_REGISTRY="your_local_registry"
export LOCAL_USER="your_local_registry_username"
export LOCAL_PASS="your_local_registry_password"
export IBM_ENTITLEMENT_KEY="your_ibm_entitlement_key"
export AUTH_JSON_PATH="${HOME}/.airgap/auth.json"
mkdir -p "$(dirname "${AUTH_JSON_PATH}")"
skopeo login cp.icr.io --username cp --password "${IBM_ENTITLEMENT_KEY}" --authfile "${AUTH_JSON_PATH}"
skopeo login "${LOCAL_REGISTRY}" --username "${LOCAL_USER}" --password "${LOCAL_PASS}" --authfile "${AUTH_JSON_PATH}"Copy operator images
# ibm-watsonx-orchestrate-operator (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://icr.io/cpopen/ibm-watsonx-orchestrate-operator@sha256:e34c7accfb2422afe01b33156868d3d28be01b3bd47742a3daaddf4a66ff4215 \
docker://$LOCAL_REGISTRY/cpopen/ibm-watsonx-orchestrate-operator@sha256:e34c7accfb2422afe01b33156868d3d28be01b3bd47742a3daaddf4a66ff4215
Copy operand images
# tools-runtime (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/tools-runtime@sha256:ed47e51a756c9bce38f8c450815a9e15f76586dca6a472968bd321a13fd3d58e \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/tools-runtime@sha256:ed47e51a756c9bce38f8c450815a9e15f76586dca6a472968bd321a13fd3d58e
# tools-runtime-manager (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/tools-runtime-manager@sha256:a4d78ac6a6e1c074f87868f4c761c66c5c9cc948c438dac3b94e4f9f2340c5db \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/tools-runtime-manager@sha256:a4d78ac6a6e1c074f87868f4c761c66c5c9cc948c438dac3b94e4f9f2340c5db
# tools-runtime-scheduler (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/tools-runtime-scheduler@sha256:04999e93827b7ef0c2f8a907de4d94e2ac35d688bfed4679c193d3be6ee77f38 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/tools-runtime-scheduler@sha256:04999e93827b7ef0c2f8a907de4d94e2ac35d688bfed4679c193d3be6ee77f38
After copying, verify the images exist in $LOCAL_REGISTRY.
Create 5.3.1-patch2-hf0.sh with the contents below.
#!/bin/bash
# -----------------------------------------------------------------------------
# watsonx Orchestrate 5.3.1 Patch2 Hotfix
# - Verifies watsonx Orchestrate version from .status.versionStatus.status.
# - Images of Operators are replaced with the image from hotfix script.
# * HOTFIX_LABEL_VALUE for this hotfix is 5.3.1-patch2-hf0
# * If an existing label value matches x.x.x.x and is higher than HOTFIX_LABEL_VALUE,
# the script exits early after informing you
# - Deletes a fixed set of Jobs in the operands namespace and waits for all to reappear with
# new UIDs and succeed
# -----------------------------------------------------------------------------
# -----------------------------
# Helpers
# -----------------------------
ts() { date +"%Y-%m-%d %H:%M:%S"; }
require() {
command -v "$1" >/dev/null 2>&1 || { echo "[$(ts)] Missing required command: $1"; exit 1; }
}
get_wo_version() {
ns="$1"
oc get wo -n "$ns" -o jsonpath='{.items[0].status.versionStatus.status}' 2>/dev/null || true
}
get_wo_cr_version() {
ns="$1"
oc get wo -n "$ns" -o jsonpath='{.items[0].spec.version}' 2>/dev/null || true
}
# -----------------------------
# Patch operator deployment images
# -----------------------------
OPERATOR_IMAGES="icr.io/cpopen/ibm-watsonx-orchestrate-operator@sha256:e34c7accfb2422afe01b33156868d3d28be01b3bd47742a3daaddf4a66ff4215"
if [ -z "${PROJECT_CPD_INST_OPERATORS:-}" ]; then
echo "[ERROR] PROJECT_CPD_INST_OPERATORS is not set. Exiting."
exit 1
fi
# Required WO version
REQUIRED_WO_VERSION="${REQUIRED_WO_VERSION:-5.3.1}"
REQUIRED_WO_CR_VERSION="${REQUIRED_WO_CR_VERSION:-7.1.1}"
# -----------------------------
# Validations and version check
# -----------------------------
require oc
# Make sure oc login is done
if ! oc whoami &>/dev/null; then
echo "[$(ts)] Error: Not logged in to OpenShift"
exit 1
fi
echo "[$(ts)] Checking wo.status.versionStatus.status in ${PROJECT_CPD_INST_OPERANDS}"
WO_VER="$(get_wo_version "$PROJECT_CPD_INST_OPERANDS")"
WO_CR_VER="$(get_wo_cr_version "$PROJECT_CPD_INST_OPERANDS")"
# Check if versions match required versions
if [ "$WO_VER" != "$REQUIRED_WO_VERSION" ] || [ "$WO_CR_VER" != "$REQUIRED_WO_CR_VERSION" ]; then
echo "[$(ts)] Error: Version mismatch!"
echo "[$(ts)] WO Version: $WO_VER (required: $REQUIRED_WO_VERSION)"
echo "[$(ts)] WO CR Version: $WO_CR_VER (required: $REQUIRED_WO_CR_VERSION)"
exit 1
else
echo "[$(ts)] Version check passed: $WO_VER , CR version: $WO_CR_VER"
fi
# Hotfix label configuration
HOTFIX_LABEL_KEY="${HOTFIX_LABEL_KEY:-hotfix}"
HOTFIX_LABEL_VALUE="${HOTFIX_LABEL_VALUE:-5.3.1-patch2-hf0}"
WO_CR_NAME=wo
is_semver4() {
v="$1"
printf '%s' "$v" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'
}
# Backup dir for deployments
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CLUSTER_NAME="$(oc whoami --show-console | sed 's/.*console-openshift-console\.apps\.\([^.]*\)\..*/\1/')"
BACKUP_DIR="${SCRIPT_DIR}/wxo_deployment_backups/$CLUSTER_NAME"
mkdir -p "$BACKUP_DIR"
if [ -n "${OPERATOR_IMAGES:-}" ]; then
echo "[$(ts)] Updating operator deployment images in ${PROJECT_CPD_INST_OPERATORS}"
patched_deps=""
# Use a here-document to avoid subshell so patched_deps is preserved
while IFS= read -r img; do
[ -z "$img" ] && continue
# Extract base image name (e.g., ibm-wxo-component-operator)
base="$(basename "$img" | cut -d'@' -f1)"
echo "[$(ts)] Processing image: $img (base=$base)"
dep=""
case "$base" in
ibm-watsonx-orchestrate-operator)
dep="wo-operator"
;;
ibm-wxo-component-operator)
dep="ibm-wxo-componentcontroller-manager"
;;
*)
dep="$(oc -n "$PROJECT_CPD_INST_OPERATORS" get deploy --no-headers 2>/dev/null \
| grep "$base" | awk 'NR==1{print $1}')"
;;
esac
# Skip bundle/catalog images if they ever slip in
if echo "$base" | grep -Eq 'bundle|catalog'; then
echo "[$(ts)] Skipping $base (bundle/catalog image – not tied to deployment)"
continue
fi
if [ -z "$dep" ]; then
echo "[$(ts)] WARNING: no matching deployment found for $base — skipping"
continue
fi
# -----------------------------
# Backup deployment YAML
# -----------------------------
backup_file="${BACKUP_DIR}/${dep}-$(date +%Y%m%d%H%M%S).yaml"
if oc -n "$PROJECT_CPD_INST_OPERATORS" get deploy "$dep" -o yaml > "$backup_file" 2>/dev/null; then
echo "[$(ts)] Backed up deployment/$dep → $backup_file"
else
echo "[$(ts)] WARNING: failed to back up deployment/$dep"
fi
# Determine container name (assume first container is operator)
cname="$(oc -n "$PROJECT_CPD_INST_OPERATORS" get deploy "$dep" \
-o jsonpath='{.spec.template.spec.containers[0].name}' 2>/dev/null)"
if [ -z "$cname" ]; then
echo "[$(ts)] WARNING: cannot determine container name for $dep — skipping"
continue
fi
echo "[$(ts)] Patching deployment/$dep container '$cname' → $img"
if oc -n "$PROJECT_CPD_INST_OPERATORS" set image "deployment/$dep" "$cname=$img" >/dev/null 2>&1; then
echo "[$(ts)] ✓ Image updated for $dep"
patched_deps="$patched_deps $dep"
else
echo "[$(ts)] ✗ ERROR: failed to patch $dep"
fi
done <<EOF
$OPERATOR_IMAGES
EOF
# -----------------------------
# Label WO CR with configurable label and value
# -----------------------------
if [ -n "$WO_CR_NAME" ]; then
current_label="$(oc -n "$PROJECT_CPD_INST_OPERANDS" get wo "$WO_CR_NAME" -o jsonpath="{.metadata.labels.${HOTFIX_LABEL_KEY}}" 2>/dev/null || true)"
if [ "$current_label" = "$HOTFIX_LABEL_VALUE" ]; then
echo "[$(ts)] WO CR ${WO_CR_NAME} already labeled ${HOTFIX_LABEL_KEY}=${HOTFIX_LABEL_VALUE}"
else
echo "[$(ts)] Setting label ${HOTFIX_LABEL_KEY}=${HOTFIX_LABEL_VALUE} on WO CR ${WO_CR_NAME} in ns ${PROJECT_CPD_INST_OPERANDS}"
oc -n "$PROJECT_CPD_INST_OPERANDS" label wo "$WO_CR_NAME" "${HOTFIX_LABEL_KEY}=${HOTFIX_LABEL_VALUE}" --overwrite >/dev/null 2>&1 || true
new_label="$(oc -n "$PROJECT_CPD_INST_OPERANDS" get wo "$WO_CR_NAME" -o jsonpath="{.metadata.labels.${HOTFIX_LABEL_KEY}}" 2>/dev/null || true)"
if [ "$new_label" = "$HOTFIX_LABEL_VALUE" ]; then
echo "[$(ts)] Label set: ${HOTFIX_LABEL_KEY}=${HOTFIX_LABEL_VALUE}"
else
echo "[$(ts)] WARNING: could not confirm ${HOTFIX_LABEL_KEY}=${HOTFIX_LABEL_VALUE} label was set"
fi
fi
else
echo "[$(ts)] No WO CR found in ns ${PROJECT_CPD_INST_OPERANDS}, skipping label."
fi
# -----------------------------
# Verify patched deployments are healthy (1/1 or 2/2)
# -----------------------------
if [ -n "${patched_deps// /}" ]; then
echo "[$(ts)] Verifying rollout status for patched deployments..."
for dep in $patched_deps; do
echo "[$(ts)] Checking deployment/$dep..."
# Wait for rollout to complete
if oc -n "$PROJECT_CPD_INST_OPERATORS" rollout status deploy/"$dep" --timeout=300s; then
# Check Ready/Desired replica ratio
ratio="$(oc -n "$PROJECT_CPD_INST_OPERATORS" get deploy "$dep" \
-o jsonpath='{.status.readyReplicas}/{.status.replicas}' 2>/dev/null || echo '0/0')"
echo "[$(ts)] Ready/Desired: $ratio"
if [ "$ratio" = "1/1" ] || [ "$ratio" = "2/2" ]; then
echo "[$(ts)] ✓ Deployment $dep is healthy (pods up and running)."
else
echo "[$(ts)] ⚠ WARNING: Deployment $dep is not at 1/1 or 2/2; current $ratio"
fi
else
echo "[$(ts)] ✗ ERROR: rollout status for deployment/$dep did not complete successfully."
fi
done
else
echo "[$(ts)] No deployments were patched; skipping health verification."
fi
else
echo "[$(ts)] No OPERATOR_IMAGES specified — skipping operator image patch."
fi
# Let's delete the redis cronjob and and allow the operator to create a new equivalent one.
oc delete cronjob wo-watson-orchestrate-redis-cronjob --ignore-not-found
# -----------------------------
# Final message
# -----------------------------
echo "------------------------------------------------------------------"
echo "[$(ts)] 5.3.1-patch2-hf0 Hotfix steps completed."
echo "Backups saved under ${BACKUP_DIR}"
echo "Monitor the watsonx Orchestrate CR status by running:"
echo " oc get wo -n ${PROJECT_CPD_INST_OPERANDS} -o yaml | grep -E 'watsonxOrchestrateStatus|${HOTFIX_LABEL_KEY}'"
echo "Ensure the watsonx Orchestrate CR status is 'Completed' and label ${HOTFIX_LABEL_KEY}=${HOTFIX_LABEL_VALUE} is present."
echo "It will take another 15–20 minutes for the updated components to be applied and restarted."
echo "------------------------------------------------------------------"
Make the script executable:
chmod 775 5.3.1-patch2-hf0.shRun the script:
nohup sh 5.3.1-patch2-hf0.sh &Watch progress:
tail -f nohup.outVerify CR status and label:
oc get wo -n "${PROJECT_CPD_INST_OPERANDS}" -o yaml | grep hotfix
hotfix: 5.3.1-patch2-hf0Was this topic helpful?
Document Information
Modified date:
21 April 2026
UID
ibm17269038