runbooks 1.1.4__py3-none-any.whl → 1.1.6__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.
Files changed (273) hide show
  1. runbooks/__init__.py +31 -2
  2. runbooks/__init___optimized.py +18 -4
  3. runbooks/_platform/__init__.py +1 -5
  4. runbooks/_platform/core/runbooks_wrapper.py +141 -138
  5. runbooks/aws2/accuracy_validator.py +812 -0
  6. runbooks/base.py +7 -0
  7. runbooks/cfat/assessment/compliance.py +1 -1
  8. runbooks/cfat/assessment/runner.py +1 -0
  9. runbooks/cfat/cloud_foundations_assessment.py +227 -239
  10. runbooks/cli/__init__.py +1 -1
  11. runbooks/cli/commands/cfat.py +64 -23
  12. runbooks/cli/commands/finops.py +1005 -54
  13. runbooks/cli/commands/inventory.py +135 -91
  14. runbooks/cli/commands/operate.py +9 -36
  15. runbooks/cli/commands/security.py +42 -18
  16. runbooks/cli/commands/validation.py +432 -18
  17. runbooks/cli/commands/vpc.py +81 -17
  18. runbooks/cli/registry.py +22 -10
  19. runbooks/cloudops/__init__.py +20 -27
  20. runbooks/cloudops/base.py +96 -107
  21. runbooks/cloudops/cost_optimizer.py +544 -542
  22. runbooks/cloudops/infrastructure_optimizer.py +5 -4
  23. runbooks/cloudops/interfaces.py +224 -225
  24. runbooks/cloudops/lifecycle_manager.py +5 -4
  25. runbooks/cloudops/mcp_cost_validation.py +252 -235
  26. runbooks/cloudops/models.py +78 -53
  27. runbooks/cloudops/monitoring_automation.py +5 -4
  28. runbooks/cloudops/notebook_framework.py +177 -213
  29. runbooks/cloudops/security_enforcer.py +125 -159
  30. runbooks/common/accuracy_validator.py +17 -12
  31. runbooks/common/aws_pricing.py +349 -326
  32. runbooks/common/aws_pricing_api.py +211 -212
  33. runbooks/common/aws_profile_manager.py +40 -36
  34. runbooks/common/aws_utils.py +74 -79
  35. runbooks/common/business_logic.py +126 -104
  36. runbooks/common/cli_decorators.py +36 -60
  37. runbooks/common/comprehensive_cost_explorer_integration.py +455 -463
  38. runbooks/common/cross_account_manager.py +197 -204
  39. runbooks/common/date_utils.py +27 -39
  40. runbooks/common/decorators.py +29 -19
  41. runbooks/common/dry_run_examples.py +173 -208
  42. runbooks/common/dry_run_framework.py +157 -155
  43. runbooks/common/enhanced_exception_handler.py +15 -4
  44. runbooks/common/enhanced_logging_example.py +50 -64
  45. runbooks/common/enhanced_logging_integration_example.py +65 -37
  46. runbooks/common/env_utils.py +16 -16
  47. runbooks/common/error_handling.py +40 -38
  48. runbooks/common/lazy_loader.py +41 -23
  49. runbooks/common/logging_integration_helper.py +79 -86
  50. runbooks/common/mcp_cost_explorer_integration.py +476 -493
  51. runbooks/common/mcp_integration.py +99 -79
  52. runbooks/common/memory_optimization.py +140 -118
  53. runbooks/common/module_cli_base.py +37 -58
  54. runbooks/common/organizations_client.py +175 -193
  55. runbooks/common/patterns.py +23 -25
  56. runbooks/common/performance_monitoring.py +67 -71
  57. runbooks/common/performance_optimization_engine.py +283 -274
  58. runbooks/common/profile_utils.py +111 -37
  59. runbooks/common/rich_utils.py +315 -141
  60. runbooks/common/sre_performance_suite.py +177 -186
  61. runbooks/enterprise/__init__.py +1 -1
  62. runbooks/enterprise/logging.py +144 -106
  63. runbooks/enterprise/security.py +187 -204
  64. runbooks/enterprise/validation.py +43 -56
  65. runbooks/finops/__init__.py +26 -30
  66. runbooks/finops/account_resolver.py +1 -1
  67. runbooks/finops/advanced_optimization_engine.py +980 -0
  68. runbooks/finops/automation_core.py +268 -231
  69. runbooks/finops/business_case_config.py +184 -179
  70. runbooks/finops/cli.py +660 -139
  71. runbooks/finops/commvault_ec2_analysis.py +157 -164
  72. runbooks/finops/compute_cost_optimizer.py +336 -320
  73. runbooks/finops/config.py +20 -20
  74. runbooks/finops/cost_optimizer.py +484 -618
  75. runbooks/finops/cost_processor.py +332 -214
  76. runbooks/finops/dashboard_runner.py +1006 -172
  77. runbooks/finops/ebs_cost_optimizer.py +991 -657
  78. runbooks/finops/elastic_ip_optimizer.py +317 -257
  79. runbooks/finops/enhanced_mcp_integration.py +340 -0
  80. runbooks/finops/enhanced_progress.py +32 -29
  81. runbooks/finops/enhanced_trend_visualization.py +3 -2
  82. runbooks/finops/enterprise_wrappers.py +223 -285
  83. runbooks/finops/executive_export.py +203 -160
  84. runbooks/finops/helpers.py +130 -288
  85. runbooks/finops/iam_guidance.py +1 -1
  86. runbooks/finops/infrastructure/__init__.py +80 -0
  87. runbooks/finops/infrastructure/commands.py +506 -0
  88. runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
  89. runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
  90. runbooks/finops/markdown_exporter.py +337 -174
  91. runbooks/finops/mcp_validator.py +1952 -0
  92. runbooks/finops/nat_gateway_optimizer.py +1512 -481
  93. runbooks/finops/network_cost_optimizer.py +657 -587
  94. runbooks/finops/notebook_utils.py +226 -188
  95. runbooks/finops/optimization_engine.py +1136 -0
  96. runbooks/finops/optimizer.py +19 -23
  97. runbooks/finops/rds_snapshot_optimizer.py +367 -411
  98. runbooks/finops/reservation_optimizer.py +427 -363
  99. runbooks/finops/scenario_cli_integration.py +64 -65
  100. runbooks/finops/scenarios.py +1277 -438
  101. runbooks/finops/schemas.py +218 -182
  102. runbooks/finops/snapshot_manager.py +2289 -0
  103. runbooks/finops/types.py +3 -3
  104. runbooks/finops/validation_framework.py +259 -265
  105. runbooks/finops/vpc_cleanup_exporter.py +189 -144
  106. runbooks/finops/vpc_cleanup_optimizer.py +591 -573
  107. runbooks/finops/workspaces_analyzer.py +171 -182
  108. runbooks/integration/__init__.py +89 -0
  109. runbooks/integration/mcp_integration.py +1920 -0
  110. runbooks/inventory/CLAUDE.md +816 -0
  111. runbooks/inventory/__init__.py +2 -2
  112. runbooks/inventory/aws_decorators.py +2 -3
  113. runbooks/inventory/check_cloudtrail_compliance.py +2 -4
  114. runbooks/inventory/check_controltower_readiness.py +152 -151
  115. runbooks/inventory/check_landingzone_readiness.py +85 -84
  116. runbooks/inventory/cloud_foundations_integration.py +144 -149
  117. runbooks/inventory/collectors/aws_comprehensive.py +1 -1
  118. runbooks/inventory/collectors/aws_networking.py +109 -99
  119. runbooks/inventory/collectors/base.py +4 -0
  120. runbooks/inventory/core/collector.py +495 -313
  121. runbooks/inventory/core/formatter.py +11 -0
  122. runbooks/inventory/draw_org_structure.py +8 -9
  123. runbooks/inventory/drift_detection_cli.py +69 -96
  124. runbooks/inventory/ec2_vpc_utils.py +2 -2
  125. runbooks/inventory/find_cfn_drift_detection.py +5 -7
  126. runbooks/inventory/find_cfn_orphaned_stacks.py +7 -9
  127. runbooks/inventory/find_cfn_stackset_drift.py +5 -6
  128. runbooks/inventory/find_ec2_security_groups.py +48 -42
  129. runbooks/inventory/find_landingzone_versions.py +4 -6
  130. runbooks/inventory/find_vpc_flow_logs.py +7 -9
  131. runbooks/inventory/inventory_mcp_cli.py +48 -46
  132. runbooks/inventory/inventory_modules.py +103 -91
  133. runbooks/inventory/list_cfn_stacks.py +9 -10
  134. runbooks/inventory/list_cfn_stackset_operation_results.py +1 -3
  135. runbooks/inventory/list_cfn_stackset_operations.py +79 -57
  136. runbooks/inventory/list_cfn_stacksets.py +8 -10
  137. runbooks/inventory/list_config_recorders_delivery_channels.py +49 -39
  138. runbooks/inventory/list_ds_directories.py +65 -53
  139. runbooks/inventory/list_ec2_availability_zones.py +2 -4
  140. runbooks/inventory/list_ec2_ebs_volumes.py +32 -35
  141. runbooks/inventory/list_ec2_instances.py +23 -28
  142. runbooks/inventory/list_ecs_clusters_and_tasks.py +26 -34
  143. runbooks/inventory/list_elbs_load_balancers.py +22 -20
  144. runbooks/inventory/list_enis_network_interfaces.py +26 -33
  145. runbooks/inventory/list_guardduty_detectors.py +2 -4
  146. runbooks/inventory/list_iam_policies.py +2 -4
  147. runbooks/inventory/list_iam_roles.py +5 -7
  148. runbooks/inventory/list_iam_saml_providers.py +4 -6
  149. runbooks/inventory/list_lambda_functions.py +38 -38
  150. runbooks/inventory/list_org_accounts.py +6 -8
  151. runbooks/inventory/list_org_accounts_users.py +55 -44
  152. runbooks/inventory/list_rds_db_instances.py +31 -33
  153. runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
  154. runbooks/inventory/list_route53_hosted_zones.py +3 -5
  155. runbooks/inventory/list_servicecatalog_provisioned_products.py +37 -41
  156. runbooks/inventory/list_sns_topics.py +2 -4
  157. runbooks/inventory/list_ssm_parameters.py +4 -7
  158. runbooks/inventory/list_vpc_subnets.py +2 -4
  159. runbooks/inventory/list_vpcs.py +7 -10
  160. runbooks/inventory/mcp_inventory_validator.py +554 -468
  161. runbooks/inventory/mcp_vpc_validator.py +359 -442
  162. runbooks/inventory/organizations_discovery.py +63 -55
  163. runbooks/inventory/recover_cfn_stack_ids.py +7 -8
  164. runbooks/inventory/requirements.txt +0 -1
  165. runbooks/inventory/rich_inventory_display.py +35 -34
  166. runbooks/inventory/run_on_multi_accounts.py +3 -5
  167. runbooks/inventory/unified_validation_engine.py +281 -253
  168. runbooks/inventory/verify_ec2_security_groups.py +1 -1
  169. runbooks/inventory/vpc_analyzer.py +735 -697
  170. runbooks/inventory/vpc_architecture_validator.py +293 -348
  171. runbooks/inventory/vpc_dependency_analyzer.py +384 -380
  172. runbooks/inventory/vpc_flow_analyzer.py +1 -1
  173. runbooks/main.py +49 -34
  174. runbooks/main_final.py +91 -60
  175. runbooks/main_minimal.py +22 -10
  176. runbooks/main_optimized.py +131 -100
  177. runbooks/main_ultra_minimal.py +7 -2
  178. runbooks/mcp/__init__.py +36 -0
  179. runbooks/mcp/integration.py +679 -0
  180. runbooks/monitoring/performance_monitor.py +9 -4
  181. runbooks/operate/dynamodb_operations.py +3 -1
  182. runbooks/operate/ec2_operations.py +145 -137
  183. runbooks/operate/iam_operations.py +146 -152
  184. runbooks/operate/networking_cost_heatmap.py +29 -8
  185. runbooks/operate/rds_operations.py +223 -254
  186. runbooks/operate/s3_operations.py +107 -118
  187. runbooks/operate/vpc_operations.py +646 -616
  188. runbooks/remediation/base.py +1 -1
  189. runbooks/remediation/commons.py +10 -7
  190. runbooks/remediation/commvault_ec2_analysis.py +70 -66
  191. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
  192. runbooks/remediation/multi_account.py +24 -21
  193. runbooks/remediation/rds_snapshot_list.py +86 -60
  194. runbooks/remediation/remediation_cli.py +92 -146
  195. runbooks/remediation/universal_account_discovery.py +83 -79
  196. runbooks/remediation/workspaces_list.py +46 -41
  197. runbooks/security/__init__.py +19 -0
  198. runbooks/security/assessment_runner.py +1150 -0
  199. runbooks/security/baseline_checker.py +812 -0
  200. runbooks/security/cloudops_automation_security_validator.py +509 -535
  201. runbooks/security/compliance_automation_engine.py +17 -17
  202. runbooks/security/config/__init__.py +2 -2
  203. runbooks/security/config/compliance_config.py +50 -50
  204. runbooks/security/config_template_generator.py +63 -76
  205. runbooks/security/enterprise_security_framework.py +1 -1
  206. runbooks/security/executive_security_dashboard.py +519 -508
  207. runbooks/security/multi_account_security_controls.py +959 -1210
  208. runbooks/security/real_time_security_monitor.py +422 -444
  209. runbooks/security/security_baseline_tester.py +1 -1
  210. runbooks/security/security_cli.py +143 -112
  211. runbooks/security/test_2way_validation.py +439 -0
  212. runbooks/security/two_way_validation_framework.py +852 -0
  213. runbooks/sre/production_monitoring_framework.py +167 -177
  214. runbooks/tdd/__init__.py +15 -0
  215. runbooks/tdd/cli.py +1071 -0
  216. runbooks/utils/__init__.py +14 -17
  217. runbooks/utils/logger.py +7 -2
  218. runbooks/utils/version_validator.py +50 -47
  219. runbooks/validation/__init__.py +6 -6
  220. runbooks/validation/cli.py +9 -3
  221. runbooks/validation/comprehensive_2way_validator.py +745 -704
  222. runbooks/validation/mcp_validator.py +906 -228
  223. runbooks/validation/terraform_citations_validator.py +104 -115
  224. runbooks/validation/terraform_drift_detector.py +461 -454
  225. runbooks/vpc/README.md +617 -0
  226. runbooks/vpc/__init__.py +8 -1
  227. runbooks/vpc/analyzer.py +577 -0
  228. runbooks/vpc/cleanup_wrapper.py +476 -413
  229. runbooks/vpc/cli_cloudtrail_commands.py +339 -0
  230. runbooks/vpc/cli_mcp_validation_commands.py +480 -0
  231. runbooks/vpc/cloudtrail_audit_integration.py +717 -0
  232. runbooks/vpc/config.py +92 -97
  233. runbooks/vpc/cost_engine.py +411 -148
  234. runbooks/vpc/cost_explorer_integration.py +553 -0
  235. runbooks/vpc/cross_account_session.py +101 -106
  236. runbooks/vpc/enhanced_mcp_validation.py +917 -0
  237. runbooks/vpc/eni_gate_validator.py +961 -0
  238. runbooks/vpc/heatmap_engine.py +185 -160
  239. runbooks/vpc/mcp_no_eni_validator.py +680 -639
  240. runbooks/vpc/nat_gateway_optimizer.py +358 -0
  241. runbooks/vpc/networking_wrapper.py +15 -8
  242. runbooks/vpc/pdca_remediation_planner.py +528 -0
  243. runbooks/vpc/performance_optimized_analyzer.py +219 -231
  244. runbooks/vpc/runbooks_adapter.py +1167 -241
  245. runbooks/vpc/tdd_red_phase_stubs.py +601 -0
  246. runbooks/vpc/test_data_loader.py +358 -0
  247. runbooks/vpc/tests/conftest.py +314 -4
  248. runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
  249. runbooks/vpc/tests/test_cost_engine.py +0 -2
  250. runbooks/vpc/topology_generator.py +326 -0
  251. runbooks/vpc/unified_scenarios.py +1297 -1124
  252. runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
  253. runbooks-1.1.6.dist-info/METADATA +327 -0
  254. runbooks-1.1.6.dist-info/RECORD +489 -0
  255. runbooks/finops/README.md +0 -414
  256. runbooks/finops/accuracy_cross_validator.py +0 -647
  257. runbooks/finops/business_cases.py +0 -950
  258. runbooks/finops/dashboard_router.py +0 -922
  259. runbooks/finops/ebs_optimizer.py +0 -973
  260. runbooks/finops/embedded_mcp_validator.py +0 -1629
  261. runbooks/finops/enhanced_dashboard_runner.py +0 -527
  262. runbooks/finops/finops_dashboard.py +0 -584
  263. runbooks/finops/finops_scenarios.py +0 -1218
  264. runbooks/finops/legacy_migration.py +0 -730
  265. runbooks/finops/multi_dashboard.py +0 -1519
  266. runbooks/finops/single_dashboard.py +0 -1113
  267. runbooks/finops/unlimited_scenarios.py +0 -393
  268. runbooks-1.1.4.dist-info/METADATA +0 -800
  269. runbooks-1.1.4.dist-info/RECORD +0 -468
  270. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/WHEEL +0 -0
  271. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/entry_points.txt +0 -0
  272. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/licenses/LICENSE +0 -0
  273. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/top_level.txt +0 -0
@@ -1,527 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Enhanced FinOps Dashboard Runner
4
-
5
- This module provides enterprise-grade FinOps dashboard capabilities including:
6
- - Multi-profile AWS cost analysis with Rich console formatting
7
- - Advanced audit reporting with PDF/CSV/JSON export
8
- - Resource utilization tracking and optimization recommendations
9
- - Budget monitoring and alerting integration
10
- - Trend analysis and forecasting capabilities
11
- """
12
-
13
- import argparse
14
- import csv
15
- import json
16
- from collections import defaultdict
17
- from datetime import datetime, timedelta
18
- from pathlib import Path
19
- from typing import Any, Dict, List, Optional, Tuple, Union
20
-
21
- import boto3
22
- from rich import box
23
- from rich.console import Console
24
- from rich.panel import Panel
25
- from rich.progress import Progress, SpinnerColumn, TextColumn, track
26
- from rich.status import Status
27
- from rich.table import Column, Table
28
- from rich.tree import Tree
29
-
30
- from ..common.rich_utils import get_console
31
-
32
- # Import FinOpsConfig for backward compatibility with tests
33
- from .finops_dashboard import FinOpsConfig
34
-
35
- console = Console()
36
-
37
-
38
- class EnhancedFinOpsDashboard:
39
- """Enhanced FinOps Dashboard with production-tested capabilities from runbooks finops"""
40
-
41
- def __init__(self, config: Optional[Dict[str, Any]] = None):
42
- self.config = config or {}
43
- self.console = Console()
44
- self.rich_console = self.console # Use the console instance directly
45
-
46
- # Export directory setup
47
- self.export_dir = Path("artifacts/finops-exports")
48
- self.export_dir.mkdir(parents=True, exist_ok=True)
49
-
50
- def get_aws_profiles(self) -> List[str]:
51
- """Get available AWS profiles from AWS CLI configuration"""
52
- try:
53
- import configparser
54
- import os
55
-
56
- aws_config_path = os.path.expanduser("~/.aws/config")
57
- aws_credentials_path = os.path.expanduser("~/.aws/credentials")
58
-
59
- profiles = set()
60
-
61
- # Parse AWS config file
62
- if os.path.exists(aws_config_path):
63
- config = configparser.ConfigParser()
64
- config.read(aws_config_path)
65
- for section in config.sections():
66
- if section.startswith("profile "):
67
- profiles.add(section.replace("profile ", ""))
68
- elif section == "default":
69
- profiles.add("default")
70
-
71
- # Parse AWS credentials file
72
- if os.path.exists(aws_credentials_path):
73
- credentials = configparser.ConfigParser()
74
- credentials.read(aws_credentials_path)
75
- profiles.update(credentials.sections())
76
-
77
- return sorted(list(profiles))
78
-
79
- except Exception as e:
80
- console.print(f"āš ļø Error reading AWS profiles: {e}", style="yellow")
81
- return []
82
-
83
- def get_account_info(self, profile: str) -> Dict[str, Any]:
84
- """Get AWS account information for a profile"""
85
- try:
86
- session = boto3.Session(profile_name=profile)
87
- sts = session.client("sts")
88
-
89
- identity = sts.get_caller_identity()
90
-
91
- return {
92
- "account_id": identity["Account"],
93
- "user_arn": identity["Arn"],
94
- "user_id": identity["UserId"],
95
- "profile": profile,
96
- "status": "active",
97
- }
98
-
99
- except Exception as e:
100
- return {"account_id": "N/A", "profile": profile, "status": "error", "error": str(e)}
101
-
102
- def get_resource_audit_data(self, profile: str, regions: Optional[List[str]] = None) -> Dict[str, Any]:
103
- """
104
- Get comprehensive resource audit data for a profile
105
-
106
- Enhanced with additional resource types and cost impact analysis
107
- """
108
- audit_data = {
109
- "profile": profile,
110
- "account_info": self.get_account_info(profile),
111
- "untagged_resources": 0,
112
- "stopped_instances": 0,
113
- "unused_volumes": 0,
114
- "unused_eips": 0,
115
- "budget_alerts": 0,
116
- "cost_optimization_opportunities": [],
117
- "regional_breakdown": {},
118
- "total_potential_savings": 0.0,
119
- }
120
-
121
- if audit_data["account_info"]["status"] == "error":
122
- return audit_data
123
-
124
- try:
125
- session = boto3.Session(profile_name=profile)
126
-
127
- # Default to common regions if none specified
128
- if not regions:
129
- regions = ["us-east-1", "us-west-2", "eu-west-1"]
130
-
131
- for region in regions:
132
- region_data = self._audit_region_resources(session, region)
133
- audit_data["regional_breakdown"][region] = region_data
134
-
135
- # Aggregate data
136
- audit_data["untagged_resources"] += region_data["untagged_resources"]
137
- audit_data["stopped_instances"] += region_data["stopped_instances"]
138
- audit_data["unused_volumes"] += region_data["unused_volumes"]
139
- audit_data["unused_eips"] += region_data["unused_eips"]
140
- audit_data["total_potential_savings"] += region_data["potential_savings"]
141
- audit_data["cost_optimization_opportunities"].extend(region_data["optimization_opportunities"])
142
-
143
- # Get budget information
144
- audit_data["budget_alerts"] = self._get_budget_alerts(session)
145
-
146
- except Exception as e:
147
- console.print(f"āš ļø Error auditing resources for {profile}: {e}", style="yellow")
148
-
149
- return audit_data
150
-
151
- def _audit_region_resources(self, session: boto3.Session, region: str) -> Dict[str, Any]:
152
- """Audit resources in a specific region"""
153
- region_data = {
154
- "region": region,
155
- "untagged_resources": 0,
156
- "stopped_instances": 0,
157
- "unused_volumes": 0,
158
- "unused_eips": 0,
159
- "potential_savings": 0.0,
160
- "optimization_opportunities": [],
161
- }
162
-
163
- try:
164
- ec2 = session.client("ec2", region_name=region)
165
-
166
- # Get stopped EC2 instances
167
- instances_response = ec2.describe_instances(
168
- Filters=[{"Name": "instance-state-name", "Values": ["stopped"]}]
169
- )
170
-
171
- stopped_instances = []
172
- for reservation in instances_response["Reservations"]:
173
- for instance in reservation["Instances"]:
174
- stopped_instances.append(
175
- {
176
- "instance_id": instance["InstanceId"],
177
- "instance_type": instance["InstanceType"],
178
- "launch_time": instance.get("LaunchTime"),
179
- "tags": instance.get("Tags", []),
180
- }
181
- )
182
-
183
- region_data["stopped_instances"] = len(stopped_instances)
184
-
185
- # Calculate potential savings from stopped instances (rough estimate)
186
- # Assume average $50/month per stopped instance in savings opportunity
187
- region_data["potential_savings"] += len(stopped_instances) * 50.0
188
-
189
- if stopped_instances:
190
- region_data["optimization_opportunities"].append(
191
- {
192
- "type": "stopped_instances",
193
- "count": len(stopped_instances),
194
- "description": f"{len(stopped_instances)} stopped EC2 instances - consider termination",
195
- "potential_savings": len(stopped_instances) * 50.0,
196
- "priority": "high",
197
- }
198
- )
199
-
200
- # Get unused EBS volumes
201
- volumes_response = ec2.describe_volumes(Filters=[{"Name": "status", "Values": ["available"]}])
202
-
203
- unused_volumes = volumes_response["Volumes"]
204
- region_data["unused_volumes"] = len(unused_volumes)
205
-
206
- # Note: EBS cost calculation requires real AWS Cost Explorer pricing data
207
- # Hardcoded pricing estimates removed per compliance requirements
208
- volume_savings = 0 # Cannot calculate without real AWS pricing API
209
- region_data["potential_savings"] += volume_savings
210
-
211
- if unused_volumes:
212
- region_data["optimization_opportunities"].append(
213
- {
214
- "type": "unused_volumes",
215
- "count": len(unused_volumes),
216
- "description": f"{len(unused_volumes)} unused EBS volumes",
217
- "potential_savings": volume_savings,
218
- "priority": "medium",
219
- }
220
- )
221
-
222
- # Get unused Elastic IPs
223
- eips_response = ec2.describe_addresses()
224
- unused_eips = [eip for eip in eips_response["Addresses"] if "InstanceId" not in eip]
225
- region_data["unused_eips"] = len(unused_eips)
226
-
227
- # Unused EIP cost: $3.65/month each
228
- eip_savings = len(unused_eips) * 3.65
229
- region_data["potential_savings"] += eip_savings
230
-
231
- if unused_eips:
232
- region_data["optimization_opportunities"].append(
233
- {
234
- "type": "unused_eips",
235
- "count": len(unused_eips),
236
- "description": f"{len(unused_eips)} unused Elastic IPs",
237
- "potential_savings": eip_savings,
238
- "priority": "high",
239
- }
240
- )
241
-
242
- # Count untagged resources (simplified check)
243
- untagged_count = 0
244
- for instance in stopped_instances:
245
- if not instance["tags"]:
246
- untagged_count += 1
247
- for volume in unused_volumes:
248
- if not volume.get("Tags"):
249
- untagged_count += 1
250
-
251
- region_data["untagged_resources"] = untagged_count
252
-
253
- except Exception as e:
254
- console.print(f"āš ļø Error auditing {region}: {e}", style="yellow")
255
-
256
- return region_data
257
-
258
- def _get_budget_alerts(self, session: boto3.Session) -> int:
259
- """Get budget alert count"""
260
- try:
261
- budgets = session.client("budgets")
262
-
263
- # Get account ID for budgets API
264
- sts = session.client("sts")
265
- account_id = sts.get_caller_identity()["Account"]
266
-
267
- response = budgets.describe_budgets(AccountId=account_id)
268
- return len(response.get("Budgets", []))
269
-
270
- except Exception:
271
- return 0 # Budgets API might not be accessible
272
-
273
- def generate_audit_report(
274
- self, profiles: Optional[List[str]] = None, regions: Optional[List[str]] = None
275
- ) -> Dict[str, Any]:
276
- """Generate comprehensive audit report for specified profiles"""
277
-
278
- if not profiles:
279
- profiles = self.get_aws_profiles()
280
- if not profiles:
281
- console.print("āŒ No AWS profiles found", style="red")
282
- return {}
283
-
284
- audit_results = {
285
- "report_metadata": {
286
- "generated_at": datetime.now().isoformat(),
287
- "profiles_analyzed": len(profiles),
288
- "regions_analyzed": len(regions) if regions else 3,
289
- "report_type": "comprehensive_audit",
290
- },
291
- "profile_data": {},
292
- "summary": {
293
- "total_untagged_resources": 0,
294
- "total_stopped_instances": 0,
295
- "total_unused_volumes": 0,
296
- "total_unused_eips": 0,
297
- "total_budget_alerts": 0,
298
- "total_potential_savings": 0.0,
299
- "optimization_opportunities": [],
300
- },
301
- }
302
-
303
- with Progress(
304
- SpinnerColumn(), TextColumn("[progress.description]{task.description}"), console=console
305
- ) as progress:
306
- for profile in profiles:
307
- task = progress.add_task(f"Auditing profile {profile}...", total=None)
308
-
309
- profile_data = self.get_resource_audit_data(profile, regions)
310
- audit_results["profile_data"][profile] = profile_data
311
-
312
- # Aggregate summary data
313
- summary = audit_results["summary"]
314
- summary["total_untagged_resources"] += profile_data["untagged_resources"]
315
- summary["total_stopped_instances"] += profile_data["stopped_instances"]
316
- summary["total_unused_volumes"] += profile_data["unused_volumes"]
317
- summary["total_unused_eips"] += profile_data["unused_eips"]
318
- summary["total_budget_alerts"] += profile_data["budget_alerts"]
319
- summary["total_potential_savings"] += profile_data["total_potential_savings"]
320
- summary["optimization_opportunities"].extend(profile_data["cost_optimization_opportunities"])
321
-
322
- progress.remove_task(task)
323
-
324
- return audit_results
325
-
326
- def display_audit_report(self, audit_results: Dict[str, Any]):
327
- """Display audit report with enhanced Rich formatting"""
328
-
329
- summary = audit_results["summary"]
330
- profile_data = audit_results["profile_data"]
331
-
332
- # Report header
333
- header_panel = Panel.fit(
334
- f"[bold bright_cyan]šŸ¢ AWS FinOps Comprehensive Audit Report[/bold bright_cyan]\n\n"
335
- f"šŸ“Š Profiles Analyzed: [yellow]{len(profile_data)}[/yellow]\n"
336
- f"šŸ•’ Generated: [green]{audit_results['report_metadata']['generated_at'][:19]}[/green]\n"
337
- f"šŸ’° Total Savings Potential: [bold green]${summary['total_potential_savings']:.2f}/month[/bold green]",
338
- title="Audit Report",
339
- style="bright_cyan",
340
- )
341
- console.print(header_panel)
342
-
343
- # Summary table
344
- summary_table = Table(title="šŸ“ˆ Executive Summary", box=box.ASCII_DOUBLE_HEAD, style="bright_cyan")
345
- summary_table.add_column("Metric", style="cyan", width=25)
346
- summary_table.add_column("Count", style="yellow", width=10)
347
- summary_table.add_column("Impact", style="green", width=20)
348
-
349
- summary_table.add_row("Untagged Resources", str(summary["total_untagged_resources"]), "Compliance Risk")
350
- summary_table.add_row(
351
- "Stopped Instances",
352
- str(summary["total_stopped_instances"]),
353
- f"${summary['total_stopped_instances'] * 50:.0f}/month potential",
354
- )
355
- summary_table.add_row("Unused Volumes", str(summary["total_unused_volumes"]), "Storage waste")
356
- summary_table.add_row(
357
- "Unused EIPs", str(summary["total_unused_eips"]), f"${summary['total_unused_eips'] * 3.65:.0f}/month waste"
358
- )
359
- summary_table.add_row("Budget Alerts", str(summary["total_budget_alerts"]), "Monitoring coverage")
360
-
361
- console.print(summary_table)
362
-
363
- # Profile-specific table
364
- profile_table = Table(
365
- title="šŸ‘„ Profile-Specific Analysis", show_lines=True, box=box.ASCII_DOUBLE_HEAD, style="bright_cyan"
366
- )
367
-
368
- profile_table.add_column("Profile", justify="center", width=20)
369
- profile_table.add_column("Account ID", justify="center", width=15)
370
- profile_table.add_column("Untagged", width=10)
371
- profile_table.add_column("Stopped EC2", width=12)
372
- profile_table.add_column("Unused Vol", width=12)
373
- profile_table.add_column("Unused EIP", width=12)
374
- profile_table.add_column("Savings", width=12)
375
-
376
- for profile, data in profile_data.items():
377
- account_info = data["account_info"]
378
- profile_table.add_row(
379
- profile,
380
- account_info["account_id"] if account_info["status"] == "active" else "ERROR",
381
- str(data["untagged_resources"]),
382
- str(data["stopped_instances"]),
383
- str(data["unused_volumes"]),
384
- str(data["unused_eips"]),
385
- f"${data['total_potential_savings']:.0f}",
386
- )
387
-
388
- console.print(profile_table)
389
-
390
- # Top optimization opportunities
391
- if summary["optimization_opportunities"]:
392
- console.print("\n[bold blue]šŸŽÆ Top Optimization Opportunities[/bold blue]")
393
-
394
- # Sort by potential savings
395
- sorted_opportunities = sorted(
396
- summary["optimization_opportunities"], key=lambda x: x.get("potential_savings", 0), reverse=True
397
- )
398
-
399
- for i, opp in enumerate(sorted_opportunities[:10], 1): # Top 10
400
- priority_color = {"high": "red", "medium": "yellow", "low": "green"}
401
- color = priority_color.get(opp.get("priority", "low"), "white")
402
-
403
- console.print(
404
- f"{i:2d}. [bold {color}]{opp['description']}[/bold {color}] "
405
- f"([green]${opp.get('potential_savings', 0):.0f}/month[/green])"
406
- )
407
-
408
- def export_audit_report(
409
- self, audit_results: Dict[str, Any], formats: List[str] = ["json", "csv"]
410
- ) -> Dict[str, str]:
411
- """Export audit report in multiple formats"""
412
-
413
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
414
- export_files = {}
415
-
416
- # JSON export
417
- if "json" in formats:
418
- json_file = self.export_dir / f"finops_audit_report_{timestamp}.json"
419
- with open(json_file, "w") as f:
420
- json.dump(audit_results, f, indent=2, default=str)
421
- export_files["json"] = str(json_file)
422
-
423
- # CSV export
424
- if "csv" in formats:
425
- csv_file = self.export_dir / f"finops_audit_summary_{timestamp}.csv"
426
- with open(csv_file, "w", newline="") as f:
427
- writer = csv.writer(f)
428
-
429
- # Header
430
- writer.writerow(
431
- [
432
- "Profile",
433
- "Account_ID",
434
- "Untagged_Resources",
435
- "Stopped_Instances",
436
- "Unused_Volumes",
437
- "Unused_EIPs",
438
- "Budget_Alerts",
439
- "Potential_Savings_Monthly",
440
- ]
441
- )
442
-
443
- # Data rows
444
- for profile, data in audit_results["profile_data"].items():
445
- writer.writerow(
446
- [
447
- profile,
448
- data["account_info"]["account_id"],
449
- data["untagged_resources"],
450
- data["stopped_instances"],
451
- data["unused_volumes"],
452
- data["unused_eips"],
453
- data["budget_alerts"],
454
- f"${data['total_potential_savings']:.2f}",
455
- ]
456
- )
457
-
458
- export_files["csv"] = str(csv_file)
459
-
460
- return export_files
461
-
462
- def run_comprehensive_audit(
463
- self,
464
- profiles: Optional[List[str]] = None,
465
- regions: Optional[List[str]] = None,
466
- export_formats: List[str] = ["json", "csv"],
467
- display_report: bool = True,
468
- ) -> Dict[str, Any]:
469
- """Run comprehensive FinOps audit with reporting and export"""
470
-
471
- console.print("[bold bright_cyan]šŸš€ Starting Enhanced FinOps Audit...[/bold bright_cyan]")
472
-
473
- # Generate audit data
474
- audit_results = self.generate_audit_report(profiles, regions)
475
-
476
- if not audit_results:
477
- console.print("āŒ No audit data generated", style="red")
478
- return {}
479
-
480
- # Display report
481
- if display_report:
482
- self.display_audit_report(audit_results)
483
-
484
- # Export results
485
- if export_formats:
486
- console.print(f"\nšŸ“„ Exporting report in formats: {', '.join(export_formats)}")
487
- export_files = self.export_audit_report(audit_results, export_formats)
488
-
489
- console.print("āœ… Export completed:")
490
- for format_type, file_path in export_files.items():
491
- console.print(f" šŸ“ {format_type.upper()}: {file_path}")
492
-
493
- # Summary of potential savings
494
- total_savings = audit_results["summary"]["total_potential_savings"]
495
- if total_savings > 0:
496
- annual_savings = total_savings * 12
497
- console.print(f"\nšŸ’° [bold green]Total Optimization Potential:[/bold green]")
498
- console.print(f" Monthly: [yellow]${total_savings:.2f}[/yellow]")
499
- console.print(f" Annual: [green]${annual_savings:.2f}[/green]")
500
-
501
- return audit_results
502
-
503
-
504
- # CLI integration functions
505
- def enhanced_audit_cli(
506
- profiles: Optional[str] = None,
507
- regions: Optional[str] = None,
508
- export_formats: str = "json,csv",
509
- output_dir: Optional[str] = None,
510
- ) -> None:
511
- """CLI command for enhanced FinOps audit"""
512
-
513
- profile_list = profiles.split(",") if profiles else None
514
- region_list = regions.split(",") if regions else None
515
- format_list = export_formats.split(",") if export_formats else ["json"]
516
-
517
- dashboard = EnhancedFinOpsDashboard()
518
-
519
- if output_dir:
520
- dashboard.export_dir = Path(output_dir)
521
- dashboard.export_dir.mkdir(parents=True, exist_ok=True)
522
-
523
- audit_results = dashboard.run_comprehensive_audit(
524
- profiles=profile_list, regions=region_list, export_formats=format_list, display_report=True
525
- )
526
-
527
- return audit_results