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.
- runbooks/__init__.py +1 -1
- runbooks/cfat/README.md +12 -1
- runbooks/cfat/__init__.py +1 -1
- runbooks/cfat/assessment/compliance.py +4 -1
- runbooks/cfat/assessment/runner.py +42 -34
- runbooks/cfat/models.py +1 -1
- runbooks/cloudops/__init__.py +123 -0
- runbooks/cloudops/base.py +385 -0
- runbooks/cloudops/cost_optimizer.py +811 -0
- runbooks/cloudops/infrastructure_optimizer.py +29 -0
- runbooks/cloudops/interfaces.py +828 -0
- runbooks/cloudops/lifecycle_manager.py +29 -0
- runbooks/cloudops/mcp_cost_validation.py +678 -0
- runbooks/cloudops/models.py +251 -0
- runbooks/cloudops/monitoring_automation.py +29 -0
- runbooks/cloudops/notebook_framework.py +676 -0
- runbooks/cloudops/security_enforcer.py +449 -0
- runbooks/common/__init__.py +152 -0
- runbooks/common/accuracy_validator.py +1039 -0
- runbooks/common/context_logger.py +440 -0
- runbooks/common/cross_module_integration.py +594 -0
- runbooks/common/enhanced_exception_handler.py +1108 -0
- runbooks/common/enterprise_audit_integration.py +634 -0
- runbooks/common/mcp_cost_explorer_integration.py +900 -0
- runbooks/common/mcp_integration.py +548 -0
- runbooks/common/performance_monitor.py +387 -0
- runbooks/common/profile_utils.py +216 -0
- runbooks/common/rich_utils.py +172 -1
- runbooks/feedback/user_feedback_collector.py +440 -0
- runbooks/finops/README.md +377 -458
- runbooks/finops/__init__.py +4 -21
- runbooks/finops/account_resolver.py +279 -0
- runbooks/finops/accuracy_cross_validator.py +638 -0
- runbooks/finops/aws_client.py +721 -36
- runbooks/finops/budget_integration.py +313 -0
- runbooks/finops/cli.py +59 -5
- runbooks/finops/cost_optimizer.py +1340 -0
- runbooks/finops/cost_processor.py +211 -37
- runbooks/finops/dashboard_router.py +900 -0
- runbooks/finops/dashboard_runner.py +990 -232
- runbooks/finops/embedded_mcp_validator.py +288 -0
- runbooks/finops/enhanced_dashboard_runner.py +8 -7
- runbooks/finops/enhanced_progress.py +327 -0
- runbooks/finops/enhanced_trend_visualization.py +423 -0
- runbooks/finops/finops_dashboard.py +184 -1829
- runbooks/finops/helpers.py +509 -196
- runbooks/finops/iam_guidance.py +400 -0
- runbooks/finops/markdown_exporter.py +466 -0
- runbooks/finops/multi_dashboard.py +1502 -0
- runbooks/finops/optimizer.py +15 -15
- runbooks/finops/profile_processor.py +2 -2
- runbooks/finops/runbooks.inventory.organizations_discovery.log +0 -0
- runbooks/finops/runbooks.security.report_generator.log +0 -0
- runbooks/finops/runbooks.security.run_script.log +0 -0
- runbooks/finops/runbooks.security.security_export.log +0 -0
- runbooks/finops/schemas.py +589 -0
- runbooks/finops/service_mapping.py +195 -0
- runbooks/finops/single_dashboard.py +710 -0
- runbooks/finops/tests/test_reference_images_validation.py +1 -1
- runbooks/inventory/README.md +12 -1
- runbooks/inventory/core/collector.py +157 -29
- runbooks/inventory/list_ec2_instances.py +9 -6
- runbooks/inventory/list_ssm_parameters.py +10 -10
- runbooks/inventory/organizations_discovery.py +210 -164
- runbooks/inventory/rich_inventory_display.py +74 -107
- runbooks/inventory/run_on_multi_accounts.py +13 -13
- runbooks/inventory/runbooks.inventory.organizations_discovery.log +0 -0
- runbooks/inventory/runbooks.security.security_export.log +0 -0
- runbooks/main.py +1371 -240
- runbooks/metrics/dora_metrics_engine.py +711 -17
- runbooks/monitoring/performance_monitor.py +433 -0
- runbooks/operate/README.md +394 -0
- runbooks/operate/base.py +215 -47
- runbooks/operate/ec2_operations.py +435 -5
- runbooks/operate/iam_operations.py +598 -3
- runbooks/operate/privatelink_operations.py +1 -1
- runbooks/operate/rds_operations.py +508 -0
- runbooks/operate/s3_operations.py +508 -0
- runbooks/operate/vpc_endpoints.py +1 -1
- runbooks/remediation/README.md +489 -13
- runbooks/remediation/base.py +5 -3
- runbooks/remediation/commons.py +8 -4
- runbooks/security/ENTERPRISE_SECURITY_FRAMEWORK.md +506 -0
- runbooks/security/README.md +12 -1
- runbooks/security/__init__.py +265 -33
- runbooks/security/cloudops_automation_security_validator.py +1164 -0
- runbooks/security/compliance_automation.py +12 -10
- runbooks/security/compliance_automation_engine.py +1021 -0
- runbooks/security/enterprise_security_framework.py +930 -0
- runbooks/security/enterprise_security_policies.json +293 -0
- runbooks/security/executive_security_dashboard.py +1247 -0
- runbooks/security/integration_test_enterprise_security.py +879 -0
- runbooks/security/module_security_integrator.py +641 -0
- runbooks/security/multi_account_security_controls.py +2254 -0
- runbooks/security/real_time_security_monitor.py +1196 -0
- runbooks/security/report_generator.py +1 -1
- runbooks/security/run_script.py +4 -8
- runbooks/security/security_baseline_tester.py +39 -52
- runbooks/security/security_export.py +99 -120
- runbooks/sre/README.md +472 -0
- runbooks/sre/__init__.py +33 -0
- runbooks/sre/mcp_reliability_engine.py +1049 -0
- runbooks/sre/performance_optimization_engine.py +1032 -0
- runbooks/sre/production_monitoring_framework.py +584 -0
- runbooks/sre/reliability_monitoring_framework.py +1011 -0
- runbooks/validation/__init__.py +2 -2
- runbooks/validation/benchmark.py +154 -149
- runbooks/validation/cli.py +159 -147
- runbooks/validation/mcp_validator.py +291 -248
- runbooks/vpc/README.md +478 -0
- runbooks/vpc/__init__.py +2 -2
- runbooks/vpc/manager_interface.py +366 -351
- runbooks/vpc/networking_wrapper.py +68 -36
- runbooks/vpc/rich_formatters.py +22 -8
- runbooks-0.9.1.dist-info/METADATA +308 -0
- {runbooks-0.7.9.dist-info ā runbooks-0.9.1.dist-info}/RECORD +120 -59
- {runbooks-0.7.9.dist-info ā runbooks-0.9.1.dist-info}/entry_points.txt +1 -1
- runbooks/finops/cross_validation.py +0 -375
- runbooks-0.7.9.dist-info/METADATA +0 -636
- {runbooks-0.7.9.dist-info ā runbooks-0.9.1.dist-info}/WHEEL +0 -0
- {runbooks-0.7.9.dist-info ā runbooks-0.9.1.dist-info}/licenses/LICENSE +0 -0
- {runbooks-0.7.9.dist-info ā runbooks-0.9.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,385 @@
|
|
1
|
+
"""
|
2
|
+
Base CloudOps Class with Enterprise Patterns
|
3
|
+
|
4
|
+
Provides common functionality for all CloudOps automation classes including:
|
5
|
+
- Rich CLI integration with enterprise UX standards
|
6
|
+
- Performance monitoring and benchmarking
|
7
|
+
- AWS profile management with multi-account support
|
8
|
+
- Error handling and logging
|
9
|
+
- Business metrics collection
|
10
|
+
|
11
|
+
Strategic Alignment:
|
12
|
+
- Integrates with existing runbooks architecture
|
13
|
+
- Follows Rich CLI standards from rich_utils.py
|
14
|
+
- Supports multi-profile enterprise configurations
|
15
|
+
"""
|
16
|
+
|
17
|
+
import asyncio
|
18
|
+
import time
|
19
|
+
from typing import Dict, List, Optional, Any, Union
|
20
|
+
import boto3
|
21
|
+
from botocore.exceptions import ClientError, NoCredentialsError, ProfileNotFound
|
22
|
+
from dataclasses import dataclass
|
23
|
+
from datetime import datetime
|
24
|
+
|
25
|
+
from runbooks.common.rich_utils import (
|
26
|
+
console, print_header, print_success, print_error, print_warning, print_info,
|
27
|
+
create_table, create_progress_bar, format_cost, create_panel, STATUS_INDICATORS
|
28
|
+
)
|
29
|
+
from .models import (
|
30
|
+
BusinessScenario, ExecutionMode, RiskLevel,
|
31
|
+
ProfileConfiguration, CloudOpsExecutionResult, BusinessMetrics, ResourceImpact
|
32
|
+
)
|
33
|
+
|
34
|
+
@dataclass
|
35
|
+
class PerformanceBenchmark:
|
36
|
+
"""Performance benchmarking for enterprise operations."""
|
37
|
+
operation_name: str
|
38
|
+
start_time: float
|
39
|
+
end_time: Optional[float] = None
|
40
|
+
success: bool = True
|
41
|
+
error_message: Optional[str] = None
|
42
|
+
|
43
|
+
@property
|
44
|
+
def duration(self) -> float:
|
45
|
+
"""Calculate operation duration."""
|
46
|
+
if self.end_time:
|
47
|
+
return self.end_time - self.start_time
|
48
|
+
return time.time() - self.start_time
|
49
|
+
|
50
|
+
class CloudOpsBase:
|
51
|
+
"""
|
52
|
+
Base class for all CloudOps automation scenarios.
|
53
|
+
|
54
|
+
Provides enterprise-grade functionality including:
|
55
|
+
- Rich CLI integration with consistent UX
|
56
|
+
- Performance monitoring and benchmarking
|
57
|
+
- Multi-account AWS profile management
|
58
|
+
- Error handling with business-focused messaging
|
59
|
+
- Audit trail and logging
|
60
|
+
"""
|
61
|
+
|
62
|
+
def __init__(
|
63
|
+
self,
|
64
|
+
profile: str = "default",
|
65
|
+
dry_run: bool = True,
|
66
|
+
execution_mode: ExecutionMode = ExecutionMode.DRY_RUN
|
67
|
+
):
|
68
|
+
"""
|
69
|
+
Initialize CloudOps base class.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
profile: AWS profile name for operations
|
73
|
+
dry_run: Enable dry-run mode (safe analysis only)
|
74
|
+
execution_mode: Execution mode (dry_run/execute/validate_only)
|
75
|
+
"""
|
76
|
+
self.profile = profile
|
77
|
+
self.dry_run = dry_run
|
78
|
+
self.execution_mode = execution_mode
|
79
|
+
|
80
|
+
# Performance monitoring
|
81
|
+
self.benchmarks: List[PerformanceBenchmark] = []
|
82
|
+
self.session_start_time = time.time()
|
83
|
+
|
84
|
+
# AWS session management
|
85
|
+
self.session: Optional[boto3.Session] = None
|
86
|
+
self.available_regions: List[str] = []
|
87
|
+
|
88
|
+
# Business metrics collection
|
89
|
+
self.resources_analyzed = 0
|
90
|
+
self.resources_impacted: List[ResourceImpact] = []
|
91
|
+
|
92
|
+
# Initialize AWS session
|
93
|
+
self._initialize_aws_session()
|
94
|
+
|
95
|
+
def _initialize_aws_session(self) -> None:
|
96
|
+
"""Initialize AWS session with profile validation."""
|
97
|
+
try:
|
98
|
+
self.session = boto3.Session(profile_name=self.profile)
|
99
|
+
|
100
|
+
# Validate session by getting caller identity
|
101
|
+
sts = self.session.client('sts')
|
102
|
+
identity = sts.get_caller_identity()
|
103
|
+
|
104
|
+
self.account_id = identity.get('Account', 'unknown')
|
105
|
+
self.user_arn = identity.get('Arn', 'unknown')
|
106
|
+
|
107
|
+
print_success(f"AWS session initialized for profile: {self.profile}")
|
108
|
+
print_info(f"Account ID: {self.account_id}")
|
109
|
+
|
110
|
+
except ProfileNotFound:
|
111
|
+
error_msg = f"AWS profile '{self.profile}' not found in local configuration"
|
112
|
+
print_error(error_msg)
|
113
|
+
raise ValueError(error_msg)
|
114
|
+
|
115
|
+
except NoCredentialsError:
|
116
|
+
error_msg = f"No valid credentials found for profile '{self.profile}'"
|
117
|
+
print_error(error_msg)
|
118
|
+
raise ValueError(error_msg)
|
119
|
+
|
120
|
+
except ClientError as e:
|
121
|
+
error_msg = f"AWS authentication failed for profile '{self.profile}': {str(e)}"
|
122
|
+
print_error(error_msg)
|
123
|
+
raise ValueError(error_msg)
|
124
|
+
|
125
|
+
def _get_available_regions(self, service_name: str = 'ec2') -> List[str]:
|
126
|
+
"""Get available AWS regions for a service."""
|
127
|
+
if not self.available_regions:
|
128
|
+
try:
|
129
|
+
client = self.session.client(service_name, region_name='us-east-1')
|
130
|
+
response = client.describe_regions()
|
131
|
+
self.available_regions = [region['RegionName'] for region in response['Regions']]
|
132
|
+
except Exception as e:
|
133
|
+
print_warning(f"Could not fetch available regions: {str(e)}")
|
134
|
+
# Fallback to common regions
|
135
|
+
self.available_regions = [
|
136
|
+
'us-east-1', 'us-west-2', 'eu-west-1', 'ap-southeast-1'
|
137
|
+
]
|
138
|
+
return self.available_regions
|
139
|
+
|
140
|
+
def start_benchmark(self, operation_name: str) -> PerformanceBenchmark:
|
141
|
+
"""Start performance benchmarking for an operation."""
|
142
|
+
benchmark = PerformanceBenchmark(
|
143
|
+
operation_name=operation_name,
|
144
|
+
start_time=time.time()
|
145
|
+
)
|
146
|
+
self.benchmarks.append(benchmark)
|
147
|
+
return benchmark
|
148
|
+
|
149
|
+
def complete_benchmark(
|
150
|
+
self,
|
151
|
+
benchmark: PerformanceBenchmark,
|
152
|
+
success: bool = True,
|
153
|
+
error_message: Optional[str] = None
|
154
|
+
) -> None:
|
155
|
+
"""Complete performance benchmarking."""
|
156
|
+
benchmark.end_time = time.time()
|
157
|
+
benchmark.success = success
|
158
|
+
benchmark.error_message = error_message
|
159
|
+
|
160
|
+
duration = benchmark.duration
|
161
|
+
|
162
|
+
# Rich CLI performance feedback
|
163
|
+
if success:
|
164
|
+
if duration < 30: # < 30s target for single account
|
165
|
+
print_success(f"ā
{benchmark.operation_name} completed ({duration:.1f}s)")
|
166
|
+
elif duration < 120: # < 120s target for multi-account
|
167
|
+
print_warning(f"ā ļø {benchmark.operation_name} completed ({duration:.1f}s) - approaching time limit")
|
168
|
+
else:
|
169
|
+
print_error(f"ā° {benchmark.operation_name} completed ({duration:.1f}s) - exceeds performance target")
|
170
|
+
else:
|
171
|
+
print_error(f"ā {benchmark.operation_name} failed ({duration:.1f}s): {error_message}")
|
172
|
+
|
173
|
+
async def execute_with_monitoring(
|
174
|
+
self,
|
175
|
+
operation_name: str,
|
176
|
+
operation_func,
|
177
|
+
*args,
|
178
|
+
**kwargs
|
179
|
+
) -> Any:
|
180
|
+
"""
|
181
|
+
Execute an operation with comprehensive monitoring.
|
182
|
+
|
183
|
+
Args:
|
184
|
+
operation_name: Human-readable operation name
|
185
|
+
operation_func: Async function to execute
|
186
|
+
*args, **kwargs: Arguments to pass to operation_func
|
187
|
+
|
188
|
+
Returns:
|
189
|
+
Result of operation_func execution
|
190
|
+
"""
|
191
|
+
benchmark = self.start_benchmark(operation_name)
|
192
|
+
|
193
|
+
try:
|
194
|
+
with console.status(f"[cyan]Executing {operation_name}..."):
|
195
|
+
if asyncio.iscoroutinefunction(operation_func):
|
196
|
+
result = await operation_func(*args, **kwargs)
|
197
|
+
else:
|
198
|
+
result = operation_func(*args, **kwargs)
|
199
|
+
|
200
|
+
self.complete_benchmark(benchmark, success=True)
|
201
|
+
return result
|
202
|
+
|
203
|
+
except Exception as e:
|
204
|
+
error_message = str(e)
|
205
|
+
self.complete_benchmark(benchmark, success=False, error_message=error_message)
|
206
|
+
|
207
|
+
# Rich CLI error display
|
208
|
+
print_error(f"Operation failed: {operation_name}")
|
209
|
+
print_error(f"Error details: {error_message}")
|
210
|
+
|
211
|
+
raise
|
212
|
+
|
213
|
+
def create_resource_impact(
|
214
|
+
self,
|
215
|
+
resource_type: str,
|
216
|
+
resource_id: str,
|
217
|
+
region: str,
|
218
|
+
estimated_cost: Optional[float] = None,
|
219
|
+
projected_savings: Optional[float] = None,
|
220
|
+
risk_level: RiskLevel = RiskLevel.LOW,
|
221
|
+
modification_required: bool = False,
|
222
|
+
**kwargs
|
223
|
+
) -> ResourceImpact:
|
224
|
+
"""
|
225
|
+
Create a standardized ResourceImpact object.
|
226
|
+
|
227
|
+
Args:
|
228
|
+
resource_type: AWS resource type (e.g., 'nat-gateway', 'ec2-instance')
|
229
|
+
resource_id: Unique resource identifier
|
230
|
+
region: AWS region
|
231
|
+
estimated_cost: Current monthly cost estimate
|
232
|
+
projected_savings: Projected monthly savings
|
233
|
+
risk_level: Risk level for modification
|
234
|
+
modification_required: Whether resource needs modification
|
235
|
+
**kwargs: Additional ResourceImpact fields
|
236
|
+
|
237
|
+
Returns:
|
238
|
+
ResourceImpact object with standardized business metrics
|
239
|
+
"""
|
240
|
+
impact = ResourceImpact(
|
241
|
+
resource_type=resource_type,
|
242
|
+
resource_id=resource_id,
|
243
|
+
region=region,
|
244
|
+
account_id=self.account_id,
|
245
|
+
estimated_monthly_cost=estimated_cost,
|
246
|
+
projected_savings=projected_savings,
|
247
|
+
risk_level=risk_level,
|
248
|
+
modification_required=modification_required,
|
249
|
+
**kwargs
|
250
|
+
)
|
251
|
+
|
252
|
+
self.resources_impacted.append(impact)
|
253
|
+
self.resources_analyzed += 1
|
254
|
+
|
255
|
+
return impact
|
256
|
+
|
257
|
+
def display_execution_summary(self, result: CloudOpsExecutionResult) -> None:
|
258
|
+
"""
|
259
|
+
Display Rich CLI execution summary for business stakeholders.
|
260
|
+
|
261
|
+
Args:
|
262
|
+
result: CloudOpsExecutionResult with business metrics
|
263
|
+
"""
|
264
|
+
# Executive Summary Panel
|
265
|
+
summary_content = (
|
266
|
+
f"š Resources Analyzed: {result.resources_analyzed:,}\n"
|
267
|
+
f"šÆ Resources Impacted: {len(result.resources_impacted):,}\n"
|
268
|
+
f"š° Monthly Savings: {format_cost(result.business_metrics.total_monthly_savings)}\n"
|
269
|
+
f"ā±ļø Execution Time: {result.execution_time:.1f}s\n"
|
270
|
+
f"š”ļø Risk Level: {result.business_metrics.overall_risk_level.value.title()}"
|
271
|
+
)
|
272
|
+
|
273
|
+
if result.business_metrics.roi_percentage:
|
274
|
+
summary_content += f"\nš ROI: {result.business_metrics.roi_percentage:.1f}%"
|
275
|
+
|
276
|
+
summary_panel = create_panel(
|
277
|
+
summary_content,
|
278
|
+
title="Executive Business Impact Summary",
|
279
|
+
border_style="green" if result.success else "red"
|
280
|
+
)
|
281
|
+
console.print(summary_panel)
|
282
|
+
|
283
|
+
# Performance Benchmarks Table
|
284
|
+
if self.benchmarks:
|
285
|
+
perf_table = create_table(
|
286
|
+
title="Performance Benchmarks",
|
287
|
+
columns=[
|
288
|
+
{"name": "Operation", "style": "cyan"},
|
289
|
+
{"name": "Duration", "style": "yellow"},
|
290
|
+
{"name": "Status", "style": "green"}
|
291
|
+
]
|
292
|
+
)
|
293
|
+
|
294
|
+
for benchmark in self.benchmarks:
|
295
|
+
status_icon = "ā
" if benchmark.success else "ā"
|
296
|
+
duration_str = f"{benchmark.duration:.1f}s"
|
297
|
+
|
298
|
+
# Color code performance
|
299
|
+
if benchmark.duration < 30:
|
300
|
+
duration_style = "green"
|
301
|
+
elif benchmark.duration < 120:
|
302
|
+
duration_style = "yellow"
|
303
|
+
else:
|
304
|
+
duration_style = "red"
|
305
|
+
|
306
|
+
perf_table.add_row(
|
307
|
+
benchmark.operation_name,
|
308
|
+
f"[{duration_style}]{duration_str}[/{duration_style}]",
|
309
|
+
status_icon
|
310
|
+
)
|
311
|
+
|
312
|
+
console.print(perf_table)
|
313
|
+
|
314
|
+
# Recommendations Display
|
315
|
+
if result.recommendations:
|
316
|
+
recommendations_text = "\n".join([f"⢠{rec}" for rec in result.recommendations])
|
317
|
+
rec_panel = create_panel(
|
318
|
+
recommendations_text,
|
319
|
+
title="Strategic Recommendations",
|
320
|
+
border_style="blue"
|
321
|
+
)
|
322
|
+
console.print(rec_panel)
|
323
|
+
|
324
|
+
def create_business_metrics(
|
325
|
+
self,
|
326
|
+
total_savings: float = 0.0,
|
327
|
+
implementation_cost: Optional[float] = None,
|
328
|
+
overall_risk: RiskLevel = RiskLevel.LOW
|
329
|
+
) -> BusinessMetrics:
|
330
|
+
"""
|
331
|
+
Create standardized business metrics for executive reporting.
|
332
|
+
|
333
|
+
Args:
|
334
|
+
total_savings: Total projected monthly savings
|
335
|
+
implementation_cost: One-time implementation cost
|
336
|
+
overall_risk: Overall risk level for the operation
|
337
|
+
|
338
|
+
Returns:
|
339
|
+
BusinessMetrics object with calculated ROI and business impact
|
340
|
+
"""
|
341
|
+
# Calculate ROI if implementation cost is provided
|
342
|
+
roi_percentage = None
|
343
|
+
payback_period = None
|
344
|
+
|
345
|
+
if implementation_cost and implementation_cost > 0 and total_savings > 0:
|
346
|
+
annual_savings = total_savings * 12
|
347
|
+
roi_percentage = (annual_savings / implementation_cost - 1) * 100
|
348
|
+
payback_period = int(implementation_cost / total_savings)
|
349
|
+
|
350
|
+
return BusinessMetrics(
|
351
|
+
total_monthly_savings=total_savings,
|
352
|
+
implementation_cost=implementation_cost,
|
353
|
+
roi_percentage=roi_percentage,
|
354
|
+
payback_period_months=payback_period,
|
355
|
+
overall_risk_level=overall_risk,
|
356
|
+
operational_efficiency_gain=80.0 if total_savings > 1000 else 50.0, # Estimate based on savings
|
357
|
+
manual_effort_reduction=90.0, # High automation benefit
|
358
|
+
business_continuity_impact="minimal"
|
359
|
+
)
|
360
|
+
|
361
|
+
def get_session_summary(self) -> Dict[str, Any]:
|
362
|
+
"""Get comprehensive session summary for audit trail."""
|
363
|
+
total_duration = time.time() - self.session_start_time
|
364
|
+
successful_ops = sum(1 for b in self.benchmarks if b.success)
|
365
|
+
failed_ops = len(self.benchmarks) - successful_ops
|
366
|
+
|
367
|
+
return {
|
368
|
+
"profile_used": self.profile,
|
369
|
+
"account_id": getattr(self, 'account_id', 'unknown'),
|
370
|
+
"execution_mode": self.execution_mode.value,
|
371
|
+
"total_session_duration": total_duration,
|
372
|
+
"resources_analyzed": self.resources_analyzed,
|
373
|
+
"resources_impacted": len(self.resources_impacted),
|
374
|
+
"successful_operations": successful_ops,
|
375
|
+
"failed_operations": failed_ops,
|
376
|
+
"performance_benchmarks": [
|
377
|
+
{
|
378
|
+
"operation": b.operation_name,
|
379
|
+
"duration": b.duration,
|
380
|
+
"success": b.success,
|
381
|
+
"error": b.error_message
|
382
|
+
}
|
383
|
+
for b in self.benchmarks
|
384
|
+
]
|
385
|
+
}
|