Coverage for gco / stacks / constants.py: 100.00%

132 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-10-28 16:19 +0000

1"""Pinned version constants for GCO infrastructure. 

2 

3Single source of truth for all version-pinned infrastructure components. 

4Centralising these makes it easy to: 

5 

61. See every pinned version at a glance 

72. Update versions in one place 

83. Let the dependency scanner (`.github/scripts/dependency-scan.sh`) 

9 find them with a simple import instead of regex scraping 

104. Write tests that assert versions haven't drifted 

11 

12When updating a version here, also check: 

13- ``lambda/helm-installer/charts.yaml`` for Helm chart versions 

14- ``requirements-lock.txt`` for Python dependency versions 

15- ``cdk.json`` context for ``kubernetes_version`` 

16 

17The dependency scanner runs monthly and opens an issue when any of 

18these fall behind the latest available release. 

19""" 

20 

21from __future__ import annotations 

22 

23from collections.abc import Collection, Mapping 

24from functools import lru_cache 

25from types import MappingProxyType 

26 

27# Resource-governance defaults live in gco.resource_governance (a 

28# runtime-shippable module) because the manifest/queue processors need the 

29# same values inside their container images, whose build context deliberately 

30# excludes gco/stacks/** (see _SERVICE_IMAGE_COMMON_EXCLUDES in the regional 

31# stack). Re-exported here so synth-side code keeps one import home. 

32from gco.resource_governance import ( 

33 DEFAULT_MANIFEST_RESOURCE_CAPS as DEFAULT_MANIFEST_RESOURCE_CAPS, 

34) 

35from gco.resource_governance import ( 

36 DEFAULT_RESOURCE_QUOTA as DEFAULT_RESOURCE_QUOTA, 

37) 

38from gco.resource_governance import ( 

39 parse_k8s_quantity as parse_k8s_quantity, 

40) 

41 

42# --------------------------------------------------------------------------- 

43# Lambda Runtimes 

44# --------------------------------------------------------------------------- 

45# Keep every Lambda language runtime here rather than spelling enum members in 

46# individual stacks. The monthly dependency scan compares these constants with 

47# the newest managed runtimes exposed by aws-cdk-lib and checks the Node major 

48# against .nvmrc, package.json, and Dockerfile.dev. 

49LAMBDA_PYTHON_RUNTIME = "PYTHON_3_14" 

50"""CDK enum name for Python Lambdas (``lambda_.Runtime.PYTHON_3_14``).""" 

51 

52LAMBDA_NODEJS_RUNTIME = "NODEJS_24_X" 

53"""CDK enum name for Node.js Lambdas (``lambda_.Runtime.NODEJS_24_X``).""" 

54 

55LAMBDA_SOURCE_ASSET_EXCLUDE = ( 

56 "__pycache__", 

57 "*.pyc", 

58 "*.pyo", 

59 ".mypy_cache", 

60 ".pytest_cache", 

61 ".DS_Store", 

62) 

63"""Local caches never packaged from a ``lambda/`` source directory. 

64 

65A test run that imports a handler writes its bytecode next to it, and these 

66files would otherwise ship in the function's zip and enter its asset hash, so 

67a working checkout would publish different code than a clean clone of the 

68same commit. CDK matches a pattern without a slash against every name below 

69the asset directory. ``gco.stacks.lambda_assets.lambda_source_code`` applies 

70them to the zipped source directories, and the CLI leaves the same caches out 

71of its own Lambda builds (``cli/stacks.py``). 

72""" 

73 

74 

75# --------------------------------------------------------------------------- 

76# Deployment Region Contract 

77# --------------------------------------------------------------------------- 

78@lru_cache(maxsize=1) 

79def cloudformation_region_partitions() -> Mapping[str, str]: 

80 """Return immutable SDK-known CloudFormation Region-to-partition metadata. 

81 

82 Botocore endpoint metadata covers every AWS partition and requires neither 

83 credentials nor a network request. Keeping this dynamic avoids a project 

84 allowlist that would reject opt-in, sovereign, or newly supported Regions 

85 already known to the installed SDK. 

86 """ 

87 import boto3 

88 

89 session = boto3.Session() 

90 region_partitions: dict[str, str] = {} 

91 for partition in session.get_available_partitions(): 

92 for region in session.get_available_regions( 

93 "cloudformation", 

94 partition_name=partition, 

95 ): 

96 recorded_partition = region_partitions.setdefault(region, partition) 

97 if recorded_partition != partition: 

98 raise RuntimeError( 

99 "AWS SDK endpoint metadata assigns CloudFormation region " 

100 f"{region!r} to both {recorded_partition!r} and {partition!r}" 

101 ) 

102 if not region_partitions: 

103 raise RuntimeError("AWS SDK endpoint metadata contains no CloudFormation regions") 

104 return MappingProxyType(region_partitions) 

105 

106 

107@lru_cache(maxsize=1) 

108def known_cloudformation_regions() -> frozenset[str]: 

109 """Return every AWS SDK-known Region that exposes CloudFormation.""" 

110 return frozenset(cloudformation_region_partitions()) 

111 

112 

113def validated_deployment_partition( 

114 regions: Collection[object], 

115 *, 

116 region_partitions: Mapping[str, str] | None = None, 

117) -> str: 

118 """Require a deployment topology to resolve to exactly one AWS partition. 

119 

120 A single credentials/account context and this application's cross-stack 

121 references cannot span commercial, China, GovCloud, or ISO partitions. 

122 Region count remains deliberately unlimited within the selected partition. 

123 """ 

124 if not regions: 

125 raise ValueError("At least one deployment region must be specified") 

126 

127 metadata = ( 

128 cloudformation_region_partitions() if region_partitions is None else region_partitions 

129 ) 

130 if not metadata: 

131 raise RuntimeError("AWS SDK endpoint metadata contains no CloudFormation regions") 

132 

133 regions_by_partition: dict[str, list[str]] = {} 

134 for region in regions: 

135 if not isinstance(region, str) or region not in metadata: 

136 raise ValueError( 

137 f"Invalid region {region!r}; expected an AWS region with a " 

138 "CloudFormation endpoint known to the installed SDK" 

139 ) 

140 partition = metadata[region] 

141 regions_by_partition.setdefault(partition, []).append(region) 

142 

143 if len(regions_by_partition) != 1: 

144 details = "; ".join( 

145 f"{partition}: {', '.join(sorted(partition_regions))}" 

146 for partition, partition_regions in sorted(regions_by_partition.items()) 

147 ) 

148 raise ValueError( 

149 f"Deployment regions must all belong to a single AWS partition; found {details}" 

150 ) 

151 return next(iter(regions_by_partition)) 

152 

153 

154CONTROL_PLANE_ONLY_CONTEXT_KEY = "gco:control-plane-only" 

155"""Run-scoped CDK context key that synthesizes the app with zero workload Regions. 

156 

157Passing ``--context gco:control-plane-only=true`` makes ``ConfigLoader`` report an 

158empty ``deployment_regions.regional`` without editing ``cdk.json``, so the 

159synthesized app contains only the global, API Gateway, and monitoring stacks. 

160``gco upgrade`` uses it to update the monitoring stack in place so it stops 

161referencing the regional stacks before those are destroyed and recreated. Any 

162value other than the string ``"true"`` (case-insensitive) leaves the configured 

163Region list alone. 

164""" 

165 

166 

167def control_plane_only_requested(value: object) -> bool: 

168 """Return whether a ``gco:control-plane-only`` context value opts in.""" 

169 if value is True: 

170 return True 

171 return isinstance(value, str) and value.strip().lower() == "true" 

172 

173 

174def validated_regional_deployment_regions( 

175 value: object, 

176 *, 

177 known_regions: Collection[str] | None = None, 

178) -> tuple[str, ...]: 

179 """Return a unique, possibly empty list of SDK-known workload Regions. 

180 

181 There is deliberately no project-specific allowlist, minimum, or maximum 

182 count. An empty list is a valid *control-plane-only* topology: the global, 

183 API Gateway, and monitoring stacks stand with no regional cluster behind 

184 them, which is how a deployment is scaled to zero workload Regions (and 

185 what ``gco upgrade`` passes through while it recreates them). The optional 

186 ``known_regions`` argument lets callers reuse endpoint metadata they have 

187 already loaded while preserving this one validation contract. 

188 """ 

189 if not isinstance(value, list): 

190 raise ValueError("deployment_regions.regional must be a list of AWS region names") 

191 

192 regions: list[str] = [] 

193 valid_regions = ( 

194 known_cloudformation_regions() if known_regions is None else frozenset(known_regions) 

195 ) 

196 if not valid_regions: 

197 raise RuntimeError("AWS SDK endpoint metadata contains no CloudFormation regions") 

198 

199 for region in value: 

200 if not isinstance(region, str) or region not in valid_regions: 

201 raise ValueError( 

202 f"Invalid region {region!r}; expected an AWS region with a " 

203 "CloudFormation endpoint known to the installed SDK" 

204 ) 

205 regions.append(region) 

206 if len(regions) != len(set(regions)): 

207 raise ValueError("Duplicate regions found in configuration") 

208 return tuple(regions) 

209 

210 

211# --------------------------------------------------------------------------- 

212# HTTP Request Body Limits 

213# --------------------------------------------------------------------------- 

214DEFAULT_MAX_REQUEST_BODY_BYTES = 1_048_576 

215"""Default hard cap shared by API ingress and in-cluster request middleware.""" 

216 

217MAX_CONFIGURABLE_REQUEST_BODY_BYTES = 10 * 1024 * 1024 

218"""Largest supported cap; matches API Gateway's request payload ceiling.""" 

219 

220# The cross-region aggregator has a deliberately read-mostly regional contract. 

221# Keep both its identity policy and each regional API resource policy generated 

222# from this exact allowlist so a compromised aggregator cannot reach unrelated 

223# control-plane mutations exposed by the regional greedy route. 

224AGGREGATOR_REGIONAL_API_ROUTES = ( 

225 ("GET", "api/v1/jobs"), 

226 ("DELETE", "api/v1/jobs"), 

227 ("GET", "api/v1/health"), 

228 ("GET", "api/v1/status"), 

229 # Read-only introspection of the region's deployed job validation policy. 

230 # Callers need it before submission to know whether a manifest will be 

231 # admitted; it exposes the same class of deployment metadata as 

232 # api/v1/status (which already reports the caps and namespace allowlist) 

233 # and mutates nothing. 

234 ("GET", "api/v1/policy"), 

235) 

236 

237 

238def validated_request_body_limit(value: object) -> int: 

239 """Return a safe request-body limit or reject an inconsistent deployment.""" 

240 if type(value) is not int or value < 1 or value > MAX_CONFIGURABLE_REQUEST_BODY_BYTES: 

241 raise ValueError( 

242 "max_request_body_bytes must be an integer between 1 and " 

243 f"{MAX_CONFIGURABLE_REQUEST_BODY_BYTES}" 

244 ) 

245 return value 

246 

247 

248# --------------------------------------------------------------------------- 

249# API Gateway Auth Secret 

250# --------------------------------------------------------------------------- 

251# Physical name of the Secrets Manager secret that holds the rotating HMAC 

252# signing key used by trusted API Gateway proxy Lambdas. It is created by 

253# ``GCOApiGatewayGlobalStack`` (in the ``api_gateway`` region) and read by the 

254# regional service-account role and regional API proxy Lambda. The historical 

255# ``api-gateway-auth-token`` suffix is retained to avoid replacing deployments. 

256 

257 

258def api_gateway_auth_secret_name(project_name: str) -> str: 

259 """Secrets Manager name for the proxy-to-backend HMAC signing key. 

260 

261 Derived from ``project_name`` (``<project_name>/api-gateway-auth-token``) 

262 so two deployments in the same account+region do not collide on the secret 

263 name. For the default ``project_name="gco"`` this renders 

264 ``gco/api-gateway-auth-token`` — byte-for-byte identical to the pre-#139 

265 literal, so existing deployments see no resource replacement. 

266 

267 Single source of truth shared by the call sites that must agree exactly: 

268 

269 1. ``GCOApiGatewayGlobalStack._create_secret`` — the ``secret_name`` the 

270 secret is actually created with. 

271 2. ``GCORegionalStack`` (the manifest-processor, inference-proxy and 

272 health-monitor roles) and ``GCORegionalApiGatewayStack`` (both proxy 

273 Lambda roles) — the IAM ``Resource`` granting read access to the 

274 secret: ``arn:<partition>:secretsmanager:<API Gateway Region>:<account>: 

275 secret:<this name>-??????``. Building it from the name renders the same 

276 grant in every topology, whereas the passed-in cross-stack reference 

277 becomes a native export when the stacks share a Region (issue #125, 

278 PR #461). ``-??????`` matches the six random characters Secrets Manager 

279 appends to the name in the ARN and nothing else, so the grant needs no 

280 cdk-nag acknowledgment. 

281 

282 Call this helper with the stack's ``project_name`` rather than re-typing 

283 the name. ``tests/test_cdk_synthesis_matrix.py`` checks every rendered 

284 grant on the secret against the API Gateway Region. 

285 """ 

286 return f"{project_name}/api-gateway-auth-token" # nosec B105 # secret path/name, not a credential 

287 

288 

289def cross_region_aggregator_role_name(project_name: str) -> str: 

290 """IAM role name used by regional API resource-policy principals. 

291 

292 IAM roles are global within an account, and the role ARN is embedded in 

293 API Gateway resource policies synthesized in other regions. A deterministic 

294 project-scoped physical name avoids an unsupported cross-region 

295 CloudFormation export. ``project_name`` is validated at 31 characters, so 

296 this 24-character suffix keeps the result below IAM's 64-character limit. 

297 """ 

298 return f"{project_name}-cross-region-aggregator" 

299 

300 

301# --------------------------------------------------------------------------- 

302# Backend TLS private PKI 

303# --------------------------------------------------------------------------- 

304 

305 

306def backend_tls_server_name(project_name: str) -> str: 

307 """Private certificate identity asserted by every backend TLS client. 

308 

309 The name deliberately does not need public DNS. Proxy clients connect to 

310 Global Accelerator or an internal ALB's real DNS name while sending this 

311 value as SNI and verifying it against the deployment-local root CA. 

312 """ 

313 return f"backend.{project_name}.gco.internal" 

314 

315 

316def backend_tls_root_secret_name(project_name: str) -> str: 

317 """Secrets Manager name containing the deployment-local root private key.""" 

318 return f"{project_name}/backend-tls/root-ca" 

319 

320 

321def backend_tls_root_ca_parameter_name(project_name: str) -> str: 

322 """SSM parameter containing only the public root trust bundle.""" 

323 return f"/{project_name}/backend-tls/root-ca.pem" 

324 

325 

326def backend_tls_certificate_parameter_prefix(project_name: str) -> str: 

327 """SSM prefix under which regional imported-certificate ARNs are stored.""" 

328 return f"/{project_name}/backend-tls/certificate-arn/" 

329 

330 

331def backend_tls_certificate_arn_parameter_name(project_name: str, region: str) -> str: 

332 """SSM parameter containing one region's stable imported ACM ARN.""" 

333 return f"{backend_tls_certificate_parameter_prefix(project_name)}{region}" 

334 

335 

336# --------------------------------------------------------------------------- 

337# EKS Add-on Versions 

338# --------------------------------------------------------------------------- 

339# Pinned to specific eksbuild versions for reproducible deployments. 

340# The dependency scanner checks ``aws eks describe-addon-versions`` monthly 

341# and opens an issue when newer builds are available. 

342 

343EKS_ADDON_POD_IDENTITY_AGENT = "v1.4.0-eksbuild.3" 

344"""EKS Pod Identity Agent — enables IRSA and Pod Identity for service accounts.""" 

345 

346EKS_ADDON_METRICS_SERVER = "v0.9.0-eksbuild.11" 

347"""Kubernetes Metrics Server — provides CPU/memory metrics for HPA and ``kubectl top``. 

348 

349The ``v0.9.x`` line registers only ``metrics.k8s.io/v1beta1``; the ``v1`` API 

350that went GA in Kubernetes 1.37 arrives with a later metrics-server release. 

351The two in-cluster callers (``gco.services.health_monitor`` and the jobs API 

352route) read the version through ``METRICS_API_VERSION`` in 

353``gco/k8s_api_versions.py``. When this pin moves to a release that also 

354registers ``v1`` (upstream ``master`` does; expected from ``v0.10.x``), flip 

355that constant. 

356""" 

357 

358EKS_ADDON_EFS_CSI_DRIVER = "v3.4.2-eksbuild.1" 

359"""Amazon EFS CSI Driver — mounts EFS file systems as Kubernetes persistent volumes.""" 

360 

361EKS_ADDON_CLOUDWATCH_OBSERVABILITY = "v6.7.0-eksbuild.1" 

362"""Amazon CloudWatch Observability — Container Insights, Prometheus metrics, FluentBit logs.""" 

363 

364EKS_ADDON_FSX_CSI_DRIVER = "v1.10.0-eksbuild.2" 

365"""Amazon FSx CSI Driver — mounts FSx for Lustre file systems as Kubernetes persistent volumes.""" 

366 

367# --------------------------------------------------------------------------- 

368# EKS Cluster Subnet Constraints 

369# --------------------------------------------------------------------------- 

370# A few Availability Zones cannot host the subnets you pass when creating an 

371# EKS cluster (the control-plane elastic network interfaces). EKS rejects 

372# cluster creation if any supplied subnet is in one of these zones. The 

373# constraint is published by *Availability Zone ID* (e.g. ``use1-az3``), which 

374# is stable across accounts — unlike the AZ *name* (``us-east-1e``), which AWS 

375# randomizes per account. Match by ID, then resolve to this account's names. 

376# Source: https://docs.aws.amazon.com/eks/latest/userguide/network-reqs.html 

377# ("Subnet requirements for clusters" — disallowed Availability Zone IDs). 

378 

379EKS_UNSUPPORTED_AZ_IDS: dict[str, tuple[str, ...]] = { 

380 "us-east-1": ("use1-az3",), 

381 "us-west-1": ("usw1-az2",), 

382 "ca-central-1": ("cac1-az3",), 

383} 

384"""AWS-region → Availability Zone IDs that cannot hold EKS cluster subnets. 

385 

386The regional VPC deliberately spans every AZ in the region (one public + one 

387private subnet each), but the EKS cluster's control-plane subnet selection must 

388exclude any subnet in these zones or ``CreateCluster`` fails with 

389``InvalidParameterException``. Regions absent from this map have no such 

390restriction. Keep in sync with the AWS EKS networking requirements doc. 

391""" 

392 

393# --------------------------------------------------------------------------- 

394# Aurora PostgreSQL Engine Version 

395# --------------------------------------------------------------------------- 

396# Pinned to a specific minor version. The dependency scanner checks 

397# ``aws rds describe-db-engine-versions`` monthly for newer releases 

398# within the same major line. 

399 

400AURORA_POSTGRES_VERSION = "17.11" 

401"""Aurora PostgreSQL engine version, applied via ``rds.AuroraPostgresEngineVersion.of()``. 

402 

403A plain ``major.minor`` string rather than a CDK enum name: enum members lag 

404new RDS minor releases, which needlessly coupled an Aurora engine bump to an 

405aws-cdk-lib release. The dependency scanner validates this pin directly 

406against ``rds describe-db-engine-versions`` — the authoritative source — so 

407a newer minor is reported the day RDS ships it, independent of the CDK 

408library's enum catalog. 

409""" 

410# --------------------------------------------------------------------------- 

411# Analytics Environment Constants 

412# --------------------------------------------------------------------------- 

413# Pinned values consumed by the optional analytics environment (SageMaker 

414# Studio, EMR Serverless, Cognito hosted UI, and the always-on 

415# Cluster_Shared_Bucket in ``GCOGlobalStack``). Keeping them here lets the 

416# analytics stack, the regional stack, the global stack, and the tests import 

417# from a single source of truth. 

418 

419EMR_SERVERLESS_RELEASE_LABEL = "emr-spark-8.1.0" 

420"""EMR Serverless Spark release label used for ``emrserverless.CfnApplication``. 

421 

422Pinned to a stable Spark release so analytics workloads get a reproducible 

423runtime across deployments. Update alongside the EKS add-ons above when a 

424newer EMR release is validated against the studio notebooks. 

425 

426Two label families are valid for the ``SPARK`` application this pins: the 

427classic ``emr-N.x.y`` line (Spark 3; ``emr-7.14.0`` was the last pin on it) 

428and the AWS runtime for Apache Spark line, ``emr-spark-N.x.y`` (Spark 4; 

429``emr-spark-8.0.0`` GA, then ``8.1.0``), which is the current major and the 

430one pinned here. The monthly dependency scan ranks both families by version 

431and reports the newer one, so a future major shows up as "new major 

432available". Moving between families is a Spark major-version change for 

433every notebook that runs on the application; the repository ships no Spark 

434job of its own, so the pin carried no code change of ours. 

435""" 

436 

437SAGEMAKER_ROLE_NAME_PREFIX = "AmazonSageMaker" 

438"""Required prefix for the SageMaker Studio execution role name. 

439 

440Amazon SageMaker requires execution roles used by Studio domains to have a 

441name that starts with ``AmazonSageMaker`` so that AWS-managed policies and 

442service-linked trust relationships resolve correctly. Any role name generated 

443for ``SageMaker_Execution_Role`` must begin with this prefix. 

444""" 

445 

446 

447def cognito_domain_prefix_default(project_name: str) -> str: 

448 """Default prefix for the Cognito hosted-UI domain. 

449 

450 Derived from ``project_name`` (``<project_name>-studio``). The full domain 

451 prefix is assembled at synth time by appending the account id (e.g. 

452 ``gco-studio-123456789012``) so it stays globally unique within 

453 ``cognito.UserPoolDomain``. Operators may override the prefix through the 

454 ``analytics_environment.cognito.domain_prefix`` field in ``cdk.json``. 

455 

456 For ``project_name="gco"`` this renders ``gco-studio`` — identical to the 

457 pre-#139 literal. 

458 """ 

459 return f"{project_name}-studio" 

460 

461 

462STUDIO_PRESIGNED_URL_EXPIRY_SECONDS = 300 

463"""Default expiry (in seconds) for SageMaker Studio presigned domain URLs. 

464 

465Five minutes matches the shortest window accepted by 

466``CreatePresignedDomainUrl`` while still giving a user enough time to click 

467the link after the ``/studio/login`` Lambda returns it. The presigned-URL 

468Lambda reads this through the ``URL_EXPIRES_SECONDS`` environment variable 

469and callers may override it per-request. 

470""" 

471 

472 

473# --------------------------------------------------------------------------- 

474# S3 bucket naming policy 

475# --------------------------------------------------------------------------- 

476# No GCO stack sets an explicit ``bucket_name``. S3 bucket names live in one 

477# global namespace and S3 does not guarantee a deleted name becomes reusable 

478# promptly — a validation cycle hit ``BucketAlreadyExists`` on a 

479# project/account/region name three days after its previous incarnation was 

480# deleted. CloudFormation-generated names (``<stack>-<construct>-<random>``) 

481# are unique per stack instance, so destroy-and-redeploy, retained buckets 

482# from earlier deployments, and parallel deployments in one account can never 

483# collide. The owning stack publishes each bucket's identity (``name``, 

484# ``arn``, ``region``) as SSM parameters under a ``project_name``-derived 

485# prefix; every consumer resolves the bucket from that contract and nothing 

486# reconstructs a bucket name. ``tests/test_bucket_naming_contract.py`` 

487# enforces the policy on the stack sources. 

488 

489 

490def cluster_shared_ssm_parameter_prefix(project_name: str) -> str: 

491 """SSM parameter namespace for the cluster-shared bucket metadata. 

492 

493 Derived from ``project_name`` (``/<project_name>/cluster-shared-bucket``). 

494 ``GCOGlobalStack`` writes ``<prefix>/name``, ``<prefix>/arn``, and 

495 ``<prefix>/region`` under this path; ``GCORegionalStack`` (always) and 

496 ``GCOAnalyticsStack`` (when enabled) read them back via 

497 ``cr.AwsCustomResource`` against the global region. Treat the full paths as 

498 the contract — the bucket's physical name is CloudFormation-generated and 

499 is only knowable through them. For ``project_name="gco"`` this renders 

500 ``/gco/cluster-shared-bucket``. 

501 """ 

502 return f"/{project_name}/cluster-shared-bucket" 

503 

504 

505def regional_shared_ssm_parameter_prefix(project_name: str) -> str: 

506 """SSM parameter namespace for the regional general-purpose bucket metadata. 

507 

508 Derived from ``project_name`` (``/<project_name>/regional-shared-bucket``). 

509 Each ``GCORegionalStack`` provisions exactly one general-purpose bucket per 

510 region, unconditionally (no ``cdk.json`` toggle gates its existence), and 

511 writes ``<prefix>/name``, ``<prefix>/arn``, and ``<prefix>/region`` under 

512 this path **in its own region's** parameter store, exactly as the model 

513 bucket and cluster-shared bucket publish theirs. In-region workloads (and 

514 the regional upload surface) read them back to resolve the bucket — its 

515 physical name is CloudFormation-generated and never reconstructed. 

516 

517 The per-region inference monitor builds the same path at runtime from its 

518 injected ``PROJECT_NAME`` environment variable rather than importing this 

519 helper (it needs no CDK imports at runtime), so keep the two in lockstep. 

520 For ``project_name="gco"`` this renders ``/gco/regional-shared-bucket``. 

521 """ 

522 return f"/{project_name}/regional-shared-bucket" 

523 

524 

525MOONCAKE_COLD_TIER_KEY_PREFIX = "mooncake-kv" 

526"""Object-key prefix for Mooncake cold-tier KV objects in the regional bucket. 

527 

528The per-region inference monitor resolves an endpoint's cold-tier object-store 

529URI to ``s3://<regional-shared-bucket>/mooncake-kv/<endpoint>/`` (the bucket 

530name comes from that region's ``/<project>/regional-shared-bucket/name`` 

531parameter), and the ``gco inference populate-kv`` upload surface writes under 

532the same prefix, so operator-supplied warm-up objects land exactly where an 

533endpoint's pods read them. This is the shared contract between the two sides; 

534the monitor keeps a local copy of this value so it needs no CDK imports at 

535runtime, so keep the two in lockstep if the prefix ever changes. 

536""" 

537 

538# --------------------------------------------------------------------------- 

539# Cost Monitoring Constants 

540# --------------------------------------------------------------------------- 

541# Shared contract between the monitoring stack (which owns the cost report 

542# bucket, Glue database/table, and Athena workgroup and grants the regional 

543# cost-monitor roles through the bucket and key policies), the regional stacks 

544# (which let the cost-monitor role read the published bucket identity), the 

545# cost-monitor service (which resolves the bucket from SSM and writes Parquet 

546# reports), and the CLI (which queries Athena). Everything below is derived 

547# from ``project_name`` so two deployments in one account never collide. 

548 

549COST_REPORT_SCHEDULED_PREFIX = "reports" 

550"""Object-key prefix for scheduled cost allocation reports. 

551 

552The cost-monitor service writes Hive-partitioned Parquet objects under 

553``reports/region=<region>/date=<YYYY-MM-DD>/...`` and the Glue table's 

554partition projection reads the same layout — keep the two in lockstep. 

555""" 

556 

557COST_REPORT_ADHOC_PREFIX = "adhoc" 

558"""Object-key prefix for ad-hoc (user-requested) cost reports. 

559 

560Kept out of the scheduled ``reports/`` prefix so an ad-hoc report whose 

561window overlaps a scheduled window can never double-count in Athena 

562aggregations over the scheduled table. 

563""" 

564 

565COST_ATHENA_RESULTS_PREFIX = "athena-results" 

566"""Object-key prefix for Athena query results inside the cost report bucket.""" 

567 

568 

569def cost_report_ssm_parameter_prefix(project_name: str) -> str: 

570 """SSM parameter namespace for the cost report bucket identity. 

571 

572 Derived from ``project_name`` (``/<project_name>/cost-report-bucket``). 

573 ``GCOMonitoringStack`` writes ``<prefix>/name``, ``<prefix>/arn``, and 

574 ``<prefix>/region`` under this path **in the monitoring region's** 

575 parameter store — the same publish-then-resolve contract the model, 

576 cluster-shared, and regional-shared buckets use. The bucket's physical 

577 name is CloudFormation-generated (see the S3 bucket naming policy above), 

578 so these parameters are the only way to learn it: 

579 

580 * the per-region cost-monitor service reads ``<prefix>/name`` at runtime 

581 (``COST_REPORT_BUCKET_PARAMETER`` / ``COST_REPORT_BUCKET_PARAMETER_REGION`` 

582 injected by ``GCORegionalStack``). The monitoring stack deploys *after* 

583 the regional stacks, so on a fresh deploy-all the parameter does not 

584 exist yet when the service first boots; it retries on every scheduled 

585 pass until it does; 

586 * the regional cost-monitor role is granted ``ssm:GetParameter`` on the 

587 ``/name`` parameter by literal ARN, while S3 and KMS access come from 

588 the monitoring stack's bucket and key policies (principal based); 

589 * ``gco storage`` and release validation read ``<prefix>/name`` and 

590 ``<prefix>/arn`` instead of reconstructing a name. 

591 

592 For ``project_name="gco"`` this renders ``/gco/cost-report-bucket``. 

593 """ 

594 return f"/{project_name}/cost-report-bucket" 

595 

596 

597def cost_glue_database_name(project_name: str) -> str: 

598 """Glue database name for cost analytics. 

599 

600 Glue database names must not contain hyphens, so the project name's 

601 hyphens are folded to underscores (``gco`` renders ``gco_cost``). 

602 """ 

603 return f"{project_name.replace('-', '_')}_cost" 

604 

605 

606COST_GLUE_ALLOCATION_TABLE = "allocation_reports" 

607"""Glue table over the scheduled cost allocation reports.""" 

608 

609 

610def cost_athena_workgroup_name(project_name: str) -> str: 

611 """Athena workgroup name for cost analytics queries.""" 

612 return f"{project_name}-cost" 

613 

614 

615MOONCAKE_MASTER_DEFAULT_IMAGE = "vllm/vllm-openai:v0.32.0" 

616"""Default container image for the shared per-region Mooncake master. 

617 

618The master StatefulSet runs the ``mooncake_master`` daemon (RPC + built-in HTTP 

619metadata server). That binary ships in the ``mooncake-transfer-engine`` package 

620that the upstream vLLM OpenAI server image already bundles, so the same pinned 

621image used for disaggregated prefill/decode pods also serves the master without 

622a separate build. The inference monitor reads this through the 

623``MOONCAKE_MASTER_IMAGE`` environment variable and a per-endpoint 

624``spec.mooncake.store.master_image`` overrides it. 

625 

626Keep this tag in lockstep with ``cli/images.py:_DISAGGREGATED_DEFAULT_IMAGE`` 

627(the disaggregated role-pod default); bump both together when validating a new 

628vLLM release and never use a mutable/rolling tag such as ``latest``. 

629"""