Expire terminal mutation identities by configured epoch
This commit is contained in:
parent
4b044b1456
commit
cc23211e63
1 changed files with 565 additions and 12 deletions
|
|
@ -362,6 +362,207 @@ spec:
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${NUTHATCH_IDEMPOTENCY_MODE:-}" = verify ]; then
|
||||
pod_curl() {
|
||||
destination="$1"
|
||||
shift
|
||||
command curl --insecure \
|
||||
--resolve "nuthatch-@@LANE@@:8080:$destination" "$@"
|
||||
}
|
||||
|
||||
printf first-epoch >/tmp/epoch-one
|
||||
first_size="$(wc -c </tmp/epoch-one | tr -d ' ')"
|
||||
first_digest="$(sha256sum /tmp/epoch-one | cut -d' ' -f1)"
|
||||
operation=73000000-0000-4000-8000-000000000001
|
||||
mutation_url="$base/upload?root=personal&path=idempotency.txt&operation_id=$operation"
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_A" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header "X-Declared-Size: $first_size" \
|
||||
--header "X-Content-SHA256: $first_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--data-binary @/tmp/epoch-one \
|
||||
"$mutation_url" >/tmp/epoch-first.json
|
||||
grep -F '"result":"succeeded"' /tmp/epoch-first.json
|
||||
grep -F '"idempotency_window_seconds":2' \
|
||||
/tmp/epoch-first.json
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_B" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header "X-Declared-Size: $first_size" \
|
||||
--header "X-Content-SHA256: $first_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--data-binary @/tmp/epoch-one \
|
||||
"$mutation_url" >/tmp/epoch-replay.json
|
||||
grep -F '"result":"succeeded"' /tmp/epoch-replay.json
|
||||
grep -F '"idempotency_window_seconds":2' \
|
||||
/tmp/epoch-replay.json
|
||||
|
||||
printf conflict >/tmp/conflict
|
||||
conflict_size="$(wc -c </tmp/conflict | tr -d ' ')"
|
||||
conflict_digest="$(sha256sum /tmp/conflict | cut -d' ' -f1)"
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_B" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header "X-Declared-Size: $conflict_size" \
|
||||
--header "X-Content-SHA256: $conflict_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--data-binary @/tmp/conflict \
|
||||
"$mutation_url" >/tmp/epoch-conflict.json
|
||||
grep -F '"result":"conflict"' /tmp/epoch-conflict.json
|
||||
|
||||
sleep 3
|
||||
printf second-epoch-a >/tmp/epoch-two-a
|
||||
printf second-epoch-b >/tmp/epoch-two-b
|
||||
second_a_size="$(wc -c </tmp/epoch-two-a | tr -d ' ')"
|
||||
second_b_size="$(wc -c </tmp/epoch-two-b | tr -d ' ')"
|
||||
second_a_digest="$(
|
||||
sha256sum /tmp/epoch-two-a | cut -d' ' -f1
|
||||
)"
|
||||
second_b_digest="$(
|
||||
sha256sum /tmp/epoch-two-b | cut -d' ' -f1
|
||||
)"
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_A" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header "X-Declared-Size: $second_a_size" \
|
||||
--header "X-Content-SHA256: $second_a_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--data-binary @/tmp/epoch-two-a \
|
||||
"$mutation_url" >/tmp/epoch-two-a.json &
|
||||
epoch_two_a_pid=$!
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_B" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header "X-Declared-Size: $second_b_size" \
|
||||
--header "X-Content-SHA256: $second_b_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--data-binary @/tmp/epoch-two-b \
|
||||
"$mutation_url" >/tmp/epoch-two-b.json &
|
||||
epoch_two_b_pid=$!
|
||||
wait "$epoch_two_a_pid"
|
||||
wait "$epoch_two_b_pid"
|
||||
test "$(
|
||||
grep -lF '"result":"succeeded"' \
|
||||
/tmp/epoch-two-a.json /tmp/epoch-two-b.json |
|
||||
wc -l |
|
||||
tr -d ' '
|
||||
)" = 1
|
||||
test "$(
|
||||
grep -lF '"result":"conflict"' \
|
||||
/tmp/epoch-two-a.json /tmp/epoch-two-b.json |
|
||||
wc -l |
|
||||
tr -d ' '
|
||||
)" = 1
|
||||
if grep -F '"result":"succeeded"' \
|
||||
/tmp/epoch-two-a.json >/dev/null; then
|
||||
epoch_two_body=/tmp/epoch-two-a
|
||||
epoch_two_size="$second_a_size"
|
||||
epoch_two_digest="$second_a_digest"
|
||||
epoch_two_ip="$NUTHATCH_IDEMPOTENCY_IP_B"
|
||||
else
|
||||
epoch_two_body=/tmp/epoch-two-b
|
||||
epoch_two_size="$second_b_size"
|
||||
epoch_two_digest="$second_b_digest"
|
||||
epoch_two_ip="$NUTHATCH_IDEMPOTENCY_IP_A"
|
||||
fi
|
||||
pod_curl "$epoch_two_ip" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header "X-Declared-Size: $epoch_two_size" \
|
||||
--header "X-Content-SHA256: $epoch_two_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--data-binary @"$epoch_two_body" \
|
||||
"$mutation_url" >/tmp/epoch-two-replay.json
|
||||
grep -F '"result":"succeeded"' /tmp/epoch-two-replay.json
|
||||
grep -F '"idempotency_window_seconds":2' \
|
||||
/tmp/epoch-two-replay.json
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_A" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
"$base/download?root=personal&path=idempotency.txt" \
|
||||
>/tmp/epoch-download
|
||||
cmp "$epoch_two_body" /tmp/epoch-download
|
||||
|
||||
dd if=/dev/zero of=/tmp/active-body bs=1048576 count=1 \
|
||||
status=none
|
||||
active_digest="$(
|
||||
sha256sum /tmp/active-body | cut -d' ' -f1
|
||||
)"
|
||||
active_operation=73000000-0000-4000-8000-000000000002
|
||||
active_url="$base/upload?root=personal&path=active-window.bin&operation_id=$active_operation"
|
||||
(
|
||||
dd if=/tmp/active-body bs=65536 count=1 status=none
|
||||
sleep 5
|
||||
dd if=/tmp/active-body bs=65536 skip=1 count=15 status=none
|
||||
) |
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_A" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header 'X-Declared-Size: 1048576' \
|
||||
--header "X-Content-SHA256: $active_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--request POST \
|
||||
--upload-file - \
|
||||
"$active_url" >/tmp/active-first.json &
|
||||
active_pid=$!
|
||||
sleep 3
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_B" \
|
||||
--fail --silent --show-error \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header 'X-Declared-Size: 1048576' \
|
||||
--header "X-Content-SHA256: $active_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--data-binary @/tmp/epoch-one \
|
||||
"$active_url" >/tmp/active-replay.json
|
||||
grep -F '"result":"pending"' /tmp/active-replay.json
|
||||
lock_status="$(
|
||||
pod_curl "$NUTHATCH_IDEMPOTENCY_IP_B" \
|
||||
--silent --show-error \
|
||||
--output /tmp/active-lock.json \
|
||||
--write-out '%{http_code}' \
|
||||
--cookie "$cookies" \
|
||||
--header 'Content-Type: application/octet-stream' \
|
||||
--header "X-Declared-Size: $first_size" \
|
||||
--header "X-Content-SHA256: $first_digest" \
|
||||
--header "X-CSRF-Token: $csrf" \
|
||||
--data-binary @/tmp/epoch-one \
|
||||
"$base/upload?root=personal&path=active-window.bin&operation_id=73000000-0000-4000-8000-000000000003"
|
||||
)"
|
||||
test "$lock_status" = 409
|
||||
grep -F '"error":"mutation_rejected"' /tmp/active-lock.json
|
||||
wait "$active_pid"
|
||||
grep -F '"result":"succeeded"' /tmp/active-first.json
|
||||
|
||||
printf '%s\n' \
|
||||
'{"epoch":1,"action":"Init"}' \
|
||||
'{"epoch":1,"action":"FirstRequest","observation":{"result":"pending","disposition":"first"}}' \
|
||||
'{"epoch":1,"action":"PrepareEffect"}' \
|
||||
'{"epoch":1,"action":"DispatchEffect"}' \
|
||||
'{"epoch":1,"action":"ExternalEffectApplied"}' \
|
||||
'{"epoch":1,"action":"FinalizeSuccess"}' \
|
||||
'{"epoch":1,"action":"ReplayRequest","observation":{"result":"succeeded","disposition":"replay"}}' \
|
||||
'{"epoch":1,"action":"ConflictRequest","observation":{"result":"conflict","disposition":"conflict"}}' \
|
||||
'{"after_epoch":1,"action":"TraceCut","reason":"terminal_identity_expired"}' \
|
||||
'{"epoch":2,"action":"Init"}' \
|
||||
'{"epoch":2,"action":"FirstRequest","observation":{"result":"pending","disposition":"first"}}' \
|
||||
'{"epoch":2,"action":"PrepareEffect"}' \
|
||||
'{"epoch":2,"action":"DispatchEffect"}' \
|
||||
'{"epoch":2,"action":"ExternalEffectApplied"}' \
|
||||
'{"epoch":2,"action":"FinalizeSuccess"}' \
|
||||
'{"epoch":2,"action":"ReplayRequest","observation":{"result":"succeeded","disposition":"replay"}}'
|
||||
printf 'Cross-process idempotency epoch probes passed\n'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${NUTHATCH_STREAMING_MODE:-}" = large ]; then
|
||||
large_bytes="${NUTHATCH_STREAMING_LARGE_BYTES:?}"
|
||||
printf 'Preparing %s-byte streaming object\n' "$large_bytes"
|
||||
|
|
@ -955,6 +1156,24 @@ spec:
|
|||
name: @@PROFILE_NAME@@
|
||||
key: NUTHATCH_STREAMING_THROTTLE_BURST_BYTES
|
||||
optional: true
|
||||
- name: NUTHATCH_IDEMPOTENCY_MODE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: @@PROFILE_NAME@@
|
||||
key: NUTHATCH_IDEMPOTENCY_MODE
|
||||
optional: true
|
||||
- name: NUTHATCH_IDEMPOTENCY_IP_A
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: @@PROFILE_NAME@@
|
||||
key: NUTHATCH_IDEMPOTENCY_IP_A
|
||||
optional: true
|
||||
- name: NUTHATCH_IDEMPOTENCY_IP_B
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: @@PROFILE_NAME@@
|
||||
key: NUTHATCH_IDEMPOTENCY_IP_B
|
||||
optional: true
|
||||
- name: NUTHATCH_OIDC_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
|
|
|
|||
Loading…
Reference in a new issue