Add platform infrastructure configuration
This commit is contained in:
Executable
+193
@@ -0,0 +1,193 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
# Secret이 셸 추적에 노출되지 않도록 호출자가 bash -x를 사용해도 끈다.
|
||||
set +x
|
||||
|
||||
readonly NAMESPACE="object-storage"
|
||||
readonly OBJECTSTORE="minio-aistor"
|
||||
readonly ROOT_SECRET="aistor-root-configuration"
|
||||
readonly S3_ENDPOINT="http://minio.object-storage.svc.cluster.local"
|
||||
readonly MC_IMAGE="quay.io/minio/aistor/mc@sha256:c5ec777c080fd6292b7529309a0f311c58c3a92e268c9c57c0901da86881949b"
|
||||
readonly PASS_LINE="AISTOR_S3_SMOKE_PASS bucket-create object-write object-read object-delete bucket-delete"
|
||||
|
||||
execute_requested=false
|
||||
pod_name=""
|
||||
|
||||
fail() {
|
||||
printf 'ERROR: %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "$pod_name" ]]; then
|
||||
kubectl --namespace "$NAMESPACE" delete pod "$pod_name" \
|
||||
--ignore-not-found --wait=true --timeout=30s >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage:
|
||||
bash scripts/validate/aistor-s3-smoke.sh --execute
|
||||
|
||||
Creates one restricted, short-lived AIStor Client Pod. It authenticates with
|
||||
object-storage/aistor-root-configuration and performs:
|
||||
bucket create -> object write -> SHA-256 read check
|
||||
-> object delete -> bucket delete
|
||||
|
||||
The script never prints credentials. It removes the temporary bucket and Pod.
|
||||
Type APPLY only when prompted because this performs temporary S3 writes.
|
||||
USAGE
|
||||
}
|
||||
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
--execute)
|
||||
execute_requested=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
usage >&2
|
||||
fail "unsupported argument: $1"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ "$execute_requested" == true ]] || {
|
||||
usage
|
||||
fail "--execute is required"
|
||||
}
|
||||
|
||||
for command_name in kubectl grep jq; do
|
||||
command -v "$command_name" >/dev/null 2>&1 || \
|
||||
fail "${command_name} is required"
|
||||
done
|
||||
|
||||
[[ "$(
|
||||
kubectl --namespace "$NAMESPACE" get objectstore "$OBJECTSTORE" \
|
||||
--output=jsonpath='{.status.currentState}'
|
||||
)" == "Initialized" ]] || fail "ObjectStore is not Initialized"
|
||||
[[ "$(
|
||||
kubectl --namespace "$NAMESPACE" get objectstore "$OBJECTSTORE" \
|
||||
--output=jsonpath='{.status.healthStatus}'
|
||||
)" == "green" ]] || fail "ObjectStore health is not green"
|
||||
kubectl --namespace "$NAMESPACE" get secret "$ROOT_SECRET" >/dev/null
|
||||
|
||||
printf '%s\n' \
|
||||
"Target: ${NAMESPACE}/${OBJECTSTORE}" \
|
||||
"Endpoint: ${S3_ENDPOINT}" \
|
||||
'Temporary resources: one bucket, one object, and one restricted client Pod' \
|
||||
'No credential value will be printed.'
|
||||
printf 'Type APPLY to run the authenticated S3 smoke test: '
|
||||
IFS= read -r confirmation
|
||||
[[ "$confirmation" == "APPLY" ]] || fail "confirmation did not match APPLY"
|
||||
|
||||
pod_name="aistor-s3-smoke-$(date +%H%M%S)-$$"
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
smoke_command='set -eu
|
||||
. /run/aistor-root/config.env
|
||||
bucket="platform-smoke-$(date +%s)"
|
||||
cleanup_bucket() { mc rb --force "local/${bucket}" >/dev/null 2>&1 || true; }
|
||||
trap cleanup_bucket EXIT
|
||||
mc alias set local "'"$S3_ENDPOINT"'" "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" --api S3v4 >/dev/null
|
||||
payload="aistor-authenticated-smoke-$(date +%s)"
|
||||
expected="$(printf "%s" "$payload" | sha256sum | cut -d " " -f 1)"
|
||||
mc mb "local/${bucket}" >/dev/null
|
||||
printf "%s" "$payload" | mc pipe "local/${bucket}/probe.txt" >/dev/null
|
||||
actual="$(mc cat "local/${bucket}/probe.txt" | sha256sum | cut -d " " -f 1)"
|
||||
[ "$expected" = "$actual" ]
|
||||
mc stat "local/${bucket}/probe.txt" >/dev/null
|
||||
mc rm "local/${bucket}/probe.txt" >/dev/null
|
||||
mc rb "local/${bucket}" >/dev/null
|
||||
trap - EXIT
|
||||
printf "%s\n" "'"$PASS_LINE"'"'
|
||||
|
||||
overrides="$(
|
||||
jq -nc --arg command "$smoke_command" --arg image "$MC_IMAGE" '{
|
||||
spec: {
|
||||
automountServiceAccountToken: false,
|
||||
securityContext: {
|
||||
runAsNonRoot: true,
|
||||
runAsUser: 1000,
|
||||
runAsGroup: 1000,
|
||||
fsGroup: 1000,
|
||||
seccompProfile: {type: "RuntimeDefault"}
|
||||
},
|
||||
containers: [{
|
||||
name: "aistor-s3-smoke",
|
||||
image: $image,
|
||||
imagePullPolicy: "IfNotPresent",
|
||||
command: ["/bin/sh", "-ec"],
|
||||
args: [$command],
|
||||
securityContext: {
|
||||
allowPrivilegeEscalation: false,
|
||||
capabilities: {drop: ["ALL"]},
|
||||
readOnlyRootFilesystem: true
|
||||
},
|
||||
env: [{name: "MC_CONFIG_DIR", value: "/tmp/mc"}],
|
||||
volumeMounts: [
|
||||
{name: "root-config", mountPath: "/run/aistor-root", readOnly: true},
|
||||
{name: "tmp", mountPath: "/tmp"}
|
||||
]
|
||||
}],
|
||||
volumes: [
|
||||
{
|
||||
name: "root-config",
|
||||
secret: {secretName: "'"$ROOT_SECRET"'", defaultMode: 256}
|
||||
},
|
||||
{name: "tmp", emptyDir: {}}
|
||||
]
|
||||
}
|
||||
}'
|
||||
)"
|
||||
|
||||
kubectl --namespace "$NAMESPACE" run "$pod_name" \
|
||||
--image="$MC_IMAGE" \
|
||||
--restart=Never \
|
||||
--labels='platform.hyeonworks.com/aistor-client=true,app.kubernetes.io/name=aistor-s3-smoke' \
|
||||
--overrides="$overrides"
|
||||
|
||||
succeeded=false
|
||||
for _ in $(seq 1 90); do
|
||||
phase="$(
|
||||
kubectl --namespace "$NAMESPACE" get pod "$pod_name" \
|
||||
--output=jsonpath='{.status.phase}'
|
||||
)"
|
||||
if [[ "$phase" == "Succeeded" ]]; then
|
||||
succeeded=true
|
||||
break
|
||||
fi
|
||||
[[ "$phase" != "Failed" ]] || break
|
||||
|
||||
waiting_reason="$(
|
||||
kubectl --namespace "$NAMESPACE" get pod "$pod_name" \
|
||||
--output=jsonpath='{.status.containerStatuses[0].state.waiting.reason}' \
|
||||
2>/dev/null || true
|
||||
)"
|
||||
case "$waiting_reason" in
|
||||
CreateContainerConfigError|CrashLoopBackOff|ErrImagePull|ImagePullBackOff)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [[ "$succeeded" != true ]]; then
|
||||
kubectl --namespace "$NAMESPACE" logs "$pod_name" || true
|
||||
kubectl --namespace "$NAMESPACE" describe pod "$pod_name" | tail -n 60
|
||||
fail "authenticated S3 smoke test failed"
|
||||
fi
|
||||
|
||||
log_output="$(kubectl --namespace "$NAMESPACE" logs "$pod_name")"
|
||||
grep --fixed-strings --line-regexp --quiet "$PASS_LINE" <<<"$log_output" || \
|
||||
fail "smoke Pod did not emit the exact success contract"
|
||||
printf '%s\n' "$PASS_LINE"
|
||||
printf '%s\n' \
|
||||
"Client image: ${MC_IMAGE}" \
|
||||
'Temporary bucket, object, and client Pod cleanup: complete'
|
||||
Reference in New Issue
Block a user