Skip to content

Commit c05d89d

Browse files
committed
RHAIENG-5599: Fix GHA refresh rpm lock file
Add GitHub Action to automate regeneration of rpms.lock.yaml (ODH and RHDS)
1 parent 3ccbf64 commit c05d89d

6 files changed

Lines changed: 95 additions & 178 deletions

File tree

.github/workflows/rpms-lock-renewal.yaml

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ on: # yamllint disable-line rule:truthy
2222
description: 'Branch to update'
2323
required: false
2424
default: 'main'
25+
use_cache:
26+
description: 'Use GHCR layer cache (Uncheck to rebuild from scratch)'
27+
required: false
28+
default: true
29+
type: boolean
2530

2631
jobs:
2732
refresh-rpm-lock-files:
@@ -32,15 +37,23 @@ jobs:
3237
cancel-in-progress: false
3338
permissions:
3439
contents: read # checkout only; push and PR creation use the PAT
40+
packages: write # push/pull rpm-lockfile build cache to ghcr.io
3541
env:
3642
BRANCH: ${{ github.event.inputs.branch || 'main' }}
3743
# Scheduled runs refresh ODH only; RHDS requires manual dispatch with subscription secrets.
3844
VARIANT: ${{ github.event.inputs.variant || 'odh' }}
3945
TMPDIR: /home/runner/.local/share/containers/tmpdir
4046
CONTAINER_HOST: unix:///var/run/podman/podman.sock
4147
CI: "true"
48+
# workflow_dispatch only; scheduled runs always use cache (input unset → true).
49+
USE_CACHE: ${{ github.event.inputs.use_cache != 'false' && 'true' || 'false' }}
50+
# GitHub Container Registry used for podman build layer cache (see build-notebooks-TEMPLATE.yaml).
51+
CACHE: "ghcr.io/${{ github.repository }}/rpm-lockfile-build-cache-${{ github.event.inputs.variant || 'odh' }}"
4252

4353
steps:
54+
- name: Downcase CACHE registry path
55+
run: echo "CACHE=${CACHE,,}" >> "${GITHUB_ENV}"
56+
4457
- name: Checkout code
4558
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
4659
with:
@@ -55,11 +68,9 @@ jobs:
5568
- name: Prepare Podman temp directory
5669
run: mkdir -p "$TMPDIR"
5770

58-
- name: Install Podman
59-
uses: ./.github/actions/install-podman-action
60-
with:
61-
platform: linux/amd64
62-
71+
# RHDS secrets and registry auth must be configured before Install Podman.
72+
# install-podman-action runs `sudo podman system reset`, which can leave
73+
# root-owned files under $HOME/.config/containers and break a later cp.
6374
- name: Install git-crypt
6475
if: env.VARIANT == 'rhds'
6576
uses: ./.github/actions/apt-install
@@ -79,6 +90,9 @@ jobs:
7990
if: env.VARIANT == 'rhds'
8091
run: |
8192
mkdir -p "$HOME/.config/containers"
93+
# Don't use sudo here. With CONTAINER_HOST set, podman is a remote client
94+
# that forwards auth to the rootful server during builds; credentials
95+
# must be readable by the runner user (see build-notebooks-TEMPLATE.yaml).
8296
cp ci/secrets/pull-secret.json "$HOME/.config/containers/auth.json"
8397
8498
- name: Mask subscription credentials
@@ -96,13 +110,53 @@ jobs:
96110
echo "::add-mask::${SUBSCRIPTION_ACTIVATION_KEY}"
97111
echo "::add-mask::${SUBSCRIPTION_ORG}"
98112
113+
- name: Login to GitHub Container Registry
114+
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
115+
with:
116+
registry: ghcr.io
117+
username: ${{ github.actor }}
118+
password: ${{ secrets.GITHUB_TOKEN }}
119+
120+
- name: Install Podman
121+
uses: ./.github/actions/install-podman-action
122+
with:
123+
platform: linux/amd64
124+
99125
- name: Free up disk space
100126
uses: ./.github/actions/free-up-disk-space
101127

128+
- name: Compute CONTAINER_BUILD_CACHE_ARGS
129+
id: container-build-cache-args
130+
shell: python
131+
env:
132+
USE_CACHE: ${{ env.USE_CACHE }}
133+
run: |
134+
import os
135+
import sys
136+
137+
cache = os.environ["CACHE"]
138+
event_name = os.environ["GITHUB_EVENT_NAME"]
139+
use_cache = os.environ.get("USE_CACHE", "true").lower() == "true"
140+
141+
if event_name not in ("schedule", "workflow_dispatch"):
142+
raise ValueError(f"Unexpected event name: {event_name}")
143+
144+
if use_cache:
145+
cache_args = f"--cache-from {cache} --cache-to {cache}"
146+
print("Using and updating GHCR layer cache", file=sys.stderr)
147+
else:
148+
# Skip --cache-from for a clean rebuild; still publish fresh layers afterward.
149+
cache_args = f"--cache-to {cache}"
150+
print("Rebuild from scratch (skipping --cache-from); will refresh GHCR cache after build", file=sys.stderr)
151+
152+
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f:
153+
f.write(f"CONTAINER_BUILD_CACHE_ARGS={cache_args}\n")
154+
102155
- name: Regenerate rpms.lock.yaml
103156
env:
104157
SUBSCRIPTION_ACTIVATION_KEY: ${{ secrets.SUBSCRIPTION_ACTIVATION_KEY }}
105158
SUBSCRIPTION_ORG: ${{ secrets.SUBSCRIPTION_ORG }}
159+
CONTAINER_BUILD_CACHE_ARGS: ${{ steps.container-build-cache-args.outputs.CONTAINER_BUILD_CACHE_ARGS }}
106160
run: |
107161
set -euo pipefail
108162
@@ -116,7 +170,10 @@ jobs:
116170
"codeserver/ubi9-python-3.12/prefetch-input/${VARIANT}/rpms.in.yaml"
117171
)
118172
119-
echo "Regenerating RPM lockfiles for variant: ${VARIANT}"
173+
echo "Regenerating RPM lockfiles for variant: ${VARIANT} (USE_CACHE=${USE_CACHE})"
174+
if [[ "$USE_CACHE" == "false" ]]; then
175+
podman rmi -f localhost/notebook-rpm-lockfile:latest 2>/dev/null || true
176+
fi
120177
for rpm_input in "${RPM_INPUTS[@]}"; do
121178
if [[ ! -f "$rpm_input" ]]; then
122179
echo "Skipping missing input: $rpm_input"
@@ -151,8 +208,14 @@ jobs:
151208
git commit -m "Update ${VARIANT_UPPER} rpms.lock.yaml lock files"
152209
git push -u "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" "$BRANCH_NAME"
153210
211+
# gh pr create fails if the label does not exist yet.
212+
gh label create "automated-rpms-lockfile-update" \
213+
--description "Auto-created RPM lockfile update PR" \
214+
--color "0E8A16" \
215+
2>/dev/null || true
216+
154217
gh pr create \
155-
--title "Update ${VARIANT_UPPER} rpms.lock.yaml lock files" \
218+
--title "GHA: Update ${VARIANT_UPPER} rpms.lock.yaml lock files" \
156219
--head "$BRANCH_NAME" \
157220
--body "$(cat <<EOF
158221
Automated regeneration of \`rpms.lock.yaml\` from \`rpms.in.yaml\` for the **${VARIANT_UPPER}** variant.

scripts/lockfile-generators/Dockerfile.rpm-lockfile

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
#
33
# Used by create-rpm-lockfile.sh to resolve RPM packages listed in
44
# rpms.in.yaml into a fully pinned rpms.lock.yaml (exact URLs + checksums
5-
# per architecture). The image includes rpm-lockfile-prototype, createrepo_c
6-
# (for repo metadata), and optionally registers with subscription-manager
7-
# to access RHEL-only repos.
5+
# per architecture). The image includes rpm-lockfile-prototype and
6+
# optionally registers with subscription-manager to access RHEL-only repos.
7+
# RPM download + repodata for local builds use hermeto-fetch-rpm.sh, not this image.
88
#
99
# Not used during the actual notebook image build — only for lockfile generation.
1010

@@ -31,13 +31,10 @@ RUN if [ -n "$ACTIVATION_KEY" ] && [ -n "$ORG" ]; then \
3131
# export INJECT_RHEL_VERSION="--releasever=\"${RHEL_VERSION}\" "; \
3232
fi
3333

34-
# To install modulemd-tools (createrepo_c) for Development only, not for Production
35-
COPY helpers/rhsm-pulp.repo /etc/yum.repos.d/rhsm-pulp.repo
36-
3734
# Don't run upgrade, it upgrades from 9.6 to 9.7 which is not desired here
3835
# Add --releasever when RHEL_VERSION is set (e.g. for RHEL/UBI) to pin repo release
3936
RUN releasever_opt=; [ -n "$RHEL_VERSION" ] && releasever_opt="--releasever=${RHEL_VERSION}"; \
40-
dnf $releasever_opt install -y python3 python3-pip python3-dnf skopeo rpm git modulemd-tools patch && \
37+
dnf $releasever_opt install -y python3 python3-pip python3-dnf skopeo rpm git patch && \
4138
dnf clean all
4239

4340
# --index-url: override the base image's pip.conf which may point to a restricted

scripts/lockfile-generators/README.md

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -228,14 +228,12 @@ internally. Option 6 (Git submodule) is a manual setup.
228228
| ----------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
229229
| `helpers/pylock-to-requirements.py` | pip | Convert `pylock.<flavor>.toml` (PEP 751) to pip-compatible `requirements.<flavor>.txt` with `--hash` lines. |
230230
| `helpers/download-pip-packages.py` | pip | Standalone pip downloader: downloads wheels/sdists from a `requirements.txt` (with `--hash` lines) into `cachi2/output/deps/pip/`. Not called by `create-requirements-lockfile.sh` (which has its own inline download from pylock.toml). |
231-
| `helpers/download-rpms.sh` | RPM | Download RPMs from `rpms.lock.yaml` via `wget` into `cachi2/output/deps/rpm/` and create DNF repo metadata. Standalone alternative to `hermeto-fetch-rpm.sh`. |
232231
| `helpers/hermeto-fetch-rpm.sh` | RPM | Download RPMs from `rpms.lock.yaml` using [Hermeto](https://github.com/hermetoproject/hermeto) in a container. Handles RHEL entitlement cert extraction for `cdn.redhat.com` auth. Called by `create-rpm-lockfile.sh --download`. |
233232
| `helpers/hermeto-fetch-npm.sh` | npm | Alternative npm fetcher using [Hermeto](https://github.com/hermetoproject/hermeto) in a container. |
234233
| `helpers/hermeto-fetch-gomod.sh` | Go modules | Fetches Go dependencies from a directory with `go.mod`/`go.sum` using [Hermeto](https://github.com/hermetoproject/hermeto) in a container. Output: `cachi2/output/deps/gomod/`. Called by `create-go-lockfile.sh`. |
235234
| `rewrite-npm-urls.sh` | npm (Dockerfile) | Rewrites `resolved` URLs in `package-lock.json` / `package.json` to `file:///cachi2/output/deps/npm/`. |
236235
| `helpers/rpm-lockfile-generate.sh` | RPM | Runs `rpm-lockfile-prototype` inside the lockfile container. Not for direct host use. |
237-
| `Dockerfile.rpm-lockfile` | RPM | Builds the container image for `create-rpm-lockfile.sh` (includes `rpm-lockfile-prototype` v0.20.0, `createrepo_c`, `modulemd-tools`). Applies patches from `patches/` at build time. |
238-
| `helpers/rhsm-pulp.repo` | RPM | DNF repo file for RHEL 9 E4S appstream (used inside the lockfile container to install `modulemd-tools`). |
236+
| `Dockerfile.rpm-lockfile` | RPM | Builds the container image for `create-rpm-lockfile.sh` (includes `rpm-lockfile-prototype` v0.20.0). Applies patches from `patches/` at build time. Does not install internal-only corp repos. |
239237
| `patches/apply-patches.sh` | RPM (build) | Applies local patches to pip-installed packages inside the `notebook-rpm-lockfile` container during `docker build`. |
240238
| `patches/rpm-lockfile-prototype-dnf-conf.patch` | RPM (build) | Adds `RPM_LOCKFILE_MODULE_PLATFORM_ID` and `RPM_LOCKFILE_SKIP_UNAVAILABLE` env var support to `rpm-lockfile-prototype`'s DNF config. |
241239

@@ -590,25 +588,6 @@ and `--org` to register a temporary UBI container and extract fresh certs.
590588

591589
**Requirements:** `podman`, network access.
592590

593-
### Helper: `helpers/download-rpms.sh`
594-
595-
Standalone alternative to `hermeto-fetch-rpm.sh` that downloads RPMs directly
596-
via `wget`. Downloads RPMs from a lockfile into `cachi2/output/deps/rpm/`,
597-
verifies checksums (when `yq` is available), and creates DNF repo metadata using
598-
the first available method: `createrepo_c` → `createrepo` → container fallback
599-
(runs `createrepo_c` + `repo2module` + `modifyrepo_c` inside the
600-
`notebook-rpm-lockfile` image via podman).
601-
602-
Does not handle RHEL entitlement — use `hermeto-fetch-rpm.sh` when downloading
603-
from `cdn.redhat.com` repos that require subscription certs.
604-
605-
```bash
606-
./scripts/lockfile-generators/helpers/download-rpms.sh \
607-
--lock-file codeserver/ubi9-python-3.12/prefetch-input/odh/rpms.lock.yaml
608-
```
609-
610-
**Requirements:** `wget`. `yq` recommended for checksum verification.
611-
612591
### Helper: `helpers/rpm-lockfile-generate.sh`
613592

614593
Invoked **inside** the `notebook-rpm-lockfile` container by `create-rpm-lockfile.sh`.

scripts/lockfile-generators/create-rpm-lockfile.sh

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,26 @@ else
109109
fi
110110

111111
# First build the image, so we can run rpm-lockfile-prototype inside it
112-
echo "--- Building Lockfile Generator Image ---"
113-
podman build \
114-
-f "$SCRIPTS_PATH/Dockerfile.rpm-lockfile" \
115-
--platform linux/x86_64 \
116-
--build-arg RHEL_VERSION="$RHEL_VERSION" \
117-
--build-arg BASE_IMAGE="$BASE_IMAGE" \
118-
--build-arg ACTIVATION_KEY="$ACTIVATION_KEY" \
119-
--build-arg ORG="$ORG" \
120-
-t notebook-rpm-lockfile "$SCRIPTS_PATH"
112+
CACHE_ARGS=()
113+
if [[ -n "${CONTAINER_BUILD_CACHE_ARGS:-}" ]]; then
114+
# shellcheck disable=SC2206
115+
CACHE_ARGS=($CONTAINER_BUILD_CACHE_ARGS)
116+
fi
117+
118+
if podman image exists localhost/notebook-rpm-lockfile:latest 2>/dev/null; then
119+
echo "--- Reusing existing Lockfile Generator Image ---"
120+
else
121+
echo "--- Building Lockfile Generator Image ---"
122+
podman build \
123+
-f "$SCRIPTS_PATH/Dockerfile.rpm-lockfile" \
124+
--platform linux/x86_64 \
125+
--build-arg RHEL_VERSION="$RHEL_VERSION" \
126+
--build-arg BASE_IMAGE="$BASE_IMAGE" \
127+
--build-arg ACTIVATION_KEY="$ACTIVATION_KEY" \
128+
--build-arg ORG="$ORG" \
129+
"${CACHE_ARGS[@]}" \
130+
-t notebook-rpm-lockfile "$SCRIPTS_PATH"
131+
fi
121132

122133
# Second run rpm-lockfile-prototype to generate the lockfile
123134
echo "--- Generating Lockfile using rpm-lockfile-prototype --"

scripts/lockfile-generators/helpers/download-rpms.sh

Lines changed: 0 additions & 126 deletions
This file was deleted.

scripts/lockfile-generators/helpers/rhsm-pulp.repo

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)