Pin multigres container image tags in image_defaults.go for operator releases. Compares upstream multigres code changes between the current and new SHA, highlights breaking changes and new features, then updates the tags. Triggered by user requests like "prepare images for release", "pin image tags", "pin upstream images", or "upgrade multigres images".
Upgrade multigres container image tags in api/v1alpha1/image_defaults.go to the latest SHA tags, with an upstream code review between the old and new versions.
Run the fetch script to get the latest SHA tags:
python3 tools/skills/pin_upstream_images/scripts/fetch_latest_tags.py
This outputs KEY_TAG=sha-XXXXXXX for each image. The script resolves which sha-* tag currently points to the same digest as main for each of:
ghcr.io/multigres/multigres -> used by DefaultMultiAdminImage, DefaultMultiOrchImage, DefaultMultiPoolerImage, DefaultMultiGatewayImageghcr.io/multigres/pgctld -> used by DefaultPostgresImageghcr.io/multigres/multiadmin-web -> used by DefaultMultiAdminWebImageImmediately update api/v1alpha1/image_defaults.go by replacing the old sha-XXXXXXX tags with the new ones:
| Constant | Image | Tag source |
|---|---|---|
| DefaultPostgresImage | ghcr.io/multigres/pgctld | PGCTLD_TAG |
| DefaultMultiAdminImage | ghcr.io/multigres/multigres | MULTIGRES_TAG |
| DefaultMultiAdminWebImage | ghcr.io/multigres/multiadmin-web | MULTIADMIN_WEB_TAG |
| DefaultMultiOrchImage | ghcr.io/multigres/multigres | MULTIGRES_TAG |
| DefaultMultiPoolerImage | ghcr.io/multigres/multigres | MULTIGRES_TAG |
| DefaultMultiGatewayImage | ghcr.io/multigres/multigres | MULTIGRES_TAG |
Do NOT modify DefaultEtcdImage -- it uses a separate versioned release.
If old and new SHAs are identical for all images, inform the user that images are already up to date and stop.
All multigres images (multigres, pgctld, multiadmin-web) are built from the same monorepo: https://github.com/multigres/multigres. Perform the comparison there.
Clone or pull the upstream multigres repo to /tmp/multigres:
if [ -d /tmp/multigres ]; then
cd /tmp/multigres && git fetch --all && git checkout main && git pull
else
git clone https://github.com/multigres/multigres /tmp/multigres
fi
Identify the unique old and new SHA values from Step 2. Since multigres/multigres and multigres/pgctld may have different SHA tags, compare each distinct old->new pair. Typically:
For each distinct old->new SHA pair, run:
cd /tmp/multigres
git log --oneline <old-sha>..<new-sha>
git diff --stat <old-sha>..<new-sha>
Filter: only review changes to multigres binary code. The images we pin are Go binaries (pgctld, multipooler, multiorch, multigateway, multiadmin, multiadmin-web). Only changes that end up compiled into those binaries can affect the operator. Ignore changes to:
demo/ — demo manifests, k8s YAML examples. These are not compiled into any binary.go/test/ — test-only code, test helpers, end-to-end test infrastructure.*.md, docs/, README* — documentation.go/cmd/, go/services/, go/common/, go/provisioner/, go/tools/ (library code used by binaries).When listing upstream commits, still include all of them for completeness, but mark test-only or non-binary commits as "No impact (test/docs/demo only)" and skip the detailed diff review for those.
For the remaining binary-relevant changes, selectively review the full diff for files that affect the operator (e.g., changes to CLI flags, configuration, proto definitions, RPC interfaces, container entrypoints, health checks, pooler behavior, orchestrator logic, gateway behavior, backup/restore, topology management).
This is the critical step. Do NOT make hypothetical recommendations. For each upstream change identified in Step 3, search the operator codebase to determine concrete impact.
For every potentially impactful upstream change:
Search the operator code using grep_search, view_file_outline, and view_code_item to find whether the operator references, uses, or depends on the changed upstream construct (proto field, gRPC service, CLI flag, topology record field, env var, behavior, etc.).
Classify each change with evidence:
Do not speculate. Every recommendation must be backed by a concrete search result (or confirmed absence) in the operator codebase. No "if the operator does X" phrasing -- either it does or it doesn't.
Per-container analysis is mandatory. When an upstream change affects a component's requirements (env vars, flags, volumes, config files), verify the requirement is satisfied on the specific container for that component in containers.go. Finding a reference elsewhere in the operator is NOT sufficient — each container builder (buildPgctldContainer, buildMultiPoolerSidecar, buildMultiOrchContainer, etc.) is independent. A requirement met on one container does NOT mean it is met on another.
This step is mandatory. Independent of the diff review above, mechanically verify that every CLI flag the operator passes to upstream components still exists. This catches flag removals/renames that the diff review might miss.
Extract every hardcoded --flag-name string from pkg/resource-handler/controller/shard/containers.go:
grep -oE '\-\-[a-z][a-z0-9-]+' pkg/resource-handler/controller/shard/containers.go | sort -u
For each upstream component (pgctld, multipooler, multiorch), get its current flag set from the upstream repo at the new SHA:
cd /tmp/multigres
# pgctld flags
grep -rh 'FlagName:' go/cmd/pgctld/ go/services/pgctld/ 2>/dev/null | grep -oE '"[a-z][a-z0-9-]+"' | tr -d '"' | sort -u
# multipooler flags
grep -rh 'FlagName:' go/services/multipooler/ 2>/dev/null | grep -oE '"[a-z][a-z0-9-]+"' | tr -d '"' | sort -u
# multiorch flags
grep -rh 'FlagName:' go/services/multiorch/ 2>/dev/null | grep -oE '"[a-z][a-z0-9-]+"' | tr -d '"' | sort -u
Cross-check: for each flag in the operator's containers.go, confirm it exists in the corresponding upstream component's flag set. Flag any mismatches as Action required — flag removed/renamed upstream.
This step is mandatory. Independent of the diff review, mechanically verify that every environment variable required by upstream components is set on the correct operator container(s). This catches cases where an env var exists on one container but a different component now also requires it.
Find every required env var in upstream at the new SHA:
cd /tmp/multigres
# Required env vars (fatal if missing)
grep -rn 'os.Getenv\|os.LookupEnv' go/services/multipooler/ go/cmd/pgctld/ go/services/multiorch/ go/services/multigateway/ 2>/dev/null | grep -v _test.go
# Specifically look for hard failures on missing env vars
grep -rn 'is required\|must be set\|MustGetenv' go/services/multipooler/ go/cmd/pgctld/ go/services/multiorch/ go/services/multigateway/ 2>/dev/null | grep -v _test.go
For each required env var found, check containers.go to confirm it is set on the specific container for that component:
multipooler env vars → must be in buildMultiPoolerSidecarpgctld env vars → must be in buildPgctldContainermultiorch env vars → must be in buildMultiOrchContainermultigateway env vars → must be in buildMultiGatewayContainer (if exists)Critical: An env var being set on one container does NOT mean it's set on another. Check each component's container builder independently.
Flag any missing env vars as Action required — env var required by [component] but not set on [container].
Present a structured summary to the user:
Commits between old and new:
git log --oneline)Impact Analysis: For each upstream change, include:
Flag Compatibility:
Environment Variable Compatibility:
After presenting the report in Step 5, determine the next step based on the findings:
If any action-required items were found:
image_defaults.go.If no action-required items were found (only no-impact / new-feature-opportunity):
Only run this when confident no operator code changes are needed, or after the user has approved and all action-required fixes have been applied. This is a final verification that the new images work correctly with the operator.
Build and deploy to kind:
make kind-redeploy
If no kind cluster exists, use make kind-deploy.
Apply a sample workload:
kubectl apply -f config/samples/minimal.yaml
Wait for pods and check health:
# Wait up to 2 minutes for pods to stabilize
sleep 60
kubectl get pods
If any pool pods are in CrashLoopBackOff or Init:Error:
kubectl logs <pod> -c multipooler and kubectl logs <pod> -c postgresmake kind-redeploy and re-verifyIf all pods reach Running/Ready, the upgrade is verified. Clean up:
kubectl delete multigrescluster --all
Display the image_defaults.go diff to the user.
Suggest a branch name and generate a commit message using the generate_commit_message skill:
release/pin-image-tags-YYYY-MM-DDgit log --oneline) as bullet points under a "Upstream changes:" sectiondeps(images): pin multigres images to sha-XXXXXXX
Upgrade default container images for pgctld and multigres
from sha-AAAAAAA to sha-BBBBBBB. multiadmin-web remains at
sha-CCCCCCC.
Upstream changes (AAAAAAA..BBBBBBB):
- fix(component): description of fix
- feat(component): description of feature
- refactor(component): description of refactoring
...
Operator impact:
- No breaking changes detected
- New feature opportunity: <description if any>
If the old and new SHAs are the same for an image group, note that no changes occurred and skip the diff.