The Altinity and RabbitMQ strategy Pods ran platform-migrations, a 349 MB image carrying kubectl, helm and etcd-migrate whose ENTRYPOINT is the migration runner, and whose pins were stamped from packages/core/platform so every migration change moved the backup clients too. Build images/backup-http-client (alpine + curl + jq + ca-certificates, non-root) from this package's Makefile and stamp both client keys from it. The cross-package stamp in packages/core/platform/Makefile and the platform-migrations-specific check in hack/image-pin-consistency.bats go away; the general one-digest-per-repository check still covers the two keys sharing one image. Fixes #3420 Assisted-by: LLM Signed-off-by: Andrey Kolkov <androndo@gmail.com>
RabbitMQ backup/restore demo
This demo backs up and restores a Cozystack-managed RabbitMQ instance, proving data integrity by round-tripping a sentinel definition through object storage. It provisions its own Bucket, Rabbitmq strategy and BackupClass so the round-trip is self-contained; the platform ships an equivalent cozy-default-rabbitmq strategy that writes to the shared cozy-backups system bucket, which you can route to from your own BackupClass instead.
What is backed up
RabbitMQ's cluster operator ships no backup CRD, and RabbitMQ has no consistent online export of message payloads. This strategy therefore backs up broker definitions — vhosts, users, permissions, queues, exchanges, bindings, policies and parameters — via the management HTTP API (GET /api/definitions), and restores them with POST /api/definitions. Message payloads are out of scope, and there is no point-in-time recovery: a full-data backup would be a Velero volume snapshot, which is a different strategy.
Definitions import is additive: an in-place restore re-creates dropped definitions but does not delete objects that exist live but not in the backup.
Prerequisites
The backupstrategy-controller and the backup CRDs must be installed (the platform default backups stack). run-all.sh provisions its own Bucket, reads the S3 coordinates from its BucketInfo, projects them into a rabbitmq-backup-creds Secret, copies the endpoint's CA into rabbitmq-backup-ca, and reuses the container image the shipped cozy-default-rabbitmq strategy runs — so that strategy must be present, but this demo does not write to the system bucket.
To-copy restore imports the source's definitions into a separate broker via POST /api/definitions, which merges the source's users, permissions and vhosts into the target. It does not clobber the target's own operator-generated default user, because the cluster-operator gives each RabbitmqCluster a distinct random default username. It does, however, import the source's users (with their password hashes), so after a to-copy restore those source credentials are valid logins on the target — grant access accordingly.
Each backup is stored under a per-run key (<namespace>/<application>/<backup-name>/definitions.json), so distinct backups of one application do not overwrite each other and a restore reads the exact object its Backup recorded.
Flow
00-helpers.sh— shared bash helpers (waiters, sentinel seed/check viarabbitmqctl).00-bucket.yaml— the demoBucketbacking the round-trip.03-rabbitmq-strategy.yaml— theRabbitmqstrategy (S3 coordinates filled from the Bucket byrun-all.sh).04-backupclass.yaml— therabbitmq-defaultBackupClassmappingRabbitMQto that strategy.05-rabbitmq-src.yaml— the source application (nobackup:block; the strategy carries the S3 coordinates).10-backupjob-adhoc.yaml— an ad-hocBackupJobrouted torabbitmq-default.15-plan.yaml— a cronPlanfor scheduled backups.20-rabbitmq-target.yaml— a separate application for restore-to-copy.25-restorejob-in-place.yaml/30-restorejob-to-copy.yaml— the two restore flows.
Run the whole round-trip:
./run-all.sh # backup, drop the sentinel, restore in place, then restore to a copy
./cleanup.sh # remove this demo's objects (idempotent)
SKIP_RESTORE=1 ./run-all.sh stops after a successful backup (backup-only smoke). Override NAMESPACE (default tenant-root) to run elsewhere. BucketInfo advertises the external S3 ingress endpoint, which in-cluster Pods cannot always reach or TLS-validate; set S3_ENDPOINT=https://seaweedfs-s3.<ns>.svc:8333 to target the in-cluster SeaweedFS instead — the .svc FQDN is the name the SeaweedFS serving cert's SAN covers, so curl can verify TLS against the copied CA (the e2e harness does this).