Repository navigation
Expand file tree
/
Copy pathdemo.sh
More file actions
executable file
·200 lines (177 loc) · 7.06 KB
/
Copy pathdemo.sh
File metadata and controls
executable file
·200 lines (177 loc) · 7.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#!/usr/bin/env bash
# End-to-end demo: start RustFS, start ravel-server against it, push one OTLP
# metric export, query it back by commit token, print both results.
#
# The OTLP fixture is generated fresh on every run (via the ravel-server
# `gen_otlp_fixture` example) instead of being a static checked-in blob,
# because OTLP ingest rejects points more than 2 hours old and a stale
# checked-in timestamp would make the demo fail non-deterministically.
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT_DIR"
RUSTFS_COMPOSE="deploy/docker-compose/rustfs.yml"
RUSTFS_ENDPOINT="http://127.0.0.1:9000"
FIXTURE_PATH="examples/otlp_metrics_fixture.pb"
export RAVEL_S3_ENDPOINT="$RUSTFS_ENDPOINT"
export RAVEL_S3_BUCKET="ravel-dev"
export RAVEL_S3_REGION="us-east-1"
export RAVEL_S3_ACCESS_KEY="ravel"
export RAVEL_S3_SECRET_KEY="ravel-dev-secret"
HTTP_ADDR="127.0.0.1:14318"
GRPC_ADDR="127.0.0.1:14317"
TENANT_TOKEN="demo-token"
TENANT_NAME="demo-tenant"
SERVER_PID=""
STARTED_RUSTFS=0
log() {
echo "[demo] $*" >&2
}
cleanup() {
if [[ -n "$SERVER_PID" ]] && kill -0 "$SERVER_PID" 2>/dev/null; then
log "stopping ravel-server (pid $SERVER_PID)"
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
fi
if [[ "$STARTED_RUSTFS" -eq 1 ]]; then
log "stopping RustFS"
docker compose -f "$RUSTFS_COMPOSE" down >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
rustfs_healthy() {
curl --silent --fail --max-time 2 "${RUSTFS_ENDPOINT}/health" >/dev/null 2>&1
}
wait_for() {
local description="$1"
shift
local attempt
for attempt in $(seq 1 30); do
if "$@"; then
return 0
fi
sleep 1
done
log "timed out waiting for ${description}"
return 1
}
# The compose file's createbucket service creates the ravel-dev bucket with
# Object Lock, versioning and the lifecycle rule and reads all three back. The
# demo does not create the bucket itself: a plain create racing that service
# would leave a bucket without Object Lock, and the service's read-back would
# then fail.
#
# createbucket_exit_code prints the service's exit code once it has exited. It
# polls `docker compose ps --all`, which lists an exited container with its
# exit code. `docker compose wait` would not do: once the service has already
# exited, it prints "no containers for project" and exits 1 whatever the
# service's own exit code was. The listing also carries any container a
# `docker compose run createbucket` left behind (named
# <project>-createbucket-run-<id>), so only the service's own container,
# <project>-createbucket-<index>, is read. DEMO_CREATEBUCKET_POLLS overrides
# the 180 one-second polls; scripts/demo.test.sh sets it.
createbucket_exit_code() {
local attempt line="" listing name rest polls="${DEMO_CREATEBUCKET_POLLS:-180}"
if [[ ! "$polls" =~ ^[1-9][0-9]*$ ]]; then
log "DEMO_CREATEBUCKET_POLLS must be a positive whole number of polls, not '${polls}'"
return 1
fi
for attempt in $(seq 1 "$polls"); do
listing="$(docker compose -f "$RUSTFS_COMPOSE" ps --all \
--format '{{.Name}} {{.State}} {{.ExitCode}}' createbucket 2>/dev/null)" || listing=""
line=""
while read -r name rest; do
if [[ "$name" =~ -createbucket-[0-9]+$ ]]; then
line="$rest"
fi
done <<<"$listing"
case "$line" in
"exited "*)
printf '%s\n' "${line#exited }"
return 0
;;
esac
sleep 1
done
log "timed out waiting for the createbucket service to exit (last state: ${line:-not listed})"
return 1
}
if rustfs_healthy; then
log "RustFS already running at ${RUSTFS_ENDPOINT}; ${RAVEL_S3_BUCKET} is expected to exist (the qualify step below reports it if not)"
else
log "starting RustFS via docker compose"
docker compose -f "$RUSTFS_COMPOSE" up -d
STARTED_RUSTFS=1
wait_for "RustFS to become healthy" rustfs_healthy
log "waiting for the createbucket service to set up ${RAVEL_S3_BUCKET}"
createbucket_rc="$(createbucket_exit_code)" || createbucket_rc=timeout
if [[ "$createbucket_rc" != 0 ]]; then
log "the createbucket service failed (exit ${createbucket_rc}); its output:"
docker compose -f "$RUSTFS_COMPOSE" logs createbucket >&2 || true
exit 1
fi
fi
log "building ravel-server and ravel-cli"
cargo build --quiet -p ravel-server -p ravel-cli
# ADR-0050 section 6 (EC7): server startup on a non-Memory store
# refuses unless `sys/qualification` is already present, and there is
# deliberately no bootstrap-and-continue path for it (unlike the tenancy
# marker and gc-config objects). A bucket created fresh above has no such
# record yet, so qualify it before starting the server or it refuses to start.
log "qualifying store backend (ravel-cli store qualify)"
cargo run --quiet -p ravel-cli -- --store s3 store qualify
log "generating fresh OTLP fixture at ${FIXTURE_PATH}"
mkdir -p examples
cargo run --quiet -p ravel-server --example gen_otlp_fixture > "$FIXTURE_PATH"
log "starting ravel-server on ${HTTP_ADDR}"
# A fresh bucket refuses to start unless a tenant-hash scheme is chosen
# (keyed is the default for a real deployment; an unspecified scheme is
# FreshBucketNeedsKey). This is a throwaway dev bucket, so opt out explicitly,
# exactly as the compose quickstart does. Safe on a reused rustfs-data/ too: an
# existing unkeyed marker validates against this flag.
cargo run --quiet -p ravel-server -- \
--store s3 \
--tenant-hash-unkeyed \
--listen-http "$HTTP_ADDR" \
--listen-grpc "$GRPC_ADDR" \
--tenant-token "${TENANT_TOKEN}=${TENANT_NAME}" &
SERVER_PID=$!
server_query_reachable() {
curl --silent --fail --max-time 2 \
-H "Authorization: Bearer ${TENANT_TOKEN}" \
"http://${HTTP_ADDR}/api/v1/query?query=up" >/dev/null 2>&1
}
log "waiting for ravel-server to accept connections"
wait_for "ravel-server to accept connections" server_query_reachable
log "sending OTLP metrics export"
export_headers_file="$(mktemp)"
curl --silent --show-error --fail \
--dump-header "$export_headers_file" \
--output /dev/null \
-X POST "http://${HTTP_ADDR}/v1/metrics" \
-H "Authorization: Bearer ${TENANT_TOKEN}" \
-H "Content-Type: application/x-protobuf" \
--data-binary "@${FIXTURE_PATH}"
commit_token="$(grep -i '^x-ravel-commit-token:' "$export_headers_file" | sed 's/^[^:]*:[[:space:]]*//' | tr -d '\r')"
rm -f "$export_headers_file"
if [[ -z "$commit_token" ]]; then
log "export succeeded but no commit token header was returned"
exit 1
fi
log "export accepted, commit token: ${commit_token}"
log "querying ingested metric with min_commit_token"
query_response="$(curl --silent --show-error --fail \
-H "Authorization: Bearer ${TENANT_TOKEN}" \
--get "http://${HTTP_ADDR}/api/v1/query" \
--data-urlencode "query=demo_requests_total" \
--data-urlencode "min_commit_token=${commit_token}")"
echo "export result: commit_token=${commit_token}"
echo "query result: ${query_response}"
if ! grep -q '"status":"success"' <<<"$query_response"; then
log "query response did not report success"
exit 1
fi
if ! grep -q 'demo_requests_total' <<<"$query_response"; then
log "query response did not contain the ingested series"
exit 1
fi
log "demo complete"