aws-inventory-manager 0.17.12__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.
- aws_inventory_manager-0.17.12.dist-info/LICENSE +21 -0
- aws_inventory_manager-0.17.12.dist-info/METADATA +1292 -0
- aws_inventory_manager-0.17.12.dist-info/RECORD +152 -0
- aws_inventory_manager-0.17.12.dist-info/WHEEL +5 -0
- aws_inventory_manager-0.17.12.dist-info/entry_points.txt +2 -0
- aws_inventory_manager-0.17.12.dist-info/top_level.txt +1 -0
- src/__init__.py +3 -0
- src/aws/__init__.py +11 -0
- src/aws/client.py +128 -0
- src/aws/credentials.py +191 -0
- src/aws/rate_limiter.py +177 -0
- src/cli/__init__.py +12 -0
- src/cli/config.py +130 -0
- src/cli/main.py +4046 -0
- src/cloudtrail/__init__.py +5 -0
- src/cloudtrail/query.py +642 -0
- src/config_service/__init__.py +21 -0
- src/config_service/collector.py +346 -0
- src/config_service/detector.py +256 -0
- src/config_service/resource_type_mapping.py +328 -0
- src/cost/__init__.py +5 -0
- src/cost/analyzer.py +226 -0
- src/cost/explorer.py +209 -0
- src/cost/reporter.py +237 -0
- src/delta/__init__.py +5 -0
- src/delta/calculator.py +206 -0
- src/delta/differ.py +185 -0
- src/delta/formatters.py +272 -0
- src/delta/models.py +154 -0
- src/delta/reporter.py +234 -0
- src/matching/__init__.py +6 -0
- src/matching/config.py +52 -0
- src/matching/normalizer.py +450 -0
- src/matching/prompts.py +33 -0
- src/models/__init__.py +21 -0
- src/models/config_diff.py +135 -0
- src/models/cost_report.py +87 -0
- src/models/deletion_operation.py +104 -0
- src/models/deletion_record.py +97 -0
- src/models/delta_report.py +122 -0
- src/models/efs_resource.py +80 -0
- src/models/elasticache_resource.py +90 -0
- src/models/group.py +318 -0
- src/models/inventory.py +133 -0
- src/models/protection_rule.py +123 -0
- src/models/report.py +288 -0
- src/models/resource.py +111 -0
- src/models/security_finding.py +102 -0
- src/models/snapshot.py +122 -0
- src/restore/__init__.py +20 -0
- src/restore/audit.py +175 -0
- src/restore/cleaner.py +461 -0
- src/restore/config.py +209 -0
- src/restore/deleter.py +976 -0
- src/restore/dependency.py +254 -0
- src/restore/safety.py +115 -0
- src/security/__init__.py +0 -0
- src/security/checks/__init__.py +0 -0
- src/security/checks/base.py +56 -0
- src/security/checks/ec2_checks.py +88 -0
- src/security/checks/elasticache_checks.py +149 -0
- src/security/checks/iam_checks.py +102 -0
- src/security/checks/rds_checks.py +140 -0
- src/security/checks/s3_checks.py +95 -0
- src/security/checks/secrets_checks.py +96 -0
- src/security/checks/sg_checks.py +142 -0
- src/security/cis_mapper.py +97 -0
- src/security/models.py +53 -0
- src/security/reporter.py +174 -0
- src/security/scanner.py +87 -0
- src/snapshot/__init__.py +6 -0
- src/snapshot/capturer.py +453 -0
- src/snapshot/filter.py +259 -0
- src/snapshot/inventory_storage.py +236 -0
- src/snapshot/report_formatter.py +250 -0
- src/snapshot/reporter.py +189 -0
- src/snapshot/resource_collectors/__init__.py +5 -0
- src/snapshot/resource_collectors/apigateway.py +140 -0
- src/snapshot/resource_collectors/backup.py +136 -0
- src/snapshot/resource_collectors/base.py +81 -0
- src/snapshot/resource_collectors/cloudformation.py +55 -0
- src/snapshot/resource_collectors/cloudwatch.py +109 -0
- src/snapshot/resource_collectors/codebuild.py +69 -0
- src/snapshot/resource_collectors/codepipeline.py +82 -0
- src/snapshot/resource_collectors/dynamodb.py +65 -0
- src/snapshot/resource_collectors/ec2.py +240 -0
- src/snapshot/resource_collectors/ecs.py +215 -0
- src/snapshot/resource_collectors/efs_collector.py +102 -0
- src/snapshot/resource_collectors/eks.py +200 -0
- src/snapshot/resource_collectors/elasticache_collector.py +79 -0
- src/snapshot/resource_collectors/elb.py +126 -0
- src/snapshot/resource_collectors/eventbridge.py +156 -0
- src/snapshot/resource_collectors/glue.py +199 -0
- src/snapshot/resource_collectors/iam.py +188 -0
- src/snapshot/resource_collectors/kms.py +111 -0
- src/snapshot/resource_collectors/lambda_func.py +139 -0
- src/snapshot/resource_collectors/rds.py +109 -0
- src/snapshot/resource_collectors/route53.py +86 -0
- src/snapshot/resource_collectors/s3.py +105 -0
- src/snapshot/resource_collectors/secretsmanager.py +70 -0
- src/snapshot/resource_collectors/sns.py +68 -0
- src/snapshot/resource_collectors/sqs.py +82 -0
- src/snapshot/resource_collectors/ssm.py +160 -0
- src/snapshot/resource_collectors/stepfunctions.py +74 -0
- src/snapshot/resource_collectors/vpcendpoints.py +79 -0
- src/snapshot/resource_collectors/waf.py +159 -0
- src/snapshot/storage.py +351 -0
- src/storage/__init__.py +21 -0
- src/storage/audit_store.py +419 -0
- src/storage/database.py +294 -0
- src/storage/group_store.py +763 -0
- src/storage/inventory_store.py +320 -0
- src/storage/resource_store.py +416 -0
- src/storage/schema.py +339 -0
- src/storage/snapshot_store.py +363 -0
- src/utils/__init__.py +12 -0
- src/utils/export.py +305 -0
- src/utils/hash.py +60 -0
- src/utils/logging.py +63 -0
- src/utils/pagination.py +41 -0
- src/utils/paths.py +51 -0
- src/utils/progress.py +41 -0
- src/utils/unsupported_resources.py +306 -0
- src/web/__init__.py +5 -0
- src/web/app.py +97 -0
- src/web/dependencies.py +69 -0
- src/web/routes/__init__.py +1 -0
- src/web/routes/api/__init__.py +18 -0
- src/web/routes/api/charts.py +156 -0
- src/web/routes/api/cleanup.py +186 -0
- src/web/routes/api/filters.py +253 -0
- src/web/routes/api/groups.py +305 -0
- src/web/routes/api/inventories.py +80 -0
- src/web/routes/api/queries.py +202 -0
- src/web/routes/api/resources.py +393 -0
- src/web/routes/api/snapshots.py +314 -0
- src/web/routes/api/views.py +260 -0
- src/web/routes/pages.py +198 -0
- src/web/services/__init__.py +1 -0
- src/web/templates/base.html +955 -0
- src/web/templates/components/navbar.html +31 -0
- src/web/templates/components/sidebar.html +104 -0
- src/web/templates/pages/audit_logs.html +86 -0
- src/web/templates/pages/cleanup.html +279 -0
- src/web/templates/pages/dashboard.html +227 -0
- src/web/templates/pages/diff.html +175 -0
- src/web/templates/pages/error.html +30 -0
- src/web/templates/pages/groups.html +721 -0
- src/web/templates/pages/queries.html +246 -0
- src/web/templates/pages/resources.html +2429 -0
- src/web/templates/pages/snapshot_detail.html +271 -0
- src/web/templates/pages/snapshots.html +429 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""EKS resource collector."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Tuple
|
|
4
|
+
|
|
5
|
+
from ...models.resource import Resource
|
|
6
|
+
from ...utils.hash import compute_config_hash
|
|
7
|
+
from .base import BaseResourceCollector
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EKSCollector(BaseResourceCollector):
|
|
11
|
+
"""Collector for Amazon EKS (Elastic Kubernetes Service) resources."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def service_name(self) -> str:
|
|
15
|
+
return "eks"
|
|
16
|
+
|
|
17
|
+
def collect(self) -> List[Resource]:
|
|
18
|
+
"""Collect EKS resources.
|
|
19
|
+
|
|
20
|
+
Collects:
|
|
21
|
+
- EKS Clusters
|
|
22
|
+
- Node Groups (within each cluster)
|
|
23
|
+
- Fargate Profiles (within each cluster)
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
List of EKS resources
|
|
27
|
+
"""
|
|
28
|
+
resources = []
|
|
29
|
+
|
|
30
|
+
# Collect clusters
|
|
31
|
+
cluster_resources, cluster_names = self._collect_clusters()
|
|
32
|
+
resources.extend(cluster_resources)
|
|
33
|
+
|
|
34
|
+
# Collect node groups for each cluster
|
|
35
|
+
resources.extend(self._collect_node_groups(cluster_names))
|
|
36
|
+
|
|
37
|
+
# Collect Fargate profiles for each cluster
|
|
38
|
+
resources.extend(self._collect_fargate_profiles(cluster_names))
|
|
39
|
+
|
|
40
|
+
self.logger.debug(f"Collected {len(resources)} EKS resources in {self.region}")
|
|
41
|
+
return resources
|
|
42
|
+
|
|
43
|
+
def _collect_clusters(self) -> Tuple[List[Resource], List[str]]: # type: ignore
|
|
44
|
+
"""Collect EKS clusters.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Tuple of (list of cluster resources, list of cluster names)
|
|
48
|
+
"""
|
|
49
|
+
resources = []
|
|
50
|
+
cluster_names = []
|
|
51
|
+
client = self._create_client()
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
paginator = client.get_paginator("list_clusters")
|
|
55
|
+
for page in paginator.paginate():
|
|
56
|
+
for cluster_name in page.get("clusters", []):
|
|
57
|
+
cluster_names.append(cluster_name)
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
# Get detailed cluster info
|
|
61
|
+
cluster_response = client.describe_cluster(name=cluster_name)
|
|
62
|
+
cluster = cluster_response.get("cluster", {})
|
|
63
|
+
|
|
64
|
+
cluster_arn = cluster.get("arn", "")
|
|
65
|
+
|
|
66
|
+
# Extract tags
|
|
67
|
+
tags = cluster.get("tags", {})
|
|
68
|
+
|
|
69
|
+
# Extract creation date
|
|
70
|
+
created_at = cluster.get("createdAt")
|
|
71
|
+
|
|
72
|
+
# Create resource
|
|
73
|
+
resource = Resource(
|
|
74
|
+
arn=cluster_arn,
|
|
75
|
+
resource_type="AWS::EKS::Cluster",
|
|
76
|
+
name=cluster_name,
|
|
77
|
+
region=self.region,
|
|
78
|
+
tags=tags,
|
|
79
|
+
config_hash=compute_config_hash(cluster),
|
|
80
|
+
created_at=created_at,
|
|
81
|
+
raw_config=cluster,
|
|
82
|
+
)
|
|
83
|
+
resources.append(resource)
|
|
84
|
+
|
|
85
|
+
except Exception as e:
|
|
86
|
+
self.logger.debug(f"Error processing cluster {cluster_name}: {e}")
|
|
87
|
+
continue
|
|
88
|
+
|
|
89
|
+
except Exception as e:
|
|
90
|
+
self.logger.error(f"Error collecting EKS clusters in {self.region}: {e}")
|
|
91
|
+
|
|
92
|
+
return resources, cluster_names
|
|
93
|
+
|
|
94
|
+
def _collect_node_groups(self, cluster_names: List[str]) -> List[Resource]:
|
|
95
|
+
"""Collect EKS node groups for given clusters.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
cluster_names: List of cluster names to collect node groups from
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
List of node group resources
|
|
102
|
+
"""
|
|
103
|
+
resources = []
|
|
104
|
+
client = self._create_client()
|
|
105
|
+
|
|
106
|
+
for cluster_name in cluster_names:
|
|
107
|
+
try:
|
|
108
|
+
paginator = client.get_paginator("list_nodegroups")
|
|
109
|
+
for page in paginator.paginate(clusterName=cluster_name):
|
|
110
|
+
for nodegroup_name in page.get("nodegroups", []):
|
|
111
|
+
try:
|
|
112
|
+
# Get detailed node group info
|
|
113
|
+
ng_response = client.describe_nodegroup(
|
|
114
|
+
clusterName=cluster_name, nodegroupName=nodegroup_name
|
|
115
|
+
)
|
|
116
|
+
nodegroup = ng_response.get("nodegroup", {})
|
|
117
|
+
|
|
118
|
+
ng_arn = nodegroup.get("nodegroupArn", "")
|
|
119
|
+
|
|
120
|
+
# Extract tags
|
|
121
|
+
tags = nodegroup.get("tags", {})
|
|
122
|
+
|
|
123
|
+
# Extract creation date
|
|
124
|
+
created_at = nodegroup.get("createdAt")
|
|
125
|
+
|
|
126
|
+
# Create resource
|
|
127
|
+
resource = Resource(
|
|
128
|
+
arn=ng_arn,
|
|
129
|
+
resource_type="AWS::EKS::Nodegroup",
|
|
130
|
+
name=f"{cluster_name}/{nodegroup_name}",
|
|
131
|
+
region=self.region,
|
|
132
|
+
tags=tags,
|
|
133
|
+
config_hash=compute_config_hash(nodegroup),
|
|
134
|
+
created_at=created_at,
|
|
135
|
+
raw_config=nodegroup,
|
|
136
|
+
)
|
|
137
|
+
resources.append(resource)
|
|
138
|
+
|
|
139
|
+
except Exception as e:
|
|
140
|
+
self.logger.debug(f"Error processing node group {nodegroup_name}: {e}")
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
except Exception as e:
|
|
144
|
+
self.logger.debug(f"Error collecting node groups for cluster {cluster_name}: {e}")
|
|
145
|
+
|
|
146
|
+
return resources
|
|
147
|
+
|
|
148
|
+
def _collect_fargate_profiles(self, cluster_names: List[str]) -> List[Resource]:
|
|
149
|
+
"""Collect EKS Fargate profiles for given clusters.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
cluster_names: List of cluster names to collect Fargate profiles from
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
List of Fargate profile resources
|
|
156
|
+
"""
|
|
157
|
+
resources = []
|
|
158
|
+
client = self._create_client()
|
|
159
|
+
|
|
160
|
+
for cluster_name in cluster_names:
|
|
161
|
+
try:
|
|
162
|
+
paginator = client.get_paginator("list_fargate_profiles")
|
|
163
|
+
for page in paginator.paginate(clusterName=cluster_name):
|
|
164
|
+
for profile_name in page.get("fargateProfileNames", []):
|
|
165
|
+
try:
|
|
166
|
+
# Get detailed Fargate profile info
|
|
167
|
+
profile_response = client.describe_fargate_profile(
|
|
168
|
+
clusterName=cluster_name, fargateProfileName=profile_name
|
|
169
|
+
)
|
|
170
|
+
profile = profile_response.get("fargateProfile", {})
|
|
171
|
+
|
|
172
|
+
profile_arn = profile.get("fargateProfileArn", "")
|
|
173
|
+
|
|
174
|
+
# Extract tags
|
|
175
|
+
tags = profile.get("tags", {})
|
|
176
|
+
|
|
177
|
+
# Extract creation date
|
|
178
|
+
created_at = profile.get("createdAt")
|
|
179
|
+
|
|
180
|
+
# Create resource
|
|
181
|
+
resource = Resource(
|
|
182
|
+
arn=profile_arn,
|
|
183
|
+
resource_type="AWS::EKS::FargateProfile",
|
|
184
|
+
name=f"{cluster_name}/{profile_name}",
|
|
185
|
+
region=self.region,
|
|
186
|
+
tags=tags,
|
|
187
|
+
config_hash=compute_config_hash(profile),
|
|
188
|
+
created_at=created_at,
|
|
189
|
+
raw_config=profile,
|
|
190
|
+
)
|
|
191
|
+
resources.append(resource)
|
|
192
|
+
|
|
193
|
+
except Exception as e:
|
|
194
|
+
self.logger.debug(f"Error processing Fargate profile {profile_name}: {e}")
|
|
195
|
+
continue
|
|
196
|
+
|
|
197
|
+
except Exception as e:
|
|
198
|
+
self.logger.debug(f"Error collecting Fargate profiles for cluster {cluster_name}: {e}")
|
|
199
|
+
|
|
200
|
+
return resources
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""ElastiCache resource collector."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
from ...models.resource import Resource
|
|
8
|
+
from ...utils.hash import compute_config_hash
|
|
9
|
+
from .base import BaseResourceCollector
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ElastiCacheCollector(BaseResourceCollector):
|
|
13
|
+
"""Collector for AWS ElastiCache resources (Redis and Memcached clusters)."""
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def service_name(self) -> str:
|
|
17
|
+
return "elasticache"
|
|
18
|
+
|
|
19
|
+
def collect(self) -> List[Resource]:
|
|
20
|
+
"""Collect ElastiCache cluster resources.
|
|
21
|
+
|
|
22
|
+
Collects both Redis and Memcached clusters using the ElastiCache API.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
List of ElastiCache cluster resources
|
|
26
|
+
"""
|
|
27
|
+
resources = []
|
|
28
|
+
account_id = self._get_account_id()
|
|
29
|
+
|
|
30
|
+
# Collect cache clusters (both Redis and Memcached)
|
|
31
|
+
resources.extend(self._collect_cache_clusters(account_id))
|
|
32
|
+
|
|
33
|
+
self.logger.debug(f"Collected {len(resources)} ElastiCache clusters in {self.region}")
|
|
34
|
+
return resources
|
|
35
|
+
|
|
36
|
+
def _collect_cache_clusters(self, account_id: str) -> List[Resource]:
|
|
37
|
+
"""Collect ElastiCache cache clusters.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
account_id: AWS account ID
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
List of Resource objects representing ElastiCache clusters
|
|
44
|
+
"""
|
|
45
|
+
resources = []
|
|
46
|
+
client = self._create_client()
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
paginator = client.get_paginator("describe_cache_clusters")
|
|
50
|
+
# ShowCacheNodeInfo=False for performance (we don't need node-level details)
|
|
51
|
+
for page in paginator.paginate(ShowCacheNodeInfo=False):
|
|
52
|
+
for cluster in page.get("CacheClusters", []):
|
|
53
|
+
cluster_id = cluster["CacheClusterId"]
|
|
54
|
+
cluster_arn = cluster["ARN"]
|
|
55
|
+
|
|
56
|
+
# Extract tags
|
|
57
|
+
tags = {}
|
|
58
|
+
try:
|
|
59
|
+
tag_response = client.list_tags_for_resource(ResourceName=cluster_arn)
|
|
60
|
+
tags = {tag["Key"]: tag["Value"] for tag in tag_response.get("TagList", [])}
|
|
61
|
+
except Exception as e:
|
|
62
|
+
self.logger.debug(f"Could not get tags for ElastiCache cluster {cluster_id}: {e}")
|
|
63
|
+
|
|
64
|
+
# Create resource
|
|
65
|
+
resource = Resource(
|
|
66
|
+
arn=cluster_arn,
|
|
67
|
+
resource_type="elasticache:cluster",
|
|
68
|
+
name=cluster_id,
|
|
69
|
+
region=self.region,
|
|
70
|
+
tags=tags,
|
|
71
|
+
config_hash=compute_config_hash(cluster),
|
|
72
|
+
raw_config=cluster,
|
|
73
|
+
)
|
|
74
|
+
resources.append(resource)
|
|
75
|
+
|
|
76
|
+
except Exception as e:
|
|
77
|
+
self.logger.error(f"Error collecting ElastiCache clusters in {self.region}: {e}")
|
|
78
|
+
|
|
79
|
+
return resources
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""ELB/ALB resource collector."""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from ...models.resource import Resource
|
|
6
|
+
from ...utils.hash import compute_config_hash
|
|
7
|
+
from .base import BaseResourceCollector
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ELBCollector(BaseResourceCollector):
|
|
11
|
+
"""Collector for AWS Load Balancer resources (Classic ELB, ALB, NLB)."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def service_name(self) -> str:
|
|
15
|
+
return "elb"
|
|
16
|
+
|
|
17
|
+
def collect(self) -> List[Resource]:
|
|
18
|
+
"""Collect ELB resources.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
List of load balancers
|
|
22
|
+
"""
|
|
23
|
+
resources = []
|
|
24
|
+
account_id = self._get_account_id()
|
|
25
|
+
|
|
26
|
+
# Collect v2 load balancers (ALB, NLB, GWLB)
|
|
27
|
+
resources.extend(self._collect_v2_load_balancers(account_id))
|
|
28
|
+
|
|
29
|
+
# Collect classic load balancers
|
|
30
|
+
resources.extend(self._collect_classic_load_balancers(account_id))
|
|
31
|
+
|
|
32
|
+
self.logger.debug(f"Collected {len(resources)} load balancers in {self.region}")
|
|
33
|
+
return resources
|
|
34
|
+
|
|
35
|
+
def _collect_v2_load_balancers(self, account_id: str) -> List[Resource]:
|
|
36
|
+
"""Collect ALB/NLB/GWLB load balancers."""
|
|
37
|
+
resources = []
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
elbv2_client = self._create_client("elbv2")
|
|
41
|
+
|
|
42
|
+
paginator = elbv2_client.get_paginator("describe_load_balancers")
|
|
43
|
+
for page in paginator.paginate():
|
|
44
|
+
for lb in page.get("LoadBalancers", []):
|
|
45
|
+
lb_arn = lb["LoadBalancerArn"]
|
|
46
|
+
lb_name = lb["LoadBalancerName"]
|
|
47
|
+
lb_type = lb.get("Type", "application") # application, network, gateway
|
|
48
|
+
|
|
49
|
+
# Get tags
|
|
50
|
+
tags = {}
|
|
51
|
+
try:
|
|
52
|
+
tag_response = elbv2_client.describe_tags(ResourceArns=[lb_arn])
|
|
53
|
+
for tag_desc in tag_response.get("TagDescriptions", []):
|
|
54
|
+
tags = {tag["Key"]: tag["Value"] for tag in tag_desc.get("Tags", [])}
|
|
55
|
+
except Exception as e:
|
|
56
|
+
self.logger.debug(f"Could not get tags for load balancer {lb_name}: {e}")
|
|
57
|
+
|
|
58
|
+
# Determine resource type
|
|
59
|
+
if lb_type == "application":
|
|
60
|
+
resource_type = "AWS::ElasticLoadBalancingV2::LoadBalancer::Application"
|
|
61
|
+
elif lb_type == "network":
|
|
62
|
+
resource_type = "AWS::ElasticLoadBalancingV2::LoadBalancer::Network"
|
|
63
|
+
elif lb_type == "gateway":
|
|
64
|
+
resource_type = "AWS::ElasticLoadBalancingV2::LoadBalancer::Gateway"
|
|
65
|
+
else:
|
|
66
|
+
resource_type = "AWS::ElasticLoadBalancingV2::LoadBalancer"
|
|
67
|
+
|
|
68
|
+
# Create resource
|
|
69
|
+
resource = Resource(
|
|
70
|
+
arn=lb_arn,
|
|
71
|
+
resource_type=resource_type,
|
|
72
|
+
name=lb_name,
|
|
73
|
+
region=self.region,
|
|
74
|
+
tags=tags,
|
|
75
|
+
config_hash=compute_config_hash(lb),
|
|
76
|
+
created_at=lb.get("CreatedTime"),
|
|
77
|
+
raw_config=lb,
|
|
78
|
+
)
|
|
79
|
+
resources.append(resource)
|
|
80
|
+
|
|
81
|
+
except Exception as e:
|
|
82
|
+
self.logger.error(f"Error collecting v2 load balancers in {self.region}: {e}")
|
|
83
|
+
|
|
84
|
+
return resources
|
|
85
|
+
|
|
86
|
+
def _collect_classic_load_balancers(self, account_id: str) -> List[Resource]:
|
|
87
|
+
"""Collect classic load balancers."""
|
|
88
|
+
resources = []
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
elb_client = self._create_client("elb")
|
|
92
|
+
|
|
93
|
+
paginator = elb_client.get_paginator("describe_load_balancers")
|
|
94
|
+
for page in paginator.paginate():
|
|
95
|
+
for lb in page.get("LoadBalancerDescriptions", []):
|
|
96
|
+
lb_name = lb["LoadBalancerName"]
|
|
97
|
+
|
|
98
|
+
# Build ARN (classic ELBs don't return ARN directly)
|
|
99
|
+
lb_arn = f"arn:aws:elasticloadbalancing:{self.region}:{account_id}:loadbalancer/{lb_name}"
|
|
100
|
+
|
|
101
|
+
# Get tags
|
|
102
|
+
tags = {}
|
|
103
|
+
try:
|
|
104
|
+
tag_response = elb_client.describe_tags(LoadBalancerNames=[lb_name])
|
|
105
|
+
for tag_desc in tag_response.get("TagDescriptions", []):
|
|
106
|
+
tags = {tag["Key"]: tag["Value"] for tag in tag_desc.get("Tags", [])}
|
|
107
|
+
except Exception as e:
|
|
108
|
+
self.logger.debug(f"Could not get tags for classic ELB {lb_name}: {e}")
|
|
109
|
+
|
|
110
|
+
# Create resource
|
|
111
|
+
resource = Resource(
|
|
112
|
+
arn=lb_arn,
|
|
113
|
+
resource_type="AWS::ElasticLoadBalancing::LoadBalancer",
|
|
114
|
+
name=lb_name,
|
|
115
|
+
region=self.region,
|
|
116
|
+
tags=tags,
|
|
117
|
+
config_hash=compute_config_hash(lb),
|
|
118
|
+
created_at=lb.get("CreatedTime"),
|
|
119
|
+
raw_config=lb,
|
|
120
|
+
)
|
|
121
|
+
resources.append(resource)
|
|
122
|
+
|
|
123
|
+
except Exception as e:
|
|
124
|
+
self.logger.error(f"Error collecting classic load balancers in {self.region}: {e}")
|
|
125
|
+
|
|
126
|
+
return resources
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"""EventBridge resource collector."""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from ...models.resource import Resource
|
|
6
|
+
from ...utils.hash import compute_config_hash
|
|
7
|
+
from .base import BaseResourceCollector
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EventBridgeCollector(BaseResourceCollector):
|
|
11
|
+
"""Collector for Amazon EventBridge resources (Event Buses, Rules)."""
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def service_name(self) -> str:
|
|
15
|
+
return "eventbridge"
|
|
16
|
+
|
|
17
|
+
def collect(self) -> List[Resource]:
|
|
18
|
+
"""Collect EventBridge resources.
|
|
19
|
+
|
|
20
|
+
Collects:
|
|
21
|
+
- Event Buses (custom and partner buses)
|
|
22
|
+
- Event Rules (across all buses)
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
List of EventBridge resources
|
|
26
|
+
"""
|
|
27
|
+
resources = []
|
|
28
|
+
|
|
29
|
+
# Collect Event Buses
|
|
30
|
+
resources.extend(self._collect_event_buses())
|
|
31
|
+
|
|
32
|
+
# Collect Event Rules (across all buses)
|
|
33
|
+
resources.extend(self._collect_event_rules())
|
|
34
|
+
|
|
35
|
+
self.logger.debug(f"Collected {len(resources)} EventBridge resources in {self.region}")
|
|
36
|
+
return resources
|
|
37
|
+
|
|
38
|
+
def _collect_event_buses(self) -> List[Resource]:
|
|
39
|
+
"""Collect EventBridge Event Buses.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
List of Event Bus resources
|
|
43
|
+
"""
|
|
44
|
+
resources = []
|
|
45
|
+
client = self._create_client("events")
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
paginator = client.get_paginator("list_event_buses")
|
|
49
|
+
for page in paginator.paginate():
|
|
50
|
+
for bus in page.get("EventBuses", []):
|
|
51
|
+
bus_name = bus["Name"]
|
|
52
|
+
bus_arn = bus["Arn"]
|
|
53
|
+
|
|
54
|
+
# Get tags
|
|
55
|
+
tags = {}
|
|
56
|
+
try:
|
|
57
|
+
tag_response = client.list_tags_for_resource(ResourceARN=bus_arn)
|
|
58
|
+
for tag in tag_response.get("Tags", []):
|
|
59
|
+
tags[tag["Key"]] = tag["Value"]
|
|
60
|
+
except Exception as e:
|
|
61
|
+
self.logger.debug(f"Could not get tags for event bus {bus_name}: {e}")
|
|
62
|
+
|
|
63
|
+
# Extract creation time (if available)
|
|
64
|
+
created_at = bus.get("CreationTime")
|
|
65
|
+
|
|
66
|
+
# Create resource
|
|
67
|
+
resource = Resource(
|
|
68
|
+
arn=bus_arn,
|
|
69
|
+
resource_type="AWS::Events::EventBus",
|
|
70
|
+
name=bus_name,
|
|
71
|
+
region=self.region,
|
|
72
|
+
tags=tags,
|
|
73
|
+
config_hash=compute_config_hash(bus),
|
|
74
|
+
created_at=created_at,
|
|
75
|
+
raw_config=bus,
|
|
76
|
+
)
|
|
77
|
+
resources.append(resource)
|
|
78
|
+
|
|
79
|
+
except Exception as e:
|
|
80
|
+
self.logger.error(f"Error collecting EventBridge event buses in {self.region}: {e}")
|
|
81
|
+
|
|
82
|
+
return resources
|
|
83
|
+
|
|
84
|
+
def _collect_event_rules(self) -> List[Resource]:
|
|
85
|
+
"""Collect EventBridge Rules across all event buses.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
List of Event Rule resources
|
|
89
|
+
"""
|
|
90
|
+
resources = []
|
|
91
|
+
client = self._create_client("events")
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
# First, get all event buses to collect rules from each
|
|
95
|
+
event_buses = ["default"] # Start with default bus
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
paginator = client.get_paginator("list_event_buses")
|
|
99
|
+
for page in paginator.paginate():
|
|
100
|
+
for bus in page.get("EventBuses", []):
|
|
101
|
+
bus_name = bus["Name"]
|
|
102
|
+
if bus_name != "default":
|
|
103
|
+
event_buses.append(bus_name)
|
|
104
|
+
except Exception as e:
|
|
105
|
+
self.logger.debug(f"Error listing event buses: {e}")
|
|
106
|
+
|
|
107
|
+
# Collect rules from each bus
|
|
108
|
+
for bus_name in event_buses:
|
|
109
|
+
try:
|
|
110
|
+
paginator = client.get_paginator("list_rules")
|
|
111
|
+
for page in paginator.paginate(EventBusName=bus_name):
|
|
112
|
+
for rule in page.get("Rules", []):
|
|
113
|
+
rule_name = rule["Name"]
|
|
114
|
+
rule_arn = rule["Arn"]
|
|
115
|
+
|
|
116
|
+
# Get tags
|
|
117
|
+
tags = {}
|
|
118
|
+
try:
|
|
119
|
+
tag_response = client.list_tags_for_resource(ResourceARN=rule_arn)
|
|
120
|
+
for tag in tag_response.get("Tags", []):
|
|
121
|
+
tags[tag["Key"]] = tag["Value"]
|
|
122
|
+
except Exception as e:
|
|
123
|
+
self.logger.debug(f"Could not get tags for rule {rule_name}: {e}")
|
|
124
|
+
|
|
125
|
+
# Get full rule details
|
|
126
|
+
try:
|
|
127
|
+
rule_details = client.describe_rule(Name=rule_name, EventBusName=bus_name)
|
|
128
|
+
# Merge with basic rule info
|
|
129
|
+
full_rule = {**rule, **rule_details}
|
|
130
|
+
except Exception as e:
|
|
131
|
+
self.logger.debug(f"Could not get details for rule {rule_name}: {e}")
|
|
132
|
+
full_rule = rule
|
|
133
|
+
|
|
134
|
+
# Extract creation time (not typically available for rules)
|
|
135
|
+
created_at = None
|
|
136
|
+
|
|
137
|
+
# Create resource
|
|
138
|
+
resource = Resource(
|
|
139
|
+
arn=rule_arn,
|
|
140
|
+
resource_type="AWS::Events::Rule",
|
|
141
|
+
name=rule_name,
|
|
142
|
+
region=self.region,
|
|
143
|
+
tags=tags,
|
|
144
|
+
config_hash=compute_config_hash(full_rule),
|
|
145
|
+
created_at=created_at,
|
|
146
|
+
raw_config=full_rule,
|
|
147
|
+
)
|
|
148
|
+
resources.append(resource)
|
|
149
|
+
|
|
150
|
+
except Exception as e:
|
|
151
|
+
self.logger.error(f"Error collecting rules from event bus {bus_name}: {e}")
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
self.logger.error(f"Error collecting EventBridge rules in {self.region}: {e}")
|
|
155
|
+
|
|
156
|
+
return resources
|