69 lines
3.2 KiB
Bash
Executable File
69 lines
3.2 KiB
Bash
Executable File
#!/bin/sh
|
|
# upload -> HEAD -> download -> delete -> wrong-credential rejection, in that order, none skippable.
|
|
#
|
|
# A readiness probe says the server answers. This says an object written to it comes back byte for
|
|
# byte and then stops existing when deleted, which is the property anything storing a file depends
|
|
# on. The wrong-credential step is here because a bucket that accepts anyone is also "working".
|
|
#
|
|
# It runs on the MinIO server image rather than the mc client image, and the reason is worth keeping:
|
|
# minio/mc ships mc and almost nothing else — no sed, no grep, no cmp — so steps 2 and 3 below called
|
|
# two binaries that are not there. The script had never run to find out. The wrapper's one-shot loop
|
|
# lost its stdin to `docker compose run` and executed only the first client per lane, so this one was
|
|
# skipped in every lane that declared it while all three lanes reported green.
|
|
#
|
|
# minio/minio carries mc, and also sha256sum, cut and tr. The lane already pulls it for the server,
|
|
# so this costs no image, and the digest comparison is a stronger identity check than cmp: it fails
|
|
# on any differing byte and says so without dumping the bytes.
|
|
set -eu
|
|
|
|
KEY="smoke/$(date +%s)-$$"
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "${WORK}"' EXIT
|
|
|
|
mc alias set caskeleton "${MINIO_ENDPOINT}" "${MINIO_ROOT_USER}" "${MINIO_ROOT_PASSWORD}"
|
|
|
|
# 1. upload known bytes
|
|
head -c 65536 /dev/urandom > "${WORK}/payload"
|
|
EXPECTED_SIZE="$(wc -c < "${WORK}/payload" | tr -d ' ')"
|
|
mc cp "${WORK}/payload" "caskeleton/${MINIO_BUCKET}/${KEY}"
|
|
|
|
# 2. HEAD: size must match. Parsed with tr and cut because this image has no sed or grep: the JSON is
|
|
# split onto one field per line, the size field is selected, and everything but its digits dropped.
|
|
ACTUAL_SIZE="$(mc stat --json "caskeleton/${MINIO_BUCKET}/${KEY}" \
|
|
| tr ',' '\n' | tr -d ' ' | while IFS= read -r field; do
|
|
case "${field}" in '"size":'*) echo "${field}" | cut -d: -f2 | tr -dc '0-9' ;; esac
|
|
done)"
|
|
if [ -z "${ACTUAL_SIZE}" ]; then
|
|
echo "object-storage-smoke: mc stat reported no size for the uploaded object" >&2
|
|
exit 1
|
|
fi
|
|
if [ "${ACTUAL_SIZE}" != "${EXPECTED_SIZE}" ]; then
|
|
echo "object-storage-smoke: HEAD reported ${ACTUAL_SIZE} bytes, uploaded ${EXPECTED_SIZE}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# 3. download: bytes must be identical, by digest rather than by cmp
|
|
mc cp "caskeleton/${MINIO_BUCKET}/${KEY}" "${WORK}/roundtrip"
|
|
UPLOADED_DIGEST="$(sha256sum < "${WORK}/payload" | cut -d' ' -f1)"
|
|
RETURNED_DIGEST="$(sha256sum < "${WORK}/roundtrip" | cut -d' ' -f1)"
|
|
if [ "${UPLOADED_DIGEST}" != "${RETURNED_DIGEST}" ]; then
|
|
echo "object-storage-smoke: downloaded bytes differ from what was uploaded" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# 4. delete: must then be absent
|
|
mc rm "caskeleton/${MINIO_BUCKET}/${KEY}"
|
|
if mc stat "caskeleton/${MINIO_BUCKET}/${KEY}" >/dev/null 2>&1; then
|
|
echo "object-storage-smoke: object still present after delete" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# 5. a deliberately wrong credential must be refused
|
|
if mc alias set rejected "${MINIO_ENDPOINT}" "${MINIO_ROOT_USER}" "definitely-not-the-password" >/dev/null 2>&1 \
|
|
&& mc ls "rejected/${MINIO_BUCKET}" >/dev/null 2>&1; then
|
|
echo "object-storage-smoke: a wrong password was accepted" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "object-storage-smoke: upload, head, download, delete and credential rejection all passed"
|