Skip to content
Merged
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
64 changes: 37 additions & 27 deletions .ci/images/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Base image from Microsoft Playwright
# Playwright v1.59.1-noble includes Node 24.14.1
FROM mcr.microsoft.com/playwright:v1.61.1-noble@sha256:824f1a789072e648c62541c2cfa4479c4061a290d5c27766d67dc1dcbc19b321
# Base image from Microsoft Playwright (multi-arch: amd64 + arm64)
# Playwright v1.61.1-noble includes Node 24.14.1
# Pinned to manifest list digest to support both platforms
FROM mcr.microsoft.com/playwright:v1.61.1-noble@sha256:5b8f294aff9041b7191c34a4bab3ac270157a28774d4b0660e9743297b697e48

Check notice

Code scanning / SonarCloud

Docker containers should not run as a privileged user Low

This image runs with "root" or "containerAdministrator" as the default user. Make sure it is safe here. See more on SonarQube Cloud

Check warning on line 4 in .ci/images/Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This image runs with "root" or "containerAdministrator" as the default user. Make sure it is safe here.

See more on https://sonarcloud.io/project/issues?id=redhat-developer_rhdh&issues=AZ8X0LE2BnJrKekKT7rL&open=AZ8X0LE2BnJrKekKT7rL&pullRequest=5036

Check warning on line 4 in .ci/images/Dockerfile

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use either the version tag or the digest for the image instead of both.

See more on https://sonarcloud.io/project/issues?id=redhat-developer_rhdh&issues=AZ8X0LE2BnJrKekKT7rM&open=AZ8X0LE2BnJrKekKT7rM&pullRequest=5036

# Automatically set by buildx/podman based on --platform (amd64 or arm64)
ARG TARGETARCH

# Set environment variables for the container
ENV CI=1 \
Expand All @@ -9,12 +13,9 @@
_MITSHM=0 \
NODE_PATH=/usr/local/lib/node_modules \
HELM_VERSION="v3.17.2" \
OC_VERSION="4.19.17" \
OC_VERSION="4.22.3" \
OCM_VERSION="0.1.76" \
GO_VERSION="1.19" \
GO_SHA256="464b6b66591f6cf055bc5df90a9750bf5fbc9d038722bb84a9d56a2bea974be6" \
GOPATH="/go" \
PATH="$GOPATH/bin:/usr/local/go/bin:$PATH"
UMOCI_VERSION="v0.6.0"

# Copy Yarn configuration files to correctly use the project-defined Yarn version
COPY .yarn /root/.yarn
Expand Down Expand Up @@ -52,15 +53,22 @@
# Check where Node.js loads required modules
node -p 'module.paths'

# Install Helm, OpenShift CLI, ocm-cli, and yq
RUN curl -fsSL -o /tmp/helm.tar.gz "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" && \
tar -xzvf /tmp/helm.tar.gz -C /tmp && mv /tmp/linux-amd64/helm /usr/local/bin/helm && \
curl -fsSL -o /tmp/openshift-client-linux.tar.gz "https://mirror.openshift.com/pub/openshift-v4/clients/ocp/${OC_VERSION}/openshift-client-linux-${OC_VERSION}.tar.gz" && \
# Install Helm, OpenShift CLI, oc-mirror, ocm-cli, and yq
# OC client: amd64 has no arch suffix (default), arm64 needs "-arm64".
# oc-mirror: arm64 lives under "openshift-v4/aarch64/" mirror tree.
RUN OC_ARCH_SUFFIX=$([ "${TARGETARCH}" = "arm64" ] && echo "-arm64" || echo "") && \
OC_MIRROR_TREE=$([ "${TARGETARCH}" = "arm64" ] && echo "openshift-v4/aarch64" || echo "openshift-v4") && \
curl -fsSL -o /tmp/helm.tar.gz "https://get.helm.sh/helm-${HELM_VERSION}-linux-${TARGETARCH}.tar.gz" && \
tar -xzvf /tmp/helm.tar.gz -C /tmp && mv /tmp/linux-${TARGETARCH}/helm /usr/local/bin/helm && \
curl -fsSL -o /tmp/openshift-client-linux.tar.gz "https://mirror.openshift.com/pub/openshift-v4/clients/ocp/${OC_VERSION}/openshift-client-linux${OC_ARCH_SUFFIX}-${OC_VERSION}.tar.gz" && \
tar -xzvf /tmp/openshift-client-linux.tar.gz -C /usr/local/bin oc kubectl && \
curl -Lo /usr/local/bin/ocm "https://github.com/openshift-online/ocm-cli/releases/download/v${OCM_VERSION}/ocm-linux-amd64" && \
curl -fsSL -o /tmp/oc-mirror.tar.gz "https://mirror.openshift.com/pub/${OC_MIRROR_TREE}/clients/ocp/${OC_VERSION}/oc-mirror.tar.gz" && \
tar -xzvf /tmp/oc-mirror.tar.gz -C /usr/local/bin oc-mirror && \
chmod +x /usr/local/bin/oc-mirror && \
curl -Lo /usr/local/bin/ocm "https://github.com/openshift-online/ocm-cli/releases/download/v${OCM_VERSION}/ocm-linux-${TARGETARCH}" && \
chmod +x /usr/local/bin/ocm && \
curl -fsSL "https://github.com/mikefarah/yq/releases/download/v4.43.1/yq_linux_amd64.tar.gz" | tar -xz && \
mv yq_linux_amd64 /usr/local/bin/yq && \
curl -fsSL "https://github.com/mikefarah/yq/releases/download/v4.43.1/yq_linux_${TARGETARCH}.tar.gz" | tar -xz && \
mv yq_linux_${TARGETARCH} /usr/local/bin/yq && \
rm -rf /tmp/* /var/tmp/*

# Install Azure CLI
Expand All @@ -74,29 +82,31 @@
apt-get install google-cloud-cli google-cloud-sdk-gke-gcloud-auth-plugin -y && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install AWS CLI
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
# Install AWS CLI (uname -m returns x86_64 on amd64, aarch64 on arm64 — matching AWS URL naming)
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip" -o "awscliv2.zip" && \
unzip awscliv2.zip && \
./aws/install
./aws/install && \
rm -rf awscliv2.zip aws/

# Install skopeo
# Install skopeo and podman
RUN apt-get update -y && \
apt-get install -y skopeo
apt-get install -y --no-install-recommends skopeo podman && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install PostgreSQL CLI (psql only)
RUN apt-get update && \
apt-get install -y --no-install-recommends postgresql-client && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# Install umoci
RUN curl -LO "https://github.com/opencontainers/umoci/releases/download/v0.4.7/umoci.amd64" && \
chmod +x umoci.amd64 && \
mv umoci.amd64 /usr/local/bin/umoci
# Install umoci (v0.6.0+ provides multi-arch binaries)
RUN curl -LO "https://github.com/opencontainers/umoci/releases/download/${UMOCI_VERSION}/umoci.linux.${TARGETARCH}" && \
chmod +x "umoci.linux.${TARGETARCH}" && \
mv "umoci.linux.${TARGETARCH}" /usr/local/bin/umoci

# Install opm
RUN curl -LO "https://github.com/operator-framework/operator-registry/releases/download/v1.47.0/linux-amd64-opm" && \
chmod +x linux-amd64-opm && \
mv linux-amd64-opm /usr/local/bin/opm
RUN curl -LO "https://github.com/operator-framework/operator-registry/releases/download/v1.47.0/linux-${TARGETARCH}-opm" && \
chmod +x "linux-${TARGETARCH}-opm" && \
mv "linux-${TARGETARCH}-opm" /usr/local/bin/opm

# Install Operator SDK CLI (required to install OLM on K8s clusters)
RUN export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac) && \
Expand Down
127 changes: 118 additions & 9 deletions .github/workflows/push-e2e-runner.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
name: Build & Push e2e-runner Image to Quay.io

on:
pull_request:
paths:
- '.ci/images/Dockerfile'
- '.yarnrc.yml'
push:
branches:
- main
- 'release-1.*'
- 'release-*'
paths:
- '.ci/images/Dockerfile'
- '.yarnrc.yml'
Expand All @@ -16,7 +20,7 @@ on:
default: 'NONE'

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
cancel-in-progress: true

env:
Expand All @@ -25,12 +29,17 @@ env:

jobs:
build-image:
name: Build & Push e2e-runner Image
name: Build e2e-runner (${{ matrix.os }})
env:
HAS_QUAY_AUTH: ${{ secrets.QUAY_USERNAME != '' && secrets.QUAY_TOKEN != '' }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04]
os:
- ubuntu-24.04
- ubuntu-24.04-arm
runs-on: ${{ matrix.os }}
timeout-minutes: 120
permissions:
contents: read
packages: write
Expand All @@ -44,41 +53,141 @@ jobs:
- name: Prepare Environment Variables
env:
INPUT_BRANCH: ${{ inputs.branch }}
PR_NUMBER: ${{ github.event.number }}
run: |
echo "PLATFORM=linux/amd64" >> $GITHUB_ENV
# Detect platform from runner's native architecture
arch=$(dpkg --print-architecture)
echo "PLATFORM=linux/${arch}" >> $GITHUB_ENV
echo "PLATFORM_PAIR=linux-${arch}" >> $GITHUB_ENV
echo "PLATFORM_ARCH=${arch}" >> $GITHUB_ENV

# create image tag from the correct branch (either from a push or a workflow_dispatch trigger)
# Create image tag from the correct branch (either from a push or a workflow_dispatch trigger)
if [[ "$INPUT_BRANCH" ]] && [[ "$INPUT_BRANCH" != "NONE" ]]; then
echo "Switch to $INPUT_BRANCH"
git checkout "$INPUT_BRANCH"
IMAGE_TAG="$INPUT_BRANCH"
elif [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
IMAGE_TAG="pr-${PR_NUMBER}"
else
echo "Use current branch $GITHUB_REF"
IMAGE_TAG=$(git rev-parse --abbrev-ref HEAD)
fi
echo "Use IMAGE_TAG = $IMAGE_TAG"
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV

- name: Check Quay credentials
if: github.event_name != 'pull_request'
run: |
if [ "$HAS_QUAY_AUTH" != "true" ]; then
echo "::error::Missing QUAY_USERNAME or QUAY_TOKEN secrets"
exit 1
fi

- name: Get the last commit short SHA
uses: ./.github/actions/get-sha

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0

- name: Login to Quay
if: github.event_name != 'pull_request'
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }}

- name: Build and Push Image
id: build-push
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
with:
context: .
file: .ci/images/Dockerfile
push: true
push: ${{ github.event_name != 'pull_request' }}
tags: |
${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}:${{ env.IMAGE_TAG }}
${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}:${{ env.IMAGE_TAG }}-${{ env.SHORT_SHA }}
${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}:${{ env.IMAGE_TAG }}-${{ env.PLATFORM_ARCH }}
Comment thread
zdrapela marked this conversation as resolved.
${{ env.REGISTRY }}/${{ env.REGISTRY_IMAGE }}:${{ env.IMAGE_TAG }}-${{ env.SHORT_SHA }}-${{ env.PLATFORM_ARCH }}
labels: |
quay.expires-after=1w
platforms: ${{ env.PLATFORM }}

- name: Export digest
if: github.event_name != 'pull_request'
env:
DIGEST: ${{ steps.build-push.outputs.digest }}
run: |
mkdir -p /tmp/digests
digest="$DIGEST"
touch "/tmp/digests/${digest#sha256:}"

- name: Upload digest
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1

merge:
name: Create multi-arch manifest
if: github.event_name != 'pull_request'
runs-on: ubuntu-24.04
Comment thread
zdrapela marked this conversation as resolved.
timeout-minutes: 20
needs: build-image
permissions:
contents: read
packages: write

steps:
- name: Checkout Repository
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
fetch-depth: 0

- name: Prepare Environment Variables
env:
INPUT_BRANCH: ${{ inputs.branch }}
run: |
if [[ "$INPUT_BRANCH" ]] && [[ "$INPUT_BRANCH" != "NONE" ]]; then
git checkout "$INPUT_BRANCH"
IMAGE_TAG="$INPUT_BRANCH"
else
IMAGE_TAG=$(git rev-parse --abbrev-ref HEAD)
fi
echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV

- name: Get the last commit short SHA
uses: ./.github/actions/get-sha

- name: Download digests
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0

- name: Login to Quay
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }}

- name: Create manifest list and push
working-directory: /tmp/digests
run: |
for tag in \
"${REGISTRY}/${REGISTRY_IMAGE}:${IMAGE_TAG}" \
"${REGISTRY}/${REGISTRY_IMAGE}:${IMAGE_TAG}-${SHORT_SHA}"; do
echo "Creating multi-arch manifest for: $tag"
docker buildx imagetools create -t "$tag" \
$(printf "${REGISTRY}/${REGISTRY_IMAGE}@sha256:%s " *)
Comment thread
zdrapela marked this conversation as resolved.
done

- name: Inspect image
run: |
docker buildx imagetools inspect "${REGISTRY}/${REGISTRY_IMAGE}:${IMAGE_TAG}"
3 changes: 2 additions & 1 deletion e2e-tests/container-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ set -e
if ! command -v vault &> /dev/null; then
VAULT_VERSION="${VAULT_VERSION:-1.15.4}"
log::info "Installing vault ${VAULT_VERSION}..."
curl -fsSL "https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip" -o /tmp/vault.zip
VAULT_ARCH=$(dpkg --print-architecture)
curl -fsSL "https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_${VAULT_ARCH}.zip" -o /tmp/vault.zip
unzip -q /tmp/vault.zip -d /usr/local/bin/
rm /tmp/vault.zip
fi
Expand Down
25 changes: 21 additions & 4 deletions e2e-tests/local-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RUNNER_IMAGE="quay.io/rhdh-community/rhdh-e2e-runner:main"
RUNNER_IMAGE="${RUNNER_IMAGE:-quay.io/rhdh-community/rhdh-e2e-runner:main}"
RUN_CONFIG_FILE="$SCRIPT_DIR/.local-test/run-config.env"

# Source logging library
Expand All @@ -23,6 +23,8 @@ Options:
-r, --repo IMAGE_REPO Image repository (e.g., rhdh/rhdh-hub-rhel9)
-t, --tag TAG_NAME Image tag (e.g., next, latest, 1.5)
-p, --pr PR_NUMBER PR number (sets repo to rhdh-community/rhdh, tag to pr-<number>)
-i, --runner-image IMG Override the e2e runner container image
(default: quay.io/rhdh-community/rhdh-e2e-runner:main)
-s, --skip-tests Deploy only, skip running tests
-h, --help Show this help message

Expand All @@ -45,6 +47,9 @@ Examples:
# Run on GKE
./local-run.sh -j periodic-ci-gke-helm-nightly -r rhdh/rhdh-hub-rhel9 -t next -s

# Use a locally built runner image
./local-run.sh --runner-image localhost/rhdh-e2e-runner:test

EOF
exit 0
}
Expand Down Expand Up @@ -73,6 +78,10 @@ while [[ $# -gt 0 ]]; do
CLI_TAG_NAME="pr-$2"
shift 2
;;
-i | --runner-image)
RUNNER_IMAGE="$2"
Comment thread
zdrapela marked this conversation as resolved.
shift 2
;;
-s | --skip-tests)
CLI_SKIP_TESTS="true"
shift
Expand Down Expand Up @@ -357,9 +366,16 @@ if [[ "$CLI_MODE" == "false" ]]; then
echo ""
fi

# Pull runner image first (can take a while)
# Pull runner image (always attempt; fall back to local copy if pull fails)
log::section "Pulling runner container image"
podman pull "$RUNNER_IMAGE" --platform=linux/amd64
if ! podman pull "$RUNNER_IMAGE"; then
if podman image exists "$RUNNER_IMAGE" 2>/dev/null; then
log::info "Pull failed but image exists locally: $RUNNER_IMAGE"
else
log::error "Failed to pull image and no local copy: $RUNNER_IMAGE"
exit 1
fi
fi

export VAULT_ADDR='https://vault.ci.openshift.org'

Expand Down Expand Up @@ -434,9 +450,10 @@ log::info "Container log: $CONTAINER_LOG"
echo ""

CONTAINER_EXIT_CODE=0
# no -t: stdout is piped to tee and CI has no TTY
podman run -v "$WORK_DIR":/tmp/rhdh \
-v "$SCRIPT_DIR/container-init.sh":/tmp/container-init.sh:ro \
-it -u root --privileged \
-i -u root --privileged \
Comment thread
zdrapela marked this conversation as resolved.
--mount type=tmpfs,destination=/tmp/secrets \
-e VAULT_ADDR="$VAULT_ADDR" \
-e VAULT_TOKEN="$VAULT_TOKEN" \
Expand Down
Loading