|
7 | 7 | # promoted (or restored by a rollback), so a rejected candidate never records |
8 | 8 | # anything. It copies the revision's image digest, service account, Modal |
9 | 9 | # token and database URL (at the secret versions the revision pins) and its |
10 | | -# plain telemetry settings; nothing else. A revision without the simulation |
11 | | -# database URL predates the safety check, so its schedule is paused. |
| 10 | +# plain telemetry settings; nothing else. A revision deployed before the |
| 11 | +# safety check existed has no job code, so its schedule is paused instead. |
12 | 12 | # |
13 | | -# Environment: PROJECT_ID, REGION, SERVICE, SAFETY_CHECK_REVISION, |
14 | | -# SAFETY_CHECK_SCHEDULER_SERVICE_ACCOUNT, RUNNER_TEMP. |
| 13 | +# With the argument `pause`, only pause the schedule: a workflow does this |
| 14 | +# when pointing the job at a revision failed part way, so the job never keeps |
| 15 | +# running the image traffic just moved away from. |
| 16 | +# |
| 17 | +# Environment: PROJECT_ID, REGION, SERVICE, and unless pausing, |
| 18 | +# SAFETY_CHECK_REVISION, SAFETY_CHECK_SCHEDULER_SERVICE_ACCOUNT, RUNNER_TEMP. |
15 | 19 | set -euo pipefail |
16 | 20 |
|
17 | 21 | fail() { |
18 | 22 | printf '%s\n' "$*" >&2 |
19 | 23 | exit 1 |
20 | 24 | } |
21 | 25 |
|
| 26 | +pause_schedule() { |
| 27 | + if gcloud scheduler jobs describe "${job}" "${scheduler_location[@]}" >/dev/null 2>&1; then |
| 28 | + gcloud scheduler jobs pause "${job}" "${scheduler_location[@]}" --quiet |
| 29 | + fi |
| 30 | +} |
| 31 | + |
22 | 32 | # Every five minutes: SAFETY_CHECK_INTERVAL in |
23 | 33 | # policyengine_simulation_entry.run_recording. |
24 | 34 | SCHEDULE="*/5 * * * *" |
25 | 35 | SECRETS=(SIMULATION_DATABASE_URL MODAL_TOKEN_ID MODAL_TOKEN_SECRET) |
26 | 36 | PLAIN_VARIABLES_FILTER='^(APP_ENVIRONMENT|CLOUD_RUN_REGION|OBSERVABILITY_[A-Z_]+|OTEL_[A-Z_]+|POLICYENGINE_OTEL_GOOGLE_AUDIENCE)$' |
27 | 37 |
|
28 | | -for variable_name in PROJECT_ID REGION SERVICE SAFETY_CHECK_REVISION \ |
29 | | - SAFETY_CHECK_SCHEDULER_SERVICE_ACCOUNT RUNNER_TEMP; do |
| 38 | +for variable_name in PROJECT_ID REGION SERVICE; do |
30 | 39 | [[ -n "${!variable_name:-}" ]] || fail "${variable_name} is required" |
31 | 40 | done |
32 | 41 | [[ "${PROJECT_ID}" =~ ^[a-z][a-z0-9-]{4,28}[a-z0-9]$ ]] || fail "PROJECT_ID is invalid" |
33 | 42 | [[ "${REGION}" =~ ^[a-z]+-[a-z]+[0-9]+$ ]] || fail "REGION is invalid" |
34 | 43 | [[ "${SERVICE}" =~ ^[a-z]([a-z0-9-]{0,47}[a-z0-9])?$ ]] || fail "SERVICE is invalid" |
35 | | -[[ "${SAFETY_CHECK_REVISION}" =~ ^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$ ]] \ |
36 | | - || fail "SAFETY_CHECK_REVISION is invalid" |
37 | | -[[ "${SAFETY_CHECK_SCHEDULER_SERVICE_ACCOUNT}" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.gserviceaccount\.com$ ]] \ |
38 | | - || fail "SAFETY_CHECK_SCHEDULER_SERVICE_ACCOUNT is invalid" |
39 | 44 |
|
40 | 45 | job="${SERVICE}-safety-check" |
41 | 46 | location=(--project "${PROJECT_ID}" --region "${REGION}") |
42 | 47 | scheduler_location=(--project "${PROJECT_ID}" --location "${REGION}") |
43 | 48 |
|
| 49 | +if [[ "${1:-}" == "pause" ]]; then |
| 50 | + pause_schedule |
| 51 | + printf 'The safety check schedule for %s is paused.\n' "${SERVICE}" |
| 52 | + exit 0 |
| 53 | +fi |
| 54 | + |
| 55 | +for variable_name in SAFETY_CHECK_REVISION SAFETY_CHECK_SCHEDULER_SERVICE_ACCOUNT RUNNER_TEMP; do |
| 56 | + [[ -n "${!variable_name:-}" ]] || fail "${variable_name} is required" |
| 57 | +done |
| 58 | +[[ "${SAFETY_CHECK_REVISION}" =~ ^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$ ]] \ |
| 59 | + || fail "SAFETY_CHECK_REVISION is invalid" |
| 60 | +[[ "${SAFETY_CHECK_SCHEDULER_SERVICE_ACCOUNT}" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.gserviceaccount\.com$ ]] \ |
| 61 | + || fail "SAFETY_CHECK_SCHEDULER_SERVICE_ACCOUNT is invalid" |
| 62 | + |
44 | 63 | revision_json="$(gcloud run revisions describe "${SAFETY_CHECK_REVISION}" "${location[@]}" --format=json)" |
45 | 64 | revision_service="$(jq -r '.metadata.labels["serving.knative.dev/service"] // ""' <<<"${revision_json}")" |
46 | 65 | [[ "${revision_service}" == "${SERVICE}" ]] \ |
47 | 66 | || fail "${SAFETY_CHECK_REVISION} belongs to ${revision_service:-no service}, not ${SERVICE}" |
48 | 67 |
|
49 | | -if ! jq -e '.spec.containers[0].env // [] | any(.name == "SIMULATION_DATABASE_URL")' >/dev/null <<<"${revision_json}"; then |
50 | | - if gcloud scheduler jobs describe "${job}" "${scheduler_location[@]}" >/dev/null 2>&1; then |
51 | | - gcloud scheduler jobs pause "${job}" "${scheduler_location[@]}" --quiet |
52 | | - fi |
53 | | - printf '%s has no simulation database, so the safety check is paused.\n' "${SAFETY_CHECK_REVISION}" |
| 68 | +# Every revision deployed with the safety check has the simulation database |
| 69 | +# and the expected Modal caller (SIMULATION_CALL_REPORT_MODAL_WORKSPACE_ID, |
| 70 | +# which the deploy has required since then); an older one has no job code. |
| 71 | +if ! jq -e ' |
| 72 | + .spec.containers[0].env // [] |
| 73 | + | any(.name == "SIMULATION_DATABASE_URL") |
| 74 | + and any(.name == "SIMULATION_CALL_REPORT_MODAL_WORKSPACE_ID") |
| 75 | +' >/dev/null <<<"${revision_json}"; then |
| 76 | + pause_schedule |
| 77 | + printf '%s predates the safety check, so its schedule is paused.\n' "${SAFETY_CHECK_REVISION}" |
54 | 78 | exit 0 |
55 | 79 | fi |
56 | 80 |
|
|
0 commit comments