Coverage for app.py: 100.00%
60 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-09-14 22:07 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-09-14 22:07 +0000
1#!/usr/bin/env python3
2"""
3GCO (Global Capacity Orchestrator on AWS) - Multi-Region EKS Auto Mode Platform for AI/ML Workloads
5This is the main CDK application entry point that orchestrates the deployment of:
6- Global Stack: partition-wide state plus AWS Global Accelerator in the commercial `aws` partition
7- API Gateway Stack: Centralized IAM-authenticated entry point
8- Regional Stacks: EKS clusters, internal ALBs, and services per region
9- Regional API Bridges: SigV4 entry points with VPC Lambdas for aggregation and direct access (optional in `aws`, required elsewhere)
10- Monitoring Stack: Cross-region CloudWatch dashboards and alarms
11- Optional Analytics Stack: SageMaker Studio and EMR Serverless
13Architecture:
14 Commercial `aws`: User → API Gateway (IAM Auth) → Global Accelerator → Internal Regional ALB → EKS Services
15 Other partitions: User → Regional API Gateway (IAM Auth) → VPC Lambda → Internal Regional ALB → EKS Services
16 Aggregator → Regional API Gateway (SigV4) → VPC Lambda → Internal Regional ALB
18Usage:
19 cdk deploy --all # Deploy all stacks
20 cdk deploy gco-us-east-1 # Deploy single region
21 cdk destroy --all # Cleanup all resources
22"""
24import os
25from pathlib import Path
27import aws_cdk as cdk
28import jsii
29from constructs import IConstruct
31from cli.stacks import cdk_asset_consumer
32from gco.config.config_loader import ConfigLoader
33from gco.stacks.analytics_stack import GCOAnalyticsStack
34from gco.stacks.api_gateway_global_stack import AnalyticsApiConfig, GCOApiGatewayGlobalStack
35from gco.stacks.global_stack import GCOGlobalStack
36from gco.stacks.monitoring_stack import GCOMonitoringStack
37from gco.stacks.nag_suppressions import nag_validation_plugins
38from gco.stacks.regional_api_gateway_stack import GCORegionalApiGatewayStack
39from gco.stacks.regional_stack import GCORegionalStack
41# <pyflowchart-code-diagram> BEGIN - auto-inserted, do not edit
42# Generated at (UTC): 2026-09-01T14:42:56Z
43# Generated from Git commit: 89b000378ed5a912a38c06f4feab2b029936ebcc
44# Flowchart(s) generated from this file:
45# * ``main`` -> ``diagrams/code_diagrams/app.main.html``
46# (PNG: ``diagrams/code_diagrams/app.main.png``)
47# Regenerate with ``SOURCE_DATE_EPOCH=<unix-seconds> GCO_DIAGRAM_SOURCE_COMMIT=<40-char-sha> python diagrams/generate.py --code-only``.
48# <pyflowchart-code-diagram> END
51# AWS Solutions guidance identifier. Only the GCO *global* stack description is
52# prefixed with this string, so a single deployment is attributable to the
53# published guidance (SO9707) through one stack.
54SOLUTION_ID = "SO9707"
55SOLUTION_DESCRIPTION_PREFIX = (
56 f"({SOLUTION_ID}) - Guidance for EKS AutoMode Clusters with Global Capacity Orchestrator on AWS"
57)
60@jsii.implements(cdk.IAspect)
61class LambdaTracingAspect:
62 """CDK Aspect that enables X-Ray tracing on all Lambda functions.
64 This catches CDK Provider Framework Lambdas that we don't create directly,
65 ensuring every Lambda in the stack has tracing=ACTIVE.
66 """
68 def visit(self, node: IConstruct) -> None:
69 if isinstance(node, cdk.aws_lambda.CfnFunction):
70 node.tracing_config = cdk.aws_lambda.CfnFunction.TracingConfigProperty(mode="Active")
73@cdk_asset_consumer(Path(__file__).resolve().parent)
74def main() -> None:
75 """
76 Main application entry point.
78 Creates and configures all CDK stacks with proper dependencies:
79 1. Global stack (shared state plus optional Global Accelerator) - must be created first
80 2. API Gateway stack - uses Global Accelerator DNS only when available
81 3. Regional stacks - depend on both global stacks
82 4. Regional API bridges - depend on their matching regional stack
83 (direct caller access is optional in `aws` and required elsewhere)
84 5. Monitoring stack - depends on all regional stacks
85 6. Optional analytics stack - feeds Studio routes into the API Gateway stack
86 """
87 app = cdk.App()
89 # Enable cdk-nag compliance rule packs. These validate the synthesized
90 # CloudFormation templates against security best practices. Any violations
91 # that aren't explicitly acknowledged (see nag_suppressions.py) are written
92 # to the cloud assembly's policy-validation report.
93 # Note: These are rule packs, not certifications — passing cdk-nag does not
94 # make the deployment automatically compliant with these frameworks.
96 # The X-Ray tracing aspect must run before the nag packs *see* the
97 # templates. In cdk-nag v3 the packs are IPolicyValidationPlugins that
98 # validate the synthesized templates AFTER every Aspect has run, so
99 # registering the aspect here guarantees tracing=Active is already set by
100 # the time the Serverless pack checks for it.
101 cdk.Aspects.of(app).add(LambdaTracingAspect())
103 # Register the five rule packs (AWS Solutions, HIPAA, NIST 800-53 R5,
104 # PCI DSS 3.2.1, Serverless) as CDK policy-validation plugins. Each pack
105 # reads the acknowledgment metadata written by ``acknowledge_nag_findings``
106 # natively, so the packs run directly.
107 cdk.Validations.of(app).add_plugins(*nag_validation_plugins(app, verbose=True))
109 # Load configuration from cdk.json
110 config = ConfigLoader(app)
112 # Get configuration values
113 project_name = config.get_project_name()
114 deployment_regions = config.get_deployment_regions()
115 tags = config.get_tags()
117 # Extract region configurations
118 global_region = deployment_regions["global"]
119 api_gateway_region = deployment_regions["api_gateway"]
120 monitoring_region = deployment_regions["monitoring"]
121 regional_regions = deployment_regions["regional"]
122 api_gateway_config = config.get_api_gateway_config()
123 manifest_processor_config = config.get_manifest_processor_config()
125 # Apply common tags to all stacks
126 for key, value in tags.items():
127 cdk.Tags.of(app).add(key, value)
129 # Resolve the target AWS account for every stack. Deploying (or even
130 # synthesizing against real infrastructure) requires valid credentials, so
131 # the CDK CLI populates CDK_DEFAULT_ACCOUNT from the active identity. Pairing
132 # it with each stack's region makes the stacks *environment-specific*, which
133 # is what lets CDK's availability-zones context provider look up the real AZ
134 # list for the account+region. The regional VPC relies on that lookup to
135 # place a subnet in every AZ (regional_stack.py uses max_azs=99). When the
136 # variable is unset — e.g. an environment-agnostic ``cdk synth`` in CI — this
137 # is None and stacks stay agnostic exactly as before.
138 account = os.environ.get("CDK_DEFAULT_ACCOUNT")
140 # Create global resources. Global Accelerator itself is included only in
141 # the commercial ``aws`` partition; the shared data plane remains
142 # available everywhere through regional IAM-authenticated API bridges.
143 global_stack = GCOGlobalStack(
144 app,
145 f"{project_name}-global",
146 config=config,
147 env=cdk.Environment(account=account, region=global_region),
148 description=f"{SOLUTION_DESCRIPTION_PREFIX} - Shared global resources for GCO (Global Capacity Orchestrator on AWS)",
149 )
151 # Create global API Gateway stack (authenticated entry point)
152 api_gateway_stack = GCOApiGatewayGlobalStack(
153 app,
154 f"{project_name}-api-gateway",
155 global_accelerator_dns=global_stack.get_accelerator_dns_name(),
156 project_name=project_name,
157 api_gateway_config=api_gateway_config,
158 registry_region=global_region,
159 certificate_regions=regional_regions,
160 backend_tls_config=config.get_backend_tls_config(),
161 max_request_body_bytes=manifest_processor_config.get("max_request_body_bytes", 1_048_576),
162 env=cdk.Environment(account=account, region=api_gateway_region),
163 description="Global API Gateway with IAM authentication",
164 )
165 api_gateway_stack.add_stack_dependency(global_stack)
167 # Create regional stacks for each configured region
168 regional_stacks = []
169 for region in regional_regions:
170 regional_stack = GCORegionalStack(
171 app,
172 f"{project_name}-{region}",
173 config=config,
174 region=region,
175 auth_secret_arn=api_gateway_stack.secret.secret_arn,
176 env=cdk.Environment(account=account, region=region),
177 description=f"Regional resources for {region} - EKS cluster, ALB, and services",
178 )
180 # Add dependencies
181 regional_stack.add_stack_dependency(global_stack)
182 regional_stack.add_stack_dependency(api_gateway_stack)
183 regional_stacks.append(regional_stack)
185 # Every region gets an IAM-authenticated API bridge so the centralized
186 # aggregator can reach the private ALB through a VPC-attached Lambda.
187 # In commercial ``aws``, ``regional_api_enabled`` controls whether
188 # other account principals may invoke the bridge directly. Other
189 # partitions enable that IAM-authenticated workload ingress
190 # automatically. Neither mode disables the aggregator's required path.
191 regional_api_stack = GCORegionalApiGatewayStack(
192 app,
193 f"{project_name}-regional-api-{region}",
194 config=config,
195 region=region,
196 vpc=regional_stack.vpc,
197 auth_secret_arn=api_gateway_stack.secret.secret_arn,
198 aggregator_role_arn=api_gateway_stack.aggregator_role.role_arn,
199 env=cdk.Environment(account=account, region=region),
200 description=f"Regional aggregation and workload bridge for {region}",
201 )
202 regional_api_stack.add_stack_dependency(regional_stack)
204 # Create monitoring stack
205 monitoring_stack = GCOMonitoringStack(
206 app,
207 f"{project_name}-monitoring",
208 config=config,
209 global_stack=global_stack,
210 regional_stacks=regional_stacks,
211 api_gateway_stack=api_gateway_stack,
212 env=cdk.Environment(account=account, region=monitoring_region),
213 description="Cross-region monitoring and observability for GCO (Global Capacity Orchestrator on AWS)",
214 )
216 # Add dependencies on all regional stacks
217 for regional_stack in regional_stacks:
218 monitoring_stack.add_stack_dependency(regional_stack)
220 # Optionally instantiate the analytics stack when explicitly enabled via
221 # cdk.json. The stack lives in the API gateway region so the
222 # presigned-URL Lambda can be wired into the existing /studio/* API
223 # Gateway routes without a cross-region hop.
224 # When the toggle is off, the stack is skipped entirely so cdk synth
225 # emits no SageMaker, EMR Serverless, or Cognito resources.
226 if config.get_analytics_enabled():
227 # Note: we intentionally do NOT pass ``api_gateway_secret_arn``
228 # here. That kwarg is reserved for future auth wiring and is not
229 # consumed by any CloudFormation resource. Passing the secret
230 # ARN (a cross-stack token) would force an implicit
231 # ``analytics_stack → api_gateway_stack`` dependency, which
232 # would deadlock against the reverse dependency we add below
233 # (api_gateway_stack needs the presigned-URL Lambda ARN).
234 analytics_stack = GCOAnalyticsStack(
235 app,
236 f"{project_name}-analytics",
237 config=config,
238 env=cdk.Environment(account=account, region=api_gateway_region),
239 description="Optional ML and analytics environment (SageMaker Studio, EMR Serverless, Cognito)",
240 )
241 analytics_stack.add_stack_dependency(global_stack)
243 # Wire the analytics stack's presigned-URL Lambda into the API
244 # Gateway stack via a mutator. The API gateway stack was already
245 # created above (before the analytics stack) because every
246 # regional stack declares a dependency on it; re-ordering the
247 # two globals would ripple through the entire stack graph. The
248 # mutator lets us defer the /studio/* wiring until both stacks
249 # exist without changing the existing dependency chain.
250 #
251 # ``api_gateway_stack.add_stack_dependency(analytics_stack)`` ensures
252 # the analytics stack (and its Lambda) finish deploying before
253 # CloudFormation updates the API gateway stack — the Lambda
254 # ARN is now a cross-stack reference on the API gateway side.
255 analytics_api_config = AnalyticsApiConfig(
256 user_pool_arn=analytics_stack.cognito_pool.user_pool_arn,
257 user_pool_client_id=analytics_stack.cognito_client.user_pool_client_id,
258 presigned_url_lambda=analytics_stack.presigned_url_lambda,
259 studio_domain_name=analytics_stack.studio_domain.domain_name or "",
260 callback_url=(
261 f"https://{api_gateway_stack.api.rest_api_id}."
262 f"execute-api.{api_gateway_region}."
263 f"{api_gateway_stack.url_suffix}/prod/studio/callback"
264 ),
265 )
266 api_gateway_stack.set_analytics_config(analytics_api_config)
267 api_gateway_stack.add_stack_dependency(analytics_stack)
269 app.synth()
272if __name__ == "__main__":
273 main()