Skip to content

Commit 34f3a5c

Browse files
committed
fix(relay): staging director deploys run as relay-dir with rehome identity, and can register one cell's cap
Rebased onto main as one commit after its parent squash-merged.
1 parent e9bf6d1 commit 34f3a5c

5 files changed

Lines changed: 122 additions & 5 deletions

‎.github/workflows/cloud-bootstrap-relay-staging-capacity.yml‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,6 @@ jobs:
544544
--capacity-service-account "${CAPACITY_SERVICE_ACCOUNT}" \
545545
--capacity-cell-id "${cell_id}" \
546546
--director-cells-json "${desired_cells_json}" \
547-
--min-instances 0 \
548547
--prune-revisions true \
549548
--release-id "bootstrap-${cell_id}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}")"
550549
echo "${director_result}"

‎.github/workflows/cloud-deploy-relay-staging.yml‎

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,35 @@ on:
1313
default: preserve
1414
type: choice
1515
options: [preserve, 'off', dry-run, 'on']
16+
expected-rehome-generation:
17+
description: Exact durable regional-rehome generation; it must remain disabled
18+
required: true
19+
type: string
20+
bootstrap-runtime-identity:
21+
description: One-time move from the stamped-cell identity to the director identity
22+
required: true
23+
default: false
24+
type: boolean
25+
predecessor-image-digest:
26+
description: Bootstrap only. Exact immutable serving predecessor digest
27+
required: false
28+
type: string
29+
capacity-cell-id:
30+
description: Register this cell's reviewed staging.tfvars cap and bound with the director
31+
required: true
32+
default: none
33+
type: choice
34+
options: [none, staging-gce-c1, staging-gce-c2, staging-gce-c3, staging-gce-c4]
35+
min-instances:
36+
description: Director floor; preserve keeps the serving revision's, so a reserve run's 2 survives
37+
required: true
38+
default: preserve
39+
type: choice
40+
options: [preserve, '0', '2']
41+
confirmation:
42+
description: BOOTSTRAP_RELAY_DIRECTOR_REHOME_IDENTITY for a bootstrap
43+
required: false
44+
type: string
1645
shadow-seat-feed-cells:
1746
description: Preserve the step-3 shadow seat-feed cells, or set all or a comma list of cell ids; dropping a reserve cell is refused
1847
required: true
@@ -47,11 +76,34 @@ jobs:
4776
CAPACITY_SERVICE_ACCOUNT: ${{ vars.STAGING_GCP_RELAY_CAPACITY_SERVICE_ACCOUNT }}
4877
ASIA_PROOF_SERVICE_ACCOUNT: ${{ vars.STAGING_GCP_RELAY_ASIA_PROOF_SERVICE_ACCOUNT }}
4978
REGIONAL_PLACEMENT_SECRET: orca-cloud-relay-regional-placement-enabled
79+
DIRECTOR_RUNTIME_SERVICE_ACCOUNT: orca-cloud-staging-relay-dir@onorca-cloud-staging.iam.gserviceaccount.com
80+
PREDECESSOR_RUNTIME_SERVICE_ACCOUNT: orca-cloud-staging-relay@onorca-cloud-staging.iam.gserviceaccount.com
81+
REHOME_AUDIENCE: https://relay-staging.onorca.dev/v1/admin/host-drain
82+
EXPECTED_REHOME_GENERATION: ${{ inputs.expected-rehome-generation }}
83+
BOOTSTRAP_RUNTIME_IDENTITY: ${{ inputs.bootstrap-runtime-identity }}
84+
PREDECESSOR_IMAGE_DIGEST: ${{ inputs.predecessor-image-digest }}
85+
CAPACITY_CELL_ID: ${{ inputs.capacity-cell-id }}
86+
MIN_INSTANCES: ${{ inputs.min-instances }}
5087
steps:
5188
- uses: actions/checkout@v4
5289

53-
- name: Require the expected immutable image
54-
run: '[[ "${EXPECTED_IMAGE_DIGEST}" =~ ^sha256:[a-f0-9]{64}$ ]]'
90+
- name: Require the expected immutable image and identity request
91+
shell: bash
92+
env:
93+
CONFIRMATION: ${{ inputs.confirmation }}
94+
run: |
95+
set -euo pipefail
96+
[[ "${EXPECTED_IMAGE_DIGEST}" =~ ^sha256:[a-f0-9]{64}$ ]]
97+
[[ "${EXPECTED_REHOME_GENERATION}" =~ ^(0|[1-9][0-9]*)$ ]]
98+
[[ "${BOOTSTRAP_RUNTIME_IDENTITY}" =~ ^(true|false)$ ]]
99+
[[ "${MIN_INSTANCES}" =~ ^(preserve|0|2)$ ]]
100+
if test "${BOOTSTRAP_RUNTIME_IDENTITY}" = true; then
101+
[[ "${PREDECESSOR_IMAGE_DIGEST}" =~ ^sha256:[a-f0-9]{64}$ ]]
102+
test "${CAPACITY_CELL_ID}" = none
103+
test "${CONFIRMATION}" = BOOTSTRAP_RELAY_DIRECTOR_REHOME_IDENTITY
104+
else
105+
test -z "${PREDECESSOR_IMAGE_DIGEST}"
106+
fi
55107
56108
- uses: hashicorp/setup-terraform@v3
57109
with:
@@ -79,6 +131,16 @@ jobs:
79131
test "${IMAGE}" = \
80132
"${GCP_REGION}-docker.pkg.dev/${GCP_PROJECT_ID}/${REPOSITORY_ID}/${IMAGE_NAME}@${EXPECTED_IMAGE_DIGEST}"
81133
echo "IMAGE=${IMAGE}" >> "${GITHUB_ENV}"
134+
if test "${CAPACITY_CELL_ID}" != none; then
135+
# The deploy script refuses any topology change beyond this one cell's cap and bound.
136+
DESIRED_CELLS_JSON="$(terraform -chdir=infra/terraform console \
137+
-var-file=environments/staging.tfvars \
138+
<<< 'local.relay_director_cells_json' | jq -er '.')"
139+
jq -e --arg cell "${CAPACITY_CELL_ID}" \
140+
'any(.[]; .id == $cell and .connectionHardCap != null)' \
141+
<<< "${DESIRED_CELLS_JSON}" >/dev/null
142+
echo "DESIRED_CELLS_JSON=${DESIRED_CELLS_JSON}" >> "${GITHUB_ENV}"
143+
fi
82144
83145
- uses: google-github-actions/setup-gcloud@v2
84146

@@ -109,6 +171,26 @@ jobs:
109171
--format='value(name)' | awk -F/ '{print $NF}')"
110172
[[ "${regional_version}" =~ ^[1-9][0-9]*$ ]]
111173
RELEASE_ID="${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${GITHUB_SHA:0:8}"
174+
identity_args=()
175+
if test "${BOOTSTRAP_RUNTIME_IDENTITY}" = true; then
176+
identity_args=(
177+
--bootstrap-runtime-identity true
178+
--predecessor-runtime-service-account "${PREDECESSOR_RUNTIME_SERVICE_ACCOUNT}"
179+
--predecessor-image-digest "${PREDECESSOR_IMAGE_DIGEST}"
180+
)
181+
fi
182+
# Omitted, the deploy script inherits the serving revision's floor.
183+
floor_args=()
184+
if test "${MIN_INSTANCES}" != preserve; then
185+
floor_args=(--min-instances "${MIN_INSTANCES}")
186+
fi
187+
topology_args=()
188+
if test "${CAPACITY_CELL_ID}" != none; then
189+
topology_args=(
190+
--capacity-cell-id "${CAPACITY_CELL_ID}"
191+
--director-cells-json "${DESIRED_CELLS_JSON}"
192+
)
193+
fi
112194
node dev/scripts/deploy-relay-blue-green.mjs \
113195
--project "${GCP_PROJECT_ID}" \
114196
--region "${GCP_REGION}" \
@@ -119,7 +201,14 @@ jobs:
119201
--capacity-service-account "${CAPACITY_SERVICE_ACCOUNT}" \
120202
--asia-proof-service-account "${ASIA_PROOF_SERVICE_ACCOUNT}" \
121203
--regional-placement-secret-version "${regional_version}" \
122-
--min-instances 0 \
204+
"${floor_args[@]}" \
205+
--runtime-service-account "${DIRECTOR_RUNTIME_SERVICE_ACCOUNT}" \
206+
"${identity_args[@]}" \
207+
--rehome-director-service-account "${DIRECTOR_RUNTIME_SERVICE_ACCOUNT}" \
208+
--rehome-audience "${REHOME_AUDIENCE}" \
209+
--rehome-control-origin https://relay-staging.onorca.dev \
210+
--expected-rehome-generation "${EXPECTED_REHOME_GENERATION}" \
211+
"${topology_args[@]}" \
123212
--admin-audience https://relay-staging.onorca.dev/v1/admin/drain \
124213
--reserve-placement "${RESERVE_PLACEMENT}" \
125214
--shadow-seat-feed-cells "${SHADOW_SEAT_FEED_CELLS}" \

‎.github/workflows/cloud-prove-relay-staging-capacity.yml‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,6 @@ jobs:
417417
--capacity-service-account "${CAPACITY_SERVICE_ACCOUNT}" \
418418
--capacity-cell-id "${TARGET_CELL_ID}" \
419419
--director-cells-json "${DESIRED_CELLS_JSON}" \
420-
--min-instances 0 \
421420
--prune-revisions true \
422421
--release-id "${RELEASE_ID}")"
423422
echo "${DEPLOY_RESULT}"

‎cloud/dev/scripts/relay-deploy-workflow-argv.test.mjs‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ function sample(flag) {
4040
return `sample-${flag}`
4141
}
4242

43+
// Flags a workflow passes through a bash array (`"${name[@]}"`), from every `name=(...)` it
44+
// assigns; parsing them all at once is the widest set that workflow can send.
45+
function arrayArguments(source, name) {
46+
const flags = []
47+
for (const match of source.matchAll(new RegExp(`\\b${name}=\\(([^)]*)\\)`, 'g'))) {
48+
for (const entry of match[1].matchAll(/(--[a-z0-9-]+)\s+("[^"]*"|\S+)/g)) {
49+
flags.push([entry[1], entry[2].replace(/^"(.*)"$/, '$1')])
50+
}
51+
}
52+
if (flags.length === 0) throw new Error(`no flags assigned to ${name}`)
53+
return flags
54+
}
55+
4356
function invocations(source, script) {
4457
const lines = source.split('\n')
4558
const found = []
@@ -49,6 +62,13 @@ function invocations(source, script) {
4962
let line = lines[index]
5063
while (line.trimEnd().endsWith('\\')) {
5164
line = lines[++index]
65+
const array = /^\s*"\$\{([a-z_]+)\[@\]\}"\s*\\?\s*$/.exec(line)
66+
if (array) {
67+
for (const [flag, value] of arrayArguments(source, array[1])) {
68+
argv.push(flag, value.includes('$') ? sample(flag.slice(2)) : value)
69+
}
70+
continue
71+
}
5272
const match = /^\s*(--[a-z0-9-]+)\s+(.+?)\s*\\?\s*$/.exec(line)
5373
if (!match) throw new Error(`unparsed ${script} argument line: ${line.trim()}`)
5474
const [, flag, raw] = match

‎cloud/dev/scripts/relay-staging-deploy-identity.test.mjs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,13 @@ test('the identity is exposed through its own outputs', () => {
223223
assert.match(outputs, /output "github_staging_relay_deploy_workload_identity_provider"/)
224224
assert.match(outputs, /output "github_staging_relay_deploy_service_account"/)
225225
})
226+
227+
// Why: relay-deploy-workflow-argv.test.mjs proves the argv parses; this pins the identity it names.
228+
test('the staging director deploy runs as relay-dir with its rehome identity', () => {
229+
const source = workflow('deploy-relay-staging.yml')
230+
const start = source.indexOf('node dev/scripts/deploy-relay-blue-green.mjs')
231+
const block = source.slice(start, source.indexOf('\n\n', start))
232+
assert.match(block, /--runtime-service-account "\$\{DIRECTOR_RUNTIME_SERVICE_ACCOUNT\}"/)
233+
assert.match(block, /--rehome-director-service-account "\$\{DIRECTOR_RUNTIME_SERVICE_ACCOUNT\}"/)
234+
assert.match(source, /DIRECTOR_RUNTIME_SERVICE_ACCOUNT: orca-cloud-staging-relay-dir@/)
235+
})

0 commit comments

Comments
 (0)