runbooks 0.7.6__py3-none-any.whl → 0.7.9__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/base.py +5 -1
- runbooks/cfat/__init__.py +8 -4
- runbooks/cfat/assessment/collectors.py +171 -14
- runbooks/cfat/assessment/compliance.py +871 -0
- runbooks/cfat/assessment/runner.py +122 -11
- runbooks/cfat/models.py +6 -2
- runbooks/common/logger.py +14 -0
- runbooks/common/rich_utils.py +451 -0
- runbooks/enterprise/__init__.py +68 -0
- runbooks/enterprise/error_handling.py +411 -0
- runbooks/enterprise/logging.py +439 -0
- runbooks/enterprise/multi_tenant.py +583 -0
- runbooks/finops/README.md +468 -241
- runbooks/finops/__init__.py +39 -3
- runbooks/finops/cli.py +83 -18
- runbooks/finops/cross_validation.py +375 -0
- runbooks/finops/dashboard_runner.py +812 -164
- runbooks/finops/enhanced_dashboard_runner.py +525 -0
- runbooks/finops/finops_dashboard.py +1892 -0
- runbooks/finops/helpers.py +485 -51
- runbooks/finops/optimizer.py +823 -0
- runbooks/finops/tests/__init__.py +19 -0
- runbooks/finops/tests/results_test_finops_dashboard.xml +1 -0
- runbooks/finops/tests/run_comprehensive_tests.py +421 -0
- runbooks/finops/tests/run_tests.py +305 -0
- runbooks/finops/tests/test_finops_dashboard.py +705 -0
- runbooks/finops/tests/test_integration.py +477 -0
- runbooks/finops/tests/test_performance.py +380 -0
- runbooks/finops/tests/test_performance_benchmarks.py +500 -0
- runbooks/finops/tests/test_reference_images_validation.py +867 -0
- runbooks/finops/tests/test_single_account_features.py +715 -0
- runbooks/finops/tests/validate_test_suite.py +220 -0
- runbooks/finops/types.py +1 -1
- runbooks/hitl/enhanced_workflow_engine.py +725 -0
- runbooks/inventory/artifacts/scale-optimize-status.txt +12 -0
- runbooks/inventory/collectors/aws_comprehensive.py +442 -0
- runbooks/inventory/collectors/enterprise_scale.py +281 -0
- runbooks/inventory/core/collector.py +172 -13
- runbooks/inventory/discovery.md +1 -1
- runbooks/inventory/list_ec2_instances.py +18 -20
- runbooks/inventory/list_ssm_parameters.py +31 -3
- runbooks/inventory/organizations_discovery.py +1269 -0
- runbooks/inventory/rich_inventory_display.py +393 -0
- runbooks/inventory/run_on_multi_accounts.py +35 -19
- runbooks/inventory/runbooks.security.report_generator.log +0 -0
- runbooks/inventory/runbooks.security.run_script.log +0 -0
- runbooks/inventory/vpc_flow_analyzer.py +1030 -0
- runbooks/main.py +2215 -119
- runbooks/metrics/dora_metrics_engine.py +599 -0
- runbooks/operate/__init__.py +2 -2
- runbooks/operate/base.py +122 -10
- runbooks/operate/deployment_framework.py +1032 -0
- runbooks/operate/deployment_validator.py +853 -0
- runbooks/operate/dynamodb_operations.py +10 -6
- runbooks/operate/ec2_operations.py +319 -11
- runbooks/operate/executive_dashboard.py +779 -0
- runbooks/operate/mcp_integration.py +750 -0
- runbooks/operate/nat_gateway_operations.py +1120 -0
- runbooks/operate/networking_cost_heatmap.py +685 -0
- runbooks/operate/privatelink_operations.py +940 -0
- runbooks/operate/s3_operations.py +10 -6
- runbooks/operate/vpc_endpoints.py +644 -0
- runbooks/operate/vpc_operations.py +1038 -0
- runbooks/remediation/__init__.py +2 -2
- runbooks/remediation/acm_remediation.py +1 -1
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/cloudtrail_remediation.py +1 -1
- runbooks/remediation/cognito_remediation.py +1 -1
- runbooks/remediation/dynamodb_remediation.py +1 -1
- runbooks/remediation/ec2_remediation.py +1 -1
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -1
- runbooks/remediation/kms_enable_key_rotation.py +1 -1
- runbooks/remediation/kms_remediation.py +1 -1
- runbooks/remediation/lambda_remediation.py +1 -1
- runbooks/remediation/multi_account.py +1 -1
- runbooks/remediation/rds_remediation.py +1 -1
- runbooks/remediation/s3_block_public_access.py +1 -1
- runbooks/remediation/s3_enable_access_logging.py +1 -1
- runbooks/remediation/s3_encryption.py +1 -1
- runbooks/remediation/s3_remediation.py +1 -1
- runbooks/remediation/vpc_remediation.py +475 -0
- runbooks/security/__init__.py +3 -1
- runbooks/security/compliance_automation.py +632 -0
- runbooks/security/report_generator.py +10 -0
- runbooks/security/run_script.py +31 -5
- runbooks/security/security_baseline_tester.py +169 -30
- runbooks/security/security_export.py +477 -0
- runbooks/validation/__init__.py +10 -0
- runbooks/validation/benchmark.py +484 -0
- runbooks/validation/cli.py +356 -0
- runbooks/validation/mcp_validator.py +768 -0
- runbooks/vpc/__init__.py +38 -0
- runbooks/vpc/config.py +212 -0
- runbooks/vpc/cost_engine.py +347 -0
- runbooks/vpc/heatmap_engine.py +605 -0
- runbooks/vpc/manager_interface.py +634 -0
- runbooks/vpc/networking_wrapper.py +1260 -0
- runbooks/vpc/rich_formatters.py +679 -0
- runbooks/vpc/tests/__init__.py +5 -0
- runbooks/vpc/tests/conftest.py +356 -0
- runbooks/vpc/tests/test_cli_integration.py +530 -0
- runbooks/vpc/tests/test_config.py +458 -0
- runbooks/vpc/tests/test_cost_engine.py +479 -0
- runbooks/vpc/tests/test_networking_wrapper.py +512 -0
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/METADATA +40 -12
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/RECORD +111 -50
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/WHEEL +0 -0
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/entry_points.txt +0 -0
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/licenses/LICENSE +0 -0
- {runbooks-0.7.6.dist-info → runbooks-0.7.9.dist-info}/top_level.txt +0 -0
runbooks/operate/base.py
CHANGED
@@ -11,14 +11,30 @@ from dataclasses import dataclass, field
|
|
11
11
|
from datetime import datetime
|
12
12
|
from enum import Enum
|
13
13
|
from typing import Any, Dict, List, Optional, Union
|
14
|
+
import time
|
14
15
|
|
15
16
|
import boto3
|
16
17
|
from botocore.exceptions import ClientError, NoCredentialsError
|
17
18
|
from loguru import logger
|
19
|
+
from rich.console import Console
|
20
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn
|
21
|
+
from rich.panel import Panel
|
22
|
+
from rich.table import Table
|
18
23
|
|
19
24
|
from runbooks.inventory.models.account import AWSAccount
|
20
25
|
from runbooks.inventory.utils.aws_helpers import aws_api_retry, get_boto3_session
|
21
26
|
|
27
|
+
# Enterprise 4-Profile Architecture - Proven FinOps Patterns
|
28
|
+
ENTERPRISE_PROFILES = {
|
29
|
+
"BILLING_PROFILE": "ams-admin-Billing-ReadOnlyAccess-909135376185",
|
30
|
+
"MANAGEMENT_PROFILE": "ams-admin-ReadOnlyAccess-909135376185",
|
31
|
+
"CENTRALISED_OPS_PROFILE": "ams-centralised-ops-ReadOnlyAccess-335083429030",
|
32
|
+
"SINGLE_ACCOUNT_PROFILE": "ams-shared-services-non-prod-ReadOnlyAccess-499201730520"
|
33
|
+
}
|
34
|
+
|
35
|
+
# Rich console instance for consistent formatting
|
36
|
+
console = Console()
|
37
|
+
|
22
38
|
|
23
39
|
class OperationStatus(Enum):
|
24
40
|
"""Status of an AWS operation."""
|
@@ -118,18 +134,28 @@ class BaseOperation(ABC):
|
|
118
134
|
|
119
135
|
def __init__(self, profile: Optional[str] = None, region: Optional[str] = None, dry_run: bool = False):
|
120
136
|
"""
|
121
|
-
Initialize base operation class.
|
137
|
+
Initialize base operation class with enterprise patterns.
|
122
138
|
|
123
139
|
Args:
|
124
|
-
profile: AWS profile name for authentication
|
140
|
+
profile: AWS profile name for authentication (supports ENTERPRISE_PROFILES)
|
125
141
|
region: AWS region for operations
|
126
142
|
dry_run: Enable dry-run mode for safe testing
|
127
143
|
"""
|
128
|
-
|
144
|
+
# Support enterprise profile shortcuts
|
145
|
+
if profile in ENTERPRISE_PROFILES:
|
146
|
+
self.profile = ENTERPRISE_PROFILES[profile]
|
147
|
+
console.print(f"[blue]Using enterprise profile: {profile} -> {self.profile}[/blue]")
|
148
|
+
else:
|
149
|
+
self.profile = profile
|
150
|
+
|
129
151
|
self.region = region or "us-east-1"
|
130
152
|
self.dry_run = dry_run
|
131
153
|
self._session = None
|
132
154
|
self._clients = {}
|
155
|
+
|
156
|
+
# Performance benchmarking
|
157
|
+
self._operation_start_time = None
|
158
|
+
self._performance_target = 2.0 # <2s target for operate operations
|
133
159
|
|
134
160
|
@property
|
135
161
|
def session(self) -> boto3.Session:
|
@@ -185,7 +211,7 @@ class BaseOperation(ABC):
|
|
185
211
|
|
186
212
|
def confirm_operation(self, context: OperationContext, resource_id: str, operation_type: str) -> bool:
|
187
213
|
"""
|
188
|
-
Request user confirmation for destructive operations.
|
214
|
+
Request user confirmation for destructive operations with Rich CLI.
|
189
215
|
|
190
216
|
Args:
|
191
217
|
context: Operation context
|
@@ -196,16 +222,24 @@ class BaseOperation(ABC):
|
|
196
222
|
True if operation is confirmed
|
197
223
|
"""
|
198
224
|
if context.dry_run:
|
199
|
-
|
225
|
+
console.print(Panel(
|
226
|
+
f"[yellow]Would perform {operation_type} on {resource_id}[/yellow]",
|
227
|
+
title="🏃 DRY-RUN MODE",
|
228
|
+
border_style="yellow"
|
229
|
+
))
|
200
230
|
return True
|
201
231
|
|
202
232
|
if context.force or not self.requires_confirmation:
|
203
233
|
return True
|
204
234
|
|
205
|
-
#
|
206
|
-
|
207
|
-
f"Destructive operation: {operation_type}
|
208
|
-
|
235
|
+
# Rich CLI confirmation display
|
236
|
+
console.print(Panel(
|
237
|
+
f"[red]⚠️ Destructive operation: {operation_type}[/red]\n"
|
238
|
+
f"[white]Resource: {resource_id}[/white]\n"
|
239
|
+
f"[white]Account: {context.account.account_id}[/white]",
|
240
|
+
title="🚨 CONFIRMATION REQUIRED",
|
241
|
+
border_style="red"
|
242
|
+
))
|
209
243
|
return True # Simplified for this implementation
|
210
244
|
|
211
245
|
@aws_api_retry
|
@@ -307,5 +341,83 @@ class BaseOperation(ABC):
|
|
307
341
|
List of historical operation results
|
308
342
|
"""
|
309
343
|
# In a real implementation, this would query a database or log store
|
310
|
-
|
344
|
+
console.print(f"[blue]📊 Operation history requested for {resource_id or 'all resources'}[/blue]")
|
311
345
|
return []
|
346
|
+
|
347
|
+
def start_performance_benchmark(self) -> None:
|
348
|
+
"""Start performance timing for operation benchmarking."""
|
349
|
+
self._operation_start_time = time.time()
|
350
|
+
|
351
|
+
def end_performance_benchmark(self, operation_name: str) -> float:
|
352
|
+
"""
|
353
|
+
End performance timing and display results.
|
354
|
+
|
355
|
+
Args:
|
356
|
+
operation_name: Name of the operation for reporting
|
357
|
+
|
358
|
+
Returns:
|
359
|
+
Elapsed time in seconds
|
360
|
+
"""
|
361
|
+
if self._operation_start_time is None:
|
362
|
+
return 0.0
|
363
|
+
|
364
|
+
elapsed_time = time.time() - self._operation_start_time
|
365
|
+
|
366
|
+
# Performance validation against target
|
367
|
+
if elapsed_time <= self._performance_target:
|
368
|
+
console.print(f"[green]⚡ {operation_name} completed in {elapsed_time:.2f}s (target: {self._performance_target}s) ✅[/green]")
|
369
|
+
else:
|
370
|
+
console.print(f"[yellow]⚠️ {operation_name} completed in {elapsed_time:.2f}s (exceeded target: {self._performance_target}s)[/yellow]")
|
371
|
+
|
372
|
+
self._operation_start_time = None
|
373
|
+
return elapsed_time
|
374
|
+
|
375
|
+
def display_operation_summary(self, results: List[OperationResult]) -> None:
|
376
|
+
"""
|
377
|
+
Display operation summary using Rich table formatting.
|
378
|
+
|
379
|
+
Args:
|
380
|
+
results: List of operation results to summarize
|
381
|
+
"""
|
382
|
+
if not results:
|
383
|
+
console.print("[yellow]No operations to display[/yellow]")
|
384
|
+
return
|
385
|
+
|
386
|
+
table = Table(title="🔧 Operation Summary")
|
387
|
+
table.add_column("Operation", style="cyan")
|
388
|
+
table.add_column("Resource", style="magenta")
|
389
|
+
table.add_column("Status", style="green")
|
390
|
+
table.add_column("Duration", style="blue")
|
391
|
+
|
392
|
+
success_count = 0
|
393
|
+
total_count = len(results)
|
394
|
+
|
395
|
+
for result in results:
|
396
|
+
status_icon = "✅" if result.success else "❌"
|
397
|
+
status_text = f"{status_icon} {result.status.value}"
|
398
|
+
|
399
|
+
duration = "N/A"
|
400
|
+
if result.completed_at and result.started_at:
|
401
|
+
elapsed = (result.completed_at - result.started_at).total_seconds()
|
402
|
+
duration = f"{elapsed:.2f}s"
|
403
|
+
|
404
|
+
if result.success:
|
405
|
+
success_count += 1
|
406
|
+
|
407
|
+
table.add_row(
|
408
|
+
result.operation_type,
|
409
|
+
result.resource_id,
|
410
|
+
status_text,
|
411
|
+
duration
|
412
|
+
)
|
413
|
+
|
414
|
+
console.print(table)
|
415
|
+
|
416
|
+
# Success rate summary
|
417
|
+
success_rate = (success_count / total_count) * 100 if total_count > 0 else 0
|
418
|
+
if success_rate >= 95:
|
419
|
+
console.print(f"[green]🎯 Success Rate: {success_rate:.1f}% ({success_count}/{total_count}) - Excellent![/green]")
|
420
|
+
elif success_rate >= 90:
|
421
|
+
console.print(f"[yellow]📊 Success Rate: {success_rate:.1f}% ({success_count}/{total_count}) - Good[/yellow]")
|
422
|
+
else:
|
423
|
+
console.print(f"[red]⚠️ Success Rate: {success_rate:.1f}% ({success_count}/{total_count}) - Needs Attention[/red]")
|