terraformgraph 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- terraformgraph/__init__.py +19 -0
- terraformgraph/__main__.py +6 -0
- terraformgraph/aggregator.py +396 -0
- terraformgraph/config/aggregation_rules.yaml +132 -0
- terraformgraph/config/logical_connections.yaml +183 -0
- terraformgraph/config_loader.py +55 -0
- terraformgraph/icons.py +795 -0
- terraformgraph/layout.py +239 -0
- terraformgraph/main.py +194 -0
- terraformgraph/parser.py +341 -0
- terraformgraph/renderer.py +1134 -0
- terraformgraph-1.0.1.dist-info/METADATA +161 -0
- terraformgraph-1.0.1.dist-info/RECORD +17 -0
- terraformgraph-1.0.1.dist-info/WHEEL +5 -0
- terraformgraph-1.0.1.dist-info/entry_points.txt +2 -0
- terraformgraph-1.0.1.dist-info/licenses/LICENSE +21 -0
- terraformgraph-1.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""terraformgraph - Create architecture diagrams from Terraform configurations."""
|
|
2
|
+
|
|
3
|
+
__version__ = "1.0.1"
|
|
4
|
+
|
|
5
|
+
from .aggregator import ResourceAggregator
|
|
6
|
+
from .config_loader import ConfigLoader
|
|
7
|
+
from .layout import LayoutEngine
|
|
8
|
+
from .parser import TerraformParser
|
|
9
|
+
from .renderer import HTMLRenderer, SVGRenderer
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"__version__",
|
|
13
|
+
"TerraformParser",
|
|
14
|
+
"ResourceAggregator",
|
|
15
|
+
"LayoutEngine",
|
|
16
|
+
"SVGRenderer",
|
|
17
|
+
"HTMLRenderer",
|
|
18
|
+
"ConfigLoader",
|
|
19
|
+
]
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Resource Aggregator
|
|
3
|
+
|
|
4
|
+
Aggregates low-level Terraform resources into high-level logical services
|
|
5
|
+
for cleaner architecture diagrams.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Any, Dict, List, Optional
|
|
10
|
+
|
|
11
|
+
from .config_loader import ConfigLoader
|
|
12
|
+
from .parser import ParseResult, TerraformResource
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class LogicalService:
|
|
17
|
+
"""A high-level logical service aggregating multiple resources."""
|
|
18
|
+
service_type: str # e.g., 'alb', 'ecs', 's3', 'sqs'
|
|
19
|
+
name: str
|
|
20
|
+
icon_resource_type: str # The Terraform type to use for the icon
|
|
21
|
+
resources: List[TerraformResource] = field(default_factory=list)
|
|
22
|
+
count: int = 1 # How many instances (e.g., 24 SQS queues)
|
|
23
|
+
is_vpc_resource: bool = False
|
|
24
|
+
attributes: Dict[str, str] = field(default_factory=dict)
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def id(self) -> str:
|
|
28
|
+
return f"{self.service_type}.{self.name}"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class LogicalConnection:
|
|
33
|
+
"""A connection between logical services."""
|
|
34
|
+
source_id: str
|
|
35
|
+
target_id: str
|
|
36
|
+
label: Optional[str] = None
|
|
37
|
+
connection_type: str = 'default' # 'default', 'data_flow', 'trigger', 'encrypt'
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class AggregatedResult:
|
|
42
|
+
"""Result of aggregating resources into logical services."""
|
|
43
|
+
services: List[LogicalService] = field(default_factory=list)
|
|
44
|
+
connections: List[LogicalConnection] = field(default_factory=list)
|
|
45
|
+
vpc_services: List[LogicalService] = field(default_factory=list)
|
|
46
|
+
global_services: List[LogicalService] = field(default_factory=list)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# Define which resource types should be aggregated together
|
|
50
|
+
AGGREGATION_RULES = {
|
|
51
|
+
# Load Balancing: ALB + listeners + target groups = one ALB
|
|
52
|
+
'alb': {
|
|
53
|
+
'primary': ['aws_lb'],
|
|
54
|
+
'aggregate': ['aws_lb_listener', 'aws_lb_target_group', 'aws_lb_target_group_attachment'],
|
|
55
|
+
'icon': 'aws_lb',
|
|
56
|
+
'display_name': 'Load Balancer',
|
|
57
|
+
'is_vpc': True,
|
|
58
|
+
},
|
|
59
|
+
# ECS: cluster + services + task definitions = one ECS
|
|
60
|
+
'ecs': {
|
|
61
|
+
'primary': ['aws_ecs_cluster'],
|
|
62
|
+
'aggregate': ['aws_ecs_service', 'aws_ecs_task_definition'],
|
|
63
|
+
'icon': 'aws_ecs_cluster',
|
|
64
|
+
'display_name': 'ECS Cluster',
|
|
65
|
+
'is_vpc': True,
|
|
66
|
+
},
|
|
67
|
+
# VPC: vpc + subnets + gateways + route tables = one VPC
|
|
68
|
+
'vpc': {
|
|
69
|
+
'primary': ['aws_vpc'],
|
|
70
|
+
'aggregate': ['aws_subnet', 'aws_internet_gateway', 'aws_nat_gateway',
|
|
71
|
+
'aws_route_table', 'aws_route', 'aws_route_table_association',
|
|
72
|
+
'aws_eip', 'aws_vpc_endpoint', 'aws_db_subnet_group'],
|
|
73
|
+
'icon': 'aws_vpc',
|
|
74
|
+
'display_name': 'VPC',
|
|
75
|
+
'is_vpc': True,
|
|
76
|
+
},
|
|
77
|
+
# Security Groups: aggregate all SGs
|
|
78
|
+
'security': {
|
|
79
|
+
'primary': ['aws_security_group'],
|
|
80
|
+
'aggregate': ['aws_security_group_rule'],
|
|
81
|
+
'icon': 'aws_security_group',
|
|
82
|
+
'display_name': 'Security Groups',
|
|
83
|
+
'is_vpc': True,
|
|
84
|
+
},
|
|
85
|
+
# S3: buckets (aggregate policies, versioning, etc.)
|
|
86
|
+
's3': {
|
|
87
|
+
'primary': ['aws_s3_bucket'],
|
|
88
|
+
'aggregate': ['aws_s3_bucket_policy', 'aws_s3_bucket_versioning',
|
|
89
|
+
'aws_s3_bucket_lifecycle_configuration', 'aws_s3_bucket_notification',
|
|
90
|
+
'aws_s3_bucket_cors_configuration', 'aws_s3_bucket_public_access_block',
|
|
91
|
+
'aws_s3_bucket_ownership_controls', 'aws_s3_bucket_server_side_encryption_configuration'],
|
|
92
|
+
'icon': 'aws_s3_bucket',
|
|
93
|
+
'display_name': 'S3 Buckets',
|
|
94
|
+
'is_vpc': False,
|
|
95
|
+
},
|
|
96
|
+
# SQS: aggregate all queues
|
|
97
|
+
'sqs': {
|
|
98
|
+
'primary': ['aws_sqs_queue'],
|
|
99
|
+
'aggregate': ['aws_sqs_queue_policy'],
|
|
100
|
+
'icon': 'aws_sqs_queue',
|
|
101
|
+
'display_name': 'SQS Queues',
|
|
102
|
+
'is_vpc': False,
|
|
103
|
+
},
|
|
104
|
+
# SNS: aggregate topics
|
|
105
|
+
'sns': {
|
|
106
|
+
'primary': ['aws_sns_topic'],
|
|
107
|
+
'aggregate': ['aws_sns_topic_policy', 'aws_sns_topic_subscription'],
|
|
108
|
+
'icon': 'aws_sns_topic',
|
|
109
|
+
'display_name': 'SNS Topics',
|
|
110
|
+
'is_vpc': False,
|
|
111
|
+
},
|
|
112
|
+
# Cognito: user pool + clients + domain
|
|
113
|
+
'cognito': {
|
|
114
|
+
'primary': ['aws_cognito_user_pool'],
|
|
115
|
+
'aggregate': ['aws_cognito_user_pool_client', 'aws_cognito_user_pool_domain',
|
|
116
|
+
'aws_cognito_identity_pool', 'aws_cognito_identity_pool_roles_attachment',
|
|
117
|
+
'aws_cognito_log_delivery_configuration'],
|
|
118
|
+
'icon': 'aws_cognito_user_pool',
|
|
119
|
+
'display_name': 'Cognito',
|
|
120
|
+
'is_vpc': False,
|
|
121
|
+
},
|
|
122
|
+
# KMS: keys + aliases
|
|
123
|
+
'kms': {
|
|
124
|
+
'primary': ['aws_kms_key'],
|
|
125
|
+
'aggregate': ['aws_kms_alias'],
|
|
126
|
+
'icon': 'aws_kms_key',
|
|
127
|
+
'display_name': 'KMS Keys',
|
|
128
|
+
'is_vpc': False,
|
|
129
|
+
},
|
|
130
|
+
# Secrets Manager
|
|
131
|
+
'secrets': {
|
|
132
|
+
'primary': ['aws_secretsmanager_secret'],
|
|
133
|
+
'aggregate': ['aws_secretsmanager_secret_version'],
|
|
134
|
+
'icon': 'aws_secretsmanager_secret',
|
|
135
|
+
'display_name': 'Secrets Manager',
|
|
136
|
+
'is_vpc': False,
|
|
137
|
+
},
|
|
138
|
+
# Route53
|
|
139
|
+
'route53': {
|
|
140
|
+
'primary': ['aws_route53_zone'],
|
|
141
|
+
'aggregate': ['aws_route53_record'],
|
|
142
|
+
'icon': 'aws_route53_zone',
|
|
143
|
+
'display_name': 'Route 53',
|
|
144
|
+
'is_vpc': False,
|
|
145
|
+
},
|
|
146
|
+
# ACM Certificates
|
|
147
|
+
'acm': {
|
|
148
|
+
'primary': ['aws_acm_certificate'],
|
|
149
|
+
'aggregate': ['aws_acm_certificate_validation'],
|
|
150
|
+
'icon': 'aws_acm_certificate',
|
|
151
|
+
'display_name': 'Certificates',
|
|
152
|
+
'is_vpc': False,
|
|
153
|
+
},
|
|
154
|
+
# CloudWatch
|
|
155
|
+
'cloudwatch': {
|
|
156
|
+
'primary': ['aws_cloudwatch_log_group', 'aws_cloudwatch_metric_alarm'],
|
|
157
|
+
'aggregate': ['aws_cloudwatch_log_resource_policy', 'aws_cloudwatch_log_delivery',
|
|
158
|
+
'aws_cloudwatch_log_delivery_source', 'aws_cloudwatch_log_delivery_destination',
|
|
159
|
+
'aws_cloudwatch_dashboard'],
|
|
160
|
+
'icon': 'aws_cloudwatch_metric_alarm',
|
|
161
|
+
'display_name': 'CloudWatch',
|
|
162
|
+
'is_vpc': False,
|
|
163
|
+
},
|
|
164
|
+
# EventBridge
|
|
165
|
+
'eventbridge': {
|
|
166
|
+
'primary': ['aws_cloudwatch_event_rule', 'aws_cloudwatch_event_bus'],
|
|
167
|
+
'aggregate': ['aws_cloudwatch_event_target', 'aws_cloudwatch_event_archive'],
|
|
168
|
+
'icon': 'aws_cloudwatch_event_rule',
|
|
169
|
+
'display_name': 'EventBridge',
|
|
170
|
+
'is_vpc': False,
|
|
171
|
+
},
|
|
172
|
+
# WAF
|
|
173
|
+
'waf': {
|
|
174
|
+
'primary': ['aws_wafv2_web_acl'],
|
|
175
|
+
'aggregate': ['aws_wafv2_web_acl_association', 'aws_wafv2_rule_group'],
|
|
176
|
+
'icon': 'aws_wafv2_web_acl',
|
|
177
|
+
'display_name': 'WAF',
|
|
178
|
+
'is_vpc': False,
|
|
179
|
+
},
|
|
180
|
+
# IAM
|
|
181
|
+
'iam': {
|
|
182
|
+
'primary': ['aws_iam_role'],
|
|
183
|
+
'aggregate': ['aws_iam_policy', 'aws_iam_role_policy', 'aws_iam_role_policy_attachment',
|
|
184
|
+
'aws_iam_instance_profile'],
|
|
185
|
+
'icon': 'aws_iam_role',
|
|
186
|
+
'display_name': 'IAM Roles',
|
|
187
|
+
'is_vpc': False,
|
|
188
|
+
},
|
|
189
|
+
# ECR
|
|
190
|
+
'ecr': {
|
|
191
|
+
'primary': ['aws_ecr_repository'],
|
|
192
|
+
'aggregate': [],
|
|
193
|
+
'icon': 'aws_ecr_repository',
|
|
194
|
+
'display_name': 'ECR',
|
|
195
|
+
'is_vpc': False,
|
|
196
|
+
},
|
|
197
|
+
# DynamoDB
|
|
198
|
+
'dynamodb': {
|
|
199
|
+
'primary': ['aws_dynamodb_table'],
|
|
200
|
+
'aggregate': [],
|
|
201
|
+
'icon': 'aws_dynamodb_table',
|
|
202
|
+
'display_name': 'DynamoDB',
|
|
203
|
+
'is_vpc': False,
|
|
204
|
+
},
|
|
205
|
+
# SES
|
|
206
|
+
'ses': {
|
|
207
|
+
'primary': ['aws_ses_domain_identity'],
|
|
208
|
+
'aggregate': ['aws_ses_domain_dkim', 'aws_ses_domain_mail_from',
|
|
209
|
+
'aws_ses_identity_notification_topic', 'aws_ses_configuration_set'],
|
|
210
|
+
'icon': 'aws_ses_domain_identity',
|
|
211
|
+
'display_name': 'SES',
|
|
212
|
+
'is_vpc': False,
|
|
213
|
+
},
|
|
214
|
+
# CloudFront
|
|
215
|
+
'cloudfront': {
|
|
216
|
+
'primary': ['aws_cloudfront_distribution'],
|
|
217
|
+
'aggregate': ['aws_cloudfront_origin_access_control'],
|
|
218
|
+
'icon': 'aws_cloudfront_distribution',
|
|
219
|
+
'display_name': 'CloudFront',
|
|
220
|
+
'is_vpc': False,
|
|
221
|
+
},
|
|
222
|
+
# Bedrock
|
|
223
|
+
'bedrock': {
|
|
224
|
+
'primary': ['aws_bedrockagent_knowledge_base'],
|
|
225
|
+
'aggregate': [],
|
|
226
|
+
'icon': 'aws_bedrockagent_knowledge_base',
|
|
227
|
+
'display_name': 'Bedrock KB',
|
|
228
|
+
'is_vpc': False,
|
|
229
|
+
},
|
|
230
|
+
# Budgets
|
|
231
|
+
'budgets': {
|
|
232
|
+
'primary': ['aws_budgets_budget'],
|
|
233
|
+
'aggregate': [],
|
|
234
|
+
'icon': 'aws_budgets_budget',
|
|
235
|
+
'display_name': 'Budgets',
|
|
236
|
+
'is_vpc': False,
|
|
237
|
+
},
|
|
238
|
+
# EC2 (standalone instances like DevOps agent)
|
|
239
|
+
'ec2': {
|
|
240
|
+
'primary': ['aws_instance'],
|
|
241
|
+
'aggregate': ['aws_launch_template'],
|
|
242
|
+
'icon': 'aws_instance',
|
|
243
|
+
'display_name': 'EC2',
|
|
244
|
+
'is_vpc': True,
|
|
245
|
+
},
|
|
246
|
+
# MongoDB Atlas (external)
|
|
247
|
+
'mongodb': {
|
|
248
|
+
'primary': ['mongodbatlas_cluster'],
|
|
249
|
+
'aggregate': ['mongodbatlas_network_peering', 'mongodbatlas_project_ip_access_list'],
|
|
250
|
+
'icon': 'aws_dynamodb_table', # Use DynamoDB icon as fallback
|
|
251
|
+
'display_name': 'MongoDB Atlas',
|
|
252
|
+
'is_vpc': False,
|
|
253
|
+
},
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
# High-level connections between service types
|
|
257
|
+
LOGICAL_CONNECTIONS = [
|
|
258
|
+
# Internet -> WAF -> CloudFront -> ALB
|
|
259
|
+
('cloudfront', 'alb', 'HTTPS', 'data_flow'),
|
|
260
|
+
('waf', 'alb', 'protects', 'default'),
|
|
261
|
+
('waf', 'cognito', 'protects', 'default'),
|
|
262
|
+
|
|
263
|
+
# ALB -> ECS
|
|
264
|
+
('alb', 'ecs', 'routes to', 'data_flow'),
|
|
265
|
+
|
|
266
|
+
# ECS -> various services
|
|
267
|
+
('ecs', 'sqs', 'sends/receives', 'data_flow'),
|
|
268
|
+
('ecs', 's3', 'reads/writes', 'data_flow'),
|
|
269
|
+
('ecs', 'dynamodb', 'queries', 'data_flow'),
|
|
270
|
+
('ecs', 'secrets', 'reads', 'default'),
|
|
271
|
+
('ecs', 'bedrock', 'invokes', 'data_flow'),
|
|
272
|
+
|
|
273
|
+
# S3 -> SQS (notifications)
|
|
274
|
+
('s3', 'sqs', 'triggers', 'trigger'),
|
|
275
|
+
|
|
276
|
+
# SNS for alerts
|
|
277
|
+
('cloudwatch', 'sns', 'alerts', 'trigger'),
|
|
278
|
+
('sqs', 'sns', 'DLQ alerts', 'trigger'),
|
|
279
|
+
|
|
280
|
+
# Encryption
|
|
281
|
+
('kms', 's3', 'encrypts', 'encrypt'),
|
|
282
|
+
('kms', 'sqs', 'encrypts', 'encrypt'),
|
|
283
|
+
('kms', 'sns', 'encrypts', 'encrypt'),
|
|
284
|
+
('kms', 'secrets', 'encrypts', 'encrypt'),
|
|
285
|
+
|
|
286
|
+
# DNS
|
|
287
|
+
('route53', 'alb', 'resolves', 'default'),
|
|
288
|
+
('route53', 'cloudfront', 'resolves', 'default'),
|
|
289
|
+
|
|
290
|
+
# Certificates
|
|
291
|
+
('acm', 'alb', 'TLS', 'default'),
|
|
292
|
+
('acm', 'cloudfront', 'TLS', 'default'),
|
|
293
|
+
|
|
294
|
+
# Cognito auth
|
|
295
|
+
('cognito', 'alb', 'authenticates', 'default'),
|
|
296
|
+
|
|
297
|
+
# ECR -> ECS
|
|
298
|
+
('ecr', 'ecs', 'images', 'data_flow'),
|
|
299
|
+
|
|
300
|
+
# External
|
|
301
|
+
('ecs', 'mongodb', 'queries', 'data_flow'),
|
|
302
|
+
]
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class ResourceAggregator:
|
|
306
|
+
"""Aggregates Terraform resources into logical services."""
|
|
307
|
+
|
|
308
|
+
def __init__(self, config_loader: Optional[ConfigLoader] = None):
|
|
309
|
+
self._config = config_loader or ConfigLoader()
|
|
310
|
+
self._aggregation_rules = self._build_aggregation_rules()
|
|
311
|
+
self._logical_connections = self._config.get_logical_connections()
|
|
312
|
+
self._build_type_to_rule_map()
|
|
313
|
+
|
|
314
|
+
def _build_aggregation_rules(self) -> Dict[str, Dict[str, Any]]:
|
|
315
|
+
"""Build aggregation rules dict from config."""
|
|
316
|
+
flat_rules = self._config.get_flat_aggregation_rules()
|
|
317
|
+
result = {}
|
|
318
|
+
for service_name, config in flat_rules.items():
|
|
319
|
+
# Map YAML format (primary/secondary/in_vpc) to internal format
|
|
320
|
+
result[service_name] = {
|
|
321
|
+
'primary': config.get("primary", []),
|
|
322
|
+
'aggregate': config.get("secondary", []), # secondary in YAML -> aggregate internally
|
|
323
|
+
'icon': config.get("primary", [""])[0] if config.get("primary") else "",
|
|
324
|
+
'display_name': service_name.replace("_", " ").title(),
|
|
325
|
+
'is_vpc': config.get("in_vpc", False),
|
|
326
|
+
}
|
|
327
|
+
return result
|
|
328
|
+
|
|
329
|
+
def _build_type_to_rule_map(self) -> None:
|
|
330
|
+
"""Build a mapping from resource type to aggregation rule."""
|
|
331
|
+
self._type_to_rule: Dict[str, str] = {}
|
|
332
|
+
for rule_name, rule in self._aggregation_rules.items():
|
|
333
|
+
for res_type in rule['primary']:
|
|
334
|
+
self._type_to_rule[res_type] = rule_name
|
|
335
|
+
for res_type in rule['aggregate']:
|
|
336
|
+
self._type_to_rule[res_type] = rule_name
|
|
337
|
+
|
|
338
|
+
def aggregate(self, parse_result: ParseResult) -> AggregatedResult:
|
|
339
|
+
"""Aggregate parsed resources into logical services."""
|
|
340
|
+
result = AggregatedResult()
|
|
341
|
+
|
|
342
|
+
# Group resources by aggregation rule
|
|
343
|
+
rule_resources: Dict[str, List[TerraformResource]] = {}
|
|
344
|
+
unmatched: List[TerraformResource] = []
|
|
345
|
+
|
|
346
|
+
for resource in parse_result.resources:
|
|
347
|
+
rule_name = self._type_to_rule.get(resource.resource_type)
|
|
348
|
+
if rule_name:
|
|
349
|
+
rule_resources.setdefault(rule_name, []).append(resource)
|
|
350
|
+
else:
|
|
351
|
+
unmatched.append(resource)
|
|
352
|
+
|
|
353
|
+
# Create logical services from grouped resources
|
|
354
|
+
for rule_name, resources in rule_resources.items():
|
|
355
|
+
rule = self._aggregation_rules[rule_name]
|
|
356
|
+
|
|
357
|
+
# Count primary resources
|
|
358
|
+
primary_count = sum(1 for r in resources if r.resource_type in rule['primary'])
|
|
359
|
+
if primary_count == 0:
|
|
360
|
+
continue # Skip if no primary resources
|
|
361
|
+
|
|
362
|
+
service = LogicalService(
|
|
363
|
+
service_type=rule_name,
|
|
364
|
+
name=rule['display_name'],
|
|
365
|
+
icon_resource_type=rule['icon'],
|
|
366
|
+
resources=resources,
|
|
367
|
+
count=primary_count,
|
|
368
|
+
is_vpc_resource=rule['is_vpc'],
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
result.services.append(service)
|
|
372
|
+
if service.is_vpc_resource:
|
|
373
|
+
result.vpc_services.append(service)
|
|
374
|
+
else:
|
|
375
|
+
result.global_services.append(service)
|
|
376
|
+
|
|
377
|
+
# Create logical connections based on which services exist
|
|
378
|
+
existing_services = {s.service_type for s in result.services}
|
|
379
|
+
for conn in self._logical_connections:
|
|
380
|
+
source = conn.get("source", "")
|
|
381
|
+
target = conn.get("target", "")
|
|
382
|
+
if source in existing_services and target in existing_services:
|
|
383
|
+
result.connections.append(LogicalConnection(
|
|
384
|
+
source_id=f"{source}.{self._aggregation_rules[source]['display_name']}",
|
|
385
|
+
target_id=f"{target}.{self._aggregation_rules[target]['display_name']}",
|
|
386
|
+
label=conn.get("label", ""),
|
|
387
|
+
connection_type=conn.get("type", "default"),
|
|
388
|
+
))
|
|
389
|
+
|
|
390
|
+
return result
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def aggregate_resources(parse_result: ParseResult) -> AggregatedResult:
|
|
394
|
+
"""Convenience function to aggregate resources."""
|
|
395
|
+
aggregator = ResourceAggregator()
|
|
396
|
+
return aggregator.aggregate(parse_result)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Aggregation rules for grouping Terraform resources into logical services
|
|
2
|
+
# Format: service_name -> list of resource patterns
|
|
3
|
+
|
|
4
|
+
compute:
|
|
5
|
+
ecs:
|
|
6
|
+
primary: ["aws_ecs_cluster", "aws_ecs_service", "aws_ecs_task_definition"]
|
|
7
|
+
secondary: ["aws_ecs_capacity_provider", "aws_appautoscaling_target", "aws_appautoscaling_policy"]
|
|
8
|
+
in_vpc: true
|
|
9
|
+
|
|
10
|
+
ec2:
|
|
11
|
+
primary: ["aws_instance", "aws_launch_template", "aws_autoscaling_group"]
|
|
12
|
+
secondary: ["aws_ami", "aws_ebs_volume"]
|
|
13
|
+
in_vpc: true
|
|
14
|
+
|
|
15
|
+
networking:
|
|
16
|
+
alb:
|
|
17
|
+
primary: ["aws_lb", "aws_alb"]
|
|
18
|
+
secondary: ["aws_lb_listener", "aws_lb_target_group", "aws_alb_listener", "aws_alb_target_group"]
|
|
19
|
+
in_vpc: true
|
|
20
|
+
|
|
21
|
+
vpc:
|
|
22
|
+
primary: ["aws_vpc"]
|
|
23
|
+
secondary: ["aws_subnet", "aws_route_table", "aws_internet_gateway", "aws_nat_gateway", "aws_route_table_association", "aws_eip"]
|
|
24
|
+
in_vpc: true
|
|
25
|
+
|
|
26
|
+
security_groups:
|
|
27
|
+
primary: ["aws_security_group"]
|
|
28
|
+
secondary: ["aws_security_group_rule", "aws_vpc_security_group_ingress_rule", "aws_vpc_security_group_egress_rule"]
|
|
29
|
+
in_vpc: true
|
|
30
|
+
|
|
31
|
+
storage:
|
|
32
|
+
s3:
|
|
33
|
+
primary: ["aws_s3_bucket"]
|
|
34
|
+
secondary: ["aws_s3_bucket_policy", "aws_s3_bucket_versioning", "aws_s3_bucket_lifecycle_configuration", "aws_s3_bucket_public_access_block", "aws_s3_bucket_server_side_encryption_configuration", "aws_s3_bucket_cors_configuration", "aws_s3_bucket_notification", "aws_s3_object"]
|
|
35
|
+
in_vpc: false
|
|
36
|
+
|
|
37
|
+
database:
|
|
38
|
+
dynamodb:
|
|
39
|
+
primary: ["aws_dynamodb_table"]
|
|
40
|
+
secondary: ["aws_dynamodb_table_item", "aws_dynamodb_global_table"]
|
|
41
|
+
in_vpc: false
|
|
42
|
+
|
|
43
|
+
rds:
|
|
44
|
+
primary: ["aws_db_instance", "aws_rds_cluster"]
|
|
45
|
+
secondary: ["aws_db_subnet_group", "aws_db_parameter_group", "aws_rds_cluster_instance"]
|
|
46
|
+
in_vpc: true
|
|
47
|
+
|
|
48
|
+
elasticache:
|
|
49
|
+
primary: ["aws_elasticache_cluster", "aws_elasticache_replication_group"]
|
|
50
|
+
secondary: ["aws_elasticache_subnet_group", "aws_elasticache_parameter_group"]
|
|
51
|
+
in_vpc: true
|
|
52
|
+
|
|
53
|
+
messaging:
|
|
54
|
+
sqs:
|
|
55
|
+
primary: ["aws_sqs_queue"]
|
|
56
|
+
secondary: ["aws_sqs_queue_policy"]
|
|
57
|
+
in_vpc: false
|
|
58
|
+
|
|
59
|
+
sns:
|
|
60
|
+
primary: ["aws_sns_topic"]
|
|
61
|
+
secondary: ["aws_sns_topic_subscription", "aws_sns_topic_policy"]
|
|
62
|
+
in_vpc: false
|
|
63
|
+
|
|
64
|
+
eventbridge:
|
|
65
|
+
primary: ["aws_cloudwatch_event_rule", "aws_cloudwatch_event_bus"]
|
|
66
|
+
secondary: ["aws_cloudwatch_event_target"]
|
|
67
|
+
in_vpc: false
|
|
68
|
+
|
|
69
|
+
security:
|
|
70
|
+
kms:
|
|
71
|
+
primary: ["aws_kms_key"]
|
|
72
|
+
secondary: ["aws_kms_alias"]
|
|
73
|
+
in_vpc: false
|
|
74
|
+
|
|
75
|
+
secrets_manager:
|
|
76
|
+
primary: ["aws_secretsmanager_secret"]
|
|
77
|
+
secondary: ["aws_secretsmanager_secret_version"]
|
|
78
|
+
in_vpc: false
|
|
79
|
+
|
|
80
|
+
iam:
|
|
81
|
+
primary: ["aws_iam_role"]
|
|
82
|
+
secondary: ["aws_iam_policy", "aws_iam_role_policy", "aws_iam_role_policy_attachment", "aws_iam_policy_attachment", "aws_iam_instance_profile"]
|
|
83
|
+
in_vpc: false
|
|
84
|
+
|
|
85
|
+
edge:
|
|
86
|
+
cloudfront:
|
|
87
|
+
primary: ["aws_cloudfront_distribution"]
|
|
88
|
+
secondary: ["aws_cloudfront_origin_access_identity", "aws_cloudfront_origin_access_control", "aws_cloudfront_cache_policy", "aws_cloudfront_response_headers_policy"]
|
|
89
|
+
in_vpc: false
|
|
90
|
+
|
|
91
|
+
waf:
|
|
92
|
+
primary: ["aws_wafv2_web_acl"]
|
|
93
|
+
secondary: ["aws_wafv2_web_acl_association", "aws_wafv2_ip_set", "aws_wafv2_rule_group"]
|
|
94
|
+
in_vpc: false
|
|
95
|
+
|
|
96
|
+
route53:
|
|
97
|
+
primary: ["aws_route53_zone"]
|
|
98
|
+
secondary: ["aws_route53_record"]
|
|
99
|
+
in_vpc: false
|
|
100
|
+
|
|
101
|
+
acm:
|
|
102
|
+
primary: ["aws_acm_certificate"]
|
|
103
|
+
secondary: ["aws_acm_certificate_validation"]
|
|
104
|
+
in_vpc: false
|
|
105
|
+
|
|
106
|
+
auth:
|
|
107
|
+
cognito:
|
|
108
|
+
primary: ["aws_cognito_user_pool"]
|
|
109
|
+
secondary: ["aws_cognito_user_pool_client", "aws_cognito_identity_pool", "aws_cognito_user_pool_domain"]
|
|
110
|
+
in_vpc: false
|
|
111
|
+
|
|
112
|
+
monitoring:
|
|
113
|
+
cloudwatch:
|
|
114
|
+
primary: ["aws_cloudwatch_log_group"]
|
|
115
|
+
secondary: ["aws_cloudwatch_log_stream", "aws_cloudwatch_metric_alarm", "aws_cloudwatch_dashboard"]
|
|
116
|
+
in_vpc: false
|
|
117
|
+
|
|
118
|
+
serverless:
|
|
119
|
+
lambda:
|
|
120
|
+
primary: ["aws_lambda_function"]
|
|
121
|
+
secondary: ["aws_lambda_permission", "aws_lambda_event_source_mapping", "aws_lambda_layer_version"]
|
|
122
|
+
in_vpc: false
|
|
123
|
+
|
|
124
|
+
api_gateway:
|
|
125
|
+
primary: ["aws_api_gateway_rest_api", "aws_apigatewayv2_api"]
|
|
126
|
+
secondary: ["aws_api_gateway_resource", "aws_api_gateway_method", "aws_api_gateway_integration", "aws_api_gateway_deployment", "aws_api_gateway_stage", "aws_apigatewayv2_stage", "aws_apigatewayv2_route", "aws_apigatewayv2_integration"]
|
|
127
|
+
in_vpc: false
|
|
128
|
+
|
|
129
|
+
step_functions:
|
|
130
|
+
primary: ["aws_sfn_state_machine"]
|
|
131
|
+
secondary: []
|
|
132
|
+
in_vpc: false
|