runbooks 1.1.4__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.
- runbooks/__init__.py +31 -2
- runbooks/__init___optimized.py +18 -4
- runbooks/_platform/__init__.py +1 -5
- runbooks/_platform/core/runbooks_wrapper.py +141 -138
- runbooks/aws2/accuracy_validator.py +812 -0
- runbooks/base.py +7 -0
- runbooks/cfat/assessment/compliance.py +1 -1
- runbooks/cfat/assessment/runner.py +1 -0
- runbooks/cfat/cloud_foundations_assessment.py +227 -239
- runbooks/cli/__init__.py +1 -1
- runbooks/cli/commands/cfat.py +64 -23
- runbooks/cli/commands/finops.py +1005 -54
- runbooks/cli/commands/inventory.py +138 -35
- runbooks/cli/commands/operate.py +9 -36
- runbooks/cli/commands/security.py +42 -18
- runbooks/cli/commands/validation.py +432 -18
- runbooks/cli/commands/vpc.py +81 -17
- runbooks/cli/registry.py +22 -10
- runbooks/cloudops/__init__.py +20 -27
- runbooks/cloudops/base.py +96 -107
- runbooks/cloudops/cost_optimizer.py +544 -542
- runbooks/cloudops/infrastructure_optimizer.py +5 -4
- runbooks/cloudops/interfaces.py +224 -225
- runbooks/cloudops/lifecycle_manager.py +5 -4
- runbooks/cloudops/mcp_cost_validation.py +252 -235
- runbooks/cloudops/models.py +78 -53
- runbooks/cloudops/monitoring_automation.py +5 -4
- runbooks/cloudops/notebook_framework.py +177 -213
- runbooks/cloudops/security_enforcer.py +125 -159
- runbooks/common/accuracy_validator.py +11 -0
- runbooks/common/aws_pricing.py +349 -326
- runbooks/common/aws_pricing_api.py +211 -212
- runbooks/common/aws_profile_manager.py +40 -36
- runbooks/common/aws_utils.py +74 -79
- runbooks/common/business_logic.py +126 -104
- runbooks/common/cli_decorators.py +36 -60
- runbooks/common/comprehensive_cost_explorer_integration.py +455 -463
- runbooks/common/cross_account_manager.py +197 -204
- runbooks/common/date_utils.py +27 -39
- runbooks/common/decorators.py +29 -19
- runbooks/common/dry_run_examples.py +173 -208
- runbooks/common/dry_run_framework.py +157 -155
- runbooks/common/enhanced_exception_handler.py +15 -4
- runbooks/common/enhanced_logging_example.py +50 -64
- runbooks/common/enhanced_logging_integration_example.py +65 -37
- runbooks/common/env_utils.py +16 -16
- runbooks/common/error_handling.py +40 -38
- runbooks/common/lazy_loader.py +41 -23
- runbooks/common/logging_integration_helper.py +79 -86
- runbooks/common/mcp_cost_explorer_integration.py +476 -493
- runbooks/common/mcp_integration.py +63 -74
- runbooks/common/memory_optimization.py +140 -118
- runbooks/common/module_cli_base.py +37 -58
- runbooks/common/organizations_client.py +175 -193
- runbooks/common/patterns.py +23 -25
- runbooks/common/performance_monitoring.py +67 -71
- runbooks/common/performance_optimization_engine.py +283 -274
- runbooks/common/profile_utils.py +111 -37
- runbooks/common/rich_utils.py +201 -141
- runbooks/common/sre_performance_suite.py +177 -186
- runbooks/enterprise/__init__.py +1 -1
- runbooks/enterprise/logging.py +144 -106
- runbooks/enterprise/security.py +187 -204
- runbooks/enterprise/validation.py +43 -56
- runbooks/finops/__init__.py +26 -30
- runbooks/finops/account_resolver.py +1 -1
- runbooks/finops/advanced_optimization_engine.py +980 -0
- runbooks/finops/automation_core.py +268 -231
- runbooks/finops/business_case_config.py +184 -179
- runbooks/finops/cli.py +660 -139
- runbooks/finops/commvault_ec2_analysis.py +157 -164
- runbooks/finops/compute_cost_optimizer.py +336 -320
- runbooks/finops/config.py +20 -20
- runbooks/finops/cost_optimizer.py +484 -618
- runbooks/finops/cost_processor.py +332 -214
- runbooks/finops/dashboard_runner.py +1006 -172
- runbooks/finops/ebs_cost_optimizer.py +991 -657
- runbooks/finops/elastic_ip_optimizer.py +317 -257
- runbooks/finops/enhanced_mcp_integration.py +340 -0
- runbooks/finops/enhanced_progress.py +32 -29
- runbooks/finops/enhanced_trend_visualization.py +3 -2
- runbooks/finops/enterprise_wrappers.py +223 -285
- runbooks/finops/executive_export.py +203 -160
- runbooks/finops/helpers.py +130 -288
- runbooks/finops/iam_guidance.py +1 -1
- runbooks/finops/infrastructure/__init__.py +80 -0
- runbooks/finops/infrastructure/commands.py +506 -0
- runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
- runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
- runbooks/finops/markdown_exporter.py +337 -174
- runbooks/finops/mcp_validator.py +1952 -0
- runbooks/finops/nat_gateway_optimizer.py +1512 -481
- runbooks/finops/network_cost_optimizer.py +657 -587
- runbooks/finops/notebook_utils.py +226 -188
- runbooks/finops/optimization_engine.py +1136 -0
- runbooks/finops/optimizer.py +19 -23
- runbooks/finops/rds_snapshot_optimizer.py +367 -411
- runbooks/finops/reservation_optimizer.py +427 -363
- runbooks/finops/scenario_cli_integration.py +64 -65
- runbooks/finops/scenarios.py +1277 -438
- runbooks/finops/schemas.py +218 -182
- runbooks/finops/snapshot_manager.py +2289 -0
- runbooks/finops/types.py +3 -3
- runbooks/finops/validation_framework.py +259 -265
- runbooks/finops/vpc_cleanup_exporter.py +189 -144
- runbooks/finops/vpc_cleanup_optimizer.py +591 -573
- runbooks/finops/workspaces_analyzer.py +171 -182
- runbooks/integration/__init__.py +89 -0
- runbooks/integration/mcp_integration.py +1920 -0
- runbooks/inventory/CLAUDE.md +816 -0
- runbooks/inventory/__init__.py +2 -2
- runbooks/inventory/cloud_foundations_integration.py +144 -149
- runbooks/inventory/collectors/aws_comprehensive.py +1 -1
- runbooks/inventory/collectors/aws_networking.py +109 -99
- runbooks/inventory/collectors/base.py +4 -0
- runbooks/inventory/core/collector.py +495 -313
- runbooks/inventory/drift_detection_cli.py +69 -96
- runbooks/inventory/inventory_mcp_cli.py +48 -46
- runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
- runbooks/inventory/mcp_inventory_validator.py +549 -465
- runbooks/inventory/mcp_vpc_validator.py +359 -442
- runbooks/inventory/organizations_discovery.py +55 -51
- runbooks/inventory/rich_inventory_display.py +33 -32
- runbooks/inventory/unified_validation_engine.py +278 -251
- runbooks/inventory/vpc_analyzer.py +732 -695
- runbooks/inventory/vpc_architecture_validator.py +293 -348
- runbooks/inventory/vpc_dependency_analyzer.py +382 -378
- runbooks/inventory/vpc_flow_analyzer.py +1 -1
- runbooks/main.py +49 -34
- runbooks/main_final.py +91 -60
- runbooks/main_minimal.py +22 -10
- runbooks/main_optimized.py +131 -100
- runbooks/main_ultra_minimal.py +7 -2
- runbooks/mcp/__init__.py +36 -0
- runbooks/mcp/integration.py +679 -0
- runbooks/monitoring/performance_monitor.py +9 -4
- runbooks/operate/dynamodb_operations.py +3 -1
- runbooks/operate/ec2_operations.py +145 -137
- runbooks/operate/iam_operations.py +146 -152
- runbooks/operate/networking_cost_heatmap.py +29 -8
- runbooks/operate/rds_operations.py +223 -254
- runbooks/operate/s3_operations.py +107 -118
- runbooks/operate/vpc_operations.py +646 -616
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/commons.py +10 -7
- runbooks/remediation/commvault_ec2_analysis.py +70 -66
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
- runbooks/remediation/multi_account.py +24 -21
- runbooks/remediation/rds_snapshot_list.py +86 -60
- runbooks/remediation/remediation_cli.py +92 -146
- runbooks/remediation/universal_account_discovery.py +83 -79
- runbooks/remediation/workspaces_list.py +46 -41
- runbooks/security/__init__.py +19 -0
- runbooks/security/assessment_runner.py +1150 -0
- runbooks/security/baseline_checker.py +812 -0
- runbooks/security/cloudops_automation_security_validator.py +509 -535
- runbooks/security/compliance_automation_engine.py +17 -17
- runbooks/security/config/__init__.py +2 -2
- runbooks/security/config/compliance_config.py +50 -50
- runbooks/security/config_template_generator.py +63 -76
- runbooks/security/enterprise_security_framework.py +1 -1
- runbooks/security/executive_security_dashboard.py +519 -508
- runbooks/security/multi_account_security_controls.py +959 -1210
- runbooks/security/real_time_security_monitor.py +422 -444
- runbooks/security/security_baseline_tester.py +1 -1
- runbooks/security/security_cli.py +143 -112
- runbooks/security/test_2way_validation.py +439 -0
- runbooks/security/two_way_validation_framework.py +852 -0
- runbooks/sre/production_monitoring_framework.py +167 -177
- runbooks/tdd/__init__.py +15 -0
- runbooks/tdd/cli.py +1071 -0
- runbooks/utils/__init__.py +14 -17
- runbooks/utils/logger.py +7 -2
- runbooks/utils/version_validator.py +50 -47
- runbooks/validation/__init__.py +6 -6
- runbooks/validation/cli.py +9 -3
- runbooks/validation/comprehensive_2way_validator.py +745 -704
- runbooks/validation/mcp_validator.py +906 -228
- runbooks/validation/terraform_citations_validator.py +104 -115
- runbooks/validation/terraform_drift_detector.py +447 -451
- runbooks/vpc/README.md +617 -0
- runbooks/vpc/__init__.py +8 -1
- runbooks/vpc/analyzer.py +577 -0
- runbooks/vpc/cleanup_wrapper.py +476 -413
- runbooks/vpc/cli_cloudtrail_commands.py +339 -0
- runbooks/vpc/cli_mcp_validation_commands.py +480 -0
- runbooks/vpc/cloudtrail_audit_integration.py +717 -0
- runbooks/vpc/config.py +92 -97
- runbooks/vpc/cost_engine.py +411 -148
- runbooks/vpc/cost_explorer_integration.py +553 -0
- runbooks/vpc/cross_account_session.py +101 -106
- runbooks/vpc/enhanced_mcp_validation.py +917 -0
- runbooks/vpc/eni_gate_validator.py +961 -0
- runbooks/vpc/heatmap_engine.py +185 -160
- runbooks/vpc/mcp_no_eni_validator.py +680 -639
- runbooks/vpc/nat_gateway_optimizer.py +358 -0
- runbooks/vpc/networking_wrapper.py +15 -8
- runbooks/vpc/pdca_remediation_planner.py +528 -0
- runbooks/vpc/performance_optimized_analyzer.py +219 -231
- runbooks/vpc/runbooks_adapter.py +1167 -241
- runbooks/vpc/tdd_red_phase_stubs.py +601 -0
- runbooks/vpc/test_data_loader.py +358 -0
- runbooks/vpc/tests/conftest.py +314 -4
- runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
- runbooks/vpc/tests/test_cost_engine.py +0 -2
- runbooks/vpc/topology_generator.py +326 -0
- runbooks/vpc/unified_scenarios.py +1297 -1124
- runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
- runbooks-1.1.5.dist-info/METADATA +328 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/RECORD +214 -193
- runbooks/finops/README.md +0 -414
- runbooks/finops/accuracy_cross_validator.py +0 -647
- runbooks/finops/business_cases.py +0 -950
- runbooks/finops/dashboard_router.py +0 -922
- runbooks/finops/ebs_optimizer.py +0 -973
- runbooks/finops/embedded_mcp_validator.py +0 -1629
- runbooks/finops/enhanced_dashboard_runner.py +0 -527
- runbooks/finops/finops_dashboard.py +0 -584
- runbooks/finops/finops_scenarios.py +0 -1218
- runbooks/finops/legacy_migration.py +0 -730
- runbooks/finops/multi_dashboard.py +0 -1519
- runbooks/finops/single_dashboard.py +0 -1113
- runbooks/finops/unlimited_scenarios.py +0 -393
- runbooks-1.1.4.dist-info/METADATA +0 -800
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -19,7 +19,7 @@ from .enhanced_exception_handler import (
|
|
19
19
|
EnterpriseExceptionHandler,
|
20
20
|
ErrorContext,
|
21
21
|
create_exception_handler,
|
22
|
-
enhanced_error_handling
|
22
|
+
enhanced_error_handling,
|
23
23
|
)
|
24
24
|
|
25
25
|
|
@@ -42,13 +42,14 @@ def handle_aws_errors(module_name: str = "runbooks", enable_recovery: bool = Tru
|
|
42
42
|
def my_aws_operation(profile=None, region=None, **kwargs):
|
43
43
|
# Your AWS operation code here
|
44
44
|
"""
|
45
|
+
|
45
46
|
def decorator(f: Callable) -> Callable:
|
46
47
|
@wraps(f)
|
47
48
|
def wrapper(*args, **kwargs):
|
48
49
|
# Extract common parameters for error context
|
49
|
-
profile = kwargs.get(
|
50
|
-
region = kwargs.get(
|
51
|
-
operation = kwargs.get(
|
50
|
+
profile = kwargs.get("profile")
|
51
|
+
region = kwargs.get("region", "us-east-1")
|
52
|
+
operation = kwargs.get("operation", f.__name__)
|
52
53
|
|
53
54
|
# Create error context
|
54
55
|
context = ErrorContext(
|
@@ -56,7 +57,7 @@ def handle_aws_errors(module_name: str = "runbooks", enable_recovery: bool = Tru
|
|
56
57
|
operation=operation,
|
57
58
|
aws_profile=profile,
|
58
59
|
aws_region=region,
|
59
|
-
user_context=kwargs
|
60
|
+
user_context=kwargs,
|
60
61
|
)
|
61
62
|
|
62
63
|
# Create exception handler
|
@@ -66,31 +67,31 @@ def handle_aws_errors(module_name: str = "runbooks", enable_recovery: bool = Tru
|
|
66
67
|
return f(*args, **kwargs)
|
67
68
|
|
68
69
|
except ClientError as e:
|
69
|
-
error_code = e.response.get(
|
70
|
-
service = e.operation_name if hasattr(e,
|
70
|
+
error_code = e.response.get("Error", {}).get("Code", "Unknown")
|
71
|
+
service = e.operation_name if hasattr(e, "operation_name") else "AWS"
|
71
72
|
|
72
73
|
# Handle specific AWS errors with targeted guidance
|
73
|
-
if error_code ==
|
74
|
+
if error_code == "ExpiredToken":
|
74
75
|
print_error("AWS SSO token expired")
|
75
76
|
profile_name = profile or "your-profile"
|
76
77
|
print_info(f"Run: [bold green]aws sso login --profile {profile_name}[/]")
|
77
78
|
sys.exit(1)
|
78
79
|
|
79
|
-
elif error_code in [
|
80
|
+
elif error_code in ["AccessDenied", "UnauthorizedOperation", "Forbidden"]:
|
80
81
|
print_error(f"Access denied: {e.response['Error']['Message']}")
|
81
82
|
print_warning("Check IAM permissions for this operation")
|
82
83
|
|
83
84
|
# Provide profile recommendations
|
84
|
-
if operation in [
|
85
|
+
if operation in ["finops", "cost-analysis"]:
|
85
86
|
print_info("Try using billing profile: [bold green]--profile BILLING_PROFILE[/]")
|
86
|
-
elif operation in [
|
87
|
+
elif operation in ["inventory", "organizations"]:
|
87
88
|
print_info("Try using management profile: [bold green]--profile MANAGEMENT_PROFILE[/]")
|
88
|
-
elif operation in [
|
89
|
+
elif operation in ["operate", "resource-management"]:
|
89
90
|
print_info("Try using ops profile: [bold green]--profile CENTRALISED_OPS_PROFILE[/]")
|
90
91
|
|
91
92
|
sys.exit(1)
|
92
93
|
|
93
|
-
elif error_code in [
|
94
|
+
elif error_code in ["Throttling", "ThrottlingException", "RequestLimitExceeded"]:
|
94
95
|
print_warning(f"AWS API throttling detected: {error_code}")
|
95
96
|
print_info("Implementing automatic retry with backoff...")
|
96
97
|
time.sleep(2) # Basic backoff
|
@@ -116,11 +117,12 @@ def handle_aws_errors(module_name: str = "runbooks", enable_recovery: bool = Tru
|
|
116
117
|
|
117
118
|
except Exception as e:
|
118
119
|
print_error(f"Unexpected error in {operation}: {str(e)}")
|
119
|
-
if kwargs.get(
|
120
|
+
if kwargs.get("debug") or kwargs.get("verbose"):
|
120
121
|
console.print_exception()
|
121
122
|
sys.exit(1)
|
122
123
|
|
123
124
|
return wrapper
|
125
|
+
|
124
126
|
return decorator
|
125
127
|
|
126
128
|
|
@@ -140,11 +142,12 @@ def handle_performance_errors(target_seconds: int = 30, module_name: str = "runb
|
|
140
142
|
def my_operation(**kwargs):
|
141
143
|
# Your operation code here
|
142
144
|
"""
|
145
|
+
|
143
146
|
def decorator(f: Callable) -> Callable:
|
144
147
|
@wraps(f)
|
145
148
|
def wrapper(*args, **kwargs):
|
146
149
|
start_time = time.time()
|
147
|
-
operation = kwargs.get(
|
150
|
+
operation = kwargs.get("operation", f.__name__)
|
148
151
|
|
149
152
|
try:
|
150
153
|
result = f(*args, **kwargs)
|
@@ -168,10 +171,10 @@ def handle_performance_errors(target_seconds: int = 30, module_name: str = "runb
|
|
168
171
|
module_name=module_name,
|
169
172
|
operation=operation,
|
170
173
|
performance_context={
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
}
|
174
|
+
"execution_time": execution_time,
|
175
|
+
"target_seconds": target_seconds,
|
176
|
+
"performance_ratio": execution_time / target_seconds,
|
177
|
+
},
|
175
178
|
)
|
176
179
|
|
177
180
|
handler = create_exception_handler(module_name)
|
@@ -185,6 +188,7 @@ def handle_performance_errors(target_seconds: int = 30, module_name: str = "runb
|
|
185
188
|
raise
|
186
189
|
|
187
190
|
return wrapper
|
191
|
+
|
188
192
|
return decorator
|
189
193
|
|
190
194
|
|
@@ -200,6 +204,7 @@ def handle_validation_errors(f: Callable) -> Callable:
|
|
200
204
|
def my_validation_function(data, **kwargs):
|
201
205
|
# Your validation code here
|
202
206
|
"""
|
207
|
+
|
203
208
|
@wraps(f)
|
204
209
|
def wrapper(*args, **kwargs):
|
205
210
|
try:
|
@@ -208,15 +213,15 @@ def handle_validation_errors(f: Callable) -> Callable:
|
|
208
213
|
except (ValueError, TypeError) as e:
|
209
214
|
error_msg = str(e)
|
210
215
|
|
211
|
-
if
|
216
|
+
if "profile" in error_msg.lower():
|
212
217
|
print_error(f"Profile validation error: {error_msg}")
|
213
218
|
print_info("Check available profiles: [bold green]aws configure list-profiles[/]")
|
214
219
|
|
215
|
-
elif
|
220
|
+
elif "region" in error_msg.lower():
|
216
221
|
print_error(f"Region validation error: {error_msg}")
|
217
222
|
print_info("Use valid AWS region like: [bold green]us-east-1, us-west-2, eu-west-1[/]")
|
218
223
|
|
219
|
-
elif
|
224
|
+
elif "format" in error_msg.lower():
|
220
225
|
print_error(f"Format validation error: {error_msg}")
|
221
226
|
print_info("Supported formats: [bold green]json, csv, table, pdf, markdown[/]")
|
222
227
|
|
@@ -233,8 +238,7 @@ def handle_validation_errors(f: Callable) -> Callable:
|
|
233
238
|
return wrapper
|
234
239
|
|
235
240
|
|
236
|
-
def graceful_degradation(fallback_function: Optional[Callable] = None,
|
237
|
-
enable_fallback: bool = True):
|
241
|
+
def graceful_degradation(fallback_function: Optional[Callable] = None, enable_fallback: bool = True):
|
238
242
|
"""
|
239
243
|
Decorator for graceful degradation with fallback operations.
|
240
244
|
|
@@ -258,10 +262,11 @@ def graceful_degradation(fallback_function: Optional[Callable] = None,
|
|
258
262
|
def fallback_operation(**kwargs):
|
259
263
|
# Simpler fallback version
|
260
264
|
"""
|
265
|
+
|
261
266
|
def decorator(f: Callable) -> Callable:
|
262
267
|
@wraps(f)
|
263
268
|
def wrapper(*args, **kwargs):
|
264
|
-
operation = kwargs.get(
|
269
|
+
operation = kwargs.get("operation", f.__name__)
|
265
270
|
|
266
271
|
try:
|
267
272
|
print_info(f"🚀 Attempting primary operation: {operation}")
|
@@ -306,6 +311,7 @@ def graceful_degradation(fallback_function: Optional[Callable] = None,
|
|
306
311
|
raise primary_error
|
307
312
|
|
308
313
|
return wrapper
|
314
|
+
|
309
315
|
return decorator
|
310
316
|
|
311
317
|
|
@@ -322,6 +328,7 @@ def enterprise_error_context(module_name: str):
|
|
322
328
|
ctx.set_profile("BILLING_PROFILE")
|
323
329
|
# Your operation code here
|
324
330
|
"""
|
331
|
+
|
325
332
|
class EnterpriseErrorContext:
|
326
333
|
def __init__(self, module_name: str):
|
327
334
|
self.module_name = module_name
|
@@ -345,18 +352,11 @@ def enterprise_error_context(module_name: str):
|
|
345
352
|
|
346
353
|
def __exit__(self, exc_type, exc_value, traceback):
|
347
354
|
if exc_value is not None:
|
348
|
-
enhanced_error = self.handler.handle_exception(
|
349
|
-
exc_value,
|
350
|
-
self.context,
|
351
|
-
{'context_manager': True}
|
352
|
-
)
|
355
|
+
enhanced_error = self.handler.handle_exception(exc_value, self.context, {"context_manager": True})
|
353
356
|
|
354
357
|
# Try recovery for retryable errors
|
355
358
|
if enhanced_error.retry_possible:
|
356
|
-
recovery_success = self.handler.create_error_recovery_workflow(
|
357
|
-
enhanced_error,
|
358
|
-
interactive=False
|
359
|
-
)
|
359
|
+
recovery_success = self.handler.create_error_recovery_workflow(enhanced_error, interactive=False)
|
360
360
|
if recovery_success:
|
361
361
|
return True # Suppress exception
|
362
362
|
|
@@ -381,8 +381,9 @@ def validate_aws_profile(profile: str) -> bool:
|
|
381
381
|
"""
|
382
382
|
try:
|
383
383
|
import boto3
|
384
|
+
|
384
385
|
session = boto3.Session(profile_name=profile)
|
385
|
-
sts = session.client(
|
386
|
+
sts = session.client("sts")
|
386
387
|
identity = sts.get_caller_identity()
|
387
388
|
print_success(f"Profile validation successful: {profile}")
|
388
389
|
print_info(f"Account: {identity.get('Account', 'Unknown')}")
|
@@ -400,7 +401,7 @@ def validate_aws_profile(profile: str) -> bool:
|
|
400
401
|
sys.exit(1)
|
401
402
|
|
402
403
|
|
403
|
-
def check_aws_connectivity(region: str =
|
404
|
+
def check_aws_connectivity(region: str = "us-east-1") -> bool:
|
404
405
|
"""
|
405
406
|
Check basic AWS connectivity and service availability.
|
406
407
|
|
@@ -412,8 +413,9 @@ def check_aws_connectivity(region: str = 'us-east-1') -> bool:
|
|
412
413
|
"""
|
413
414
|
try:
|
414
415
|
import boto3
|
416
|
+
|
415
417
|
session = boto3.Session()
|
416
|
-
sts = session.client(
|
418
|
+
sts = session.client("sts", region_name=region)
|
417
419
|
sts.get_caller_identity()
|
418
420
|
print_success(f"AWS connectivity verified: {region}")
|
419
421
|
return True
|
@@ -421,4 +423,4 @@ def check_aws_connectivity(region: str = 'us-east-1') -> bool:
|
|
421
423
|
except Exception as e:
|
422
424
|
print_warning(f"AWS connectivity issue: {str(e)}")
|
423
425
|
print_info("Check internet connection and AWS service status")
|
424
|
-
return False
|
426
|
+
return False
|
runbooks/common/lazy_loader.py
CHANGED
@@ -5,7 +5,7 @@ This module implements deferred initialization to eliminate startup overhead
|
|
5
5
|
for basic CLI operations like --help and --version.
|
6
6
|
|
7
7
|
Performance Goals:
|
8
|
-
- Basic CLI operations < 0.5s
|
8
|
+
- Basic CLI operations < 0.5s
|
9
9
|
- Defer AWS/MCP initialization until needed
|
10
10
|
- Clean startup without warning pollution
|
11
11
|
"""
|
@@ -19,21 +19,21 @@ import sys
|
|
19
19
|
|
20
20
|
class LazyLoader:
|
21
21
|
"""Thread-safe lazy loader for expensive imports and initializations."""
|
22
|
-
|
22
|
+
|
23
23
|
def __init__(self):
|
24
24
|
self._cache: Dict[str, Any] = {}
|
25
25
|
self._lock = threading.Lock()
|
26
|
-
|
26
|
+
|
27
27
|
def get_or_load(self, key: str, loader_func: Callable[[], Any]) -> Any:
|
28
28
|
"""Get cached value or load it if not present."""
|
29
29
|
if key in self._cache:
|
30
30
|
return self._cache[key]
|
31
|
-
|
31
|
+
|
32
32
|
with self._lock:
|
33
33
|
# Double-check pattern
|
34
34
|
if key in self._cache:
|
35
35
|
return self._cache[key]
|
36
|
-
|
36
|
+
|
37
37
|
self._cache[key] = loader_func()
|
38
38
|
return self._cache[key]
|
39
39
|
|
@@ -44,114 +44,132 @@ _lazy_loader = LazyLoader()
|
|
44
44
|
|
45
45
|
def lazy_aws_session():
|
46
46
|
"""Lazy load AWS session creation."""
|
47
|
+
|
47
48
|
def _load_aws():
|
48
49
|
import boto3
|
49
50
|
from runbooks.common.profile_utils import create_management_session
|
51
|
+
|
50
52
|
return create_management_session()
|
51
|
-
|
53
|
+
|
52
54
|
return _lazy_loader.get_or_load("aws_session", _load_aws)
|
53
55
|
|
54
56
|
|
55
57
|
def lazy_mcp_validator():
|
56
58
|
"""Lazy load MCP validator."""
|
59
|
+
|
57
60
|
def _load_mcp():
|
58
61
|
try:
|
59
62
|
from runbooks.finops.embedded_mcp_validator import FinOpsMCPValidator
|
63
|
+
|
60
64
|
return FinOpsMCPValidator()
|
61
65
|
except ImportError:
|
62
66
|
return None
|
63
|
-
|
67
|
+
|
64
68
|
return _lazy_loader.get_or_load("mcp_validator", _load_mcp)
|
65
69
|
|
66
70
|
|
67
71
|
def lazy_rich_console():
|
68
72
|
"""Lazy load Rich console."""
|
73
|
+
|
69
74
|
def _load_rich():
|
70
75
|
try:
|
71
76
|
from rich.console import Console
|
77
|
+
|
72
78
|
return Console()
|
73
79
|
except ImportError:
|
74
80
|
# Fallback console
|
75
81
|
class SimpleConsole:
|
76
82
|
def print(self, *args, **kwargs):
|
77
83
|
print(*args)
|
84
|
+
|
78
85
|
return SimpleConsole()
|
79
|
-
|
86
|
+
|
80
87
|
return _lazy_loader.get_or_load("rich_console", _load_rich)
|
81
88
|
|
82
89
|
|
83
90
|
def lazy_performance_monitor():
|
84
91
|
"""Lazy load performance monitoring."""
|
92
|
+
|
85
93
|
def _load_monitor():
|
86
94
|
from runbooks.common.performance_monitor import get_performance_benchmark
|
95
|
+
|
87
96
|
return get_performance_benchmark
|
88
|
-
|
97
|
+
|
89
98
|
return _lazy_loader.get_or_load("performance_monitor", _load_monitor)
|
90
99
|
|
91
100
|
|
92
101
|
def lazy_pricing_api():
|
93
102
|
"""Lazy load pricing API without startup warnings."""
|
103
|
+
|
94
104
|
def _load_pricing():
|
95
105
|
try:
|
96
106
|
from runbooks.common.aws_pricing_api import PricingAPI
|
107
|
+
|
97
108
|
return PricingAPI()
|
98
109
|
except Exception:
|
99
110
|
# Return fallback pricing without warnings during basic operations
|
100
111
|
class FallbackPricing:
|
101
112
|
def get_nat_gateway_price(self, region="us-east-1"):
|
102
113
|
return 32.4 # Standard fallback rate
|
114
|
+
|
103
115
|
return FallbackPricing()
|
104
|
-
|
116
|
+
|
105
117
|
return _lazy_loader.get_or_load("pricing_api", _load_pricing)
|
106
118
|
|
107
119
|
|
108
120
|
def lazy_inventory_collector():
|
109
121
|
"""Lazy load inventory collector."""
|
122
|
+
|
110
123
|
def _load_collector():
|
111
124
|
from runbooks.inventory.core.collector import InventoryCollector
|
125
|
+
|
112
126
|
return InventoryCollector
|
113
|
-
|
127
|
+
|
114
128
|
return _lazy_loader.get_or_load("inventory_collector", _load_collector)
|
115
129
|
|
116
130
|
|
117
131
|
def lazy_import(module_name: str, attribute: Optional[str] = None):
|
118
132
|
"""Lazy import a module or module attribute."""
|
119
133
|
cache_key = f"{module_name}.{attribute}" if attribute else module_name
|
120
|
-
|
134
|
+
|
121
135
|
def _load_module():
|
122
136
|
module = importlib.import_module(module_name)
|
123
137
|
if attribute:
|
124
138
|
return getattr(module, attribute)
|
125
139
|
return module
|
126
|
-
|
140
|
+
|
127
141
|
return _lazy_loader.get_or_load(cache_key, _load_module)
|
128
142
|
|
129
143
|
|
130
144
|
def requires_aws(func):
|
131
145
|
"""Decorator to ensure AWS session is loaded before function execution."""
|
146
|
+
|
132
147
|
@wraps(func)
|
133
148
|
def wrapper(*args, **kwargs):
|
134
149
|
lazy_aws_session() # Ensure AWS is loaded
|
135
150
|
return func(*args, **kwargs)
|
151
|
+
|
136
152
|
return wrapper
|
137
153
|
|
138
154
|
|
139
155
|
def requires_mcp(func):
|
140
156
|
"""Decorator to ensure MCP validator is loaded before function execution."""
|
157
|
+
|
141
158
|
@wraps(func)
|
142
159
|
def wrapper(*args, **kwargs):
|
143
160
|
lazy_mcp_validator() # Ensure MCP is loaded
|
144
161
|
return func(*args, **kwargs)
|
162
|
+
|
145
163
|
return wrapper
|
146
164
|
|
147
165
|
|
148
166
|
def fast_startup_mode() -> bool:
|
149
167
|
"""Check if we're in fast startup mode (basic operations only)."""
|
150
168
|
import sys
|
151
|
-
|
169
|
+
|
152
170
|
# Basic operations that should be fast
|
153
|
-
fast_operations = {
|
154
|
-
|
171
|
+
fast_operations = {"--help", "-h", "--version", "-V", "help"}
|
172
|
+
|
155
173
|
# Check if any CLI args match fast operations
|
156
174
|
return any(arg in fast_operations for arg in sys.argv)
|
157
175
|
|
@@ -171,16 +189,16 @@ def defer_expensive_imports():
|
|
171
189
|
# Only defer if we're not in fast startup mode
|
172
190
|
if fast_startup_mode():
|
173
191
|
return
|
174
|
-
|
192
|
+
|
175
193
|
# Defer expensive imports for basic operations
|
176
194
|
modules_to_defer = [
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
195
|
+
"runbooks.finops.embedded_mcp_validator",
|
196
|
+
"runbooks.common.aws_pricing_api",
|
197
|
+
"runbooks.inventory.core.collector",
|
198
|
+
"runbooks.cfat.runner",
|
181
199
|
]
|
182
|
-
|
200
|
+
|
183
201
|
for module in modules_to_defer:
|
184
202
|
if module in sys.modules:
|
185
203
|
# Replace with lazy loader
|
186
|
-
sys.modules[module] = lazy_import(module)
|
204
|
+
sys.modules[module] = lazy_import(module)
|