mirror of
https://github.com/pgsty/minio.git
synced 2026-08-09 07:43:29 +03:00
6613c2a3cb
The test and verification scripts invoked ./minio and pulled their tooling from upstream infrastructure with no integrity check. Every `curl | tar` of a client or an old server binary was an unverified execution path in a script that regularly runs as a privileged user, and several fetched a floating "latest". Two installers replace all of it: - install-mcli.sh resolves a pinned pgsty/mc release, downloads the archive and its checksum manifest, requires exactly one valid manifest entry for the asset, verifies it, and installs. MCLI_BIN with a mandatory MCLI_SHA256 lets an offline or air-gapped run supply its own binary, still checksum-checked. - install-verified-fixture.sh takes source, expected SHA-256 and target, and refuses anything that does not match. Sources may be a URL or a local file. Every script that previously downloaded mc now calls install-mcli.sh. The three places that genuinely need an upstream artifact - the old MinIO server binary for the LDAP IAM upgrade-import test, the 2021 mc for the three-site replication test, and the functional-tests.sh fixture - go through install-verified-fixture.sh with the digest recorded inline. Those dl.min.io URLs remain on purpose: they are historical upstream artifacts needed to prove upgrade compatibility, and they are now pinned and verified rather than trusted. The scripts otherwise switch to ./silo, silo.service, the silo container and compose service names, and SILO_CONFIG_DIR. run-multi-site-minio-idp.sh is renamed to run-multi-site-silo-idp.sh with the Makefile target following. buildscripts/minio-upgrade.sh keeps its name and its `minio server` argv - it exists to test the MinIO-to-Silo upgrade, so the old side must stay old - but it is now pinned to an image digest rather than a tag, and its `docker system prune` and `docker volume prune` calls are removed. Those ran unfiltered against the developer's whole Docker installation; the resiliency tests had the same problem and lose their prune and `docker ps -q` sweeps too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
125 lines
5.2 KiB
Bash
Executable File
125 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
# Exercise both directions of the on-disk compatibility contract using an
|
|
# immutable pre-rebrand image and a container built from the current checkout.
|
|
# Every Docker resource is uniquely named and removed explicitly; this test
|
|
# never prunes unrelated images, containers, networks, or volumes.
|
|
|
|
repo_dir="$(git rev-parse --show-toplevel)"
|
|
old_image="${OLD_IMAGE:-docker.io/pgsty/minio@sha256:b6bfe7239bfc83fb90d31612d9704d86039dd714f7904b3f1ad68f211e602372}"
|
|
new_image="${NEW_IMAGE:-silo-upgrade-test:dev}"
|
|
suffix="$(date +%s)-$$"
|
|
network="silo-upgrade-net-${suffix}"
|
|
volume="silo-upgrade-data-${suffix}"
|
|
old_container="silo-upgrade-old-${suffix}"
|
|
new_container="silo-upgrade-new-${suffix}"
|
|
rollback_container="silo-upgrade-rollback-${suffix}"
|
|
root_user=silo-upgrade-admin
|
|
root_password=silo-upgrade-secret-123
|
|
|
|
cleanup() {
|
|
status=$?
|
|
trap - EXIT
|
|
if [ "${status}" -ne 0 ]; then
|
|
for name in "${old_container}" "${new_container}" "${rollback_container}"; do
|
|
docker logs "${name}" 2>/dev/null | tail -n 80 >&2 || true
|
|
done
|
|
fi
|
|
if [ "${KEEP_UPGRADE_TEST_RESOURCES:-0}" = 1 ]; then
|
|
printf 'Retained Docker resources for inspection: %s %s\n' "${network}" "${volume}" >&2
|
|
exit "${status}"
|
|
fi
|
|
docker rm -f "${old_container}" "${new_container}" "${rollback_container}" >/dev/null 2>&1 || true
|
|
docker network rm "${network}" >/dev/null 2>&1 || true
|
|
docker volume rm "${volume}" >/dev/null 2>&1 || true
|
|
exit "${status}"
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 130' INT TERM
|
|
|
|
wait_ready() {
|
|
name="$1"
|
|
ready=""
|
|
for _ in $(seq 1 90); do
|
|
if docker logs "${name}" 2>&1 | grep -q 'API:'; then
|
|
ready=1
|
|
break
|
|
fi
|
|
if [ "$(docker inspect -f '{{.State.Running}}' "${name}")" != true ]; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
if [ -z "${ready}" ]; then
|
|
echo "Server did not become ready: ${name}" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
start_server() {
|
|
name="$1"
|
|
image="$2"
|
|
shift 2
|
|
docker run -d --name "${name}" --network "${network}" \
|
|
--mount "source=${volume},target=/data" \
|
|
-e MINIO_CI_CD=1 -e MINIO_ROOT_USER="${root_user}" -e MINIO_ROOT_PASSWORD="${root_password}" \
|
|
"${image}" "$@" >/dev/null
|
|
wait_ready "${name}"
|
|
docker exec "${name}" mcli alias set local http://127.0.0.1:9000 "${root_user}" "${root_password}" >/dev/null
|
|
}
|
|
|
|
stop_server() {
|
|
name="$1"
|
|
docker stop -t 20 "${name}" >/dev/null
|
|
test "$(docker inspect -f '{{.State.ExitCode}}' "${name}")" = 0
|
|
docker logs "${name}" 2>&1 | grep -q 'Exiting on signal'
|
|
docker rm "${name}" >/dev/null
|
|
}
|
|
|
|
command -v docker >/dev/null
|
|
docker info >/dev/null
|
|
if ! docker image inspect "${old_image}" >/dev/null 2>&1; then
|
|
docker pull "${old_image}"
|
|
fi
|
|
|
|
if [ "${SILO_UPGRADE_SKIP_BUILD:-0}" != 1 ]; then
|
|
make -C "${repo_dir}" docker TAG="${new_image}"
|
|
fi
|
|
docker image inspect "${new_image}" >/dev/null
|
|
|
|
docker network create "${network}" >/dev/null
|
|
docker volume create "${volume}" >/dev/null
|
|
|
|
start_server "${old_container}" "${old_image}" minio server /data --address :9000
|
|
docker exec "${old_container}" mcli mb local/compat >/dev/null
|
|
docker exec "${old_container}" mcli version enable local/compat >/dev/null
|
|
printf 'old-version-1\n' | docker exec -i "${old_container}" mcli pipe local/compat/versioned.txt >/dev/null
|
|
printf 'old-version-2\n' | docker exec -i "${old_container}" mcli pipe local/compat/versioned.txt >/dev/null
|
|
test "$(docker exec "${old_container}" mcli ls --versions local/compat/versioned.txt | grep -c 'versioned.txt')" -ge 2
|
|
docker exec "${old_container}" mcli mb --with-lock local/locked >/dev/null
|
|
printf 'locked-by-old\n' | docker exec -i "${old_container}" mcli pipe local/locked/object.txt >/dev/null
|
|
dd if=/dev/zero bs=1048576 count=70 2>/dev/null | docker exec -i "${old_container}" mcli pipe local/compat/multipart.bin >/dev/null
|
|
test "$(docker exec "${old_container}" mcli stat --json local/compat/multipart.bin | jq -r '.size')" = 73400320
|
|
docker exec "${old_container}" mcli admin user add local migration-user migration-secret-123 >/dev/null
|
|
docker exec "${old_container}" mcli admin policy attach local readwrite --user migration-user >/dev/null
|
|
stop_server "${old_container}"
|
|
|
|
start_server "${new_container}" "${new_image}" silo server /data --address :9000
|
|
test "$(docker exec "${new_container}" mcli cat local/compat/versioned.txt)" = old-version-2
|
|
test "$(docker exec "${new_container}" mcli cat local/locked/object.txt)" = locked-by-old
|
|
test "$(docker exec "${new_container}" mcli stat --json local/compat/multipart.bin | jq -r '.size')" = 73400320
|
|
docker exec "${new_container}" mcli admin user info local migration-user >/dev/null
|
|
docker exec "${new_container}" mcli alias set migrated http://127.0.0.1:9000 migration-user migration-secret-123 >/dev/null
|
|
printf 'written-by-silo\n' | docker exec -i "${new_container}" mcli pipe migrated/compat/silo.txt >/dev/null
|
|
stop_server "${new_container}"
|
|
|
|
start_server "${rollback_container}" "${old_image}" minio server /data --address :9000
|
|
test "$(docker exec "${rollback_container}" mcli cat local/compat/versioned.txt)" = old-version-2
|
|
test "$(docker exec "${rollback_container}" mcli cat local/compat/silo.txt)" = written-by-silo
|
|
test "$(docker exec "${rollback_container}" mcli stat --json local/compat/multipart.bin | jq -r '.size')" = 73400320
|
|
stop_server "${rollback_container}"
|
|
|
|
echo "MinIO-to-Silo data upgrade and rollback checks passed"
|