Skip to content

Commit 24fffa9

Browse files
authored
fix: wait for OLM v1 install readiness before success (#3284)
* fix: wait for OLM v1 install readiness before success Prevent silent success on OCP 4.18 when ClusterExtension is applied but the operator never installs; wait for Serving/Installed/CRD and fail with diagnostics. * fix: merge internal registry creds into global pull secret for OLM v1 Catalogd authenticates via openshift-config/pull-secret; image-puller alone left ClusterCatalog stuck on authentication required for the rebuilt IIB. * refactor: hardcode OLM v1 wait timeouts and soften registry route dependency Drop the unused OLM_V1_WAIT_TIMEOUT env knob; always merge internal registry auth into the global pull secret and only add the external default-route when present. * refactor: address review feedback on docs and OLM v1 helpers Shorten docs, drop brew naming from usage, slim failure diagnostics to resource status, and revert incidental render_iib/message churn. * fix: tighten OLM v1 readiness and derive image namespace Wait for the Backstage CRD Established condition, derive the IIB image project from the rebuilt registry ref for puller grants, and document the exact readiness gates.
1 parent 095451d commit 24fffa9

2 files changed

Lines changed: 153 additions & 14 deletions

File tree

.rhdh/docs/installing-ci-builds.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Besides the prerequisites listed above, you will also need:
3333

3434
==== Procedure
3535

36-
. Run the link:../scripts/install-rhdh-catalog-source.sh[installation script] to create the RHDH Operator CatalogSource in your cluster. By default, it installs the Release Candidate or GA version (from the `release-1.yy` branch), but the `--next` option allows to install the current development build (from the `main` branch). For example:
36+
. Run the link:../scripts/install-rhdh-catalog-source.sh[installation script] to create the RHDH Operator CatalogSource in your cluster. By default, it installs the Release Candidate or GA version (from the `release-1.yy` branch), but the `--next` option allows to install the current development build (from the `main` branch). The script auto-detects OLM v0 or v1 and, with `--install-operator`, waits for catalog Serving, extension Installed, and the Backstage CRD Established before exiting. For example:
3737
+
3838
[source,console]
3939
----

.rhdh/scripts/install-rhdh-catalog-source.sh

Lines changed: 152 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ This script streamlines testing IIB images by configuring an OpenShift or Kubern
5959
as a catalog source. On OLM v0, a CatalogSource is created in 'openshift-marketplace' (OpenShift) or 'olm' (Kubernetes). On OLM v1,
6060
a ClusterCatalog is created (cluster-scoped); when --install-operator is also provided, a ClusterExtension, ServiceAccount, and
6161
ClusterRoleBinding are created in the '${NAMESPACE_SUBSCRIPTION}' namespace. By default, the OLM version is auto-detected based on
62-
the presence of the ClusterExtension CRD. The default catalog/resource name is 'operatorName-channelName' (eg., rhdh-fast),
63-
or 'brew-registry-stage' when using --catalog-source with a brew IIB override
62+
the presence of the ClusterExtension CRD. When installing an operator, the script waits for readiness before exiting successfully.
63+
The default catalog/resource name is 'operatorName-channelName' (eg., rhdh-fast).
6464
6565
If IIB installation fails, see https://docs.engineering.redhat.com/display/CFC/Test and
6666
follow steps in section 'Adding Brew Pull Secret'
@@ -156,6 +156,107 @@ function resolve_olm_version() {
156156
fi
157157
}
158158

159+
# On failure, print ClusterCatalog / ClusterExtension status so CI logs show why Serving/Installed never became True.
160+
function dump_olm_v1_diagnostics() {
161+
local catalog_name="${1:-}"
162+
local extension_name="${2:-}"
163+
164+
errorf "===== OLM v1 diagnostics ====="
165+
[[ -n "${catalog_name}" ]] && invoke_cluster_cli describe clustercatalog "${catalog_name}" 2>&1 || true
166+
if [[ -n "${extension_name}" ]]; then
167+
invoke_cluster_cli describe clusterextension "${extension_name}" 2>&1 || true
168+
invoke_cluster_cli get clusterextension "${extension_name}" -o jsonpath='{.status.conditions}' 2>&1 || true
169+
echo
170+
fi
171+
errorf "===== end OLM v1 diagnostics ====="
172+
}
173+
174+
# OLM v1 catalogd authenticates via openshift-config/pull-secret (--global-pull-secret),
175+
# not ClusterCatalog pullSecret fields or image-puller alone.
176+
function prepare_olm_v1_secrets() {
177+
set -euo pipefail
178+
179+
local catalogd_ns="$1"
180+
local controller_ns="$2"
181+
local image_namespace="${3:-rhdh}"
182+
183+
if [[ "${IS_OPENSHIFT}" != "true" ]]; then
184+
return 0
185+
fi
186+
187+
local internal_registry_url="image-registry.openshift-image-registry.svc:5000"
188+
# External route is optional; ClusterCatalog pulls via the internal svc URL.
189+
local external_registry_url
190+
external_registry_url=$(oc get route default-route -n openshift-image-registry --template='{{ .spec.host }}' 2>/dev/null || true)
191+
192+
local token
193+
token=$(oc whoami -t)
194+
# macOS base64 has no -w0; Linux does. Strip newlines for both.
195+
local internal_auth
196+
internal_auth=$(echo -n "kubeadmin:${token}" | base64 | tr -d '\n')
197+
198+
local existing_pull_secret
199+
existing_pull_secret=$(oc get secret pull-secret -n openshift-config -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d)
200+
201+
local merged
202+
merged=$(echo "${existing_pull_secret}" | jq \
203+
--arg url "${internal_registry_url}" \
204+
--arg auth "${internal_auth}" \
205+
'.auths[$url] = {auth: $auth}')
206+
if [[ -n "${external_registry_url}" ]]; then
207+
merged=$(echo "${merged}" | jq \
208+
--arg url "${external_registry_url}" \
209+
--arg auth "${internal_auth}" \
210+
'.auths[$url] = {auth: $auth}')
211+
else
212+
warnf "OpenShift registry default-route not found; merged credentials for ${internal_registry_url} only"
213+
fi
214+
215+
echo "${merged}" | oc set data secret/pull-secret -n openshift-config --from-file=.dockerconfigjson=/dev/stdin >&2
216+
infof "Merged internal registry credentials into global pull secret (openshift-config/pull-secret)"
217+
218+
# Namespace-scoped secrets for the operator/installer SA (marketplace secrets already created by ocp_install).
219+
if ! invoke_cluster_cli get namespace "${NAMESPACE_SUBSCRIPTION}" &>/dev/null; then
220+
invoke_cluster_cli create namespace "${NAMESPACE_SUBSCRIPTION}" >&2
221+
fi
222+
invoke_cluster_cli -n "${NAMESPACE_SUBSCRIPTION}" delete secret internal-reg-auth-for-rhdh --ignore-not-found >&2
223+
invoke_cluster_cli -n "${NAMESPACE_SUBSCRIPTION}" create secret docker-registry internal-reg-auth-for-rhdh \
224+
--docker-server="${internal_registry_url}" \
225+
--docker-username=kubeadmin \
226+
--docker-password="${token}" \
227+
--docker-email="admin@internal-registry.example.com" >&2
228+
if [[ -n "${external_registry_url}" ]]; then
229+
invoke_cluster_cli -n "${NAMESPACE_SUBSCRIPTION}" delete secret internal-reg-ext-auth-for-rhdh --ignore-not-found >&2
230+
invoke_cluster_cli -n "${NAMESPACE_SUBSCRIPTION}" create secret docker-registry internal-reg-ext-auth-for-rhdh \
231+
--docker-server="${external_registry_url}" \
232+
--docker-username=kubeadmin \
233+
--docker-password="${token}" \
234+
--docker-email="admin@internal-registry-ext.example.com" >&2
235+
fi
236+
237+
local catalogd_sa
238+
catalogd_sa=$(invoke_cluster_cli get deployment -n "${catalogd_ns}" -l 'app.kubernetes.io/name=catalogd' \
239+
-o jsonpath='{.items[0].spec.template.spec.serviceAccountName}' 2>/dev/null || true)
240+
catalogd_sa="${catalogd_sa:-catalogd-controller-manager}"
241+
242+
local controller_sa
243+
controller_sa=$(invoke_cluster_cli get deployment -n "${controller_ns}" -l 'app.kubernetes.io/name=operator-controller' \
244+
-o jsonpath='{.items[0].spec.template.spec.serviceAccountName}' 2>/dev/null || true)
245+
controller_sa="${controller_sa:-operator-controller-controller-manager}"
246+
247+
# Image project for the rebuilt IIB (created by ocp_install); ensure it exists before grants.
248+
if ! oc get namespace "${image_namespace}" &>/dev/null; then
249+
oc create namespace "${image_namespace}" >&2
250+
fi
251+
252+
debugf "Granting image-puller in namespace '${image_namespace}' to OLM v1 service accounts"
253+
if ! oc policy add-role-to-user system:image-puller "system:serviceaccount:${catalogd_ns}:${catalogd_sa}" -n "${image_namespace}" || \
254+
! oc policy add-role-to-user system:image-puller "system:serviceaccount:${controller_ns}:${controller_sa}" -n "${image_namespace}"; then
255+
errorf "Failed to grant image-puller to OLM v1 controller SAs in namespace ${image_namespace}"
256+
return 1
257+
fi
258+
}
259+
159260
function render_iib() {
160261
set -euo pipefail
161262

@@ -1008,12 +1109,18 @@ if [[ "${RESOLVED_OLM_VERSION}" == "v1" ]]; then
10081109
fi
10091110
debugf "Using operator-controller namespace: ${NAMESPACE_OLM_CONTROLLER}"
10101111

1011-
# Grant image-puller access to OLM v1 controller SAs so they can pull images from the internal registry
1012-
if [[ "${IS_OPENSHIFT}" = "true" ]]; then
1013-
oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_CATALOGD}:catalogd-controller-manager" -n rhdh ||
1014-
warnf "Failed to grant image-puller to catalogd SA; catalog image pulls from internal registry may fail"
1015-
oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_OLM_CONTROLLER}:operator-controller-controller-manager" -n rhdh ||
1016-
warnf "Failed to grant image-puller to operator-controller SA; operator image pulls from internal registry may fail"
1112+
# OpenShift IIB is rebuilt into the internal registry under <project>/iib:...
1113+
# (ocp_install uses "rhdh"). Derive the project from the image ref instead of
1114+
# assuming the RHDH app deploy namespace (e.g. showcase).
1115+
IMAGE_NAMESPACE="rhdh"
1116+
if [[ "${newIIBImage}" =~ ^image-registry\.openshift-image-registry\.svc:5000/([^/]+)/ ]]; then
1117+
IMAGE_NAMESPACE="${BASH_REMATCH[1]}"
1118+
fi
1119+
debugf "Using image namespace for OLM v1 puller grants: ${IMAGE_NAMESPACE}"
1120+
1121+
if ! prepare_olm_v1_secrets "${NAMESPACE_CATALOGD}" "${NAMESPACE_OLM_CONTROLLER}" "${IMAGE_NAMESPACE}"; then
1122+
dump_olm_v1_diagnostics "${CATALOGSOURCE_NAME}"
1123+
exit 1
10171124
fi
10181125

10191126
# Delete existing ClusterCatalog to force re-index
@@ -1023,16 +1130,25 @@ if [[ "${RESOLVED_OLM_VERSION}" == "v1" ]]; then
10231130
kind: ClusterCatalog
10241131
metadata:
10251132
name: ${CATALOGSOURCE_NAME}
1133+
labels:
1134+
olm.operatorframework.io/metadata.name: ${CATALOGSOURCE_NAME}
10261135
spec:
10271136
source:
10281137
type: Image
10291138
image:
10301139
ref: ${newIIBImage}
10311140
" > "$TMPDIR"/ClusterCatalog.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterCatalog.yml
10321141

1142+
infof "Waiting for ClusterCatalog/${CATALOGSOURCE_NAME} Serving (timeout 300s)..."
1143+
if ! invoke_cluster_cli wait "clustercatalog/${CATALOGSOURCE_NAME}" --for=condition=Serving --timeout=300s; then
1144+
errorf "ClusterCatalog/${CATALOGSOURCE_NAME} did not become Serving within 300s (check openshift-config/pull-secret and image-puller RBAC if on OpenShift)"
1145+
dump_olm_v1_diagnostics "${CATALOGSOURCE_NAME}"
1146+
exit 1
1147+
fi
1148+
10331149
if [[ -z "${TO_INSTALL}" ]]; then
10341150
echo
1035-
echo "Done. ClusterCatalog '${CATALOGSOURCE_NAME}' created."
1151+
echo "Done. ClusterCatalog '${CATALOGSOURCE_NAME}' is Serving."
10361152
echo "To install the operator, create a ClusterExtension, ServiceAccount, and ClusterRoleBinding."
10371153
exit 0
10381154
fi
@@ -1070,10 +1186,12 @@ subjects:
10701186
namespace: ${NAMESPACE_SUBSCRIPTION}
10711187
" > "$TMPDIR"/ClusterRoleBinding.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterRoleBinding.yml
10721188

1073-
# Grant installer SA image-puller access so it can pull operator images from the internal registry
10741189
if [[ "${IS_OPENSHIFT}" = "true" ]]; then
1075-
oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_SUBSCRIPTION}:${SA_NAME}" -n rhdh ||
1076-
warnf "Failed to grant image-puller to installer SA '${SA_NAME}'; operator image pulls from internal registry may fail"
1190+
if ! oc policy add-role-to-user system:image-puller "system:serviceaccount:${NAMESPACE_SUBSCRIPTION}:${SA_NAME}" -n "${IMAGE_NAMESPACE}"; then
1191+
errorf "Failed to grant image-puller to installer SA '${SA_NAME}' in namespace ${IMAGE_NAMESPACE}"
1192+
dump_olm_v1_diagnostics "${CATALOGSOURCE_NAME}" "${OPERATOR_NAME_TO_INSTALL}"
1193+
exit 1
1194+
fi
10771195
fi
10781196

10791197
# Create ClusterExtension
@@ -1094,13 +1212,34 @@ spec:
10941212
selector:
10951213
matchLabels:
10961214
olm.operatorframework.io/metadata.name: ${CATALOGSOURCE_NAME}
1215+
install:
1216+
preflight:
1217+
crdUpgradeSafety:
1218+
enforcement: None
10971219
" > "$TMPDIR"/ClusterExtension.yml && invoke_cluster_cli apply -f "$TMPDIR"/ClusterExtension.yml
10981220

1221+
infof "Waiting for ClusterExtension/${OPERATOR_NAME_TO_INSTALL} Installed (timeout 300s)..."
1222+
if ! invoke_cluster_cli wait "clusterextension/${OPERATOR_NAME_TO_INSTALL}" --for=condition=Installed --timeout=300s; then
1223+
errorf "ClusterExtension/${OPERATOR_NAME_TO_INSTALL} did not become Installed within 300s"
1224+
dump_olm_v1_diagnostics "${CATALOGSOURCE_NAME}" "${OPERATOR_NAME_TO_INSTALL}"
1225+
exit 1
1226+
fi
1227+
1228+
# When installing RHDH, wait until the Backstage CRD is Established (not merely present).
1229+
if [[ "${OPERATOR_NAME_IN_CS}" == "rhdh" || "${OPERATOR_NAME_TO_INSTALL}" == "rhdh" ]]; then
1230+
infof "Waiting for CRD backstages.rhdh.redhat.com Established (timeout 300s)..."
1231+
if ! invoke_cluster_cli wait --for=condition=Established crd/backstages.rhdh.redhat.com --timeout=300s; then
1232+
errorf "CRD backstages.rhdh.redhat.com was not Established within 300s"
1233+
dump_olm_v1_diagnostics "${CATALOGSOURCE_NAME}" "${OPERATOR_NAME_TO_INSTALL}"
1234+
exit 1
1235+
fi
1236+
fi
1237+
10991238
# Post-install output
11001239
CLUSTER_ROUTER_BASE=$(invoke_cluster_cli get ingress.config.openshift.io/cluster '-o=jsonpath={.spec.domain}' 2>/dev/null || true)
11011240

11021241
echo "
1103-
Done. ClusterExtension '${OPERATOR_NAME_TO_INSTALL}' created via OLM v1.
1242+
Done. ClusterExtension '${OPERATOR_NAME_TO_INSTALL}' is Installed via OLM v1.
11041243
11051244
To create an RHDH instance:
11061245
${CR_EXAMPLE}

0 commit comments

Comments
 (0)