runbooks 0.7.9__py3-none-any.whl → 0.9.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. runbooks/__init__.py +1 -1
  2. runbooks/cfat/README.md +12 -1
  3. runbooks/cfat/__init__.py +1 -1
  4. runbooks/cfat/assessment/compliance.py +4 -1
  5. runbooks/cfat/assessment/runner.py +42 -34
  6. runbooks/cfat/models.py +1 -1
  7. runbooks/cloudops/__init__.py +123 -0
  8. runbooks/cloudops/base.py +385 -0
  9. runbooks/cloudops/cost_optimizer.py +811 -0
  10. runbooks/cloudops/infrastructure_optimizer.py +29 -0
  11. runbooks/cloudops/interfaces.py +828 -0
  12. runbooks/cloudops/lifecycle_manager.py +29 -0
  13. runbooks/cloudops/mcp_cost_validation.py +678 -0
  14. runbooks/cloudops/models.py +251 -0
  15. runbooks/cloudops/monitoring_automation.py +29 -0
  16. runbooks/cloudops/notebook_framework.py +676 -0
  17. runbooks/cloudops/security_enforcer.py +449 -0
  18. runbooks/common/__init__.py +152 -0
  19. runbooks/common/accuracy_validator.py +1039 -0
  20. runbooks/common/context_logger.py +440 -0
  21. runbooks/common/cross_module_integration.py +594 -0
  22. runbooks/common/enhanced_exception_handler.py +1108 -0
  23. runbooks/common/enterprise_audit_integration.py +634 -0
  24. runbooks/common/mcp_cost_explorer_integration.py +900 -0
  25. runbooks/common/mcp_integration.py +548 -0
  26. runbooks/common/performance_monitor.py +387 -0
  27. runbooks/common/profile_utils.py +216 -0
  28. runbooks/common/rich_utils.py +172 -1
  29. runbooks/feedback/user_feedback_collector.py +440 -0
  30. runbooks/finops/README.md +377 -458
  31. runbooks/finops/__init__.py +4 -21
  32. runbooks/finops/account_resolver.py +279 -0
  33. runbooks/finops/accuracy_cross_validator.py +638 -0
  34. runbooks/finops/aws_client.py +721 -36
  35. runbooks/finops/budget_integration.py +313 -0
  36. runbooks/finops/cli.py +59 -5
  37. runbooks/finops/cost_optimizer.py +1340 -0
  38. runbooks/finops/cost_processor.py +211 -37
  39. runbooks/finops/dashboard_router.py +900 -0
  40. runbooks/finops/dashboard_runner.py +990 -232
  41. runbooks/finops/embedded_mcp_validator.py +288 -0
  42. runbooks/finops/enhanced_dashboard_runner.py +8 -7
  43. runbooks/finops/enhanced_progress.py +327 -0
  44. runbooks/finops/enhanced_trend_visualization.py +423 -0
  45. runbooks/finops/finops_dashboard.py +184 -1829
  46. runbooks/finops/helpers.py +509 -196
  47. runbooks/finops/iam_guidance.py +400 -0
  48. runbooks/finops/markdown_exporter.py +466 -0
  49. runbooks/finops/multi_dashboard.py +1502 -0
  50. runbooks/finops/optimizer.py +15 -15
  51. runbooks/finops/profile_processor.py +2 -2
  52. runbooks/finops/runbooks.inventory.organizations_discovery.log +0 -0
  53. runbooks/finops/runbooks.security.report_generator.log +0 -0
  54. runbooks/finops/runbooks.security.run_script.log +0 -0
  55. runbooks/finops/runbooks.security.security_export.log +0 -0
  56. runbooks/finops/schemas.py +589 -0
  57. runbooks/finops/service_mapping.py +195 -0
  58. runbooks/finops/single_dashboard.py +710 -0
  59. runbooks/finops/tests/test_reference_images_validation.py +1 -1
  60. runbooks/inventory/README.md +12 -1
  61. runbooks/inventory/core/collector.py +157 -29
  62. runbooks/inventory/list_ec2_instances.py +9 -6
  63. runbooks/inventory/list_ssm_parameters.py +10 -10
  64. runbooks/inventory/organizations_discovery.py +210 -164
  65. runbooks/inventory/rich_inventory_display.py +74 -107
  66. runbooks/inventory/run_on_multi_accounts.py +13 -13
  67. runbooks/inventory/runbooks.inventory.organizations_discovery.log +0 -0
  68. runbooks/inventory/runbooks.security.security_export.log +0 -0
  69. runbooks/main.py +1371 -240
  70. runbooks/metrics/dora_metrics_engine.py +711 -17
  71. runbooks/monitoring/performance_monitor.py +433 -0
  72. runbooks/operate/README.md +394 -0
  73. runbooks/operate/base.py +215 -47
  74. runbooks/operate/ec2_operations.py +435 -5
  75. runbooks/operate/iam_operations.py +598 -3
  76. runbooks/operate/privatelink_operations.py +1 -1
  77. runbooks/operate/rds_operations.py +508 -0
  78. runbooks/operate/s3_operations.py +508 -0
  79. runbooks/operate/vpc_endpoints.py +1 -1
  80. runbooks/remediation/README.md +489 -13
  81. runbooks/remediation/base.py +5 -3
  82. runbooks/remediation/commons.py +8 -4
  83. runbooks/security/ENTERPRISE_SECURITY_FRAMEWORK.md +506 -0
  84. runbooks/security/README.md +12 -1
  85. runbooks/security/__init__.py +265 -33
  86. runbooks/security/cloudops_automation_security_validator.py +1164 -0
  87. runbooks/security/compliance_automation.py +12 -10
  88. runbooks/security/compliance_automation_engine.py +1021 -0
  89. runbooks/security/enterprise_security_framework.py +930 -0
  90. runbooks/security/enterprise_security_policies.json +293 -0
  91. runbooks/security/executive_security_dashboard.py +1247 -0
  92. runbooks/security/integration_test_enterprise_security.py +879 -0
  93. runbooks/security/module_security_integrator.py +641 -0
  94. runbooks/security/multi_account_security_controls.py +2254 -0
  95. runbooks/security/real_time_security_monitor.py +1196 -0
  96. runbooks/security/report_generator.py +1 -1
  97. runbooks/security/run_script.py +4 -8
  98. runbooks/security/security_baseline_tester.py +39 -52
  99. runbooks/security/security_export.py +99 -120
  100. runbooks/sre/README.md +472 -0
  101. runbooks/sre/__init__.py +33 -0
  102. runbooks/sre/mcp_reliability_engine.py +1049 -0
  103. runbooks/sre/performance_optimization_engine.py +1032 -0
  104. runbooks/sre/production_monitoring_framework.py +584 -0
  105. runbooks/sre/reliability_monitoring_framework.py +1011 -0
  106. runbooks/validation/__init__.py +2 -2
  107. runbooks/validation/benchmark.py +154 -149
  108. runbooks/validation/cli.py +159 -147
  109. runbooks/validation/mcp_validator.py +291 -248
  110. runbooks/vpc/README.md +478 -0
  111. runbooks/vpc/__init__.py +2 -2
  112. runbooks/vpc/manager_interface.py +366 -351
  113. runbooks/vpc/networking_wrapper.py +68 -36
  114. runbooks/vpc/rich_formatters.py +22 -8
  115. runbooks-0.9.1.dist-info/METADATA +308 -0
  116. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/RECORD +120 -59
  117. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/entry_points.txt +1 -1
  118. runbooks/finops/cross_validation.py +0 -375
  119. runbooks-0.7.9.dist-info/METADATA +0 -636
  120. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/WHEEL +0 -0
  121. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/licenses/LICENSE +0 -0
  122. {runbooks-0.7.9.dist-info → runbooks-0.9.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Enhanced Budget Integration - Real AWS Budgets API Integration
4
+
5
+ This module provides comprehensive AWS Budgets API integration for enhanced
6
+ Budget Status column values, replacing placeholder data with real budget
7
+ information, alerts, and utilization tracking.
8
+
9
+ Features:
10
+ - Real AWS Budgets API integration
11
+ - Budget utilization calculations with visual indicators
12
+ - Budget alert thresholds and notifications
13
+ - Forecast vs actual spend analysis
14
+ - Rich CLI formatting for budget status
15
+ - Performance optimized for multi-account operations
16
+
17
+ Author: CloudOps Runbooks Team
18
+ Version: 0.8.0
19
+ """
20
+
21
+ import json
22
+ from datetime import datetime, timedelta
23
+ from typing import Any, Dict, List, Optional, Tuple
24
+
25
+ import boto3
26
+ from botocore.exceptions import ClientError
27
+ from rich.console import Console
28
+
29
+ from ..common.rich_utils import (
30
+ STATUS_INDICATORS,
31
+ format_cost,
32
+ print_info,
33
+ print_warning,
34
+ )
35
+ from ..common.rich_utils import (
36
+ console as rich_console,
37
+ )
38
+
39
+
40
+ class EnhancedBudgetAnalyzer:
41
+ """
42
+ Enhanced AWS Budgets API integration for real-time budget analysis.
43
+
44
+ Provides comprehensive budget status, utilization tracking, and alert
45
+ management across single and multi-account AWS environments.
46
+ """
47
+
48
+ def __init__(self, console: Optional[Console] = None):
49
+ self.console = console or rich_console
50
+
51
+ def get_enhanced_budget_status(
52
+ self, session: boto3.Session, current_cost: float, account_id: str
53
+ ) -> Dict[str, Any]:
54
+ """
55
+ Get enhanced budget status with real AWS Budgets API data.
56
+
57
+ Args:
58
+ session: AWS session with budget access
59
+ current_cost: Current month cost for comparison
60
+ account_id: AWS account ID for budget identification
61
+
62
+ Returns:
63
+ Dict containing enhanced budget information with Rich formatting
64
+ """
65
+ try:
66
+ budgets_client = session.client("budgets")
67
+
68
+ # Get all budgets for the account
69
+ budgets_response = budgets_client.describe_budgets(AccountId=account_id)
70
+ budgets = budgets_response.get("Budgets", [])
71
+
72
+ if not budgets:
73
+ return {
74
+ "status": "no_budget",
75
+ "display": "[dim]No Budget Set[/]",
76
+ "utilization": 0,
77
+ "details": "No budgets configured for this account",
78
+ "recommendation": "Consider setting up budget alerts",
79
+ }
80
+
81
+ # Analyze primary budget (or cost budget if multiple exist)
82
+ primary_budget = self._select_primary_budget(budgets)
83
+
84
+ if not primary_budget:
85
+ return {
86
+ "status": "no_budget",
87
+ "display": "[dim]No Cost Budget[/]",
88
+ "utilization": 0,
89
+ "details": "No cost-based budgets found",
90
+ "recommendation": "Create monthly cost budget",
91
+ }
92
+
93
+ # Get budget utilization data
94
+ utilization_response = budgets_client.describe_budget_performance_history(
95
+ AccountId=account_id, BudgetName=primary_budget["BudgetName"]
96
+ )
97
+
98
+ # Calculate enhanced budget status
99
+ budget_analysis = self._analyze_budget_performance(primary_budget, utilization_response, current_cost)
100
+
101
+ return budget_analysis
102
+
103
+ except ClientError as e:
104
+ error_code = e.response.get("Error", {}).get("Code", "Unknown")
105
+ if error_code == "AccessDeniedException":
106
+ return {
107
+ "status": "access_denied",
108
+ "display": "[yellow]⚠️ Access Denied[/]",
109
+ "utilization": 0,
110
+ "details": "No budget read permissions",
111
+ "recommendation": "Grant budgets:ViewBudget permission",
112
+ }
113
+ else:
114
+ print_warning(f"Budget API error: {error_code}")
115
+ return self._create_estimated_budget_status(current_cost)
116
+
117
+ except Exception as e:
118
+ print_warning(f"Budget analysis failed: {str(e)[:50]}")
119
+ return self._create_estimated_budget_status(current_cost)
120
+
121
+ def _select_primary_budget(self, budgets: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
122
+ """Select the primary budget for analysis (cost budget preferred)."""
123
+
124
+ # Prefer cost budgets over usage budgets
125
+ cost_budgets = [b for b in budgets if b.get("BudgetType") == "COST"]
126
+ if cost_budgets:
127
+ # Prefer monthly budgets
128
+ monthly_budgets = [b for b in cost_budgets if b.get("TimeUnit") == "MONTHLY"]
129
+ if monthly_budgets:
130
+ return monthly_budgets[0] # First monthly cost budget
131
+ return cost_budgets[0] # First cost budget
132
+
133
+ # Fallback to any budget
134
+ return budgets[0] if budgets else None
135
+
136
+ def _analyze_budget_performance(
137
+ self, budget: Dict[str, Any], performance_history: Dict[str, Any], current_cost: float
138
+ ) -> Dict[str, Any]:
139
+ """Analyze budget performance and generate enhanced status."""
140
+
141
+ budget_limit = float(budget.get("BudgetLimit", {}).get("Amount", 0))
142
+ budget_name = budget.get("BudgetName", "Unknown")
143
+
144
+ if budget_limit == 0:
145
+ return {
146
+ "status": "no_limit",
147
+ "display": "[dim]Unlimited Budget[/]",
148
+ "utilization": 0,
149
+ "details": f'Budget "{budget_name}" has no spending limit',
150
+ "recommendation": "Set budget limit for cost control",
151
+ }
152
+
153
+ # Calculate utilization
154
+ utilization_percent = (current_cost / budget_limit) * 100
155
+
156
+ # Get alerts configuration if available
157
+ alerts_info = self._analyze_budget_alerts(budget)
158
+
159
+ # Generate status based on utilization
160
+ if utilization_percent >= 100:
161
+ return {
162
+ "status": "over_budget",
163
+ "display": f"[red]🚨 Over Budget[/]\n[red]{utilization_percent:.0f}% ({format_cost(current_cost)}/{format_cost(budget_limit)})[/]",
164
+ "utilization": utilization_percent,
165
+ "details": f"Exceeded budget by {format_cost(current_cost - budget_limit)}",
166
+ "recommendation": "Immediate cost review required",
167
+ "alerts": alerts_info,
168
+ }
169
+ elif utilization_percent >= 90:
170
+ return {
171
+ "status": "critical",
172
+ "display": f"[red]⚠️ Critical[/]\n[red]{utilization_percent:.0f}% ({format_cost(current_cost)}/{format_cost(budget_limit)})[/]",
173
+ "utilization": utilization_percent,
174
+ "details": f"Approaching budget limit - {format_cost(budget_limit - current_cost)} remaining",
175
+ "recommendation": "Review and optimize high-cost services",
176
+ "alerts": alerts_info,
177
+ }
178
+ elif utilization_percent >= 75:
179
+ return {
180
+ "status": "warning",
181
+ "display": f"[yellow]⚠️ Warning[/]\n[yellow]{utilization_percent:.0f}% ({format_cost(current_cost)}/{format_cost(budget_limit)})[/]",
182
+ "utilization": utilization_percent,
183
+ "details": f"75% of budget used - {format_cost(budget_limit - current_cost)} remaining",
184
+ "recommendation": "Monitor spending closely",
185
+ "alerts": alerts_info,
186
+ }
187
+ elif utilization_percent >= 50:
188
+ return {
189
+ "status": "moderate",
190
+ "display": f"[cyan]📊 On Track[/]\n[cyan]{utilization_percent:.0f}% ({format_cost(current_cost)}/{format_cost(budget_limit)})[/]",
191
+ "utilization": utilization_percent,
192
+ "details": f"Moderate usage - {format_cost(budget_limit - current_cost)} remaining",
193
+ "recommendation": "Continue monitoring",
194
+ "alerts": alerts_info,
195
+ }
196
+ else:
197
+ return {
198
+ "status": "under_budget",
199
+ "display": f"[green]✅ Under Budget[/]\n[green]{utilization_percent:.0f}% ({format_cost(current_cost)}/{format_cost(budget_limit)})[/]",
200
+ "utilization": utilization_percent,
201
+ "details": f"Low utilization - {format_cost(budget_limit - current_cost)} available",
202
+ "recommendation": "Budget utilization is low",
203
+ "alerts": alerts_info,
204
+ }
205
+
206
+ def _analyze_budget_alerts(self, budget: Dict[str, Any]) -> Dict[str, Any]:
207
+ """Analyze budget alert configuration."""
208
+ # This would analyze budget alerts if available in the budget configuration
209
+ # For now, return basic alert info
210
+ return {"configured": False, "thresholds": [], "notification_methods": []}
211
+
212
+ def _create_estimated_budget_status(self, current_cost: float) -> Dict[str, Any]:
213
+ """Create estimated budget status when real budget data is unavailable."""
214
+
215
+ # Simple heuristic-based budget estimation
216
+ if current_cost == 0:
217
+ return {
218
+ "status": "no_usage",
219
+ "display": "[dim]No Usage[/]",
220
+ "utilization": 0,
221
+ "details": "No current usage detected",
222
+ "recommendation": "Account appears inactive",
223
+ }
224
+ elif current_cost < 100:
225
+ return {
226
+ "status": "low_cost",
227
+ "display": f"[green]💰 Low Cost[/]\n[green]{format_cost(current_cost)}/month[/]",
228
+ "utilization": 0,
229
+ "details": "Low monthly spend detected",
230
+ "recommendation": "Consider setting budget alerts",
231
+ }
232
+ elif current_cost < 1000:
233
+ return {
234
+ "status": "moderate_cost",
235
+ "display": f"[yellow]📊 Moderate[/]\n[yellow]{format_cost(current_cost)}/month[/]",
236
+ "utilization": 0,
237
+ "details": "Moderate monthly spend",
238
+ "recommendation": "Set budget limits for cost control",
239
+ }
240
+ else:
241
+ return {
242
+ "status": "high_cost",
243
+ "display": f"[red]💸 High Cost[/]\n[red]{format_cost(current_cost)}/month[/]",
244
+ "utilization": 0,
245
+ "details": "High monthly spend detected",
246
+ "recommendation": "Budget management recommended",
247
+ }
248
+
249
+ def get_budget_forecast(
250
+ self, session: boto3.Session, account_id: str, budget_name: str
251
+ ) -> Optional[Dict[str, Any]]:
252
+ """Get budget forecast information for trend analysis."""
253
+ try:
254
+ budgets_client = session.client("budgets")
255
+
256
+ # Get budget forecast (if available)
257
+ forecast_response = budgets_client.describe_budget_performance_history(
258
+ AccountId=account_id,
259
+ BudgetName=budget_name,
260
+ TimePeriod={"Start": datetime.now() - timedelta(days=90), "End": datetime.now()},
261
+ )
262
+
263
+ # Process forecast data
264
+ performance_history = forecast_response.get("BudgetPerformanceHistory", {})
265
+
266
+ return {
267
+ "forecast_available": True,
268
+ "performance_history": performance_history,
269
+ "trend_analysis": self._analyze_spending_trends(performance_history),
270
+ }
271
+
272
+ except Exception as e:
273
+ print_warning(f"Budget forecast failed: {str(e)[:50]}")
274
+ return None
275
+
276
+ def _analyze_spending_trends(self, performance_history: Dict[str, Any]) -> Dict[str, Any]:
277
+ """Analyze spending trends from budget performance history."""
278
+ # Placeholder for trend analysis logic
279
+ return {"trend_direction": "stable", "trend_confidence": "medium", "forecast_accuracy": "unknown"}
280
+
281
+
282
+ def create_budget_analyzer(console: Optional[Console] = None) -> EnhancedBudgetAnalyzer:
283
+ """Factory function to create enhanced budget analyzer."""
284
+ return EnhancedBudgetAnalyzer(console=console)
285
+
286
+
287
+ def get_enhanced_budget_status_for_profile(profile: str, current_cost: float) -> Dict[str, Any]:
288
+ """
289
+ Convenience function to get budget status for a specific profile.
290
+
291
+ Args:
292
+ profile: AWS profile name
293
+ current_cost: Current month cost
294
+
295
+ Returns:
296
+ Enhanced budget status dictionary
297
+ """
298
+ try:
299
+ session = boto3.Session(profile_name=profile)
300
+ sts = session.client("sts")
301
+ account_id = sts.get_caller_identity()["Account"]
302
+
303
+ analyzer = create_budget_analyzer()
304
+ return analyzer.get_enhanced_budget_status(session, current_cost, account_id)
305
+
306
+ except Exception as e:
307
+ return {
308
+ "status": "error",
309
+ "display": "[red]Error[/]",
310
+ "utilization": 0,
311
+ "details": f"Budget analysis failed: {str(e)[:50]}",
312
+ "recommendation": "Check AWS credentials and permissions",
313
+ }
runbooks/finops/cli.py CHANGED
@@ -96,10 +96,10 @@ def main() -> int:
96
96
  "--report-type",
97
97
  "-y",
98
98
  nargs="+",
99
- choices=["csv", "json", "pdf"],
100
- help="Specify one or more report types: csv and/or json and/or pdf (space-separated)",
99
+ choices=["csv", "json", "pdf", "markdown"],
100
+ help="Specify one or more report types: csv and/or json and/or pdf and/or markdown (space-separated)",
101
101
  type=str,
102
- default=["csv"],
102
+ default=["markdown"],
103
103
  )
104
104
  parser.add_argument(
105
105
  "--dir",
@@ -147,6 +147,44 @@ def main() -> int:
147
147
  help="Run PDCA in continuous mode (until manually stopped)",
148
148
  )
149
149
 
150
+ # Enhanced Dashboard Configuration Parameters
151
+ parser.add_argument(
152
+ "--mode",
153
+ choices=["single_account", "multi_account"],
154
+ help="Explicit dashboard mode selection (overrides auto-detection)",
155
+ type=str,
156
+ )
157
+ parser.add_argument(
158
+ "--top-services",
159
+ help="Number of top services to display in single-account mode (default: 10)",
160
+ type=int,
161
+ default=10,
162
+ )
163
+ parser.add_argument(
164
+ "--top-accounts",
165
+ help="Number of top accounts to display in multi-account mode (default: 5)",
166
+ type=int,
167
+ default=5,
168
+ )
169
+ parser.add_argument(
170
+ "--services-per-account",
171
+ help="Number of services to show per account in multi-account mode (default: 3)",
172
+ type=int,
173
+ default=3,
174
+ )
175
+ parser.add_argument(
176
+ "--format",
177
+ choices=["table", "json", "csv", "markdown"],
178
+ help="Output format for dashboard display (default: markdown)",
179
+ type=str,
180
+ default="markdown",
181
+ )
182
+ parser.add_argument(
183
+ "--no-enhanced-routing",
184
+ action="store_true",
185
+ help="Disable enhanced service-focused routing (use legacy account-per-row layout)",
186
+ )
187
+
150
188
  args = parser.parse_args()
151
189
 
152
190
  config_data: Optional[Dict[str, Any]] = None
@@ -207,8 +245,24 @@ def main() -> int:
207
245
  console.print(f"\n[red]❌ PDCA Engine failed: {str(e)}[/]")
208
246
  return 1
209
247
 
210
- # Default dashboard mode
211
- result = run_dashboard(args)
248
+ # Enhanced routing is now the default (service-per-row layout)
249
+ # Maintain backward compatibility with explicit --no-enhanced-routing flag
250
+ use_enhanced_routing = not getattr(args, "no_enhanced_routing", False)
251
+
252
+ if use_enhanced_routing:
253
+ try:
254
+ from runbooks.finops.dashboard_router import route_finops_request
255
+
256
+ console.print("[bold bright_cyan]🚀 Using Enhanced Service-Focused Dashboard[/]")
257
+ result = route_finops_request(args)
258
+ except Exception as e:
259
+ console.print(f"[yellow]⚠️ Enhanced routing failed ({str(e)[:50]}), falling back to legacy mode[/]")
260
+ result = run_dashboard(args)
261
+ else:
262
+ # Legacy dashboard mode (backward compatibility)
263
+ console.print("[dim]Using legacy dashboard mode[/]")
264
+ result = run_dashboard(args)
265
+
212
266
  return 0 if result == 0 else 1
213
267
 
214
268