runbooks 0.7.9__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/cfat/README.md +12 -1
- runbooks/cfat/__init__.py +1 -1
- runbooks/cfat/assessment/runner.py +42 -34
- runbooks/cfat/models.py +1 -1
- 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_integration.py +539 -0
- runbooks/common/performance_monitor.py +387 -0
- runbooks/common/profile_utils.py +216 -0
- runbooks/common/rich_utils.py +171 -0
- runbooks/feedback/user_feedback_collector.py +440 -0
- runbooks/finops/README.md +339 -451
- 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_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 +29 -1880
- 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/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/main.py +740 -134
- 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 +7 -5
- runbooks/operate/privatelink_operations.py +1 -1
- runbooks/operate/vpc_endpoints.py +1 -1
- runbooks/remediation/README.md +489 -13
- runbooks/remediation/commons.py +8 -4
- runbooks/security/ENTERPRISE_SECURITY_FRAMEWORK.md +506 -0
- runbooks/security/README.md +12 -1
- runbooks/security/__init__.py +164 -33
- runbooks/security/compliance_automation.py +12 -10
- 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 +1 -1
- runbooks/security/run_script.py +4 -8
- runbooks/security/security_baseline_tester.py +36 -49
- 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/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 +265 -236
- runbooks/vpc/README.md +478 -0
- runbooks/vpc/__init__.py +2 -2
- runbooks/vpc/manager_interface.py +366 -351
- runbooks/vpc/networking_wrapper.py +62 -33
- runbooks/vpc/rich_formatters.py +22 -8
- {runbooks-0.7.9.dist-info → runbooks-0.9.0.dist-info}/METADATA +136 -54
- {runbooks-0.7.9.dist-info → runbooks-0.9.0.dist-info}/RECORD +94 -55
- {runbooks-0.7.9.dist-info → runbooks-0.9.0.dist-info}/entry_points.txt +1 -1
- runbooks/finops/cross_validation.py +0 -375
- {runbooks-0.7.9.dist-info → runbooks-0.9.0.dist-info}/WHEEL +0 -0
- {runbooks-0.7.9.dist-info → runbooks-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {runbooks-0.7.9.dist-info → runbooks-0.9.0.dist-info}/top_level.txt +0 -0
@@ -20,23 +20,23 @@ Version: 0.7.8
|
|
20
20
|
from datetime import datetime
|
21
21
|
from typing import Any, Dict, List, Optional
|
22
22
|
|
23
|
-
from rich.console import Console
|
24
|
-
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn
|
25
|
-
from rich.table import Table
|
26
23
|
from rich import box
|
24
|
+
from rich.console import Console
|
27
25
|
from rich.panel import Panel
|
26
|
+
from rich.progress import BarColumn, Progress, SpinnerColumn, TaskProgressColumn, TextColumn
|
27
|
+
from rich.table import Table
|
28
28
|
from rich.text import Text
|
29
29
|
from rich.tree import Tree
|
30
30
|
|
31
31
|
from runbooks.common.rich_utils import (
|
32
|
+
STATUS_INDICATORS,
|
32
33
|
console,
|
33
|
-
|
34
|
+
create_panel,
|
34
35
|
create_progress_bar,
|
36
|
+
create_table,
|
37
|
+
print_info,
|
35
38
|
print_status,
|
36
39
|
print_success,
|
37
|
-
print_info,
|
38
|
-
create_panel,
|
39
|
-
STATUS_INDICATORS
|
40
40
|
)
|
41
41
|
|
42
42
|
|
@@ -55,14 +55,10 @@ def display_inventory_header(operation: str, profile: str, accounts: int, region
|
|
55
55
|
|
56
56
|
[yellow]Profile:[/yellow] {profile}
|
57
57
|
[yellow]Scope:[/yellow] {accounts} accounts × {regions} regions = {accounts * regions} total operations
|
58
|
-
[yellow]Started:[/yellow] {datetime.now().strftime(
|
58
|
+
[yellow]Started:[/yellow] {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
|
59
59
|
"""
|
60
|
-
|
61
|
-
console.print(create_panel(
|
62
|
-
header_text.strip(),
|
63
|
-
title="📊 Inventory Operation",
|
64
|
-
border_style="cyan"
|
65
|
-
))
|
60
|
+
|
61
|
+
console.print(create_panel(header_text.strip(), title="📊 Inventory Operation", border_style="cyan"))
|
66
62
|
|
67
63
|
|
68
64
|
def create_inventory_progress(total_operations: int, operation_name: str = "Scanning Resources") -> Progress:
|
@@ -84,14 +80,13 @@ def create_inventory_progress(total_operations: int, operation_name: str = "Scan
|
|
84
80
|
TextColumn("•"),
|
85
81
|
TextColumn("[blue]{task.completed}/{task.total} operations"),
|
86
82
|
console=console,
|
87
|
-
transient=False
|
83
|
+
transient=False,
|
88
84
|
)
|
89
85
|
|
90
86
|
|
91
|
-
def display_ec2_inventory_results(
|
92
|
-
|
93
|
-
|
94
|
-
timing_info: Optional[Dict] = None) -> None:
|
87
|
+
def display_ec2_inventory_results(
|
88
|
+
instances: List[Dict[str, Any]], accounts: int, regions: int, timing_info: Optional[Dict] = None
|
89
|
+
) -> None:
|
95
90
|
"""
|
96
91
|
Display EC2 inventory results in a professional Rich table format.
|
97
92
|
|
@@ -103,27 +98,27 @@ def display_ec2_inventory_results(instances: List[Dict[str, Any]],
|
|
103
98
|
"""
|
104
99
|
# Summary panel first
|
105
100
|
total_instances = len(instances)
|
106
|
-
|
101
|
+
|
107
102
|
# Count by state
|
108
103
|
state_counts = {}
|
109
104
|
for instance in instances:
|
110
105
|
state = instance.get("State", {}).get("Name", "unknown")
|
111
106
|
state_counts[state] = state_counts.get(state, 0) + 1
|
112
|
-
|
107
|
+
|
113
108
|
# Create status breakdown
|
114
109
|
status_text = ""
|
115
110
|
for state, count in sorted(state_counts.items()):
|
116
111
|
status_indicator = {
|
117
112
|
"running": "🟢",
|
118
|
-
"stopped": "🔴",
|
113
|
+
"stopped": "🔴",
|
119
114
|
"stopping": "🟡",
|
120
115
|
"starting": "🟡",
|
121
116
|
"terminated": "⚫",
|
122
|
-
"terminating": "🟡"
|
117
|
+
"terminating": "🟡",
|
123
118
|
}.get(state, "⚪")
|
124
|
-
|
119
|
+
|
125
120
|
status_text += f"{status_indicator} {state.title()}: {count}\n"
|
126
|
-
|
121
|
+
|
127
122
|
summary_content = f"""
|
128
123
|
[bold cyan]EC2 Inventory Summary[/bold cyan]
|
129
124
|
|
@@ -134,13 +129,9 @@ def display_ec2_inventory_results(instances: List[Dict[str, Any]],
|
|
134
129
|
[bold yellow]Instance States:[/bold yellow]
|
135
130
|
{status_text.strip()}
|
136
131
|
"""
|
137
|
-
|
138
|
-
console.print(create_panel(
|
139
|
-
|
140
|
-
title="📊 Discovery Results",
|
141
|
-
border_style="green"
|
142
|
-
))
|
143
|
-
|
132
|
+
|
133
|
+
console.print(create_panel(summary_content.strip(), title="📊 Discovery Results", border_style="green"))
|
134
|
+
|
144
135
|
# Detailed results table if instances found
|
145
136
|
if instances:
|
146
137
|
# Group instances by account for better organization
|
@@ -150,7 +141,7 @@ def display_ec2_inventory_results(instances: List[Dict[str, Any]],
|
|
150
141
|
if account_id not in instances_by_account:
|
151
142
|
instances_by_account[account_id] = []
|
152
143
|
instances_by_account[account_id].append(instance)
|
153
|
-
|
144
|
+
|
154
145
|
# Create detailed table
|
155
146
|
table = create_table(
|
156
147
|
title="🖥️ EC2 Instance Details",
|
@@ -160,26 +151,26 @@ def display_ec2_inventory_results(instances: List[Dict[str, Any]],
|
|
160
151
|
{"name": "Instance ID", "style": "magenta"},
|
161
152
|
{"name": "Type", "style": "blue"},
|
162
153
|
{"name": "State", "style": "green"},
|
163
|
-
{"name": "Name", "style": "white"}
|
154
|
+
{"name": "Name", "style": "white"},
|
164
155
|
],
|
165
|
-
box_style=box.ROUNDED
|
156
|
+
box_style=box.ROUNDED,
|
166
157
|
)
|
167
|
-
|
158
|
+
|
168
159
|
# Add rows (show first 50 instances to avoid overwhelming output)
|
169
160
|
displayed_count = 0
|
170
161
|
for account_id in sorted(instances_by_account.keys()):
|
171
162
|
account_instances = instances_by_account[account_id][:10] # Max 10 per account
|
172
|
-
|
163
|
+
|
173
164
|
for instance in account_instances:
|
174
165
|
if displayed_count >= 50: # Overall limit
|
175
166
|
break
|
176
|
-
|
167
|
+
|
177
168
|
# Extract instance information
|
178
169
|
instance_id = instance.get("InstanceId", "N/A")
|
179
170
|
instance_type = instance.get("InstanceType", "N/A")
|
180
171
|
state = instance.get("State", {}).get("Name", "unknown")
|
181
172
|
region = instance.get("Region", "N/A")
|
182
|
-
|
173
|
+
|
183
174
|
# Get instance name from tags
|
184
175
|
instance_name = "N/A"
|
185
176
|
tags = instance.get("Tags", [])
|
@@ -187,7 +178,7 @@ def display_ec2_inventory_results(instances: List[Dict[str, Any]],
|
|
187
178
|
if tag.get("Key") == "Name":
|
188
179
|
instance_name = tag.get("Value", "N/A")
|
189
180
|
break
|
190
|
-
|
181
|
+
|
191
182
|
# Style state with appropriate color
|
192
183
|
state_styled = {
|
193
184
|
"running": "[green]🟢 Running[/green]",
|
@@ -195,38 +186,37 @@ def display_ec2_inventory_results(instances: List[Dict[str, Any]],
|
|
195
186
|
"stopping": "[yellow]🟡 Stopping[/yellow]",
|
196
187
|
"starting": "[yellow]🟡 Starting[/yellow]",
|
197
188
|
"terminated": "[dim]⚫ Terminated[/dim]",
|
198
|
-
"terminating": "[yellow]🟡 Terminating[/yellow]"
|
189
|
+
"terminating": "[yellow]🟡 Terminating[/yellow]",
|
199
190
|
}.get(state, f"[white]⚪ {state.title()}[/white]")
|
200
|
-
|
191
|
+
|
201
192
|
table.add_row(
|
202
193
|
account_id[:12], # Truncate account ID
|
203
194
|
region,
|
204
195
|
instance_id,
|
205
196
|
instance_type,
|
206
197
|
state_styled,
|
207
|
-
instance_name[:20] if instance_name != "N/A" else "N/A" # Truncate long names
|
198
|
+
instance_name[:20] if instance_name != "N/A" else "N/A", # Truncate long names
|
208
199
|
)
|
209
|
-
|
200
|
+
|
210
201
|
displayed_count += 1
|
211
|
-
|
202
|
+
|
212
203
|
console.print(table)
|
213
|
-
|
204
|
+
|
214
205
|
# Show truncation message if needed
|
215
206
|
if total_instances > 50:
|
216
207
|
console.print(f"\n[dim]Showing first 50 instances. Total found: {total_instances}[/dim]")
|
217
|
-
|
208
|
+
|
218
209
|
# Timing information
|
219
210
|
if timing_info:
|
220
211
|
execution_time = timing_info.get("total_time", 0)
|
221
212
|
print_success(f"✅ Inventory scan completed in {execution_time:.2f} seconds")
|
222
|
-
|
213
|
+
|
223
214
|
print_info("💡 Use --output json or --output csv to export complete results")
|
224
215
|
|
225
216
|
|
226
|
-
def display_generic_inventory_results(
|
227
|
-
|
228
|
-
|
229
|
-
regions: int) -> None:
|
217
|
+
def display_generic_inventory_results(
|
218
|
+
resource_type: str, resources: List[Dict[str, Any]], accounts: int, regions: int
|
219
|
+
) -> None:
|
230
220
|
"""
|
231
221
|
Display generic inventory results for any resource type.
|
232
222
|
|
@@ -237,7 +227,7 @@ def display_generic_inventory_results(resource_type: str,
|
|
237
227
|
regions: Number of regions scanned
|
238
228
|
"""
|
239
229
|
total_resources = len(resources)
|
240
|
-
|
230
|
+
|
241
231
|
# Resource type icons
|
242
232
|
resource_icons = {
|
243
233
|
"rds": "🗄️",
|
@@ -247,11 +237,11 @@ def display_generic_inventory_results(resource_type: str,
|
|
247
237
|
"iam": "👤",
|
248
238
|
"cloudformation": "📚",
|
249
239
|
"ssm": "🔑",
|
250
|
-
"route53": "🌍"
|
240
|
+
"route53": "🌍",
|
251
241
|
}
|
252
|
-
|
242
|
+
|
253
243
|
icon = resource_icons.get(resource_type.lower(), "📦")
|
254
|
-
|
244
|
+
|
255
245
|
summary_content = f"""
|
256
246
|
[bold cyan]{resource_type.upper()} Inventory Summary[/bold cyan]
|
257
247
|
|
@@ -259,13 +249,9 @@ def display_generic_inventory_results(resource_type: str,
|
|
259
249
|
[green]Accounts Scanned:[/green] {accounts}
|
260
250
|
[green]Regions Scanned:[/green] {regions}
|
261
251
|
"""
|
262
|
-
|
263
|
-
console.print(create_panel(
|
264
|
-
|
265
|
-
title=f"{icon} Discovery Results",
|
266
|
-
border_style="green"
|
267
|
-
))
|
268
|
-
|
252
|
+
|
253
|
+
console.print(create_panel(summary_content.strip(), title=f"{icon} Discovery Results", border_style="green"))
|
254
|
+
|
269
255
|
if total_resources > 0:
|
270
256
|
print_success(f"✅ Found {total_resources} {resource_type} resources across {accounts} accounts")
|
271
257
|
else:
|
@@ -281,24 +267,18 @@ def display_inventory_error(error_message: str, suggestions: Optional[List[str]]
|
|
281
267
|
suggestions: Optional list of suggestions for resolution
|
282
268
|
"""
|
283
269
|
error_content = f"[bold red]❌ Inventory Operation Failed[/bold red]\n\n{error_message}"
|
284
|
-
|
270
|
+
|
285
271
|
if suggestions:
|
286
272
|
error_content += "\n\n[yellow]💡 Suggestions:[/yellow]\n"
|
287
273
|
for suggestion in suggestions:
|
288
274
|
error_content += f" • {suggestion}\n"
|
289
|
-
|
290
|
-
console.print(create_panel(
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
def display_multi_resource_summary(resource_counts: Dict[str, int],
|
299
|
-
accounts: int,
|
300
|
-
regions: int,
|
301
|
-
execution_time: float) -> None:
|
275
|
+
|
276
|
+
console.print(create_panel(error_content.strip(), title="🚨 Error", border_style="red", padding=1))
|
277
|
+
|
278
|
+
|
279
|
+
def display_multi_resource_summary(
|
280
|
+
resource_counts: Dict[str, int], accounts: int, regions: int, execution_time: float
|
281
|
+
) -> None:
|
302
282
|
"""
|
303
283
|
Display summary for multi-resource inventory operations.
|
304
284
|
|
@@ -314,22 +294,18 @@ def display_multi_resource_summary(resource_counts: Dict[str, int],
|
|
314
294
|
columns=[
|
315
295
|
{"name": "Resource Type", "style": "cyan"},
|
316
296
|
{"name": "Count", "style": "green", "justify": "right"},
|
317
|
-
{"name": "Status", "style": "yellow"}
|
318
|
-
]
|
297
|
+
{"name": "Status", "style": "yellow"},
|
298
|
+
],
|
319
299
|
)
|
320
|
-
|
300
|
+
|
321
301
|
total_resources = 0
|
322
302
|
for resource_type, count in sorted(resource_counts.items()):
|
323
303
|
status = "✅ Found" if count > 0 else "⚪ None"
|
324
|
-
table.add_row(
|
325
|
-
resource_type.title(),
|
326
|
-
str(count),
|
327
|
-
status
|
328
|
-
)
|
304
|
+
table.add_row(resource_type.title(), str(count), status)
|
329
305
|
total_resources += count
|
330
|
-
|
306
|
+
|
331
307
|
console.print(table)
|
332
|
-
|
308
|
+
|
333
309
|
# Overall summary
|
334
310
|
summary_text = f"""
|
335
311
|
[bold green]Overall Summary[/bold green]
|
@@ -340,12 +316,8 @@ def display_multi_resource_summary(resource_counts: Dict[str, int],
|
|
340
316
|
[cyan]Execution Time:[/cyan] {execution_time:.2f} seconds
|
341
317
|
[cyan]Performance:[/cyan] {(accounts * regions) / execution_time:.1f} operations/second
|
342
318
|
"""
|
343
|
-
|
344
|
-
console.print(create_panel(
|
345
|
-
summary_text.strip(),
|
346
|
-
title="🎯 Inventory Complete",
|
347
|
-
border_style="bright_blue"
|
348
|
-
))
|
319
|
+
|
320
|
+
console.print(create_panel(summary_text.strip(), title="🎯 Inventory Complete", border_style="bright_blue"))
|
349
321
|
|
350
322
|
|
351
323
|
def display_account_tree(accounts_data: Dict[str, Dict]) -> None:
|
@@ -356,38 +328,33 @@ def display_account_tree(accounts_data: Dict[str, Dict]) -> None:
|
|
356
328
|
accounts_data: Nested dictionary of account -> resource data
|
357
329
|
"""
|
358
330
|
tree = Tree("🏢 [bold cyan]AWS Organization Structure[/bold cyan]")
|
359
|
-
|
331
|
+
|
360
332
|
for account_id, account_data in accounts_data.items():
|
361
333
|
account_name = account_data.get("account_name", "Unknown")
|
362
334
|
account_branch = tree.add(f"📊 [yellow]Account: {account_id}[/yellow] ({account_name})")
|
363
|
-
|
335
|
+
|
364
336
|
# Add regions
|
365
337
|
regions = account_data.get("regions", {})
|
366
338
|
for region, region_data in regions.items():
|
367
339
|
region_branch = account_branch.add(f"🌍 [green]Region: {region}[/green]")
|
368
|
-
|
340
|
+
|
369
341
|
# Add resource counts
|
370
342
|
for resource_type, count in region_data.get("resource_counts", {}).items():
|
371
343
|
if count > 0:
|
372
|
-
icon = {
|
373
|
-
|
374
|
-
"rds": "🗄️",
|
375
|
-
"s3": "🪣",
|
376
|
-
"lambda": "⚡"
|
377
|
-
}.get(resource_type, "📦")
|
378
|
-
|
344
|
+
icon = {"ec2": "🖥️", "rds": "🗄️", "s3": "🪣", "lambda": "⚡"}.get(resource_type, "📦")
|
345
|
+
|
379
346
|
region_branch.add(f"{icon} {resource_type.upper()}: [bold]{count}[/bold] resources")
|
380
|
-
|
347
|
+
|
381
348
|
console.print(tree)
|
382
349
|
|
383
350
|
|
384
351
|
# Export public functions
|
385
352
|
__all__ = [
|
386
353
|
"display_inventory_header",
|
387
|
-
"create_inventory_progress",
|
354
|
+
"create_inventory_progress",
|
388
355
|
"display_ec2_inventory_results",
|
389
356
|
"display_generic_inventory_results",
|
390
357
|
"display_inventory_error",
|
391
358
|
"display_multi_resource_summary",
|
392
|
-
"display_account_tree"
|
393
|
-
]
|
359
|
+
"display_account_tree",
|
360
|
+
]
|
@@ -192,7 +192,9 @@ for account_num in Accounts:
|
|
192
192
|
)
|
193
193
|
response = check_account_access(aws_acct, account_num, pAccessRole)
|
194
194
|
if response["Success"]:
|
195
|
-
console.print(
|
195
|
+
console.print(
|
196
|
+
f"[green]✅ Account {account_num} was successfully connected via role {pAccessRole} from {aws_acct.acct_number}[/green]"
|
197
|
+
)
|
196
198
|
"""
|
197
199
|
Put more commands here... Or you can write functions that represent your commands and call them from here.
|
198
200
|
"""
|
@@ -201,11 +203,13 @@ for account_num in Accounts:
|
|
201
203
|
username = "Paul"
|
202
204
|
user_response = participant_user(tgt_aws_access, username=username)
|
203
205
|
else:
|
204
|
-
console.print(
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
206
|
+
console.print(
|
207
|
+
Panel(
|
208
|
+
f"Access Role {pAccessRole} failed to connect to {account_num} from {aws_acct.acct_number}",
|
209
|
+
title=f"[red]❌ Connection Error: {response['ErrorMessage']}[/red]",
|
210
|
+
border_style="red",
|
211
|
+
)
|
212
|
+
)
|
209
213
|
|
210
214
|
# Display access keys with Rich formatting
|
211
215
|
credentials_info = [
|
@@ -213,14 +217,10 @@ for account_num in Accounts:
|
|
213
217
|
f"[cyan]User:[/cyan] {user_response['User']} (created/confirmed in account {user_response['AccountId']})",
|
214
218
|
f"[cyan]Password:[/cyan] {user_response['Password']}",
|
215
219
|
f"[cyan]Access Key ID:[/cyan] {user_response['AccessKeyId']}",
|
216
|
-
f"[cyan]Secret Access Key:[/cyan] {user_response['SecretAccessKey']}"
|
220
|
+
f"[cyan]Secret Access Key:[/cyan] {user_response['SecretAccessKey']}",
|
217
221
|
]
|
218
|
-
|
219
|
-
console.print(Panel(
|
220
|
-
"\n".join(credentials_info),
|
221
|
-
title="[blue]🔑 Account Credentials[/blue]",
|
222
|
-
border_style="blue"
|
223
|
-
))
|
222
|
+
|
223
|
+
console.print(Panel("\n".join(credentials_info), title="[blue]🔑 Account Credentials[/blue]", border_style="blue"))
|
224
224
|
|
225
225
|
console.print("")
|
226
226
|
console.print("[green]✅ Thanks for using this script...[/green]")
|