From 3c1ff21ff850cd55348d1e20cdb2735eb743913e Mon Sep 17 00:00:00 2001 From: Jeremy Poulin Date: Thu, 6 Aug 2026 18:15:06 -0400 Subject: [PATCH] Add operator payload builder scripts Build scripts for creating custom OCP payloads with operator image overrides. Allows testing custom operator code before merging upstream. Features: - build-operators.sh: Build and push operator images to registry - ocp-create-payload: Create custom payload with operator overrides - Configurable operator profiles via operators.conf - Template files for user configuration Co-Authored-By: Claude Sonnet 4.5 Signed-off-by: Jeremy Poulin --- helpers/README.md | 21 + helpers/operator-payload/.gitignore | 3 + helpers/operator-payload/README.md | 221 +++++++++++ helpers/operator-payload/build-operators.sh | 365 ++++++++++++++++++ helpers/operator-payload/ocp-create-payload | 287 ++++++++++++++ .../operator-payload/operators.conf.template | 34 ++ helpers/operator-payload/profile.env.template | 11 + 7 files changed, 942 insertions(+) create mode 100644 helpers/operator-payload/.gitignore create mode 100644 helpers/operator-payload/README.md create mode 100755 helpers/operator-payload/build-operators.sh create mode 100755 helpers/operator-payload/ocp-create-payload create mode 100644 helpers/operator-payload/operators.conf.template create mode 100644 helpers/operator-payload/profile.env.template diff --git a/helpers/README.md b/helpers/README.md index 63e3476c..8a904af2 100644 --- a/helpers/README.md +++ b/helpers/README.md @@ -10,6 +10,7 @@ This directory contains multiple helper tools for various OpenShift cluster oper - **Fencing Validation**: Tools for validating two-node cluster fencing configuration and health - **arm64 Metal3 Image Builder**: Builds arm64 variants of Metal3 images for aarch64 hypervisors (Graviton) - **Custom OCP 5.x payload (optional)**: `resource-agents-build/custom-payload.sh` to build a custom RHCOS layer from the resource-agents RPM and publish a custom release image with `oc adm release new` +- **Operator Payload Builder**: `operator-payload/` scripts to build custom OCP payloads with operator overrides for testing ## Requirements @@ -397,6 +398,26 @@ ex: } ``` +### Operator Payload Builder + +Build custom OCP payloads with operator overrides for testing custom operator code. + +**Location:** `operator-payload/` + +**Usage:** + +```bash +cd helpers/operator-payload + +# Build operator image and push to registry +./build-operators.sh ceo + +# Create custom payload with operator override +./ocp-create-payload ceo -b -o +``` + +**See:** `operator-payload/README.md` for detailed documentation + ## Notes - Both tools use `rpm-ostree override replace` which is appropriate for updating existing packages diff --git a/helpers/operator-payload/.gitignore b/helpers/operator-payload/.gitignore new file mode 100644 index 00000000..09b60de2 --- /dev/null +++ b/helpers/operator-payload/.gitignore @@ -0,0 +1,3 @@ +# User-specific configuration files +profile.env +operators.conf diff --git a/helpers/operator-payload/README.md b/helpers/operator-payload/README.md new file mode 100644 index 00000000..1463db18 --- /dev/null +++ b/helpers/operator-payload/README.md @@ -0,0 +1,221 @@ +## Custom OCP Payload with Operator Overrides + +Build custom operator images and create an OCP payload with those overrides for testing. + +## Prerequisites + +- **Required Tools**: `bash`, `git`, `podman`, `oc` +- **Registry Access**: + - Read access to `registry.ci.openshift.org` (OCP CI builds) + - Write access to your target registry (e.g., `quay.io/`) +- **Credentials**: Valid `REGISTRY_AUTH_FILE` with both CI and target registry credentials +- **Operator Repositories**: Local clones of operators you want to build + +## Quick Start + +```bash +# 0. Setup configuration (first time only) +cp profile.env.template profile.env +cp operators.conf.template operators.conf +# Edit both files with your settings + +# 1. Build operator images +./build-operators.sh ceo + +# 2. Create custom payload with overrides +./ocp-create-payload ceo -b registry.ci.openshift.org/ocp/release-5:5.0.0-0.nightly-YYYY-MM-DD-HHMMSS + +# 3. Deploy cluster with custom payload +# (see "Using the Custom Payload" section) +``` + +## Workflow + +### Step 0: Setup Configuration (First Time) + +Copy template files and customize for your environment: + +```bash +# Copy templates +cp profile.env.template profile.env +cp operators.conf.template operators.conf + +# Edit profile.env - set your quay.io namespace +vi profile.env + +# Edit operators.conf - set paths to your operator repos +vi operators.conf +``` + +### Step 1: Configure Operator Profiles + +Edit `operators.conf` to define your operators: + +```ini +[ceo] +name=cluster-etcd-operator +repo=/path/to/your/cluster-etcd-operator +dockerfile=Dockerfile.ocp +default_branch=main + +[cno] +name=cluster-network-operator +repo=/path/to/your/cluster-network-operator +dockerfile=Dockerfile +default_branch=master +``` + +### Step 2: Configure Registry Settings + +Edit `profile.env` with your settings: + +```bash +# Registry namespace for built images (REQUIRED) +QUAY_NAMESPACE="quay.io/" + +# Image tag +IMAGE_TAG=latest + +# Target custom payload image +TARGET_IMAGE="quay.io//custom-ocp-payload:5.0-test" + +# Pull secret location +export REGISTRY_AUTH_FILE=~/.config/containers/auth.json +``` + +### Step 3: Build Operator Images + +Build one or more operators: + +```bash +# Build single operator +./build-operators.sh ceo + +# Build multiple operators +./build-operators.sh ceo cno + +# Override namespace/tag +./build-operators.sh ceo -n quay.io/myrepo -t dev + +# Verbose mode +./build-operators.sh ceo -v +``` + +The script will: +1. Check registry access to `registry.ci.openshift.org` +2. Build each operator image using podman +3. Tag images to your registry namespace +4. Push images to registry + +### Step 4: Create Custom Payload + +Generate a custom OCP payload with your operator overrides: + +```bash +# Specify base release (required if SNO config not present) +./ocp-create-payload ceo -b registry.ci.openshift.org/ocp/release-5:5.0.0-0.nightly-2026-07-01-125918 + +# Use built images from operators.conf (auto-detects base from SNO config if available) +./ocp-create-payload ceo + +# Override target payload image +./ocp-create-payload ceo -o quay.io/myrepo/custom:test + +# Override namespace/tag for operator images +./ocp-create-payload ceo cno -n quay.io/myrepo -t dev +``` + +The script will: +1. Look up image names for each profile in `operators.conf` +2. Generate image override arguments +3. Detect base OCP release from SNO config or use `-b` flag +4. Create custom payload with `oc adm release new` + +### Step 5: Using the Custom Payload + +#### Option A: Update SNO Config + +Edit `../../deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_sno.sh`: + +```bash +export OPENSHIFT_RELEASE_IMAGE=quay.io//custom-ocp-payload:5.0-test +``` + +Then deploy normally with dev-scripts. + +#### Option B: Extract oc Client + +```bash +# Extract oc CLI from custom payload +oc adm release extract --tools quay.io//custom-ocp-payload:5.0-test + +# Or just the oc command +oc adm release extract --command=oc --to=/usr/local/bin quay.io//custom-ocp-payload:5.0-test +``` + +## Registry Configuration + +### Configure quay.io Credentials + +On your quay.io account (legacy UI): + +1. Click _your name > Account Settings_ +2. Click _Generate encrypted password_ and enter password +3. Go to _Docker Configuration_ tab +4. Click _View \-auth.json_ +5. Copy the `"quay.io": { "auth": ... }` block +6. Add to your pull-secret as `"quay.io/username"` (avoids conflict with main quay.io entry) + +### Configure CI Registry Access + +For OCP nightly builds from `registry.ci.openshift.org`: + +1. Login to [CI cluster](https://console-openshift-console.apps.ci.l2s4.p1.openshiftapps.com/) +2. Get token and login with podman: + ```bash + oc whoami -t | podman login -u=$(oc whoami) --password-stdin \ + registry.ci.openshift.org --authfile=$REGISTRY_AUTH_FILE + ``` + +See [CI Registry Access](https://docs.ci.openshift.org/docs/how-tos/use-registries-in-build-farm/#how-do-i-gain-access-to-qci) + +## Advanced Usage + +### Custom Operator Branches + +Build from a specific branch: + +```bash +./build-operators.sh ceo:my-feature-branch +``` + +### Verify Payload Contents + +```bash +# List images in payload +oc adm release info quay.io//custom-ocp-payload:5.0-test + +# Extract specific image +oc adm release extract quay.io//custom-ocp-payload:5.0-test \ + --file=image-references > images.json +``` + +## Troubleshooting + +### Registry Authentication + +If build fails with registry auth errors: + +```bash +# Check CI registry access +./build-operators.sh ceo +# The script will provide instructions if authentication fails +``` + +### Image Name Mapping + +The payload image name comes from the `name=` field in `operators.conf`: +- `name=cluster-config-operator` → payload image `cluster-config-operator` +- `name=cli` → payload image `cli` + +Verify with: `oc adm release info | grep ` diff --git a/helpers/operator-payload/build-operators.sh b/helpers/operator-payload/build-operators.sh new file mode 100755 index 00000000..2c1d23b4 --- /dev/null +++ b/helpers/operator-payload/build-operators.sh @@ -0,0 +1,365 @@ +#!/usr/bin/bash +# Build and push operator images using profiles +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="${SCRIPT_DIR}/operators.conf" + +# shellcheck source=/dev/null +. "$SCRIPT_DIR/profile.env" + +# Default configuration (QUAY_NAMESPACE must be set in profile.env) +if [[ -z "${QUAY_NAMESPACE:-}" ]]; then + echo "Error: QUAY_NAMESPACE not set. Please configure profile.env" + exit 1 +fi +DEFAULT_NAMESPACE="${QUAY_NAMESPACE}" +DEFAULT_TAG="${IMAGE_TAG:-latest}" +DEFAULT_AUTH_FILE="${REGISTRY_AUTH_FILE:-$HOME/.config/containers/auth.json}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +usage() { + cat </dev/null | sed 's/\[//;s/\]//' | sed 's/^/ /' || echo " (none configured)" + cat </dev/null; then + echo -e "${RED}✗ Cannot pull from registry.ci.openshift.org${NC}" + echo "" + echo "To fix:" + echo " 1. Login to CI cluster: https://console-openshift-console.apps.ci.l2s4.p1.openshiftapps.com" + echo " 2. Run: podman login -u=\$(oc whoami) -p=\$(oc whoami -t) registry.ci.openshift.org --authfile=\$REGISTRY_AUTH_FILE" + echo "" + return 1 + fi + + echo -e "${GREEN}✓ Registry access verified${NC}" + return 0 +} + +build_operator() { + local operator_alias="$1" + local branch_override="${2:-}" + local namespace="$3" + local tag="$4" + local auth_file="$5" + local verbose="$6" + + local operator_name repo_path dockerfile default_branch branch + + operator_name=$(get_config "$operator_alias" "name") + repo_path=$(get_config "$operator_alias" "repo") + dockerfile=$(get_config "$operator_alias" "dockerfile" "Dockerfile.ocp") + default_branch=$(get_config "$operator_alias" "default_branch" "main") + + if [[ -z "$operator_name" ]] || [[ -z "$repo_path" ]]; then + echo -e "${RED}✗ Unknown operator: ${operator_alias}${NC}" + echo " Available: $(grep '^\[' "$CONFIG_FILE" | sed 's/\[//;s/\]//' | tr '\n' ' ')" + FAILED+=("${operator_alias}: unknown operator") + return 1 + fi + + local image_ref="${namespace}/${operator_name}:${tag}" + + echo -e "${YELLOW}Building ${operator_alias} (${operator_name})${NC}" + echo " Repo: ${repo_path}" + + # Validate repo exists + if [[ ! -d "${repo_path}" ]]; then + echo -e "${RED}✗ Repository not found: ${repo_path}${NC}" + FAILED+=("${operator_alias}: repository not found") + return 1 + fi + + pushd "${repo_path}" > /dev/null + + # Save original ref to restore later + local original_ref + original_ref=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || git rev-parse HEAD 2>/dev/null) + + # Determine which branch to use: CLI override > config default > current branch + branch="${branch_override:-$default_branch}" + + # Checkout branch if specified (either via override or default_branch) + if [[ -n "$branch" ]]; then + echo " Switching to branch: ${branch}" + if [[ "$verbose" == "true" ]]; then + if ! git checkout "${branch}" 2>&1; then + echo -e "${RED}✗ Failed to checkout branch: ${branch}${NC}" + FAILED+=("${operator_alias}: checkout failed") + popd > /dev/null + return 1 + fi + else + if ! git checkout "${branch}" 2>&1 | tail -3; then + echo -e "${RED}✗ Failed to checkout branch: ${branch}${NC}" + FAILED+=("${operator_alias}: checkout failed") + popd > /dev/null + return 1 + fi + fi + fi + + # Report current state + local current_branch + current_branch=$(git branch --show-current 2>/dev/null || echo "") + if [[ -z "$current_branch" ]]; then + echo " Branch: (detached HEAD)" + else + echo " Branch: ${current_branch}" + fi + + echo " Image: ${image_ref}" + echo " Building..." + + # Build image + if [[ "$verbose" == "true" ]]; then + if ! podman build --authfile="${auth_file}" --file "${dockerfile}" -t "${image_ref}" . 2>&1; then + echo -e "${RED}✗ Build failed for ${operator_alias}${NC}" + FAILED+=("${operator_alias}: build failed") + git checkout "${original_ref}" &>/dev/null || true + popd > /dev/null + return 1 + fi + else + if ! podman build --authfile="${auth_file}" --file "${dockerfile}" -t "${image_ref}" . 2>&1 | tail -10; then + echo -e "${RED}✗ Build failed for ${operator_alias}${NC}" + FAILED+=("${operator_alias}: build failed") + git checkout "${original_ref}" &>/dev/null || true + popd > /dev/null + return 1 + fi + fi + + # Push image + echo " Pushing..." + if [[ "$verbose" == "true" ]]; then + if ! podman push --authfile="${auth_file}" "${image_ref}" 2>&1; then + echo -e "${RED}✗ Push failed for ${operator_alias}${NC}" + FAILED+=("${operator_alias}: push failed") + git checkout "${original_ref}" &>/dev/null || true + popd > /dev/null + return 1 + fi + else + if ! podman push --authfile="${auth_file}" "${image_ref}" 2>&1 | tail -5; then + echo -e "${RED}✗ Push failed for ${operator_alias}${NC}" + FAILED+=("${operator_alias}: push failed") + git checkout "${original_ref}" &>/dev/null || true + popd > /dev/null + return 1 + fi + fi + + # Restore original ref on success + git checkout "${original_ref}" &>/dev/null || true + popd > /dev/null + + echo -e "${GREEN}✓ Successfully built and pushed: ${image_ref}${NC}" + SUCCEEDED+=("${operator_alias}: ${image_ref}") + return 0 +} + +# Parse command line +NAMESPACE="${DEFAULT_NAMESPACE}" +TAG="${DEFAULT_TAG}" +VERBOSE=false +declare -a OPERATORS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + -n|--namespace) + if [[ -z "${2:-}" ]] || [[ "$2" == -* ]]; then + echo "Error: -n/--namespace requires a value" + exit 1 + fi + NAMESPACE="$2" + shift 2 + ;; + -t|--tag) + if [[ -z "${2:-}" ]] || [[ "$2" == -* ]]; then + echo "Error: -t/--tag requires a value" + exit 1 + fi + TAG="$2" + shift 2 + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + OPERATORS+=("$1") + shift + ;; + esac +done + +if [[ ${#OPERATORS[@]} -eq 0 ]]; then + echo "Error: No operators specified" + echo "" + usage + exit 1 +fi + +# Load config files +if [[ ! -f "$CONFIG_FILE" ]]; then + echo "Error: Config file not found: $CONFIG_FILE" + exit 1 +fi + +parse_config "$CONFIG_FILE" + +echo "========================================" +echo "Building ${#OPERATORS[@]} operator(s)" +echo "Registry: ${NAMESPACE}" +echo "Tag: ${TAG}" +echo "========================================" +echo "" + +# Check registry access +if ! check_registry_access "$DEFAULT_AUTH_FILE"; then + exit 1 +fi +echo "" + +# Process each operator +for op_spec in "${OPERATORS[@]}"; do + # Split operator:branch format + if [[ "$op_spec" == *:* ]]; then + operator="${op_spec%%:*}" + branch="${op_spec#*:}" + else + operator="$op_spec" + branch="" + fi + + build_operator "$operator" "$branch" "$NAMESPACE" "$TAG" "$DEFAULT_AUTH_FILE" "$VERBOSE" || true + echo "" +done + +# Print summary +echo "========================================" +echo "BUILD SUMMARY" +echo "========================================" + +if [[ ${#SUCCEEDED[@]} -gt 0 ]]; then + echo -e "${GREEN}SUCCEEDED (${#SUCCEEDED[@]}):${NC}" + for item in "${SUCCEEDED[@]}"; do + echo -e " ${GREEN}✓${NC} $item" + done + echo "" +fi + +if [[ ${#FAILED[@]} -gt 0 ]]; then + echo -e "${RED}FAILED (${#FAILED[@]}):${NC}" + for item in "${FAILED[@]}"; do + echo -e " ${RED}✗${NC} $item" + done + echo "" + exit 1 +fi + +echo -e "${GREEN}All operators built successfully!${NC}" diff --git a/helpers/operator-payload/ocp-create-payload b/helpers/operator-payload/ocp-create-payload new file mode 100755 index 00000000..58fd2afe --- /dev/null +++ b/helpers/operator-payload/ocp-create-payload @@ -0,0 +1,287 @@ +#!/usr/bin/bash +# +# Create custom OCP payload with image overrides +# Usage: ./ocp-create-payload [options] [profile2...] +# +# Examples: +# ./ocp-create-payload ceo +# ./ocp-create-payload ceo cno -n quay.io/myrepo -t dev +# + +set -euo pipefail + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="${SCRIPT_DIR}/operators.conf" +SNO_CONFIG="${SCRIPT_DIR}/../../deploy/openshift-clusters/roles/dev-scripts/install-dev/files/config_sno.sh" +PROFILE_ENV="${SCRIPT_DIR}/profile.env" + +# Source profile.env early (if it exists) so defaults can use configured values +# shellcheck source=/dev/null +if [[ -f "$PROFILE_ENV" ]]; then + source "$PROFILE_ENV" +fi + +# Derive defaults from profile.env (if loaded) or use placeholders +DEFAULT_NAMESPACE="${QUAY_NAMESPACE:-quay.io/}" +DEFAULT_TAG="${IMAGE_TAG:-latest}" +DEFAULT_AUTH_FILE="${REGISTRY_AUTH_FILE:-$HOME/.config/containers/auth.json}" +DEFAULT_TARGET_IMAGE="${TARGET_IMAGE:-quay.io//custom-ocp-payload:test}" + +usage() { + cat < [profile2...] + +Create custom OCP payload with operator image overrides. + +OPTIONS: + -n, --namespace NAMESPACE Registry namespace (default: ${DEFAULT_NAMESPACE}) + -t, --tag TAG Image tag (default: ${DEFAULT_TAG}) + -b, --base-release IMAGE Base release image (required if SNO config not present) + -o, --target-image IMAGE Target custom payload image (default: ${DEFAULT_TARGET_IMAGE}) + -h, --help Show this help + +PROFILES: + Operator profiles from operators.conf (e.g., ceo, cno, ovnk) + +EXAMPLES: + # Specify base release + $0 ceo -b registry.ci.openshift.org/ocp/release-5:5.0.0-0.nightly-2026-07-01-125918 + + # Use SNO config for base release (if available) + $0 ceo + + # Override namespace and tag + $0 ceo cno -n quay.io/myrepo -t dev + + # Custom target image + $0 ceo -o quay.io/myrepo/custom-payload:test + +CONFIGURATION: + Profile settings loaded from: + 1. operators.conf (operator metadata) + 2. profile.env (registry namespace and image defaults) + 3. SNO config (base release, if -b not specified) + +EOF +} + +# Parse INI-style config file +declare -A CONFIG +parse_config() { + local config_file="$1" + local current_section="" + + while IFS= read -r line || [[ -n "$line" ]]; do + # Skip comments and empty lines + [[ "$line" =~ ^[[:space:]]*# ]] && continue + [[ -z "${line// }" ]] && continue + + # Section headers + if [[ "$line" =~ ^\[([^]]+)\] ]]; then + current_section="${BASH_REMATCH[1]}" + continue + fi + + # Key=value pairs + if [[ "$line" =~ ^[[:space:]]*([^=]+)=(.+)$ ]]; then + local key="${BASH_REMATCH[1]}" + local value="${BASH_REMATCH[2]}" + key="${key// }" # trim spaces + CONFIG["${current_section}.${key}"]="$value" + fi + done < "$config_file" +} + +# Get config value for a profile +get_config() { + local profile="$1" + local key="$2" + echo "${CONFIG[${profile}.${key}]:-}" +} + +# Auto-detect base release from SNO config +detect_base_release() { + if [[ -f "$SNO_CONFIG" ]]; then + local release_image + release_image=$(grep "^export OPENSHIFT_RELEASE_IMAGE=" "$SNO_CONFIG" | cut -d= -f2) + echo "$release_image" + else + echo "" + fi +} + +# Parse command line +NAMESPACE="${DEFAULT_NAMESPACE}" +TAG="${DEFAULT_TAG}" +BASE_RELEASE="" +TARGET_IMAGE="${DEFAULT_TARGET_IMAGE}" +CLI_TARGET_IMAGE="" # Track if user specified target via CLI +declare -a PROFILES=() + +while [[ $# -gt 0 ]]; do + case "$1" in + -n|--namespace) + if [[ -z "${2:-}" ]] || [[ "$2" == -* ]]; then + echo -e "${RED}Error: -n/--namespace requires a value${NC}" + exit 1 + fi + NAMESPACE="$2" + shift 2 + ;; + -t|--tag) + if [[ -z "${2:-}" ]] || [[ "$2" == -* ]]; then + echo -e "${RED}Error: -t/--tag requires a value${NC}" + exit 1 + fi + TAG="$2" + shift 2 + ;; + -b|--base-release) + if [[ -z "${2:-}" ]] || [[ "$2" == -* ]]; then + echo -e "${RED}Error: -b/--base-release requires a value${NC}" + exit 1 + fi + BASE_RELEASE="$2" + shift 2 + ;; + -o|--target-image) + if [[ -z "${2:-}" ]] || [[ "$2" == -* ]]; then + echo -e "${RED}Error: -o/--target-image requires a value${NC}" + exit 1 + fi + TARGET_IMAGE="$2" + CLI_TARGET_IMAGE="$2" # Save CLI value + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + PROFILES+=("$1") + shift + ;; + esac +done + +# Validate inputs +if [[ ${#PROFILES[@]} -eq 0 ]]; then + echo -e "${RED}Error: No operator profiles specified${NC}" + echo "" + usage + exit 1 +fi + +# Validate profile.env was loaded and has required settings +if [[ ! -f "$PROFILE_ENV" ]]; then + echo -e "${RED}Error: profile.env not found${NC}" + echo "Please copy profile.env.template to profile.env and configure your settings" + exit 1 +fi + +if [[ -z "${QUAY_NAMESPACE:-}" ]]; then + echo -e "${RED}Error: QUAY_NAMESPACE not set in profile.env${NC}" + echo "Please set QUAY_NAMESPACE to your quay.io namespace" + exit 1 +fi + +# CLI arguments already override defaults from option parsing +# TARGET_IMAGE may need restoration if CLI --target-image was used +if [[ -n "$CLI_TARGET_IMAGE" ]]; then + TARGET_IMAGE="$CLI_TARGET_IMAGE" +fi + +# Load operators.conf +if [[ ! -f "$CONFIG_FILE" ]]; then + echo -e "${RED}Error: Config file not found: $CONFIG_FILE${NC}" + exit 1 +fi + +echo -e "${GREEN}Parsing operators.conf...${NC}" +parse_config "$CONFIG_FILE" + +# Auto-detect base release if not specified +if [[ -z "$BASE_RELEASE" ]]; then + echo -e "${GREEN}Auto-detecting base release from SNO config...${NC}" + BASE_RELEASE=$(detect_base_release) + if [[ -z "$BASE_RELEASE" ]]; then + echo -e "${RED}Error: Could not auto-detect base release${NC}" + echo "Please specify with -b/--base-release or ensure SNO config exists at:" + echo " $SNO_CONFIG" + exit 1 + fi + echo -e "${GREEN} Detected: ${BASE_RELEASE}${NC}" +fi + +# Generate image overrides +echo "" +echo "========================================" +echo "Generating image overrides" +echo "========================================" +echo "Profiles: ${PROFILES[*]}" +echo "Namespace: ${NAMESPACE}" +echo "Tag: ${TAG}" +echo "" + +OVERRIDE_ARGS=() +for profile in "${PROFILES[@]}"; do + # Get image name from config + image_name=$(get_config "$profile" "name") + + if [[ -z "$image_name" ]]; then + echo -e "${RED}✗ Profile '${profile}' not found in ${CONFIG_FILE}${NC}" + exit 1 + fi + + # Construct full image reference + image_ref="${NAMESPACE}/${image_name}:${TAG}" + + echo -e "${GREEN}✓ ${image_name}=${image_ref}${NC}" + OVERRIDE_ARGS+=("${image_name}=${image_ref}") +done + +echo "" +echo "========================================" +echo "Creating custom OCP payload" +echo "========================================" +echo "Base release: ${BASE_RELEASE}" +echo "Target image: ${TARGET_IMAGE}" +echo "Auth file: ${DEFAULT_AUTH_FILE}" +echo "" + +# Check auth file exists +if [[ ! -f "$DEFAULT_AUTH_FILE" ]]; then + echo -e "${RED}Error: Registry auth file not found: ${DEFAULT_AUTH_FILE}${NC}" + echo "Please ensure your pull secret is available at this path" + exit 1 +fi + +# Build the oc adm release new command +set -x +oc adm release new -n ocp \ + --registry-config="$DEFAULT_AUTH_FILE" \ + --from-release="$BASE_RELEASE" \ + --to-image="$TARGET_IMAGE" \ + "${OVERRIDE_ARGS[@]}" +set +x + +echo "" +echo -e "${GREEN}========================================" +echo "Custom payload created successfully!" +echo "========================================${NC}" +echo "" +echo "Payload image: ${TARGET_IMAGE}" +echo "" +echo "To use this payload:" +echo " 1. Update your SNO config to use this image:" +echo " export OPENSHIFT_RELEASE_IMAGE=${TARGET_IMAGE}" +echo "" +echo " 2. Or deploy with oc adm release extract:" +echo " oc adm release extract --tools ${TARGET_IMAGE}" +echo "" diff --git a/helpers/operator-payload/operators.conf.template b/helpers/operator-payload/operators.conf.template new file mode 100644 index 00000000..e5e6fdde --- /dev/null +++ b/helpers/operator-payload/operators.conf.template @@ -0,0 +1,34 @@ +# Operator build profiles +# Format: INI-style configuration +# Copy this to operators.conf and update paths for your environment + +[ceo] +name=cluster-etcd-operator +repo=/path/to/your/cluster-etcd-operator +dockerfile=Dockerfile.ocp +default_branch=main + +[cno] +name=cluster-network-operator +repo=/path/to/your/cluster-network-operator +dockerfile=Dockerfile +default_branch=master + +[ovnk] +name=ovn-kubernetes +repo=/path/to/your/ovn-kubernetes +dockerfile=Dockerfile.ocp +default_branch=master + +[kcm] +name=kube-controller-manager +repo=/path/to/your/kube-controller-manager +dockerfile=Dockerfile.ocp +default_branch=master + +# Add more operators as needed: +# [mco] +# name=machine-config-operator +# repo=/path/to/your/machine-config-operator +# dockerfile=Dockerfile.rhel +# default_branch=main diff --git a/helpers/operator-payload/profile.env.template b/helpers/operator-payload/profile.env.template new file mode 100644 index 00000000..1bb6e3ce --- /dev/null +++ b/helpers/operator-payload/profile.env.template @@ -0,0 +1,11 @@ +# Registry namespace for built images (REQUIRED - set to your quay.io namespace) +QUAY_NAMESPACE="quay.io/" + +# Image tag for built images (default: latest) +IMAGE_TAG=latest + +# Target image for custom payload +TARGET_IMAGE="quay.io//custom-ocp-payload:5.0-test" + +# Location for your pull secret +export REGISTRY_AUTH_FILE=~/.config/containers/auth.json