Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
38 changes: 38 additions & 0 deletions .github/scripts/olm-smoke-diagnostics.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash
#
# Gather diagnostics after a failed OLM smoke test.
#
# Usage: olm-smoke-diagnostics.sh <namespace>

set -u +e
NAMESPACE="${1:?Usage: $0 <namespace>}"
OPERATOR_LABEL="app.kubernetes.io/name=lifecycle-agent-operator"

section() { echo ""; echo "=== $* ==="; }

section "Operator Pods"
oc get pods -n "${NAMESPACE}" -o wide 2>/dev/null

section "Operator Logs"
oc logs -l "${OPERATOR_LABEL}" \
-n "${NAMESPACE}" --tail=200 2>/dev/null

section "Events"
oc get events -n "${NAMESPACE}" --sort-by='.lastTimestamp' 2>/dev/null

section "IBU Status"
oc describe imagebasedupgrade upgrade 2>/dev/null

section "CSV Status"
oc get csv -n "${NAMESPACE}" -o yaml 2>/dev/null

section "CatalogSource Status"
oc get catalogsource -n "${NAMESPACE}" -o wide 2>/dev/null

section "InstallPlan Status"
oc get installplan -n "${NAMESPACE}" -o wide 2>/dev/null

section "Pods in openshift namespaces"
oc get pods -n "${NAMESPACE}" -o wide 2>/dev/null
oc get pods -n openshift-operator-lifecycle-manager -o wide 2>/dev/null
oc get pods -n openshift-marketplace -o wide 2>/dev/null
110 changes: 110 additions & 0 deletions .github/scripts/olm-smoke-verify.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/bin/bash
#
# Verify the lifecycle-agent operator after OLM installation.
# Checks CSV phase, deployment health, CRDs, RBAC, singletons, and CEL validation.
#
# Usage: olm-smoke-verify.sh <namespace>

set -euo pipefail

NAMESPACE="${1:?Usage: $0 <namespace>}"
OPERATOR_LABEL="app.kubernetes.io/name=lifecycle-agent-operator"

pass() { echo "PASS: $*"; }
fail() { echo "FAIL: $*"; exit 1; }
section() { echo ""; echo "=== $* ==="; }

section "Verifying CSV phase"
PHASE=$(oc get csv -n "${NAMESPACE}" -o jsonpath='{.items[0].status.phase}')
CSV_NAME=$(oc get csv -n "${NAMESPACE}" -o jsonpath='{.items[0].metadata.name}')
echo "CSV ${CSV_NAME}: phase=${PHASE}"
[ "${PHASE}" = "Succeeded" ] || fail "CSV phase is '${PHASE}', expected 'Succeeded'"
pass "CSV phase is Succeeded"

section "Verifying operator deployment"
oc rollout status deployment -l "${OPERATOR_LABEL}" \
-n "${NAMESPACE}" --timeout=120s
pass "Deployment rollout complete"

section "Verifying operator pod health"
POD_JSON=$(oc get pod -l "${OPERATOR_LABEL}" \
-n "${NAMESPACE}" -o json | jq '.items[0]')
POD=$(echo "${POD_JSON}" | jq -r '.metadata.name')
STATUS=$(echo "${POD_JSON}" | jq -r '.status.phase')
READY=$(echo "${POD_JSON}" | jq -r '.status.conditions[] | select(.type=="Ready") | .status')
RESTARTS=$(echo "${POD_JSON}" | jq -r '.status.containerStatuses[0].restartCount')
echo "Pod ${POD}: phase=${STATUS}, ready=${READY}, restarts=${RESTARTS}"
[ "${STATUS}" = "Running" ] || fail "Pod phase is '${STATUS}', expected 'Running'"
[ "${READY}" = "True" ] || fail "Pod readiness is '${READY}', expected 'True'"
[ "${RESTARTS}" = "0" ] || fail "Pod has ${RESTARTS} restart(s), expected 0"
pass "Operator pod healthy (Running, Ready, 0 restarts)"

section "Verifying CRDs"
for CRD in imagebasedupgrades.lca.openshift.io \
seedgenerators.lca.openshift.io \
ipconfigs.lca.openshift.io; do
oc get crd "${CRD}" > /dev/null
pass "CRD ${CRD} exists"
done

section "Verifying RBAC and metrics"
oc get sa lifecycle-agent-controller-manager -n "${NAMESPACE}" > /dev/null
pass "ServiceAccount exists"

for ROLE in lifecycle-agent-manager-role \
lifecycle-agent-imagebasedupgrade-editor-role \
lifecycle-agent-imagebasedupgrade-viewer-role \
lifecycle-agent-metrics-reader; do
oc get clusterrole "${ROLE}" > /dev/null
pass "ClusterRole ${ROLE} exists"
done

oc get clusterrolebinding lifecycle-agent-manager-rolebinding > /dev/null
pass "ClusterRoleBinding exists"

oc get service lifecycle-agent-controller-manager-metrics-service \
-n "${NAMESPACE}" > /dev/null
pass "Metrics Service exists"

section "Verifying auto-created singletons"
oc wait imagebasedupgrade upgrade --for=condition=Idle=True --timeout=120s
pass "IBU singleton 'upgrade' exists and is Idle"

oc get seedgenerator seedimage > /dev/null
pass "SeedGenerator singleton 'seedimage' exists"

oc get ipconfig ipconfig > /dev/null
pass "IPConfig singleton 'ipconfig' exists"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

section "Verifying CEL singleton name enforcement"

echo "Attempting to create IBU with wrong name (should fail)..."
if oc apply -f - 2>&1 <<'EOF'; then
apiVersion: lca.openshift.io/v1
kind: ImageBasedUpgrade
metadata:
name: wrong-name
spec:
stage: Idle
EOF
fail "IBU with wrong name was accepted (CEL validation not enforced)"
else
pass "IBU wrong-name correctly rejected"
fi

echo "Attempting to create SeedGenerator with wrong name (should fail)..."
if oc apply -f - 2>&1 <<'EOF'; then
apiVersion: lca.openshift.io/v1
kind: SeedGenerator
metadata:
name: wrong-name
spec:
seedImage: quay.io/example/seed:latest
recertImage: quay.io/example/recert:latest
EOF
fail "SeedGenerator with wrong name was accepted (CEL validation not enforced)"
else
pass "SeedGenerator wrong-name correctly rejected"
fi

section "All smoke test checks passed"
110 changes: 110 additions & 0 deletions .github/workflows/olm-smoke-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: OLM Smoke Test

on:
pull_request:
branches:
- main
- 'release-*'
paths-ignore:
- 'docs/**'
- '**/*.md'
- 'OWNERS'
- 'OWNERS_ALIASES'
- 'LICENSE'
- '.tekton/**'
- '.konflux/**'
- 'renovate.json'
- '.gitignore'
push:
branches:
- main
paths-ignore:
- 'docs/**'
- '**/*.md'
- 'OWNERS'
- 'OWNERS_ALIASES'
- 'LICENSE'
- '.tekton/**'
- '.konflux/**'
- 'renovate.json'
- '.gitignore'
workflow_dispatch:

jobs:
olm-smoke-test:
runs-on: ubuntu-24.04
timeout-minutes: 75
env:
REGISTRY_PORT: 5000
OPERATOR_IMG_NAME: lca-operator
BUNDLE_IMG_NAME: lca-bundle
IMG_TAG: smoke
OPERATOR_NAMESPACE: openshift-lifecycle-agent
INTERNAL_REGISTRY: image-registry.openshift-image-registry.svc:5000
steps:
- name: Checkout
uses: actions/checkout@v7
with:
submodules: true
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- name: Set up Go
uses: actions/setup-go@v7
with:
go-version-file: go.mod

- name: Start local registry
run: docker run -d --name registry --restart always -p ${REGISTRY_PORT}:5000 registry:2

- name: Determine host IP
run: echo "HOST_IP=$(hostname -I | awk '{print $1}')" >> "$GITHUB_ENV"

- name: Build operator image
run: |
make docker-build \
IMG="${HOST_IP}:${REGISTRY_PORT}/${OPERATOR_IMG_NAME}:${IMG_TAG}" \
ENGINE=docker \
GOARCH=amd64

- name: Push operator image to local registry
run: docker push "${HOST_IP}:${REGISTRY_PORT}/${OPERATOR_IMG_NAME}:${IMG_TAG}"

- name: Generate bundle manifests
run: |
make bundle \
IMG="${INTERNAL_REGISTRY}/openshift/${OPERATOR_IMG_NAME}:${IMG_TAG}"

- name: Build and push bundle image
run: |
docker build -f bundle.Dockerfile \
-t "${HOST_IP}:${REGISTRY_PORT}/${BUNDLE_IMG_NAME}:${IMG_TAG}" .
docker push "${HOST_IP}:${REGISTRY_PORT}/${BUNDLE_IMG_NAME}:${IMG_TAG}"

- name: Start OpenShift cluster
uses: palmsoftware/quick-ocp@v1
with:
desiredOCPVersion: "latest"
preloadImages: |
${{ env.HOST_IP }}:${{ env.REGISTRY_PORT }}/${{ env.OPERATOR_IMG_NAME }}:${{ env.IMG_TAG }}
${{ env.HOST_IP }}:${{ env.REGISTRY_PORT }}/${{ env.BUNDLE_IMG_NAME }}:${{ env.IMG_TAG }}

- name: Install operator via OLM
run: |
oc create namespace "${OPERATOR_NAMESPACE}" 2>/dev/null || true
./bin/operator-sdk run bundle \
"${INTERNAL_REGISTRY}/openshift/${BUNDLE_IMG_NAME}:${IMG_TAG}" \
--namespace "${OPERATOR_NAMESPACE}" \
--timeout 5m
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Comment thread
sebrandon1 marked this conversation as resolved.

- name: Verify operator
run: .github/scripts/olm-smoke-verify.sh "${OPERATOR_NAMESPACE}"

- name: Run operator-sdk scorecard
run: |
./bin/operator-sdk scorecard bundle/ \
--namespace "${OPERATOR_NAMESPACE}" \
--wait-time 120s \
--output text

- name: Gather diagnostics
if: failure()
run: .github/scripts/olm-smoke-diagnostics.sh "${OPERATOR_NAMESPACE}"
Loading