runbooks 1.1.3__py3-none-any.whl → 1.1.5__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 (247) 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/WEIGHT_CONFIG_README.md +1 -1
  8. runbooks/cfat/assessment/compliance.py +8 -8
  9. runbooks/cfat/assessment/runner.py +1 -0
  10. runbooks/cfat/cloud_foundations_assessment.py +227 -239
  11. runbooks/cfat/models.py +6 -2
  12. runbooks/cfat/tests/__init__.py +6 -1
  13. runbooks/cli/__init__.py +13 -0
  14. runbooks/cli/commands/cfat.py +274 -0
  15. runbooks/cli/commands/finops.py +1164 -0
  16. runbooks/cli/commands/inventory.py +379 -0
  17. runbooks/cli/commands/operate.py +239 -0
  18. runbooks/cli/commands/security.py +248 -0
  19. runbooks/cli/commands/validation.py +825 -0
  20. runbooks/cli/commands/vpc.py +310 -0
  21. runbooks/cli/registry.py +107 -0
  22. runbooks/cloudops/__init__.py +23 -30
  23. runbooks/cloudops/base.py +96 -107
  24. runbooks/cloudops/cost_optimizer.py +549 -547
  25. runbooks/cloudops/infrastructure_optimizer.py +5 -4
  26. runbooks/cloudops/interfaces.py +226 -227
  27. runbooks/cloudops/lifecycle_manager.py +5 -4
  28. runbooks/cloudops/mcp_cost_validation.py +252 -235
  29. runbooks/cloudops/models.py +78 -53
  30. runbooks/cloudops/monitoring_automation.py +5 -4
  31. runbooks/cloudops/notebook_framework.py +179 -215
  32. runbooks/cloudops/security_enforcer.py +125 -159
  33. runbooks/common/accuracy_validator.py +11 -0
  34. runbooks/common/aws_pricing.py +349 -326
  35. runbooks/common/aws_pricing_api.py +211 -212
  36. runbooks/common/aws_profile_manager.py +341 -0
  37. runbooks/common/aws_utils.py +75 -80
  38. runbooks/common/business_logic.py +127 -105
  39. runbooks/common/cli_decorators.py +36 -60
  40. runbooks/common/comprehensive_cost_explorer_integration.py +456 -464
  41. runbooks/common/cross_account_manager.py +198 -205
  42. runbooks/common/date_utils.py +27 -39
  43. runbooks/common/decorators.py +235 -0
  44. runbooks/common/dry_run_examples.py +173 -208
  45. runbooks/common/dry_run_framework.py +157 -155
  46. runbooks/common/enhanced_exception_handler.py +15 -4
  47. runbooks/common/enhanced_logging_example.py +50 -64
  48. runbooks/common/enhanced_logging_integration_example.py +65 -37
  49. runbooks/common/env_utils.py +16 -16
  50. runbooks/common/error_handling.py +40 -38
  51. runbooks/common/lazy_loader.py +41 -23
  52. runbooks/common/logging_integration_helper.py +79 -86
  53. runbooks/common/mcp_cost_explorer_integration.py +478 -495
  54. runbooks/common/mcp_integration.py +63 -74
  55. runbooks/common/memory_optimization.py +140 -118
  56. runbooks/common/module_cli_base.py +37 -58
  57. runbooks/common/organizations_client.py +176 -194
  58. runbooks/common/patterns.py +204 -0
  59. runbooks/common/performance_monitoring.py +67 -71
  60. runbooks/common/performance_optimization_engine.py +283 -274
  61. runbooks/common/profile_utils.py +248 -39
  62. runbooks/common/rich_utils.py +643 -92
  63. runbooks/common/sre_performance_suite.py +177 -186
  64. runbooks/enterprise/__init__.py +1 -1
  65. runbooks/enterprise/logging.py +144 -106
  66. runbooks/enterprise/security.py +187 -204
  67. runbooks/enterprise/validation.py +43 -56
  68. runbooks/finops/__init__.py +29 -33
  69. runbooks/finops/account_resolver.py +1 -1
  70. runbooks/finops/advanced_optimization_engine.py +980 -0
  71. runbooks/finops/automation_core.py +268 -231
  72. runbooks/finops/business_case_config.py +184 -179
  73. runbooks/finops/cli.py +660 -139
  74. runbooks/finops/commvault_ec2_analysis.py +157 -164
  75. runbooks/finops/compute_cost_optimizer.py +336 -320
  76. runbooks/finops/config.py +20 -20
  77. runbooks/finops/cost_optimizer.py +488 -622
  78. runbooks/finops/cost_processor.py +332 -214
  79. runbooks/finops/dashboard_runner.py +1006 -172
  80. runbooks/finops/ebs_cost_optimizer.py +991 -657
  81. runbooks/finops/elastic_ip_optimizer.py +317 -257
  82. runbooks/finops/enhanced_mcp_integration.py +340 -0
  83. runbooks/finops/enhanced_progress.py +40 -37
  84. runbooks/finops/enhanced_trend_visualization.py +3 -2
  85. runbooks/finops/enterprise_wrappers.py +230 -292
  86. runbooks/finops/executive_export.py +203 -160
  87. runbooks/finops/helpers.py +130 -288
  88. runbooks/finops/iam_guidance.py +1 -1
  89. runbooks/finops/infrastructure/__init__.py +80 -0
  90. runbooks/finops/infrastructure/commands.py +506 -0
  91. runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
  92. runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
  93. runbooks/finops/markdown_exporter.py +338 -175
  94. runbooks/finops/mcp_validator.py +1952 -0
  95. runbooks/finops/nat_gateway_optimizer.py +1513 -482
  96. runbooks/finops/network_cost_optimizer.py +657 -587
  97. runbooks/finops/notebook_utils.py +226 -188
  98. runbooks/finops/optimization_engine.py +1136 -0
  99. runbooks/finops/optimizer.py +25 -29
  100. runbooks/finops/rds_snapshot_optimizer.py +367 -411
  101. runbooks/finops/reservation_optimizer.py +427 -363
  102. runbooks/finops/scenario_cli_integration.py +77 -78
  103. runbooks/finops/scenarios.py +1278 -439
  104. runbooks/finops/schemas.py +218 -182
  105. runbooks/finops/snapshot_manager.py +2289 -0
  106. runbooks/finops/tests/test_finops_dashboard.py +3 -3
  107. runbooks/finops/tests/test_reference_images_validation.py +2 -2
  108. runbooks/finops/tests/test_single_account_features.py +17 -17
  109. runbooks/finops/tests/validate_test_suite.py +1 -1
  110. runbooks/finops/types.py +3 -3
  111. runbooks/finops/validation_framework.py +263 -269
  112. runbooks/finops/vpc_cleanup_exporter.py +191 -146
  113. runbooks/finops/vpc_cleanup_optimizer.py +593 -575
  114. runbooks/finops/workspaces_analyzer.py +171 -182
  115. runbooks/hitl/enhanced_workflow_engine.py +1 -1
  116. runbooks/integration/__init__.py +89 -0
  117. runbooks/integration/mcp_integration.py +1920 -0
  118. runbooks/inventory/CLAUDE.md +816 -0
  119. runbooks/inventory/README.md +3 -3
  120. runbooks/inventory/Tests/common_test_data.py +30 -30
  121. runbooks/inventory/__init__.py +2 -2
  122. runbooks/inventory/cloud_foundations_integration.py +144 -149
  123. runbooks/inventory/collectors/aws_comprehensive.py +28 -11
  124. runbooks/inventory/collectors/aws_networking.py +111 -101
  125. runbooks/inventory/collectors/base.py +4 -0
  126. runbooks/inventory/core/collector.py +495 -313
  127. runbooks/inventory/discovery.md +2 -2
  128. runbooks/inventory/drift_detection_cli.py +69 -96
  129. runbooks/inventory/find_ec2_security_groups.py +1 -1
  130. runbooks/inventory/inventory_mcp_cli.py +48 -46
  131. runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
  132. runbooks/inventory/mcp_inventory_validator.py +549 -465
  133. runbooks/inventory/mcp_vpc_validator.py +359 -442
  134. runbooks/inventory/organizations_discovery.py +56 -52
  135. runbooks/inventory/rich_inventory_display.py +33 -32
  136. runbooks/inventory/unified_validation_engine.py +278 -251
  137. runbooks/inventory/vpc_analyzer.py +733 -696
  138. runbooks/inventory/vpc_architecture_validator.py +293 -348
  139. runbooks/inventory/vpc_dependency_analyzer.py +382 -378
  140. runbooks/inventory/vpc_flow_analyzer.py +3 -3
  141. runbooks/main.py +152 -9147
  142. runbooks/main_final.py +91 -60
  143. runbooks/main_minimal.py +22 -10
  144. runbooks/main_optimized.py +131 -100
  145. runbooks/main_ultra_minimal.py +7 -2
  146. runbooks/mcp/__init__.py +36 -0
  147. runbooks/mcp/integration.py +679 -0
  148. runbooks/metrics/dora_metrics_engine.py +2 -2
  149. runbooks/monitoring/performance_monitor.py +9 -4
  150. runbooks/operate/dynamodb_operations.py +3 -1
  151. runbooks/operate/ec2_operations.py +145 -137
  152. runbooks/operate/iam_operations.py +146 -152
  153. runbooks/operate/mcp_integration.py +1 -1
  154. runbooks/operate/networking_cost_heatmap.py +33 -10
  155. runbooks/operate/privatelink_operations.py +1 -1
  156. runbooks/operate/rds_operations.py +223 -254
  157. runbooks/operate/s3_operations.py +107 -118
  158. runbooks/operate/vpc_endpoints.py +1 -1
  159. runbooks/operate/vpc_operations.py +648 -618
  160. runbooks/remediation/base.py +1 -1
  161. runbooks/remediation/commons.py +10 -7
  162. runbooks/remediation/commvault_ec2_analysis.py +71 -67
  163. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
  164. runbooks/remediation/multi_account.py +24 -21
  165. runbooks/remediation/rds_snapshot_list.py +91 -65
  166. runbooks/remediation/remediation_cli.py +92 -146
  167. runbooks/remediation/universal_account_discovery.py +83 -79
  168. runbooks/remediation/workspaces_list.py +49 -44
  169. runbooks/security/__init__.py +19 -0
  170. runbooks/security/assessment_runner.py +1150 -0
  171. runbooks/security/baseline_checker.py +812 -0
  172. runbooks/security/cloudops_automation_security_validator.py +509 -535
  173. runbooks/security/compliance_automation_engine.py +17 -17
  174. runbooks/security/config/__init__.py +2 -2
  175. runbooks/security/config/compliance_config.py +50 -50
  176. runbooks/security/config_template_generator.py +63 -76
  177. runbooks/security/enterprise_security_framework.py +1 -1
  178. runbooks/security/executive_security_dashboard.py +519 -508
  179. runbooks/security/integration_test_enterprise_security.py +5 -3
  180. runbooks/security/multi_account_security_controls.py +959 -1210
  181. runbooks/security/real_time_security_monitor.py +422 -444
  182. runbooks/security/run_script.py +1 -1
  183. runbooks/security/security_baseline_tester.py +1 -1
  184. runbooks/security/security_cli.py +143 -112
  185. runbooks/security/test_2way_validation.py +439 -0
  186. runbooks/security/two_way_validation_framework.py +852 -0
  187. runbooks/sre/mcp_reliability_engine.py +6 -6
  188. runbooks/sre/production_monitoring_framework.py +167 -177
  189. runbooks/tdd/__init__.py +15 -0
  190. runbooks/tdd/cli.py +1071 -0
  191. runbooks/utils/__init__.py +14 -17
  192. runbooks/utils/logger.py +7 -2
  193. runbooks/utils/version_validator.py +51 -48
  194. runbooks/validation/__init__.py +6 -6
  195. runbooks/validation/cli.py +9 -3
  196. runbooks/validation/comprehensive_2way_validator.py +754 -708
  197. runbooks/validation/mcp_validator.py +906 -228
  198. runbooks/validation/terraform_citations_validator.py +104 -115
  199. runbooks/validation/terraform_drift_detector.py +447 -451
  200. runbooks/vpc/README.md +617 -0
  201. runbooks/vpc/__init__.py +8 -1
  202. runbooks/vpc/analyzer.py +577 -0
  203. runbooks/vpc/cleanup_wrapper.py +476 -413
  204. runbooks/vpc/cli_cloudtrail_commands.py +339 -0
  205. runbooks/vpc/cli_mcp_validation_commands.py +480 -0
  206. runbooks/vpc/cloudtrail_audit_integration.py +717 -0
  207. runbooks/vpc/config.py +92 -97
  208. runbooks/vpc/cost_engine.py +411 -148
  209. runbooks/vpc/cost_explorer_integration.py +553 -0
  210. runbooks/vpc/cross_account_session.py +101 -106
  211. runbooks/vpc/enhanced_mcp_validation.py +917 -0
  212. runbooks/vpc/eni_gate_validator.py +961 -0
  213. runbooks/vpc/heatmap_engine.py +190 -162
  214. runbooks/vpc/mcp_no_eni_validator.py +681 -640
  215. runbooks/vpc/nat_gateway_optimizer.py +358 -0
  216. runbooks/vpc/networking_wrapper.py +15 -8
  217. runbooks/vpc/pdca_remediation_planner.py +528 -0
  218. runbooks/vpc/performance_optimized_analyzer.py +219 -231
  219. runbooks/vpc/runbooks_adapter.py +1167 -241
  220. runbooks/vpc/tdd_red_phase_stubs.py +601 -0
  221. runbooks/vpc/test_data_loader.py +358 -0
  222. runbooks/vpc/tests/conftest.py +314 -4
  223. runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
  224. runbooks/vpc/tests/test_cost_engine.py +0 -2
  225. runbooks/vpc/topology_generator.py +326 -0
  226. runbooks/vpc/unified_scenarios.py +1302 -1129
  227. runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
  228. runbooks-1.1.5.dist-info/METADATA +328 -0
  229. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/RECORD +233 -200
  230. runbooks/finops/README.md +0 -414
  231. runbooks/finops/accuracy_cross_validator.py +0 -647
  232. runbooks/finops/business_cases.py +0 -950
  233. runbooks/finops/dashboard_router.py +0 -922
  234. runbooks/finops/ebs_optimizer.py +0 -956
  235. runbooks/finops/embedded_mcp_validator.py +0 -1629
  236. runbooks/finops/enhanced_dashboard_runner.py +0 -527
  237. runbooks/finops/finops_dashboard.py +0 -584
  238. runbooks/finops/finops_scenarios.py +0 -1218
  239. runbooks/finops/legacy_migration.py +0 -730
  240. runbooks/finops/multi_dashboard.py +0 -1519
  241. runbooks/finops/single_dashboard.py +0 -1113
  242. runbooks/finops/unlimited_scenarios.py +0 -393
  243. runbooks-1.1.3.dist-info/METADATA +0 -799
  244. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
  245. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
  246. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
  247. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  """
2
2
  RDS Snapshot Lifecycle Analysis - Storage cost optimization and lifecycle management.
3
3
 
4
- Business Case: Enhanced snapshot analysis with cost calculation for $5K-24K annual savings
4
+ Business Case: Enhanced snapshot analysis with cost calculation for measurable range annual savings
5
5
  Target Accounts: 91893567291, 142964829704, 363435891329, 507583929055
6
6
  Focus: 89 manual snapshots causing storage costs and operational clutter
7
7
  Strategic Value: Operational cleanup and cost reduction through automated lifecycle management
@@ -16,8 +16,14 @@ from botocore.exceptions import ClientError
16
16
 
17
17
  from .commons import display_aws_account_info, get_client, write_to_csv
18
18
  from ..common.rich_utils import (
19
- console, print_header, print_success, print_error, print_warning,
20
- create_table, create_progress_bar, format_cost
19
+ console,
20
+ print_header,
21
+ print_success,
22
+ print_error,
23
+ print_warning,
24
+ create_table,
25
+ create_progress_bar,
26
+ format_cost,
21
27
  )
22
28
 
23
29
  logger = logging.getLogger(__name__)
@@ -36,16 +42,17 @@ def calculate_snapshot_age(create_time):
36
42
  def estimate_snapshot_cost(allocated_storage, storage_type="gp2", days_old=1):
37
43
  """
38
44
  Estimate monthly snapshot storage cost with enhanced accuracy.
39
-
40
- JIRA FinOps-23: Enhanced cost estimation for $5K-24K annual savings target
45
+
46
+ JIRA FinOps-23: Enhanced cost estimation for measurable range annual savings target
41
47
  Based on AWS RDS snapshot pricing: https://aws.amazon.com/rds/pricing/
42
48
  """
43
49
  # Real-time RDS Snapshot cost from AWS Pricing API - NO hardcoded defaults
44
50
  from runbooks.common.aws_pricing_api import pricing_api
51
+
45
52
  # Get region from caller context or default to us-east-1
46
- region = os.getenv('AWS_DEFAULT_REGION', 'us-east-1')
53
+ region = os.getenv("AWS_DEFAULT_REGION", "us-east-1")
47
54
  snapshot_cost_per_gb_month = pricing_api.get_rds_snapshot_cost_per_gb(region)
48
-
55
+
49
56
  # Calculate base monthly cost
50
57
  monthly_cost = allocated_storage * snapshot_cost_per_gb_month
51
58
 
@@ -59,28 +66,26 @@ def estimate_snapshot_cost(allocated_storage, storage_type="gp2", days_old=1):
59
66
  def calculate_manual_snapshot_savings(snapshots_data: List[Dict]) -> Dict[str, float]:
60
67
  """
61
68
  Calculate potential savings from manual snapshot cleanup.
62
-
69
+
63
70
  JIRA FinOps-23: Focuses on 89 manual snapshots for cost optimization
64
71
  """
65
72
  manual_snapshots = [s for s in snapshots_data if s.get("SnapshotType", "").lower() == "manual"]
66
-
73
+
67
74
  # Calculate costs by age groups
68
75
  old_manual_snapshots = [s for s in manual_snapshots if s.get("AgeDays", 0) >= 90] # 3+ months old
69
76
  very_old_manual_snapshots = [s for s in manual_snapshots if s.get("AgeDays", 0) >= 180] # 6+ months old
70
-
77
+
71
78
  total_manual_cost = sum(s.get("EstimatedMonthlyCost", 0) for s in manual_snapshots)
72
79
  old_manual_cost = sum(s.get("EstimatedMonthlyCost", 0) for s in old_manual_snapshots)
73
80
  very_old_manual_cost = sum(s.get("EstimatedMonthlyCost", 0) for s in very_old_manual_snapshots)
74
-
81
+
75
82
  return {
76
83
  "total_manual_snapshots": len(manual_snapshots),
77
84
  "total_manual_monthly_cost": total_manual_cost,
78
85
  "total_manual_annual_cost": total_manual_cost * 12,
79
-
80
86
  "old_manual_snapshots": len(old_manual_snapshots), # 90+ days
81
87
  "old_manual_monthly_savings": old_manual_cost,
82
88
  "old_manual_annual_savings": old_manual_cost * 12,
83
-
84
89
  "very_old_manual_snapshots": len(very_old_manual_snapshots), # 180+ days
85
90
  "very_old_manual_monthly_savings": very_old_manual_cost,
86
91
  "very_old_manual_annual_savings": very_old_manual_cost * 12,
@@ -96,15 +101,17 @@ def calculate_manual_snapshot_savings(snapshots_data: List[Dict]) -> Dict[str, f
96
101
  @click.option("--older-than", default=90, help="Focus on snapshots older than X days")
97
102
  @click.option("--calculate-savings", is_flag=True, help="Calculate detailed cost savings analysis")
98
103
  @click.option("--analyze", is_flag=True, help="Perform comprehensive cost analysis")
99
- def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type, manual_only, older_than, calculate_savings, analyze):
104
+ def get_rds_snapshot_details(
105
+ output_file, old_days, include_cost, snapshot_type, manual_only, older_than, calculate_savings, analyze
106
+ ):
100
107
  """
101
108
  Analyze RDS snapshots for lifecycle management and cost optimization.
102
-
103
- JIRA FinOps-23: Enhanced RDS snapshots analysis for $5K-24K annual savings
109
+
110
+ JIRA FinOps-23: Enhanced RDS snapshots analysis for measurable range annual savings
104
111
  Focus on 89 manual snapshots causing storage costs and operational clutter
105
112
  """
106
- print_header("RDS Snapshot Cost Optimization Analysis", "v0.9.1")
107
-
113
+ print_header("RDS Snapshot Cost Optimization Analysis", "latest version")
114
+
108
115
  account_info = display_aws_account_info()
109
116
  console.print(f"[cyan]Analyzing RDS snapshots in {account_info}[/cyan]")
110
117
 
@@ -126,19 +133,25 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
126
133
  if manual_only:
127
134
  original_count = len(snapshots)
128
135
  snapshots = [s for s in snapshots if s.get("SnapshotType", "").lower() == "manual"]
129
- console.print(f"[dim]JIRA FinOps-23 Filter: {len(snapshots)} manual snapshots (from {original_count} total)[/dim]")
130
-
136
+ console.print(
137
+ f"[dim]JIRA FinOps-23 Filter: {len(snapshots)} manual snapshots (from {original_count} total)[/dim]"
138
+ )
139
+
131
140
  if snapshot_type:
132
141
  original_count = len(snapshots)
133
142
  snapshots = [s for s in snapshots if s.get("SnapshotType", "").lower() == snapshot_type.lower()]
134
143
  console.print(f"[dim]Filtered to {len(snapshots)} snapshots of type '{snapshot_type}'[/dim]")
135
-
144
+
136
145
  if older_than > 0:
137
146
  now = datetime.now(tz=timezone.utc)
138
147
  threshold_date = now - timedelta(days=older_than)
139
148
  original_count = len(snapshots)
140
- snapshots = [s for s in snapshots if s.get("SnapshotCreateTime") and s["SnapshotCreateTime"] < threshold_date]
141
- console.print(f"[dim]Age filter: {len(snapshots)} snapshots older than {older_than} days (from {original_count})[/dim]")
149
+ snapshots = [
150
+ s for s in snapshots if s.get("SnapshotCreateTime") and s["SnapshotCreateTime"] < threshold_date
151
+ ]
152
+ console.print(
153
+ f"[dim]Age filter: {len(snapshots)} snapshots older than {older_than} days (from {original_count})[/dim]"
154
+ )
142
155
 
143
156
  data = []
144
157
  old_snapshots = []
@@ -148,11 +161,8 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
148
161
  total_estimated_cost = 0
149
162
 
150
163
  with create_progress_bar() as progress:
151
- task_id = progress.add_task(
152
- f"Analyzing {len(snapshots)} snapshots...",
153
- total=len(snapshots)
154
- )
155
-
164
+ task_id = progress.add_task(f"Analyzing {len(snapshots)} snapshots...", total=len(snapshots))
165
+
156
166
  for i, snapshot in enumerate(snapshots, 1):
157
167
  snapshot_id = snapshot["DBSnapshotIdentifier"]
158
168
 
@@ -183,7 +193,7 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
183
193
  if allocated_storage > 0:
184
194
  estimated_cost = estimate_snapshot_cost(allocated_storage, storage_type, age_days)
185
195
  total_estimated_cost += estimated_cost
186
-
196
+
187
197
  snapshot_data["EstimatedMonthlyCost"] = estimated_cost
188
198
  snapshot_data["EstimatedAnnualCost"] = estimated_cost * 12
189
199
 
@@ -234,12 +244,12 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
234
244
  "projected_annual_savings": 0.0,
235
245
  "old_manual_snapshots": 0,
236
246
  "old_manual_monthly_savings": 0.0,
237
- "old_manual_annual_savings": 0.0
247
+ "old_manual_annual_savings": 0.0,
238
248
  }
239
-
249
+
240
250
  # Create comprehensive summary table with Rich CLI
241
251
  print_header("RDS Snapshot Analysis Summary")
242
-
252
+
243
253
  summary_table = create_table(
244
254
  title="RDS Snapshot Cost Analysis - JIRA FinOps-23",
245
255
  columns=[
@@ -247,8 +257,8 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
247
257
  {"header": "Count", "style": "green bold"},
248
258
  {"header": "Storage (GB)", "style": "yellow"},
249
259
  {"header": "Monthly Cost", "style": "red"},
250
- {"header": "Annual Cost", "style": "red bold"}
251
- ]
260
+ {"header": "Annual Cost", "style": "red bold"},
261
+ ],
252
262
  )
253
263
 
254
264
  # Basic metrics
@@ -257,31 +267,31 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
257
267
  str(len(data)),
258
268
  str(total_storage),
259
269
  format_cost(total_estimated_cost) if (include_cost or calculate_savings or analyze) else "N/A",
260
- format_cost(total_estimated_cost * 12) if (include_cost or calculate_savings or analyze) else "N/A"
270
+ format_cost(total_estimated_cost * 12) if (include_cost or calculate_savings or analyze) else "N/A",
261
271
  )
262
-
272
+
263
273
  summary_table.add_row(
264
274
  "Manual Snapshots",
265
275
  str(len(manual_snapshots)),
266
276
  str(sum(s["AllocatedStorage"] for s in data if s["SnapshotType"].lower() == "manual")),
267
277
  format_cost(savings_analysis["total_manual_monthly_cost"]) if (calculate_savings or analyze) else "N/A",
268
- format_cost(savings_analysis["total_manual_annual_cost"]) if (calculate_savings or analyze) else "N/A"
278
+ format_cost(savings_analysis["total_manual_annual_cost"]) if (calculate_savings or analyze) else "N/A",
269
279
  )
270
-
280
+
271
281
  summary_table.add_row(
272
- "Automated Snapshots",
282
+ "Automated Snapshots",
273
283
  str(len(automated_snapshots)),
274
284
  str(sum(s["AllocatedStorage"] for s in data if s["SnapshotType"].lower() == "automated")),
275
285
  "Retention Policy",
276
- "Retention Policy"
286
+ "Retention Policy",
277
287
  )
278
-
288
+
279
289
  summary_table.add_row(
280
290
  f"Old Snapshots (>{old_days} days)",
281
291
  str(len(old_snapshots)),
282
292
  str(sum(s["AllocatedStorage"] for s in data if s["IsOld"])),
283
293
  "Mixed Types",
284
- "Mixed Types"
294
+ "Mixed Types",
285
295
  )
286
296
 
287
297
  # JIRA FinOps-23 specific analysis
@@ -289,20 +299,30 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
289
299
  summary_table.add_row(
290
300
  f"🎯 Manual >{older_than}d (Cleanup Target)",
291
301
  str(savings_analysis["old_manual_snapshots"]),
292
- str(sum(s["AllocatedStorage"] for s in data if s["AgeDays"] >= older_than and s["SnapshotType"].lower() == "manual")),
302
+ str(
303
+ sum(
304
+ s["AllocatedStorage"]
305
+ for s in data
306
+ if s["AgeDays"] >= older_than and s["SnapshotType"].lower() == "manual"
307
+ )
308
+ ),
293
309
  format_cost(savings_analysis["old_manual_monthly_savings"]),
294
- format_cost(savings_analysis["old_manual_annual_savings"])
310
+ format_cost(savings_analysis["old_manual_annual_savings"]),
295
311
  )
296
312
 
297
313
  console.print(summary_table)
298
314
 
299
315
  # Cleanup recommendations with Rich CLI
300
316
  cleanup_candidates = [s for s in data if s["IsOld"] and s["SnapshotType"].lower() == "manual"]
301
- high_priority_candidates = [s for s in data if s["AgeDays"] >= older_than and s["SnapshotType"].lower() == "manual"]
302
-
317
+ high_priority_candidates = [
318
+ s for s in data if s["AgeDays"] >= older_than and s["SnapshotType"].lower() == "manual"
319
+ ]
320
+
303
321
  if high_priority_candidates:
304
- print_warning(f"🎯 JIRA FinOps-23: {len(high_priority_candidates)} high-priority manual snapshots (>{older_than} days):")
305
-
322
+ print_warning(
323
+ f"🎯 JIRA FinOps-23: {len(high_priority_candidates)} high-priority manual snapshots (>{older_than} days):"
324
+ )
325
+
306
326
  # Create detailed cleanup candidates table
307
327
  cleanup_table = create_table(
308
328
  title=f"High-Priority Manual Snapshots (>{older_than} days old)",
@@ -312,44 +332,50 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
312
332
  {"header": "Age (Days)", "style": "yellow"},
313
333
  {"header": "Size (GB)", "style": "green"},
314
334
  {"header": "Monthly Cost", "style": "red"},
315
- {"header": "Engine", "style": "magenta"}
316
- ]
335
+ {"header": "Engine", "style": "magenta"},
336
+ ],
317
337
  )
318
-
338
+
319
339
  for snap in high_priority_candidates[:15]: # Show first 15 for readability
320
340
  cleanup_table.add_row(
321
- snap['DBSnapshotIdentifier'],
322
- snap['DBInstanceIdentifier'],
323
- str(snap['AgeDays']),
324
- str(snap['AllocatedStorage']),
325
- format_cost(snap['EstimatedMonthlyCost']) if snap['EstimatedMonthlyCost'] > 0 else "N/A",
326
- snap['Engine']
341
+ snap["DBSnapshotIdentifier"],
342
+ snap["DBInstanceIdentifier"],
343
+ str(snap["AgeDays"]),
344
+ str(snap["AllocatedStorage"]),
345
+ format_cost(snap["EstimatedMonthlyCost"]) if snap["EstimatedMonthlyCost"] > 0 else "N/A",
346
+ snap["Engine"],
327
347
  )
328
-
348
+
329
349
  console.print(cleanup_table)
330
-
350
+
331
351
  if len(high_priority_candidates) > 15:
332
352
  console.print(f"[dim]... and {len(high_priority_candidates) - 15} more high-priority snapshots[/dim]")
333
-
353
+
334
354
  elif cleanup_candidates:
335
355
  print_warning(f"⚠ {len(cleanup_candidates)} old manual snapshots for review (>{old_days} days)")
336
356
  else:
337
357
  print_success("✓ No old manual snapshots found")
338
358
 
339
- # Target validation (JIRA FinOps-23: $5K-24K annual savings)
359
+ # Target validation (JIRA FinOps-23: measurable range annual savings)
340
360
  if calculate_savings or analyze:
341
361
  target_min_annual = 5000.0
342
362
  target_max_annual = 24000.0
343
363
  actual_savings = savings_analysis["old_manual_annual_savings"]
344
-
364
+
345
365
  if actual_savings >= target_min_annual:
346
366
  if actual_savings <= target_max_annual:
347
- print_success(f"🎯 Target Achievement: ${actual_savings:,.0f} within JIRA FinOps-23 range (${target_min_annual:,.0f}-${target_max_annual:,.0f})")
367
+ print_success(
368
+ f"🎯 Target Achievement: ${actual_savings:,.0f} within JIRA FinOps-23 range (${target_min_annual:,.0f}-${target_max_annual:,.0f})"
369
+ )
348
370
  else:
349
- print_success(f"🎯 Target Exceeded: ${actual_savings:,.0f} exceeds JIRA FinOps-23 maximum target (${target_max_annual:,.0f})")
371
+ print_success(
372
+ f"🎯 Target Exceeded: ${actual_savings:,.0f} exceeds JIRA FinOps-23 maximum target (${target_max_annual:,.0f})"
373
+ )
350
374
  else:
351
375
  percentage = (actual_savings / target_min_annual) * 100
352
- print_warning(f"📊 Analysis: ${actual_savings:,.0f} is {percentage:.1f}% of JIRA FinOps-23 minimum target (${target_min_annual:,.0f})")
376
+ print_warning(
377
+ f"📊 Analysis: ${actual_savings:,.0f} is {percentage:.1f}% of JIRA FinOps-23 minimum target (${target_min_annual:,.0f})"
378
+ )
353
379
 
354
380
  # Encryption status
355
381
  encrypted_count = sum(1 for s in data if s["Encrypted"])