Fix Readme
Abstract
Apply this hotfix after completing the watsonx Orchestrate installation for Version 5.3.1, or after upgrading from a previous release to Version 5.3.1.
Content
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:5e75fea5876911150642c2701fd4a67f63cf3d43adfc3c78cdbd7e8ed94b952c \
docker://$LOCAL_REGISTRY/cpopen/ibm-watsonx-orchestrate-operator@sha256:5e75fea5876911150642c2701fd4a67f63cf3d43adfc3c78cdbd7e8ed94b952c
# ibm-wxo-component-operator (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://icr.io/cpopen/ibm-wxo-component-operator@sha256:c8bcd00b379fd85db5861c966358b536cd2da89c002fe3b58035b7c46c1f270a \
docker://$LOCAL_REGISTRY/cpopen/ibm-wxo-component-operator@sha256:c8bcd00b379fd85db5861c966358b536cd2da89c002fe3b58035b7c46c1f270a
Copy operand images
# agent-analytics
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/agent-analytics@sha256:c33fb77bc077dfa5e21da855f992e900e205191c9c19135d1c51060184286259 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/agent-analytics@sha256:c33fb77bc077dfa5e21da855f992e900e205191c9c19135d1c51060184286259
# ai-gateway
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/ai-gateway@sha256:b92882311a6b39bccf534ac55b2c4d2f5753ef6f7624862804bb9f9e72b5b965 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/ai-gateway@sha256:b92882311a6b39bccf534ac55b2c4d2f5753ef6f7624862804bb9f9e72b5b965
# channel-integrations (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/channel-integrations@sha256:ec9ba7f1abdd53e0e86b9c62b0fba6a1c2f10654089c4cb56c0c87156b91a81c \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/channel-integrations@sha256:ec9ba7f1abdd53e0e86b9c62b0fba6a1c2f10654089c4cb56c0c87156b91a81c
# data-exhaust-producer
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/data-exhaust-producer@sha256:924b0e206d6c3937c700710c457f19e5cc8b220e8b44541e19b5d453ae945316 \
docker://${LOCAL_REGISTRY}/cp/data-exhaust-producer@sha256:924b0e206d6c3937c700710c457f19e5cc8b220e8b44541e19b5d453ae945316
# platformuiproxy (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/platformuiproxy@sha256:808527ae6dd82d48935e5f7272abd81cfaf26599cedfff340a33a588086fe719 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/platformuiproxy@sha256:808527ae6dd82d48935e5f7272abd81cfaf26599cedfff340a33a588086fe719
# skill-server
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/skill-server@sha256:1c09616441bd87e0bd983900098e078efb188f7c2122df615dbc4d0e00c26418 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/skill-server@sha256:1c09616441bd87e0bd983900098e078efb188f7c2122df615dbc4d0e00c26418
# socket-handler
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/socket-handler@sha256:a6097d3383d3737563b782e25bb7486d4019d88f7a3d82020f49bbe3c407f7b6 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/socket-handler@sha256:a6097d3383d3737563b782e25bb7486d4019d88f7a3d82020f49bbe3c407f7b6
# 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:6ba4c52e1ba66ca44b9c07d70991b11bdc2035b1de4f64d43443094033ff7460 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/tools-runtime@sha256:6ba4c52e1ba66ca44b9c07d70991b11bdc2035b1de4f64d43443094033ff7460
# 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:038237c823419c99b73a4ca632628d286c835cdeb986b8258f336b9fe1741181 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/tools-runtime-manager@sha256:038237c823419c99b73a4ca632628d286c835cdeb986b8258f336b9fe1741181
# tools-runtime-scheduler (chnaged)
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:ebd1bda0c347807c2ad10386360f811a4fee46413bb85d39562bad28d70affbd \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/tools-runtime-scheduler@sha256:ebd1bda0c347807c2ad10386360f811a4fee46413bb85d39562bad28d70affbd
# wo-ootb-primitive-skills
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/wo-ootb-primitive-skills@sha256:faabf8d9626ced20e9d7df15924e0fa5668708ffff828fe104db056a449ab435 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/wo-ootb-primitive-skills@sha256:faabf8d9626ced20e9d7df15924e0fa5668708ffff828fe104db056a449ab435
# wxo-builder
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/wxo-builder@sha256:e82d782102ffc1ec09c797c2a70ca9f008ed972fe2ce0bd4d5f9f57c89cff0a6 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/wxo-builder@sha256:e82d782102ffc1ec09c797c2a70ca9f008ed972fe2ce0bd4d5f9f57c89cff0a6
# wxo-chat (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/wxo-chat@sha256:d91f2f4ca0cbb07a4f6ac489da7211c8ae10be81b5cce7b671c29410cf7c62c2 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/wxo-chat@sha256:d91f2f4ca0cbb07a4f6ac489da7211c8ae10be81b5cce7b671c29410cf7c62c2
# wxo-connections
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/wxo-connections@sha256:d966cee6c82fd7418f7c7ab4fc4ac0cc090f05cd47b2baa2c45737a879586dd3 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/wxo-connections@sha256:d966cee6c82fd7418f7c7ab4fc4ac0cc090f05cd47b2baa2c45737a879586dd3
# wxo-flow-runtime
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/wxo-flow-runtime@sha256:7b2e14c456e062a7a6ba4c044db1ab6b714748a4f293a7f281377e69aba85bdf \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/wxo-flow-runtime@sha256:7b2e14c456e062a7a6ba4c044db1ab6b714748a4f293a7f281377e69aba85bdf
# wxo-server-conversation_controller (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/wxo-server-conversation_controller@sha256:06214fa30eb8ea02a5312061328d69aad7482f5a4a1a44c488171aa5f6d43ce7 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/wxo-server-conversation_controller@sha256:06214fa30eb8ea02a5312061328d69aad7482f5a4a1a44c488171aa5f6d43ce7
# wxo-server-server (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/wxo-server-server@sha256:db2f9d5313cc2b6a9b01ab47d8ead0741d1a57f64aa6363c937257ada75da4f5 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/wxo-server-server@sha256:db2f9d5313cc2b6a9b01ab47d8ead0741d1a57f64aa6363c937257ada75da4f5
# wxo-server-voice (changed)
skopeo copy --all --authfile "${AUTH_JSON_PATH}" --dest-tls-verify=false --src-tls-verify=false \
docker://cp.icr.io/cp/watsonx-orchestrate/wxo-server-voice@sha256:ef5f061b98ed533ea6a863eec2cb57ec64aa48a68685ec535a1f9dc6715530d7 \
docker://${LOCAL_REGISTRY}/cp/watsonx-orchestrate/wxo-server-voice@sha256:ef5f061b98ed533ea6a863eec2cb57ec64aa48a68685ec535a1f9dc6715530d7After copying, verify the images exist in $LOCAL_REGISTRY.
Create hotfix5314.sh with the contents below.
#!/bin/bash
# -----------------------------------------------------------------------------
# watsonx Orchestrate 5.3.1 Hotfix
# - Verifies watsonx Orchestrate version from .status.versionStatus.status.
# - Images of Operators are replaced with the image from hotfix script.
# * HOTFIX_LABEL_VALUE for hotfix 3 is 5.3.1.4
# * 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:5e75fea5876911150642c2701fd4a67f63cf3d43adfc3c78cdbd7e8ed94b952c
icr.io/cpopen/ibm-wxo-component-operator@sha256:c8bcd00b379fd85db5861c966358b536cd2da89c002fe3b58035b7c46c1f270a"
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.0}"
# -----------------------------
# 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.4}"
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 Hotfix4 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 hotfix5314.shRun the script:
nohup sh hotfix5314.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.4
[{"Type":"MASTER","Line of Business":{"code":"LOB76","label":"Data Platform"},"Business Unit":{"code":"BU048","label":"IBM Software"},"Product":{"code":"SSVAUS","label":"IBM watsonx Orchestrate Cartridge for IBM Cloud Pak for Data"},"ARM Category":[{"code":"a8mKe0000008OVAIA2","label":"Operate-\u003EInstall"}],"Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":""}]
Was this topic helpful?
Document Information
Modified date:
21 May 2026
UID
ibm17273655