runbooks 0.7.7__py3-none-any.whl → 0.9.0__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 +2 -2
- runbooks/cfat/README.md +12 -1
- runbooks/cfat/__init__.py +8 -4
- runbooks/cfat/assessment/collectors.py +171 -14
- runbooks/cfat/assessment/compliance.py +546 -522
- runbooks/cfat/assessment/runner.py +129 -10
- runbooks/cfat/models.py +6 -2
- 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/logger.py +14 -0
- runbooks/common/mcp_integration.py +539 -0
- runbooks/common/performance_monitor.py +387 -0
- runbooks/common/profile_utils.py +216 -0
- runbooks/common/rich_utils.py +622 -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/feedback/user_feedback_collector.py +440 -0
- runbooks/finops/README.md +129 -14
- runbooks/finops/__init__.py +22 -3
- 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 +90 -33
- runbooks/finops/cost_processor.py +211 -37
- runbooks/finops/dashboard_router.py +900 -0
- runbooks/finops/dashboard_runner.py +1334 -399
- runbooks/finops/embedded_mcp_validator.py +288 -0
- runbooks/finops/enhanced_dashboard_runner.py +526 -0
- runbooks/finops/enhanced_progress.py +327 -0
- runbooks/finops/enhanced_trend_visualization.py +423 -0
- runbooks/finops/finops_dashboard.py +41 -0
- runbooks/finops/helpers.py +639 -323
- 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 +396 -395
- 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/service_mapping.py +195 -0
- runbooks/finops/single_dashboard.py +710 -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/README.md +12 -1
- runbooks/inventory/artifacts/scale-optimize-status.txt +12 -0
- runbooks/inventory/collectors/aws_comprehensive.py +192 -185
- runbooks/inventory/collectors/enterprise_scale.py +281 -0
- runbooks/inventory/core/collector.py +299 -12
- runbooks/inventory/list_ec2_instances.py +21 -20
- runbooks/inventory/list_ssm_parameters.py +31 -3
- runbooks/inventory/organizations_discovery.py +1315 -0
- runbooks/inventory/rich_inventory_display.py +360 -0
- runbooks/inventory/run_on_multi_accounts.py +32 -16
- 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 +4171 -1615
- runbooks/metrics/dora_metrics_engine.py +1293 -0
- runbooks/monitoring/performance_monitor.py +433 -0
- runbooks/operate/README.md +394 -0
- runbooks/operate/__init__.py +2 -2
- runbooks/operate/base.py +291 -11
- 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 +321 -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/README.md +489 -13
- 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/commons.py +8 -4
- 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/ENTERPRISE_SECURITY_FRAMEWORK.md +506 -0
- runbooks/security/README.md +12 -1
- runbooks/security/__init__.py +166 -33
- runbooks/security/compliance_automation.py +634 -0
- runbooks/security/compliance_automation_engine.py +1021 -0
- runbooks/security/enterprise_security_framework.py +931 -0
- runbooks/security/enterprise_security_policies.json +293 -0
- runbooks/security/integration_test_enterprise_security.py +879 -0
- runbooks/security/module_security_integrator.py +641 -0
- runbooks/security/report_generator.py +10 -0
- runbooks/security/run_script.py +27 -5
- runbooks/security/security_baseline_tester.py +153 -27
- runbooks/security/security_export.py +456 -0
- 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/reliability_monitoring_framework.py +1011 -0
- runbooks/validation/__init__.py +10 -0
- runbooks/validation/benchmark.py +489 -0
- runbooks/validation/cli.py +368 -0
- runbooks/validation/mcp_validator.py +797 -0
- runbooks/vpc/README.md +478 -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 +649 -0
- runbooks/vpc/networking_wrapper.py +1289 -0
- runbooks/vpc/rich_formatters.py +693 -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.7.dist-info → runbooks-0.9.0.dist-info}/METADATA +175 -65
- {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/RECORD +157 -60
- {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/entry_points.txt +1 -1
- {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/WHEEL +0 -0
- {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,622 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Rich Library Utilities for CloudOps Runbooks Platform
|
4
|
+
|
5
|
+
This module provides centralized Rich components and styling for consistent,
|
6
|
+
beautiful terminal output across all CloudOps Runbooks modules.
|
7
|
+
|
8
|
+
Features:
|
9
|
+
- Custom CloudOps theme and color schemes
|
10
|
+
- Reusable UI components (headers, footers, panels)
|
11
|
+
- Standard progress bars and spinners
|
12
|
+
- Consistent table styles
|
13
|
+
- Error/warning/success message formatting
|
14
|
+
- Tree displays for hierarchical data
|
15
|
+
- Layout templates for complex displays
|
16
|
+
|
17
|
+
Author: CloudOps Runbooks Team
|
18
|
+
Version: 0.7.8
|
19
|
+
"""
|
20
|
+
|
21
|
+
from datetime import datetime
|
22
|
+
from typing import Any, Dict, List, Optional, Union
|
23
|
+
|
24
|
+
from rich import box
|
25
|
+
from rich.columns import Columns
|
26
|
+
from rich.console import Console
|
27
|
+
from rich.layout import Layout
|
28
|
+
from rich.markdown import Markdown
|
29
|
+
from rich.panel import Panel
|
30
|
+
from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn, TimeElapsedColumn
|
31
|
+
from rich.rule import Rule
|
32
|
+
from rich.style import Style
|
33
|
+
from rich.syntax import Syntax
|
34
|
+
from rich.table import Table
|
35
|
+
from rich.text import Text
|
36
|
+
from rich.theme import Theme
|
37
|
+
from rich.tree import Tree
|
38
|
+
|
39
|
+
# CloudOps Custom Theme
|
40
|
+
CLOUDOPS_THEME = Theme(
|
41
|
+
{
|
42
|
+
"info": "cyan",
|
43
|
+
"success": "green bold",
|
44
|
+
"warning": "yellow bold",
|
45
|
+
"error": "red bold",
|
46
|
+
"critical": "red bold reverse",
|
47
|
+
"highlight": "bright_blue bold",
|
48
|
+
"header": "bright_cyan bold",
|
49
|
+
"subheader": "cyan",
|
50
|
+
"dim": "dim white",
|
51
|
+
"resource": "bright_magenta",
|
52
|
+
"cost": "bright_green",
|
53
|
+
"security": "bright_red",
|
54
|
+
"compliance": "bright_yellow",
|
55
|
+
}
|
56
|
+
)
|
57
|
+
|
58
|
+
# Initialize console with custom theme
|
59
|
+
console = Console(theme=CLOUDOPS_THEME)
|
60
|
+
|
61
|
+
# Status indicators
|
62
|
+
STATUS_INDICATORS = {
|
63
|
+
"success": "🟢",
|
64
|
+
"warning": "🟡",
|
65
|
+
"error": "🔴",
|
66
|
+
"info": "🔵",
|
67
|
+
"pending": "⚪",
|
68
|
+
"running": "🔄",
|
69
|
+
"stopped": "⏹️",
|
70
|
+
"critical": "🚨",
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
def get_console() -> Console:
|
75
|
+
"""Get the themed console instance."""
|
76
|
+
return console
|
77
|
+
|
78
|
+
|
79
|
+
def get_context_aware_console():
|
80
|
+
"""
|
81
|
+
Get a context-aware console that adapts to CLI vs Jupyter environments.
|
82
|
+
|
83
|
+
This function is a bridge to the context_logger module to maintain
|
84
|
+
backward compatibility while enabling context awareness.
|
85
|
+
|
86
|
+
Returns:
|
87
|
+
Context-aware console instance
|
88
|
+
"""
|
89
|
+
try:
|
90
|
+
from runbooks.common.context_logger import get_context_console
|
91
|
+
|
92
|
+
return get_context_console()
|
93
|
+
except ImportError:
|
94
|
+
# Fallback to regular console if context_logger not available
|
95
|
+
return console
|
96
|
+
|
97
|
+
|
98
|
+
def print_header(title: str, version: str = "0.7.8") -> None:
|
99
|
+
"""
|
100
|
+
Print a consistent header for all modules.
|
101
|
+
|
102
|
+
Args:
|
103
|
+
title: Module title
|
104
|
+
version: Module version
|
105
|
+
"""
|
106
|
+
header_text = Text()
|
107
|
+
header_text.append("CloudOps Runbooks ", style="header")
|
108
|
+
header_text.append(f"| {title} ", style="subheader")
|
109
|
+
header_text.append(f"v{version}", style="dim")
|
110
|
+
|
111
|
+
console.print()
|
112
|
+
console.print(Panel(header_text, box=box.DOUBLE, style="header"))
|
113
|
+
console.print()
|
114
|
+
|
115
|
+
|
116
|
+
def print_banner() -> None:
|
117
|
+
"""Print the CloudOps Runbooks ASCII banner."""
|
118
|
+
banner = r"""
|
119
|
+
╔═══════════════════════════════════════════════════════════════╗
|
120
|
+
║ _____ _ _ ____ ____ ║
|
121
|
+
║ / ____| | | |/ __ \ | _ \ ║
|
122
|
+
║ | | | | ___ _ _ __| | | | |_ __ ___ | |_) |_ _ __ ║
|
123
|
+
║ | | | |/ _ \| | | |/ _` | | | | '_ \/ __| | _ <| | | '_ \ ║
|
124
|
+
║ | |____| | (_) | |_| | (_| | |__| | |_) \__ \ | |_) | |_| | | |║
|
125
|
+
║ \_____|_|\___/ \__,_|\__,_|\____/| .__/|___/ |____/ \__,_|_| |║
|
126
|
+
║ | | ║
|
127
|
+
║ Enterprise AWS Automation |_| Platform v0.7.8 ║
|
128
|
+
╚═══════════════════════════════════════════════════════════════╝
|
129
|
+
"""
|
130
|
+
console.print(banner, style="header")
|
131
|
+
|
132
|
+
|
133
|
+
def create_table(
|
134
|
+
title: Optional[str] = None,
|
135
|
+
columns: List[Dict[str, Any]] = None,
|
136
|
+
show_header: bool = True,
|
137
|
+
show_footer: bool = False,
|
138
|
+
box_style: Any = box.ROUNDED,
|
139
|
+
title_style: str = "header",
|
140
|
+
) -> Table:
|
141
|
+
"""
|
142
|
+
Create a consistent styled table.
|
143
|
+
|
144
|
+
Args:
|
145
|
+
title: Table title
|
146
|
+
columns: List of column definitions [{"name": "Col1", "style": "cyan", "justify": "left"}]
|
147
|
+
show_header: Show header row
|
148
|
+
show_footer: Show footer row
|
149
|
+
box_style: Rich box style
|
150
|
+
title_style: Style for title
|
151
|
+
|
152
|
+
Returns:
|
153
|
+
Configured Table object
|
154
|
+
"""
|
155
|
+
table = Table(
|
156
|
+
title=title,
|
157
|
+
show_header=show_header,
|
158
|
+
show_footer=show_footer,
|
159
|
+
box=box_style,
|
160
|
+
title_style=title_style,
|
161
|
+
header_style="bold",
|
162
|
+
row_styles=["none", "dim"], # Alternating row colors
|
163
|
+
)
|
164
|
+
|
165
|
+
if columns:
|
166
|
+
for col in columns:
|
167
|
+
table.add_column(
|
168
|
+
col.get("name", ""),
|
169
|
+
style=col.get("style", ""),
|
170
|
+
justify=col.get("justify", "left"),
|
171
|
+
no_wrap=col.get("no_wrap", False),
|
172
|
+
)
|
173
|
+
|
174
|
+
return table
|
175
|
+
|
176
|
+
|
177
|
+
def create_progress_bar(description: str = "Processing") -> Progress:
|
178
|
+
"""
|
179
|
+
Create a consistent progress bar.
|
180
|
+
|
181
|
+
Args:
|
182
|
+
description: Progress bar description
|
183
|
+
|
184
|
+
Returns:
|
185
|
+
Configured Progress object
|
186
|
+
"""
|
187
|
+
return Progress(
|
188
|
+
SpinnerColumn(spinner_name="dots", style="cyan"),
|
189
|
+
TextColumn("[progress.description]{task.description}"),
|
190
|
+
BarColumn(bar_width=40, style="cyan", complete_style="green"),
|
191
|
+
TaskProgressColumn(),
|
192
|
+
TimeElapsedColumn(),
|
193
|
+
console=console,
|
194
|
+
transient=True,
|
195
|
+
)
|
196
|
+
|
197
|
+
|
198
|
+
def print_status(message: str, status: str = "info") -> None:
|
199
|
+
"""
|
200
|
+
Print a status message with appropriate styling and indicator.
|
201
|
+
|
202
|
+
Args:
|
203
|
+
message: Status message
|
204
|
+
status: Status type (success, warning, error, info, critical)
|
205
|
+
"""
|
206
|
+
indicator = STATUS_INDICATORS.get(status, "")
|
207
|
+
style = status if status in ["success", "warning", "error", "critical", "info"] else "info"
|
208
|
+
console.print(f"{indicator} {message}", style=style)
|
209
|
+
|
210
|
+
|
211
|
+
def print_error(message: str, exception: Optional[Exception] = None) -> None:
|
212
|
+
"""
|
213
|
+
Print an error message with optional exception details.
|
214
|
+
|
215
|
+
Args:
|
216
|
+
message: Error message
|
217
|
+
exception: Optional exception object
|
218
|
+
"""
|
219
|
+
console.print(f"{STATUS_INDICATORS['error']} {message}", style="error")
|
220
|
+
if exception:
|
221
|
+
console.print(f" Details: {str(exception)}", style="dim")
|
222
|
+
|
223
|
+
|
224
|
+
def print_success(message: str) -> None:
|
225
|
+
"""
|
226
|
+
Print a success message.
|
227
|
+
|
228
|
+
Args:
|
229
|
+
message: Success message
|
230
|
+
"""
|
231
|
+
console.print(f"{STATUS_INDICATORS['success']} {message}", style="success")
|
232
|
+
|
233
|
+
|
234
|
+
def print_warning(message: str) -> None:
|
235
|
+
"""
|
236
|
+
Print a warning message.
|
237
|
+
|
238
|
+
Args:
|
239
|
+
message: Warning message
|
240
|
+
"""
|
241
|
+
console.print(f"{STATUS_INDICATORS['warning']} {message}", style="warning")
|
242
|
+
|
243
|
+
|
244
|
+
def print_info(message: str) -> None:
|
245
|
+
"""
|
246
|
+
Print an info message.
|
247
|
+
|
248
|
+
Args:
|
249
|
+
message: Info message
|
250
|
+
"""
|
251
|
+
console.print(f"{STATUS_INDICATORS['info']} {message}", style="info")
|
252
|
+
|
253
|
+
|
254
|
+
def create_tree(label: str, style: str = "cyan") -> Tree:
|
255
|
+
"""
|
256
|
+
Create a tree for hierarchical display.
|
257
|
+
|
258
|
+
Args:
|
259
|
+
label: Root label
|
260
|
+
style: Tree style
|
261
|
+
|
262
|
+
Returns:
|
263
|
+
Tree object
|
264
|
+
"""
|
265
|
+
return Tree(label, style=style, guide_style="dim")
|
266
|
+
|
267
|
+
|
268
|
+
def print_separator(label: Optional[str] = None, style: str = "dim") -> None:
|
269
|
+
"""
|
270
|
+
Print a separator line.
|
271
|
+
|
272
|
+
Args:
|
273
|
+
label: Optional label for separator
|
274
|
+
style: Separator style
|
275
|
+
"""
|
276
|
+
if label:
|
277
|
+
console.print(Rule(label, style=style))
|
278
|
+
else:
|
279
|
+
console.print(Rule(style=style))
|
280
|
+
|
281
|
+
|
282
|
+
def create_panel(
|
283
|
+
content: Any,
|
284
|
+
title: Optional[str] = None,
|
285
|
+
subtitle: Optional[str] = None,
|
286
|
+
border_style: str = "cyan",
|
287
|
+
padding: int = 1,
|
288
|
+
) -> Panel:
|
289
|
+
"""
|
290
|
+
Create a panel for highlighting content.
|
291
|
+
|
292
|
+
Args:
|
293
|
+
content: Panel content
|
294
|
+
title: Panel title
|
295
|
+
subtitle: Panel subtitle
|
296
|
+
border_style: Border color/style
|
297
|
+
padding: Internal padding
|
298
|
+
|
299
|
+
Returns:
|
300
|
+
Panel object
|
301
|
+
"""
|
302
|
+
return Panel(
|
303
|
+
content, title=title, subtitle=subtitle, border_style=border_style, padding=(padding, padding), expand=False
|
304
|
+
)
|
305
|
+
|
306
|
+
|
307
|
+
def format_cost(amount: float, currency: str = "USD") -> Text:
|
308
|
+
"""
|
309
|
+
Format a cost value with appropriate styling.
|
310
|
+
|
311
|
+
Args:
|
312
|
+
amount: Cost amount
|
313
|
+
currency: Currency code
|
314
|
+
|
315
|
+
Returns:
|
316
|
+
Formatted Text object
|
317
|
+
"""
|
318
|
+
text = Text()
|
319
|
+
symbol = "$" if currency == "USD" else currency
|
320
|
+
if amount >= 10000:
|
321
|
+
text.append(f"{symbol}{amount:,.2f}", style="cost bold")
|
322
|
+
elif amount >= 1000:
|
323
|
+
text.append(f"{symbol}{amount:,.2f}", style="cost")
|
324
|
+
else:
|
325
|
+
text.append(f"{symbol}{amount:,.2f}", style="dim")
|
326
|
+
return text
|
327
|
+
|
328
|
+
|
329
|
+
def format_resource_count(count: int, resource_type: str) -> Text:
|
330
|
+
"""
|
331
|
+
Format a resource count with appropriate styling.
|
332
|
+
|
333
|
+
Args:
|
334
|
+
count: Resource count
|
335
|
+
resource_type: Type of resource
|
336
|
+
|
337
|
+
Returns:
|
338
|
+
Formatted Text object
|
339
|
+
"""
|
340
|
+
text = Text()
|
341
|
+
if count == 0:
|
342
|
+
text.append(f"{count} {resource_type}", style="dim")
|
343
|
+
elif count > 100:
|
344
|
+
text.append(f"{count} {resource_type}", style="warning")
|
345
|
+
else:
|
346
|
+
text.append(f"{count} {resource_type}", style="resource")
|
347
|
+
return text
|
348
|
+
|
349
|
+
|
350
|
+
def create_display_profile_name(profile_name: str, max_length: int = 25, context_aware: bool = True) -> str:
|
351
|
+
"""
|
352
|
+
Create user-friendly display version of AWS profile names for better readability.
|
353
|
+
|
354
|
+
This function intelligently truncates long enterprise profile names while preserving
|
355
|
+
meaningful information for identification. Full names remain available for AWS API calls.
|
356
|
+
|
357
|
+
Examples:
|
358
|
+
'ams-admin-Billing-ReadOnlyAccess-909135376185' → 'ams-admin-Billing-9091...'
|
359
|
+
'ams-centralised-ops-ReadOnlyAccess-335083429030' → 'ams-centralised-ops-3350...'
|
360
|
+
'short-profile' → 'short-profile' (no truncation needed)
|
361
|
+
|
362
|
+
Args:
|
363
|
+
profile_name: Full AWS profile name
|
364
|
+
max_length: Maximum display length (default 25 for table formatting)
|
365
|
+
context_aware: Whether to adapt truncation based on execution context
|
366
|
+
|
367
|
+
Returns:
|
368
|
+
User-friendly display name for console output
|
369
|
+
"""
|
370
|
+
if not profile_name or len(profile_name) <= max_length:
|
371
|
+
return profile_name
|
372
|
+
|
373
|
+
# Context-aware length adjustment
|
374
|
+
if context_aware:
|
375
|
+
try:
|
376
|
+
from runbooks.common.context_logger import ExecutionContext, get_context_config
|
377
|
+
|
378
|
+
config = get_context_config()
|
379
|
+
|
380
|
+
if config.context == ExecutionContext.JUPYTER:
|
381
|
+
# Shorter names for notebook tables
|
382
|
+
max_length = min(max_length, 20)
|
383
|
+
elif config.context == ExecutionContext.CLI:
|
384
|
+
# Slightly longer for CLI terminals
|
385
|
+
max_length = min(max_length + 5, 30)
|
386
|
+
except ImportError:
|
387
|
+
# Fallback if context_logger not available
|
388
|
+
pass
|
389
|
+
|
390
|
+
# Smart truncation strategy for AWS profile patterns
|
391
|
+
# Common patterns: ams-{type}-{service}-{permissions}-{account_id}
|
392
|
+
|
393
|
+
if "-" in profile_name:
|
394
|
+
parts = profile_name.split("-")
|
395
|
+
|
396
|
+
# Strategy 1: Keep meaningful prefix + account ID suffix
|
397
|
+
if len(parts) >= 4 and parts[-1].isdigit():
|
398
|
+
# Enterprise pattern: ams-admin-Billing-ReadOnlyAccess-909135376185
|
399
|
+
account_id = parts[-1]
|
400
|
+
prefix_parts = parts[:-2] # Skip permissions part for brevity
|
401
|
+
|
402
|
+
prefix = "-".join(prefix_parts)
|
403
|
+
account_short = account_id[:4] # First 4 digits of account ID
|
404
|
+
|
405
|
+
truncated = f"{prefix}-{account_short}..."
|
406
|
+
|
407
|
+
if len(truncated) <= max_length:
|
408
|
+
return truncated
|
409
|
+
|
410
|
+
# Strategy 2: Keep first few meaningful parts
|
411
|
+
meaningful_parts = []
|
412
|
+
current_length = 0
|
413
|
+
|
414
|
+
for part in parts:
|
415
|
+
# Skip common noise words but keep meaningful ones
|
416
|
+
if part.lower() in ["readonlyaccess", "fullaccess", "access"]:
|
417
|
+
continue
|
418
|
+
|
419
|
+
part_with_sep = f"{part}-" if meaningful_parts else part
|
420
|
+
if current_length + len(part_with_sep) + 3 <= max_length: # +3 for "..."
|
421
|
+
meaningful_parts.append(part)
|
422
|
+
current_length += len(part_with_sep)
|
423
|
+
else:
|
424
|
+
break
|
425
|
+
|
426
|
+
if len(meaningful_parts) >= 2:
|
427
|
+
return f"{'-'.join(meaningful_parts)}..."
|
428
|
+
|
429
|
+
# Strategy 3: Simple prefix truncation with ellipsis
|
430
|
+
return f"{profile_name[: max_length - 3]}..."
|
431
|
+
|
432
|
+
|
433
|
+
def format_profile_name(profile_name: str, style: str = "cyan", display_max_length: int = 25) -> Text:
|
434
|
+
"""
|
435
|
+
Format profile name with consistent styling and intelligent truncation.
|
436
|
+
|
437
|
+
This function creates a Rich Text object with:
|
438
|
+
- Smart truncation for display readability
|
439
|
+
- Consistent styling across all modules
|
440
|
+
- Hover-friendly formatting (full name in tooltip would be future enhancement)
|
441
|
+
|
442
|
+
Args:
|
443
|
+
profile_name: AWS profile name
|
444
|
+
style: Rich style for the profile name
|
445
|
+
display_max_length: Maximum length for display
|
446
|
+
|
447
|
+
Returns:
|
448
|
+
Rich Text object with formatted profile name
|
449
|
+
"""
|
450
|
+
display_name = create_display_profile_name(profile_name, display_max_length)
|
451
|
+
|
452
|
+
text = Text()
|
453
|
+
|
454
|
+
# Add visual indicators for truncated names
|
455
|
+
if display_name.endswith("..."):
|
456
|
+
# Truncated name - use slightly different style
|
457
|
+
text.append(display_name, style=f"{style} italic")
|
458
|
+
else:
|
459
|
+
# Full name - normal style
|
460
|
+
text.append(display_name, style=style)
|
461
|
+
|
462
|
+
return text
|
463
|
+
|
464
|
+
|
465
|
+
def format_account_name(
|
466
|
+
account_name: str, account_id: str, style: str = "bold bright_white", max_length: int = 35
|
467
|
+
) -> str:
|
468
|
+
"""
|
469
|
+
Format account name with ID for consistent enterprise display in tables.
|
470
|
+
|
471
|
+
This function provides consistent account display formatting across all FinOps dashboards:
|
472
|
+
- Account name with intelligent truncation
|
473
|
+
- Account ID as secondary line for identification
|
474
|
+
- Rich markup for professional presentation
|
475
|
+
|
476
|
+
Args:
|
477
|
+
account_name: Resolved account name from Organizations API
|
478
|
+
account_id: AWS account ID
|
479
|
+
style: Rich style for the account name
|
480
|
+
max_length: Maximum display length for account name
|
481
|
+
|
482
|
+
Returns:
|
483
|
+
Formatted display string with Rich markup
|
484
|
+
|
485
|
+
Example:
|
486
|
+
"Data Management"
|
487
|
+
"123456789012"
|
488
|
+
"""
|
489
|
+
if account_name and account_name != account_id and len(account_name.strip()) > 0:
|
490
|
+
# We have a resolved account name - format with both name and ID
|
491
|
+
display_name = account_name if len(account_name) <= max_length else account_name[: max_length - 3] + "..."
|
492
|
+
return f"[{style}]{display_name}[/]\n[dim]{account_id}[/]"
|
493
|
+
else:
|
494
|
+
# No resolved name available - show account ID prominently
|
495
|
+
return f"[{style}]{account_id}[/]"
|
496
|
+
|
497
|
+
|
498
|
+
def create_layout(sections: Dict[str, Any]) -> Layout:
|
499
|
+
"""
|
500
|
+
Create a layout for complex displays.
|
501
|
+
|
502
|
+
Args:
|
503
|
+
sections: Dictionary of layout sections
|
504
|
+
|
505
|
+
Returns:
|
506
|
+
Layout object
|
507
|
+
"""
|
508
|
+
layout = Layout()
|
509
|
+
|
510
|
+
# Example layout structure
|
511
|
+
if "header" in sections:
|
512
|
+
layout.split_column(Layout(name="header", size=3), Layout(name="body"), Layout(name="footer", size=3))
|
513
|
+
layout["header"].update(sections["header"])
|
514
|
+
|
515
|
+
if "body" in sections:
|
516
|
+
if isinstance(sections["body"], dict):
|
517
|
+
layout["body"].split_row(*[Layout(name=k) for k in sections["body"].keys()])
|
518
|
+
for key, content in sections["body"].items():
|
519
|
+
layout["body"][key].update(content)
|
520
|
+
else:
|
521
|
+
layout["body"].update(sections["body"])
|
522
|
+
|
523
|
+
if "footer" in sections:
|
524
|
+
layout["footer"].update(sections["footer"])
|
525
|
+
|
526
|
+
return layout
|
527
|
+
|
528
|
+
|
529
|
+
def print_json(data: Dict[str, Any], title: Optional[str] = None) -> None:
|
530
|
+
"""
|
531
|
+
Print JSON data with syntax highlighting.
|
532
|
+
|
533
|
+
Args:
|
534
|
+
data: JSON data to display
|
535
|
+
title: Optional title
|
536
|
+
"""
|
537
|
+
import json
|
538
|
+
|
539
|
+
json_str = json.dumps(data, indent=2)
|
540
|
+
syntax = Syntax(json_str, "json", theme="monokai", line_numbers=False)
|
541
|
+
if title:
|
542
|
+
console.print(Panel(syntax, title=title, border_style="cyan"))
|
543
|
+
else:
|
544
|
+
console.print(syntax)
|
545
|
+
|
546
|
+
|
547
|
+
def print_markdown(text: str) -> None:
|
548
|
+
"""
|
549
|
+
Print markdown formatted text.
|
550
|
+
|
551
|
+
Args:
|
552
|
+
text: Markdown text
|
553
|
+
"""
|
554
|
+
md = Markdown(text)
|
555
|
+
console.print(md)
|
556
|
+
|
557
|
+
|
558
|
+
def confirm_action(prompt: str, default: bool = False) -> bool:
|
559
|
+
"""
|
560
|
+
Get user confirmation with styled prompt.
|
561
|
+
|
562
|
+
Args:
|
563
|
+
prompt: Confirmation prompt
|
564
|
+
default: Default value if user just presses enter
|
565
|
+
|
566
|
+
Returns:
|
567
|
+
User's confirmation choice
|
568
|
+
"""
|
569
|
+
default_text = "[Y/n]" if default else "[y/N]"
|
570
|
+
console.print(f"\n{STATUS_INDICATORS['info']} {prompt} {default_text}: ", style="info", end="")
|
571
|
+
|
572
|
+
response = input().strip().lower()
|
573
|
+
if not response:
|
574
|
+
return default
|
575
|
+
return response in ["y", "yes"]
|
576
|
+
|
577
|
+
|
578
|
+
def create_columns(items: List[Any], equal: bool = True, expand: bool = True) -> Columns:
|
579
|
+
"""
|
580
|
+
Create columns for side-by-side display.
|
581
|
+
|
582
|
+
Args:
|
583
|
+
items: List of items to display in columns
|
584
|
+
equal: Equal width columns
|
585
|
+
expand: Expand to full width
|
586
|
+
|
587
|
+
Returns:
|
588
|
+
Columns object
|
589
|
+
"""
|
590
|
+
return Columns(items, equal=equal, expand=expand, padding=(0, 2))
|
591
|
+
|
592
|
+
|
593
|
+
# Export all public functions and constants
|
594
|
+
__all__ = [
|
595
|
+
"CLOUDOPS_THEME",
|
596
|
+
"STATUS_INDICATORS",
|
597
|
+
"console",
|
598
|
+
"get_console",
|
599
|
+
"get_context_aware_console",
|
600
|
+
"print_header",
|
601
|
+
"print_banner",
|
602
|
+
"create_table",
|
603
|
+
"create_progress_bar",
|
604
|
+
"print_status",
|
605
|
+
"print_error",
|
606
|
+
"print_success",
|
607
|
+
"print_warning",
|
608
|
+
"print_info",
|
609
|
+
"create_tree",
|
610
|
+
"print_separator",
|
611
|
+
"create_panel",
|
612
|
+
"format_cost",
|
613
|
+
"format_resource_count",
|
614
|
+
"create_display_profile_name",
|
615
|
+
"format_profile_name",
|
616
|
+
"format_account_name",
|
617
|
+
"create_layout",
|
618
|
+
"print_json",
|
619
|
+
"print_markdown",
|
620
|
+
"confirm_action",
|
621
|
+
"create_columns",
|
622
|
+
]
|
@@ -0,0 +1,68 @@
|
|
1
|
+
"""
|
2
|
+
Enterprise enhancements for CloudOps-Runbooks.
|
3
|
+
|
4
|
+
This module provides enterprise-grade enhancements including:
|
5
|
+
- Advanced error handling with actionable guidance
|
6
|
+
- Structured logging for enterprise monitoring
|
7
|
+
- Security hardening and compliance validation
|
8
|
+
- Enhanced configuration management
|
9
|
+
- Professional documentation standards
|
10
|
+
"""
|
11
|
+
|
12
|
+
from .error_handling import (
|
13
|
+
AWSServiceError,
|
14
|
+
ConfigurationError,
|
15
|
+
EnterpriseErrorHandler,
|
16
|
+
RunbooksException,
|
17
|
+
SecurityError,
|
18
|
+
ValidationError,
|
19
|
+
create_user_friendly_error,
|
20
|
+
)
|
21
|
+
from .logging import (
|
22
|
+
AuditLogger,
|
23
|
+
EnterpriseLogger,
|
24
|
+
PerformanceLogger,
|
25
|
+
configure_enterprise_logging,
|
26
|
+
)
|
27
|
+
from .security import (
|
28
|
+
ComplianceChecker,
|
29
|
+
SecurityValidator,
|
30
|
+
ZeroTrustValidator,
|
31
|
+
sanitize_input,
|
32
|
+
validate_aws_permissions,
|
33
|
+
)
|
34
|
+
from .validation import (
|
35
|
+
ConfigValidator,
|
36
|
+
InputValidator,
|
37
|
+
TypeValidator,
|
38
|
+
validate_configuration,
|
39
|
+
validate_user_input,
|
40
|
+
)
|
41
|
+
|
42
|
+
__all__ = [
|
43
|
+
# Error handling
|
44
|
+
"EnterpriseErrorHandler",
|
45
|
+
"RunbooksException",
|
46
|
+
"ConfigurationError",
|
47
|
+
"ValidationError",
|
48
|
+
"SecurityError",
|
49
|
+
"AWSServiceError",
|
50
|
+
"create_user_friendly_error",
|
51
|
+
# Logging
|
52
|
+
"EnterpriseLogger",
|
53
|
+
"AuditLogger",
|
54
|
+
"PerformanceLogger",
|
55
|
+
"configure_enterprise_logging",
|
56
|
+
# Security
|
57
|
+
"SecurityValidator",
|
58
|
+
"ComplianceChecker",
|
59
|
+
"ZeroTrustValidator",
|
60
|
+
"sanitize_input",
|
61
|
+
"validate_aws_permissions",
|
62
|
+
# Validation
|
63
|
+
"ConfigValidator",
|
64
|
+
"InputValidator",
|
65
|
+
"TypeValidator",
|
66
|
+
"validate_configuration",
|
67
|
+
"validate_user_input",
|
68
|
+
]
|