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
@@ -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
-
45
+
40
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
-
109
+
103
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
113
  print_header("RDS Snapshot Cost Optimization Analysis", "latest version")
107
-
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,25 +332,25 @@ 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:
@@ -341,15 +361,21 @@ def get_rds_snapshot_details(output_file, old_days, include_cost, snapshot_type,
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"])