Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
496ba2f
feat(ci): add disconnected OCP smoke test for Helm and Operator
zdrapela Jun 26, 2026
a69732a
fix(ci): work around rhdh-operator yq install bug in disconnected ope…
zdrapela Jun 29, 2026
e88b2d5
fix(ci): unset REGISTRY_AUTH_FILE for oc-mirror and save artifacts
zdrapela Jun 29, 2026
77a0884
fix(ci): sanitize chart repo paths for IDMS and install podman for op…
zdrapela Jun 29, 2026
1002eff
fix(ci): fix helm init container image, podman install, and revert yq…
zdrapela Jun 29, 2026
7fd04b0
fix(disconnected): replace static helm-overrides with post-renderer
zdrapela Jun 30, 2026
6144843
fix(disconnected): use minimal values for helm smoke test
zdrapela Jun 30, 2026
eea16cb
fix(disconnected): mount mirror registry CA in init container
zdrapela Jun 30, 2026
74b2a53
fix(disconnected): use per-registry CA path for mirror TLS trust
zdrapela Jul 1, 2026
ceda5da
fix(disconnected): provide registry auth for init container
zdrapela Jul 1, 2026
18ab4be
refactor(disconnected): remove runtime tool installs (oc-mirror, podman)
zdrapela Jul 2, 2026
a54df09
fix(disconnected): skip signature verification for mirrored plugins
zdrapela Jul 2, 2026
a298b77
fix(disconnected): configure proxy for Playwright and skip signature …
zdrapela Jul 3, 2026
2df41ea
fix(disconnected): set BUILDAH_ISOLATION=chroot for operator handler
zdrapela Jul 4, 2026
d784cdb
fix(disconnected): parse proxy credentials and fix nested podman
zdrapela Jul 4, 2026
e24154a
fix(disconnected): disable lightspeed and orchestrator for smoke test
zdrapela Jul 13, 2026
6633232
fix(disconnected): mirror catalog index image and fix operator storage
zdrapela Jul 13, 2026
702a34e
fix(disconnected): write storage.conf to isolated path and reset podman
zdrapela Jul 13, 2026
fd82c10
fix(disconnected): pass proxy to global-setup and fix operator storage
zdrapela Jul 14, 2026
7ed7516
fix(disconnected): wait for MCP rollout and fix rootless podman storage
zdrapela Jul 14, 2026
5c25616
fix(disconnected): use entrypoint overlay config instead of VFS override
zdrapela Jul 14, 2026
7e4e26a
fix(disconnected): write overlay config at runtime HOME instead of VFS
zdrapela Jul 14, 2026
45d033f
fix(disconnected): use VFS with pre-created graphroot to avoid chown
zdrapela Jul 14, 2026
7b0befb
fix(disconnected): use oc-mirror for operator prepare to avoid nested…
zdrapela Jul 22, 2026
9e23b86
fix(disconnected): force OLM v0 with oc-mirror prepare path
zdrapela Jul 22, 2026
5b47e6a
fix(disconnected): use minimal Backstage CR for operator smoke
zdrapela Jul 22, 2026
2fa96d6
fix(disconnected): derive operator index image from cluster OCP version
zdrapela Jul 22, 2026
9954c09
fix(disconnected): pin prepare script for OLM v1 oc-mirror path
zdrapela Jul 22, 2026
7929a6d
refactor(disconnected): share MCP, plugin-mirror, and auth helpers
zdrapela Jul 22, 2026
cc90671
fix(disconnected): reuse CONTAINER_PLATFORM_VERSION for OLM index
zdrapela Jul 22, 2026
404b479
fix(disconnected): help OLM v1 pull mirrored operator images
zdrapela Jul 22, 2026
c8b4a50
fix(disconnected): trust mirror CA for OLM v1 catalogd pulls
zdrapela Jul 22, 2026
6c9b4de
fix(disconnected): mount mirror CA for operator plugin installs
zdrapela Jul 23, 2026
901d536
fix(disconnected): avoid unsupported yq --arg in operator CR render
zdrapela Jul 23, 2026
0becc3c
fix(disconnected): always fetch prepare script from operator PR head
zdrapela Jul 23, 2026
295c6d4
fix(disconnected): avoid duplicate extraFiles ConfigMap volumes
zdrapela Jul 23, 2026
b0cb855
fix(disconnected): mount registry auth where the image allows it
zdrapela Jul 23, 2026
083b4b5
fix(disconnected): disable lightspeed and skip catalog index for oper…
zdrapela Jul 24, 2026
d8300ca
fix(disconnected): use operator default hub image for smoke
zdrapela Jul 24, 2026
7134448
fix(disconnected): point operator smoke at mirrored catalog index
zdrapela Jul 24, 2026
41f186c
fix(disconnected): mirror CI hub for operator catalog defaults
zdrapela Jul 26, 2026
72f9376
fix(disconnected): drop broken dynamic-plugins ConfigMap path
zdrapela Jul 26, 2026
8f57e62
fix(disconnected): force mirrored hub on install-dynamic-plugins
zdrapela Jul 26, 2026
09442eb
chore(ci): fetch prepare-restricted from RELEASE_BRANCH_NAME
zdrapela Jul 27, 2026
75b7b72
fix(disconnected): digest-pin hub via CR patch and RELATED_IMAGE
zdrapela Jul 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 209 additions & 0 deletions .ci/pipelines/jobs/ocp-disconnected-helm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#!/bin/bash

# shellcheck source=.ci/pipelines/lib/log.sh
source "$DIR"/lib/log.sh
# shellcheck source=.ci/pipelines/lib/common.sh
source "$DIR"/lib/common.sh
# shellcheck source=.ci/pipelines/utils.sh
source "$DIR"/utils.sh
# shellcheck source=.ci/pipelines/lib/testing.sh
source "$DIR"/lib/testing.sh
# shellcheck source=.ci/pipelines/playwright-projects.sh
source "$DIR"/playwright-projects.sh
# shellcheck source=.ci/pipelines/lib/disconnected.sh
source "$DIR"/lib/disconnected.sh

export INSTALL_METHOD="helm"

handle_ocp_disconnected_helm() {
export NAME_SPACE="${NAME_SPACE:-showcase-ci-disconnected}"

disconnected::require_env
disconnected::setup_auth

common::oc_login

K8S_CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//')
export K8S_CLUSTER_ROUTER_BASE

log::section "Chart Resolution"

local is_ga="false"
if [[ "${IMAGE_REGISTRY}" == "registry.redhat.io" ]]; then
is_ga="true"
fi

if [[ "${is_ga}" == "true" ]]; then
helm repo add openshift-helm-charts https://charts.openshift.io 2> /dev/null || true
helm repo update openshift-helm-charts
log::info "Pulling GA chart from charts.openshift.io (version: ${RELEASE_VERSION})"
helm pull openshift-helm-charts/redhat-developer-hub \
--version "${RELEASE_VERSION}" \
-d "${DISCONNECTED_TMPDIR}" || {
log::error "Failed to pull chart from charts.openshift.io"
return 1
}
else
log::info "Pulling CI chart from ${HELM_CHART_URL} (version: ${CHART_VERSION})"
helm pull "${HELM_CHART_URL}" --version "${CHART_VERSION}" \
-d "${DISCONNECTED_TMPDIR}" || {
log::error "Failed to pull chart from ${HELM_CHART_URL}"
return 1
}
fi

CHART_LOCAL_TGZ=$(find "${DISCONNECTED_TMPDIR}" -maxdepth 1 -name '*.tgz' | head -1)
export CHART_LOCAL_TGZ

if [[ -z "${CHART_LOCAL_TGZ}" ]]; then
log::error "No chart .tgz found in ${DISCONNECTED_TMPDIR}"
return 1
fi
log::success "Chart pulled: ${CHART_LOCAL_TGZ}"

# Resolve PostgreSQL image from chart values
local helm_values
helm_values=$(helm show values "${CHART_LOCAL_TGZ}" 2> /dev/null || true)

export PG_REGISTRY PG_REPO PG_TAG PG_SEPARATOR
PG_REGISTRY=$(echo "${helm_values}" | yq '.upstream.postgresql.image.registry' || true)
PG_REPO=$(echo "${helm_values}" | yq '.upstream.postgresql.image.repository' || true)
PG_TAG=$(echo "${helm_values}" | yq '.upstream.postgresql.image.tag' || true)
PG_REGISTRY="${PG_REGISTRY:-registry.redhat.io}"
PG_REPO="${PG_REPO:-rhel9/postgresql-15}"
PG_TAG="${PG_TAG:-latest}"

# The chart encodes digest refs as repository: "repo@sha256" + tag: "<hash>".
# Normalize: extract the digest qualifier into PG_SEPARATOR so that:
# - PG_REPO is always a clean path (usable in IDMS source/mirror fields)
# - Full ref is ${PG_REGISTRY}/${PG_REPO}${PG_SEPARATOR}${PG_TAG}
PG_SEPARATOR=":"
if [[ "${PG_REPO}" == *"@"* ]]; then
PG_SEPARATOR="@${PG_REPO##*@}:" # e.g., "@sha256:"
PG_REPO="${PG_REPO%@*}" # e.g., "rhel9/postgresql-15"
fi

log::info "PostgreSQL image from chart: ${PG_REGISTRY}/${PG_REPO}${PG_SEPARATOR}${PG_TAG}"

# Resolve catalog index image (same digest encoding as PG).
# The init container pulls this by digest; it must be in the mirror.
export CI_REGISTRY CI_REPO CI_TAG CI_SEPARATOR
CI_REGISTRY=$(echo "${helm_values}" | yq '.global.catalogIndex.image.registry' || true)
CI_REPO=$(echo "${helm_values}" | yq '.global.catalogIndex.image.repository' || true)
CI_TAG=$(echo "${helm_values}" | yq '.global.catalogIndex.image.tag' || true)
CI_REGISTRY="${CI_REGISTRY:-quay.io}"
CI_REPO="${CI_REPO:-rhdh/plugin-catalog-index}"
CI_TAG="${CI_TAG:-latest}"
CI_SEPARATOR=":"
if [[ "${CI_REPO}" == *"@"* ]]; then
CI_SEPARATOR="@${CI_REPO##*@}:"
CI_REPO="${CI_REPO%@*}"
fi
log::info "Catalog index from chart: ${CI_REGISTRY}/${CI_REPO}${CI_SEPARATOR}${CI_TAG}"

echo "${helm_values}" > "${ARTIFACT_DIR}/disconnected-helm-chart-values.yaml" 2> /dev/null || true

log::section "Image Mirroring"

local imageset_config="${DISCONNECTED_TMPDIR}/imageset-config.yaml"
disconnected::build_imageset_config "${imageset_config}" || {
log::error "Failed to build ImageSetConfiguration"
return 1
}

local workspace="${DISCONNECTED_TMPDIR}/oc-mirror-workspace"
disconnected::run_oc_mirror "${imageset_config}" "${workspace}" || {
log::error "oc-mirror failed — aborting"
return 1
}

log::section "Cluster Resources"

disconnected::patch_idms "${OC_MIRROR_IDMS_FILE}"

oc apply -f "${OC_MIRROR_IDMS_FILE}" || {
log::error "Failed to apply IDMS — aborting"
return 1
}
log::success "ImageDigestMirrorSet applied"

if [[ -n "${OC_MIRROR_ITMS_FILE:-}" ]]; then
oc apply -f "${OC_MIRROR_ITMS_FILE}" || {
log::error "Failed to apply ITMS — aborting"
return 1
}
log::success "ImageTagMirrorSet applied"
fi

# IDMS/ITMS changes trigger a MachineConfig update which rolls worker nodes
# (drain → apply config → reboot). Wait for all MachineConfigPools to finish
# before deploying workloads, otherwise pods get evicted mid-startup.
disconnected::wait_mcp_updated

log::section "Plugin Mirroring"
disconnected::mirror_plugins || return 1

log::section "Namespace and Secrets"

namespace::configure "${NAME_SPACE}"
disconnected::apply_plugin_mirror_configmap "${NAME_SPACE}" || return 1

# Mirror CA + registry auth for install-dynamic-plugins (skopeo).
# Post-renderer mounts CA at /etc/containers/certs.d/<registry>/ca.crt;
# the chart mounts ${RELEASE_NAME}-dynamic-plugins-registry-auth at
# /opt/app-root/src/.config/containers.
disconnected::create_mirror_registry_ca_configmap "${NAME_SPACE}" || return 1
disconnected::create_plugin_registry_auth_secret "${NAME_SPACE}" || return 1

log::section "Helm Deployment"

# Prefer the chart from oc-mirror workspace, fall back to the pulled tgz
local chart_install_path
chart_install_path="${OC_MIRROR_CHART_PATH:-${CHART_LOCAL_TGZ}}"
log::info "Installing chart from: ${chart_install_path}"

local helm_set_flags=(
--set global.clusterRouterBase="${K8S_CLUSTER_ROUTER_BASE}"
--set upstream.backstage.image.registry="${MIRROR_REGISTRY_URL}"
--set upstream.backstage.image.repository="${IMAGE_REPO}"
--set upstream.backstage.image.tag="${TAG_NAME}"
--set upstream.postgresql.image.registry="${MIRROR_REGISTRY_URL}"
)

if [[ -n "${CATALOG_INDEX_IMAGE:-}" ]]; then
helm_set_flags+=(
--set global.catalogIndex.image.registry="${MIRROR_REGISTRY_URL}"
--set global.catalogIndex.image.repository="${CATALOG_INDEX_REPO}"
--set global.catalogIndex.image.tag="${CATALOG_INDEX_TAG}"
)
fi

# Post-renderer appends disconnected volumes (registries.conf, mirror CA)
# to the rendered Deployment, avoiding the Helm "array clobber" pitfall.
local post_renderer="${DIR}/resources/disconnected/helm-post-renderer.sh"

helm upgrade -i "${RELEASE_NAME}" -n "${NAME_SPACE}" \
"${chart_install_path}" \
-f "${DIR}/value_files/values_disconnected-smoke.yaml" \
--post-renderer "${post_renderer}" \
--post-renderer-args "${MIRROR_REGISTRY_URL}" \
"${helm_set_flags[@]}" || {
log::error "Helm deployment failed"
return 1
}

log::success "RHDH deployed via Helm with mirrored images"

printf '%s\n' "${helm_set_flags[@]}" > "${ARTIFACT_DIR}/disconnected-helm-set-flags.txt" 2> /dev/null || true

log::section "Smoke Test"

if [[ -n "${HTTPS_PROXY:-}" ]]; then
log::info "HTTPS_PROXY is set (Playwright will use it): ${HTTPS_PROXY%%@*}@***"
fi

local url="https://${RELEASE_NAME}-developer-hub-${NAME_SPACE}.${K8S_CLUSTER_ROUTER_BASE}"
testing::check_and_test "${RELEASE_NAME}" "${NAME_SPACE}" "${PW_PROJECT_SMOKE_TEST}" "${url}"

log::success "Disconnected Helm smoke test completed"
}
Loading
Loading