feat(relay): declare Asia cell c31 at the c30 shape (#24310)

Claude-Session: ced32ebb-7155-4413-adad-1eccd14c2010
This commit is contained in:
Jinwoo Hong
2026-10-01 03:11:32 -04:00
committed by GitHub
parent d2dfc79764
commit 3e5c8d9f8e
23 changed files with 200 additions and 70 deletions
@@ -19,16 +19,21 @@ const SHAPES = {
production: {
directorOrigin: 'https://relay.onorca.dev',
domain: 'relay.onorca.dev',
allCells: ['production-gce-c27', 'production-gce-c28', 'production-gce-c29', 'production-gce-c30'],
allCells: [
'production-gce-c27', 'production-gce-c28', 'production-gce-c29', 'production-gce-c30',
'production-gce-c31'
],
// The launch set was registered together; each later cell registers alone beside it.
registrationWaves: [
['production-gce-c27', 'production-gce-c28', 'production-gce-c29'],
['production-gce-c30']
['production-gce-c30'],
['production-gce-c31']
],
promotionWaves: [
['production-gce-c27'],
['production-gce-c28', 'production-gce-c29'],
['production-gce-c30']
['production-gce-c30'],
['production-gce-c31']
]
}
}
@@ -526,23 +526,30 @@ function admissionArguments(environment, mode, cellIds) {
test('accepts only reviewed Asia admission waves', () => {
const accepted = [
['inspect', 'production-gce-c27,production-gce-c28,production-gce-c29'],
['inspect', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30'],
['inspect', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30,production-gce-c31'],
['inspect', 'production-gce-c30'],
['inspect', 'production-gce-c31'],
['verify', 'production-gce-c27,production-gce-c28,production-gce-c29'],
['verify', 'production-gce-c30'],
['verify', 'production-gce-c31'],
['initialize', 'production-gce-c27,production-gce-c28,production-gce-c29'],
['register', 'production-gce-c27,production-gce-c28,production-gce-c29'],
['register', 'production-gce-c30'],
['registered', 'production-gce-c30'],
['register', 'production-gce-c31'],
['registered', 'production-gce-c31'],
['promote', 'production-gce-c27'],
['promote', 'production-gce-c28,production-gce-c29'],
['promote', 'production-gce-c30'],
['recover-promotion', 'production-gce-c30'],
['promote', 'production-gce-c31'],
['recover-promotion', 'production-gce-c31'],
['rollback', 'production-gce-c27'],
['rollback', 'production-gce-c28,production-gce-c29'],
['rollback', 'production-gce-c30'],
['rollback', 'production-gce-c31'],
['rollback', 'production-gce-c27,production-gce-c28,production-gce-c29'],
['rollback', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30']
['rollback', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30,production-gce-c31']
]
for (const [mode, cellIds] of accepted) {
assert.deepEqual(
@@ -553,15 +560,21 @@ test('accepts only reviewed Asia admission waves', () => {
}
const rejected = [
['initialize', 'production-gce-c30'],
['initialize', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30'],
['register', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30'],
['initialize', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30,production-gce-c31'],
['register', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30,production-gce-c31'],
['register', 'production-gce-c30,production-gce-c31'],
['register', 'production-gce-c29,production-gce-c30'],
['registered', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30'],
['registered', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30,production-gce-c31'],
['inspect', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30'],
['verify', 'production-gce-c30,production-gce-c31'],
['verify', 'production-gce-c27,production-gce-c30'],
['promote', 'production-gce-c27,production-gce-c30'],
['promote', 'production-gce-c28,production-gce-c29,production-gce-c30'],
['promote', 'production-gce-c31'],
['promote', 'production-gce-c30,production-gce-c31'],
['promote', 'production-gce-c32'],
['rollback', 'production-gce-c27,production-gce-c30'],
['rollback', 'production-gce-c30,production-gce-c31'],
['rollback', 'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30'],
['rollback', 'production-gce-c28,production-gce-c29,production-gce-c30'],
['rollback', 'production-gce-c29'],
['register', 'staging-gce-c4']
@@ -601,6 +614,25 @@ test('registers C30 alone beside the general launch cells', async () => {
assert.deepEqual(subject.selector().membership.general, launchCells)
})
test('registers C31 alone beside the general C27-C30', async () => {
const general = [...launchCells, 'production-gce-c30']
const subject = harness({
generation: 11,
membership: { existingOnly: [], migrationOnly: [], general: [...general] }
})
const result = await operateRelayAsiaAdmission({
environment: 'production', mode: 'register', cells: ['production-gce-c31'],
expectedGeneration: 11, imageDigest: digest, attemptId: 'asia_register_c31', token: 'not-logged'
}, subject)
const request = subject.requests.find(({ path }) => path.endsWith('/add-migration-cells'))
assert.deepEqual(request.body.cells, [{
cellId: 'production-gce-c31', cellUrl: 'https://c31.relay.onorca.dev', region: 'asia-east2',
capacityRequests: 6_000, connectionHardCap: 3_000, connectionUnobservedBound: 60
}])
assert.deepEqual(result.states, { 'production-gce-c31': 'migration-only' })
assert.deepEqual(subject.selector().membership.general, general)
})
test('requires the C27 canary to be general before promoting C30', async () => {
const selector = (general) => ({
generation: 10,
@@ -16,12 +16,14 @@ const SHAPES = {
'production-gce-c27': 'asia-east2-a',
'production-gce-c28': 'asia-east2-b',
'production-gce-c29': 'asia-east2-c',
'production-gce-c30': 'asia-east2-a'
'production-gce-c30': 'asia-east2-a',
'production-gce-c31': 'asia-east2-b'
},
// The launch set, then each later additive cell; a plan targets one wave, never live cells.
waves: [
['production-gce-c27', 'production-gce-c28', 'production-gce-c29'],
['production-gce-c30']
['production-gce-c30'],
['production-gce-c31']
]
}
}
@@ -11,7 +11,8 @@ const productionCells = () => Object.fromEntries([
[27, 'asia-east2-a'],
[28, 'asia-east2-b'],
[29, 'asia-east2-c'],
[30, 'asia-east2-a']
[30, 'asia-east2-a'],
[31, 'asia-east2-b']
].map(([ordinal, zone]) => [`production-gce-c${ordinal}`, {
hostname: `c${ordinal}`, region: 'asia-east2', zone,
machine_type: 'e2-standard-4', boot_disk_gb: 30,
@@ -46,6 +47,13 @@ test('accepts the additive C30 wave without re-planning the launch cells', () =>
assert.equal(result.relay_gce_cells['production-gce-c30'].zone, 'asia-east2-a')
})
test('accepts the additive C31 wave in the next zone of the rotation', () => {
const result = prepareRelayAsiaTopologyInput({ existingCells: productionCells(),
existingAdditionalRegions: additionalRegions, environment: 'production',
cellIds: 'production-gce-c31', image })
assert.equal(result.relay_gce_cells['production-gce-c31'].zone, 'asia-east2-b')
})
// Reads the committed file so a reviewed-shape constant cannot drift from what the plan reads.
test('matches every committed production Asia cell entry', () => {
const tfvars = readFileSync(
@@ -64,10 +72,11 @@ test('matches every committed production Asia cell entry', () => {
}
committed[cellId] = cell
}
// Each wave is pinned on its own: C30 launches on the director's digest, not C27's.
// Each wave is pinned on its own: C30 and C31 launch on the director's digest, not C27's.
for (const wave of [
'production-gce-c27,production-gce-c28,production-gce-c29',
'production-gce-c30'
'production-gce-c30',
'production-gce-c31'
]) {
const committedImage = committed[wave.split(',')[0]].image
assert.doesNotThrow(() => prepareRelayAsiaTopologyInput({
@@ -109,7 +118,8 @@ test('rejects an uncommitted subnet or cell, partial wave, wrong image, and drif
'production-gce-c27,production-gce-c30',
'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30',
'production-gce-c30,production-gce-c30',
'production-gce-c31'
'production-gce-c30,production-gce-c31',
'production-gce-c32'
]) {
assert.throws(() => prepareRelayAsiaTopologyInput({
existingCells: productionCells(), existingAdditionalRegions: additionalRegions,
@@ -98,7 +98,7 @@ describe('production Relay capacity cell admission', () => {
for (const cellId of [
'production-gce-c27', 'production-gce-c28', 'production-gce-c29', 'production-gce-c30',
// Migration-only canaries: the US-only capacity rollout never touches them either.
'production-gce-c17', 'production-gce-c18'
'production-gce-c17', 'production-gce-c18', 'production-gce-c31'
]) {
const hostname = cellId.slice('production-gce-'.length)
assert.deepEqual(parseProductionCapacityCellArguments([
@@ -115,7 +115,7 @@ describe('production Relay capacity cell admission', () => {
paceWindowMs: 0
})
}
for (const cellId of ['production-gce-c12', 'production-gce-c31']) {
for (const cellId of ['production-gce-c12', 'production-gce-c32']) {
const hostname = cellId.slice('production-gce-'.length)
assert.throws(() => parseProductionCapacityCellArguments([
'--director-origin', 'https://relay.onorca.dev',
@@ -2,8 +2,8 @@ import { pathToFileURL } from 'node:url'
import { fetchAdminOnceMore } from './relay-admin-transient-retry.mjs'
// Every cell that carries the rehome identity: the sixteen US cells and the
// four asia-east2 cells that drain mis-homed hosts back the other way.
const PRODUCTION_CELL = /^production-gce-c(?:7|8|9|10|13|14|15|16|19|20|21|22|23|24|25|26|27|28|29|30)$/
// five asia-east2 cells that drain mis-homed hosts back the other way.
const PRODUCTION_CELL = /^production-gce-c(?:7|8|9|10|13|14|15|16|19|20|21|22|23|24|25|26|27|28|29|30|31)$/
const DIRECTOR_ORIGIN = 'https://relay.onorca.dev'
export function parseRehomeTrustProbeArguments(argv, environment = process.env) {
@@ -114,7 +114,8 @@ test('fails when both trust-probe attempts return a transient 503', async () =>
test('approves the asia-east2 rehome sources and still rejects unlisted cells', () => {
for (const cellId of [
'production-gce-c27', 'production-gce-c28', 'production-gce-c29', 'production-gce-c30'
'production-gce-c27', 'production-gce-c28', 'production-gce-c29', 'production-gce-c30',
'production-gce-c31'
]) {
const parsed = parseRehomeTrustProbeArguments(
argv.map((value) => (value === 'production-gce-c7' ? cellId : value)),
@@ -122,7 +123,7 @@ test('approves the asia-east2 rehome sources and still rejects unlisted cells',
)
assert.equal(parsed.cellId, cellId)
}
for (const cellId of ['production-gce-c1', 'production-gce-c17', 'production-gce-c31']) {
for (const cellId of ['production-gce-c1', 'production-gce-c17', 'production-gce-c32']) {
assert.throws(
() =>
parseRehomeTrustProbeArguments(
@@ -11,7 +11,8 @@ const C27 = 'production-gce-c27'
// Each canary proves its own cell under production load; C28/C29 promotion consumes only C27's.
const PRODUCTION_CANARIES = {
[C27]: { kind: 'production-c27-canary', origin: 'https://c27.relay.onorca.dev' },
'production-gce-c30': { kind: 'production-c30-canary', origin: 'https://c30.relay.onorca.dev' }
'production-gce-c30': { kind: 'production-c30-canary', origin: 'https://c30.relay.onorca.dev' },
'production-gce-c31': { kind: 'production-c31-canary', origin: 'https://c31.relay.onorca.dev' }
}
const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/
const SHA_PATTERN = /^[a-f0-9]{40}$/
@@ -389,6 +389,19 @@ test('builds and verifies a C30 canary from C30 runtime metrics and placement',
), /evidence kind is invalid/)
})
test('builds a C31 canary that only C31 placement satisfies', () => {
const c31 = 'production-gce-c31'
const evidence = buildProductionCanaryEvidence(canaryInput({}, c31))
assert.equal(evidence.kind, 'production-c31-canary')
assert.equal(verifyRolloutEvidence(
evidence, workflowRun(evidence),
verifyExpected('production-c31-canary', { cellIds: [c31], selectorGeneration: 9 })
), evidence)
const onC30 = canaryInput({}, c31)
onC30.loadReport.assignedCellOrigins = ['https://c30.relay.onorca.dev']
assert.throws(() => buildProductionCanaryEvidence(onC30), /C31 canary load was not placed only on C31/)
})
test('rejects a C30 canary that C30 did not serve', () => {
const onLaunchCell = canaryInput({}, c30)
onLaunchCell.loadReport.assignedCellOrigins = ['https://c27.relay.onorca.dev']
@@ -44,7 +44,8 @@ test('accepts only the reviewed Asia topology waves', () => {
[
'staging:staging-gce-c4',
'production:production-gce-c27,production-gce-c28,production-gce-c29',
'production:production-gce-c30'
'production:production-gce-c30',
'production:production-gce-c31'
]
)
})
@@ -7,12 +7,12 @@ import {
} from './relay-cloud-sql-connection-budget.mjs'
test('production shared consumers keep allowance and reserve below the ceiling', () => {
// cells: 20 pools at 10 (200) + the four asia-east2 pools at 16 (64).
// cells: 20 pools at 10 (200) + the five asia-east2 pools at 16 (80).
const report = readRelayCloudSqlConnectionBudget()
assert.deepEqual(report.consumers, { cells: 264, directors: 15, auth: 20, api: 50 })
assert.deepEqual(report.asia, { cells: 4, poolMax: 16 })
assert.equal(report.configuredMaximum, 349)
assert.deepEqual(report.consumers, { cells: 280, directors: 15, auth: 20, api: 50 })
assert.deepEqual(report.asia, { cells: 5, poolMax: 16 })
assert.equal(report.configuredMaximum, 365)
assert.equal(report.rolloutOverlap.relayDirectorCandidate, 30)
assert.equal(report.rolloutOverlap.apiCandidate, 65)
assert.equal(report.rolloutOverlap.authCandidate, 35)
@@ -22,10 +22,10 @@ test('production shared consumers keep allowance and reserve below the ceiling',
assert.equal(report.maintenanceAdminAllowance, 5)
assert.equal(report.explicitReserve, 10)
assert.equal(report.usableCeiling, 490)
assert.equal(report.operatingMaximum, 419)
assert.equal(report.remainingWithinUsableCeiling, 71)
assert.equal(report.budgetedTotal, 429)
assert.equal(report.unallocated, 71)
assert.equal(report.operatingMaximum, 435)
assert.equal(report.remainingWithinUsableCeiling, 55)
assert.equal(report.budgetedTotal, 445)
assert.equal(report.unallocated, 55)
assert.equal(report.withinBudget, true)
})
@@ -4,7 +4,10 @@ import { requireSameEvidenceCode } from './relay-evidence-code-provenance.mjs'
// Migration-only by policy: zero hosts and no reservation, so a wave rolls one without
// displacing anybody. It enters and must leave migration-only, never general.
export const SAME_CAP_MIGRATION_ONLY_CELLS = ['production-gce-c17', 'production-gce-c18']
// C31 stays here until its Asia canary promotes it; that follow-up moves it to the general list.
export const SAME_CAP_MIGRATION_ONLY_CELLS = [
'production-gce-c17', 'production-gce-c18', 'production-gce-c31'
]
export const SAME_CAP_CELLS = [
'production-gce-c7', 'production-gce-c8', 'production-gce-c9', 'production-gce-c10',
@@ -56,12 +56,19 @@ test('requires one canary or a bounded reviewed batch', () => {
rollbackDigest,
confirmation: `ROLL_RELAY_SAME_CAP ${targetDigest} production-gce-c30`
}).cells, ['production-gce-c30'])
assert.throws(() => validateSameCapWave({
assert.deepEqual(validateSameCapWave({
mode: 'canary-apply',
cellIds: 'production-gce-c31',
targetDigest,
rollbackDigest,
confirmation: `ROLL_RELAY_SAME_CAP ${targetDigest} production-gce-c31`
}).cells, ['production-gce-c31'])
assert.throws(() => validateSameCapWave({
mode: 'canary-apply',
cellIds: 'production-gce-c32',
targetDigest,
rollbackDigest,
confirmation: `ROLL_RELAY_SAME_CAP ${targetDigest} production-gce-c32`
}), /cells/)
})
@@ -107,8 +114,11 @@ test('the wave workflow chains exactly ten serial cell jobs', () => {
assert.doesNotMatch(dispatch, /\n cell_11:/)
})
test('lists only C17 and C18 as migration-only now that C30 is promoted', () => {
assert.deepEqual(SAME_CAP_MIGRATION_ONLY_CELLS, ['production-gce-c17', 'production-gce-c18'])
test('lists C31 as migration-only beside C17 and C18 until its canary promotes it', () => {
assert.deepEqual(
SAME_CAP_MIGRATION_ONLY_CELLS,
['production-gce-c17', 'production-gce-c18', 'production-gce-c31']
)
assert.equal(SAME_CAP_CELLS.includes('production-gce-c30'), true)
})
@@ -154,6 +164,17 @@ test('rolls the migration-only cells but never mixes the two classes in one wave
confirmation: `ROLL_RELAY_SAME_CAP ${targetDigest} ${asiaMixed}`,
canaryRunId: '42'
}), /all general or all migration-only/)
// Until its canary promotes it, a same-cap restore must hand C31 back isolated, never activated.
assert.equal(entryAdmission('production-gce-c31'), 'migration-only')
const asiaUnpromoted = 'production-gce-c30,production-gce-c31'
assert.throws(() => validateSameCapWave({
mode: 'batch-apply',
cellIds: asiaUnpromoted,
targetDigest,
rollbackDigest,
confirmation: `ROLL_RELAY_SAME_CAP ${targetDigest} ${asiaUnpromoted}`,
canaryRunId: '42'
}), /all general or all migration-only/)
// A mixed wave has no single selector delta for its later cells to offset from.
const mixed = 'production-gce-c7,production-gce-c17'
assert.throws(() => validateSameCapWave({
@@ -291,7 +291,7 @@ describe('same-cap roll scripts accept every same-cap cell', () => {
assert.equal(String(cellShape(cellId).cap), tfvarsHardCap(cellId), cellId)
}
assert.equal(resolveCellShape('production-gce-c12').status, 1)
assert.equal(resolveCellShape('production-gce-c31').status, 1)
assert.equal(resolveCellShape('production-gce-c32').status, 1)
})
@@ -303,9 +303,10 @@ describe('same-cap roll scripts accept every same-cap cell', () => {
const trusted = SAME_CAP_CELLS.filter((cell) => REHOME_SOURCE_CELLS.has(cell))
// Only a declared rehome source may roll at a trusted protocol at all; the job refuses
// the rest before it plans, and the next test covers them at protocol 0.
// C31 is already a rehome source but stays migration-only until its Asia canary promotes it.
assert.deepEqual(
SAME_CAP_CELLS.filter((cell) => !REHOME_SOURCE_CELLS.has(cell)),
SAME_CAP_MIGRATION_ONLY_CELLS
SAME_CAP_MIGRATION_ONLY_CELLS.filter((cell) => cell !== 'production-gce-c31')
)
for (const [cellId, protocol] of trusted.flatMap((cell) => [[cell, 1], [cell, 3]])) {
const { cap, pool } = cellShape(cellId)
@@ -40,6 +40,8 @@ const launchDigest = '5aedbca5c86de24c8b4d4bf7e3b444b76c712f281ede916cb9d90f70ca
const asiaCells = ['production-gce-c27', 'production-gce-c28', 'production-gce-c29']
// C30 launches after the launch cells rolled, so it pins the director's digest instead.
const c30Digest = '4158d8a2e18e9caec439d257f0c1e45d92ffea8c0262f057b2f08c76a134bcf0'
// C31 launches on the digest the director served when it was declared.
const c31Digest = 'f30b5cb1ec52b6b6145efecfa1b8be9e3d309403beffd8abcc64197a2087e269'
function cellBlock(tfvars, cellId) {
const start = tfvars.indexOf(`"${cellId}"`)
@@ -50,13 +52,14 @@ function cellBlock(tfvars, cellId) {
const productionCell = (cellId) => cellBlock(productionTfvars, cellId)
// Scoped to C4 by name: staging C3 serves this digest too since its 2026-09-03 re-pin.
test('pins staging C4 and the launch Asia cells to one image, and C30 to the director image', () => {
test('pins staging C4 and the launch Asia cells to one image, and C30/C31 to director images', () => {
assert.match(cellBlock(stagingTfvars, 'staging-gce-c4'), new RegExp(`relay@sha256:${launchDigest}"`))
for (const cellId of asiaCells) {
assert.match(productionCell(cellId), new RegExp(`relay@sha256:${launchDigest}"`), cellId)
}
assert.match(recoveryWorkflow, new RegExp(`TARGET_IMAGE_DIGEST: sha256:${launchDigest}`))
assert.match(productionCell('production-gce-c30'), new RegExp(`relay@sha256:${c30Digest}"`))
assert.match(productionCell('production-gce-c31'), new RegExp(`relay@sha256:${c31Digest}"`))
})
test('refreshes only empty staging C4 through the trusted capacity identity', () => {
@@ -19,11 +19,13 @@ const CELL_SHAPES = {
'production-gce-c27': 'asia-east2-a',
'production-gce-c28': 'asia-east2-b',
'production-gce-c29': 'asia-east2-c',
'production-gce-c30': 'asia-east2-a'
'production-gce-c30': 'asia-east2-a',
'production-gce-c31': 'asia-east2-b'
},
waves: [
['production-gce-c27', 'production-gce-c28', 'production-gce-c29'],
['production-gce-c30']
['production-gce-c30'],
['production-gce-c31']
]
},
staging: {
@@ -96,15 +96,16 @@ const productionConfig = {
environment: 'production', cells: ['production-gce-c30'], image: productionImage
}
// C30 joins a live Asia region: the network is a no-op and the existing C27 route is preserved.
function productionC30Plan() {
// A later cell joins a live Asia region: the network is a no-op and the existing C27 route is preserved.
function productionWavePlan(hostname = 'c30', zone = 'asia-east2-a') {
const plan = JSON.parse(JSON.stringify(resources)
.replaceAll('onorca-cloud-staging/', 'onorca-cloud/')
.replaceAll('orca-cloud-staging-relay-gce', 'orca-cloud-relay-gce')
.replaceAll('staging-gce-c4', 'production-gce-c30')
.replaceAll('relay-gce-c4', 'relay-gce-c30')
.replaceAll('cell-c4', 'cell-c30')
.replaceAll('c4.relay-staging.onorca.dev', 'c30.relay.onorca.dev')
.replaceAll('staging-gce-c4', `production-gce-${hostname}`)
.replaceAll('relay-gce-c4', `relay-gce-${hostname}`)
.replaceAll('cell-c4', `cell-${hostname}`)
.replaceAll('c4.relay-staging.onorca.dev', `${hostname}.relay.onorca.dev`)
.replaceAll('asia-east2-a', zone)
.replaceAll("'10'", "'16'"))
for (const network of plan.slice(0, 3)) {
network.change.actions = ['no-op']
@@ -124,23 +125,23 @@ function productionC30Plan() {
test('accepts the additive production C30 wave at the 16-connection Asia pool', () => {
assert.deepEqual(
validateRelayAsiaTopologyPlan({ resource_changes: productionC30Plan() }, productionConfig),
validateRelayAsiaTopologyPlan({ resource_changes: productionWavePlan() }, productionConfig),
{ environment: 'production', cells: ['production-gce-c30'], changes: 4 }
)
const staleShape = productionC30Plan()
const staleShape = productionWavePlan()
staleShape[3].change.after.metadata_startup_script =
staleShape[3].change.after.metadata_startup_script.replace("'16'", "'10'")
assert.throws(
() => validateRelayAsiaTopologyPlan({ resource_changes: staleShape }, productionConfig),
/reviewed Asia cell shape/
)
const wrongZone = productionC30Plan()
const wrongZone = productionWavePlan()
wrongZone[4].change.after.zone = 'asia-east2-b'
assert.throws(
() => validateRelayAsiaTopologyPlan({ resource_changes: wrongZone }, productionConfig),
/fixed-one Asia MIG shape/
)
const liveCellTouched = productionC30Plan()
const liveCellTouched = productionWavePlan()
liveCellTouched.push(create('google_compute_instance_template.relay_gce_cell["production-gce-c27"]'))
assert.throws(
() => validateRelayAsiaTopologyPlan({ resource_changes: liveCellTouched }, productionConfig),
@@ -148,13 +149,25 @@ test('accepts the additive production C30 wave at the 16-connection Asia pool',
)
})
test('accepts the additive production C31 wave only in asia-east2-b', () => {
const c31Config = { ...productionConfig, cells: ['production-gce-c31'] }
assert.deepEqual(
validateRelayAsiaTopologyPlan({ resource_changes: productionWavePlan('c31', 'asia-east2-b') }, c31Config),
{ environment: 'production', cells: ['production-gce-c31'], changes: 4 }
)
assert.throws(
() => validateRelayAsiaTopologyPlan({ resource_changes: productionWavePlan('c31') }, c31Config),
/fixed-one Asia MIG shape/
)
})
// The URL map pulls every cell's backend, MIG and template into a targeted plan.
const liveCellResources = ['instance_template', 'instance_group_manager', 'backend_service']
.flatMap((kind) => ['production-gce-c1', 'production-gce-c27', 'production-gce-c28', 'production-gce-c29']
.map((cellId) => `google_compute_${kind}.relay_gce_cell["${cellId}"]`))
test('accepts live cells the URL map pulls in only while they stay unchanged', () => {
const plan = productionC30Plan()
const plan = productionWavePlan()
for (const address of liveCellResources) plan.push({ address, change: { actions: ['no-op'] } })
assert.equal(
validateRelayAsiaTopologyPlan({ resource_changes: plan }, productionConfig).changes,
@@ -162,7 +175,7 @@ test('accepts live cells the URL map pulls in only while they stay unchanged', (
)
for (const address of liveCellResources) {
for (const action of [['update'], ['delete'], ['create', 'delete'], ['delete', 'create']]) {
const drifted = productionC30Plan()
const drifted = productionWavePlan()
drifted.push({ address, change: { actions: action } })
assert.throws(
() => validateRelayAsiaTopologyPlan({ resource_changes: drifted }, productionConfig),
@@ -180,7 +193,8 @@ test('accepts only a reviewed Asia topology wave', () => {
for (const cellIds of [
'production-gce-c27,production-gce-c28,production-gce-c29',
'production-gce-c29,production-gce-c27,production-gce-c28',
'production-gce-c30'
'production-gce-c30',
'production-gce-c31'
]) {
assert.doesNotThrow(
() => parseRelayAsiaTopologyPlanArguments(argv('production', cellIds, productionImage)),
@@ -192,7 +206,8 @@ test('accepts only a reviewed Asia topology wave', () => {
'production-gce-c27,production-gce-c30',
'production-gce-c27,production-gce-c28,production-gce-c29,production-gce-c30',
'production-gce-c30,production-gce-c30',
'production-gce-c31'
'production-gce-c30,production-gce-c31',
'production-gce-c32'
]) {
assert.throws(
() => parseRelayAsiaTopologyPlanArguments(argv('production', cellIds, productionImage)),