runbooks 1.1.3__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.
Files changed (247) hide show
  1. runbooks/__init__.py +31 -2
  2. runbooks/__init___optimized.py +18 -4
  3. runbooks/_platform/__init__.py +1 -5
  4. runbooks/_platform/core/runbooks_wrapper.py +141 -138
  5. runbooks/aws2/accuracy_validator.py +812 -0
  6. runbooks/base.py +7 -0
  7. runbooks/cfat/WEIGHT_CONFIG_README.md +1 -1
  8. runbooks/cfat/assessment/compliance.py +8 -8
  9. runbooks/cfat/assessment/runner.py +1 -0
  10. runbooks/cfat/cloud_foundations_assessment.py +227 -239
  11. runbooks/cfat/models.py +6 -2
  12. runbooks/cfat/tests/__init__.py +6 -1
  13. runbooks/cli/__init__.py +13 -0
  14. runbooks/cli/commands/cfat.py +274 -0
  15. runbooks/cli/commands/finops.py +1164 -0
  16. runbooks/cli/commands/inventory.py +379 -0
  17. runbooks/cli/commands/operate.py +239 -0
  18. runbooks/cli/commands/security.py +248 -0
  19. runbooks/cli/commands/validation.py +825 -0
  20. runbooks/cli/commands/vpc.py +310 -0
  21. runbooks/cli/registry.py +107 -0
  22. runbooks/cloudops/__init__.py +23 -30
  23. runbooks/cloudops/base.py +96 -107
  24. runbooks/cloudops/cost_optimizer.py +549 -547
  25. runbooks/cloudops/infrastructure_optimizer.py +5 -4
  26. runbooks/cloudops/interfaces.py +226 -227
  27. runbooks/cloudops/lifecycle_manager.py +5 -4
  28. runbooks/cloudops/mcp_cost_validation.py +252 -235
  29. runbooks/cloudops/models.py +78 -53
  30. runbooks/cloudops/monitoring_automation.py +5 -4
  31. runbooks/cloudops/notebook_framework.py +179 -215
  32. runbooks/cloudops/security_enforcer.py +125 -159
  33. runbooks/common/accuracy_validator.py +11 -0
  34. runbooks/common/aws_pricing.py +349 -326
  35. runbooks/common/aws_pricing_api.py +211 -212
  36. runbooks/common/aws_profile_manager.py +341 -0
  37. runbooks/common/aws_utils.py +75 -80
  38. runbooks/common/business_logic.py +127 -105
  39. runbooks/common/cli_decorators.py +36 -60
  40. runbooks/common/comprehensive_cost_explorer_integration.py +456 -464
  41. runbooks/common/cross_account_manager.py +198 -205
  42. runbooks/common/date_utils.py +27 -39
  43. runbooks/common/decorators.py +235 -0
  44. runbooks/common/dry_run_examples.py +173 -208
  45. runbooks/common/dry_run_framework.py +157 -155
  46. runbooks/common/enhanced_exception_handler.py +15 -4
  47. runbooks/common/enhanced_logging_example.py +50 -64
  48. runbooks/common/enhanced_logging_integration_example.py +65 -37
  49. runbooks/common/env_utils.py +16 -16
  50. runbooks/common/error_handling.py +40 -38
  51. runbooks/common/lazy_loader.py +41 -23
  52. runbooks/common/logging_integration_helper.py +79 -86
  53. runbooks/common/mcp_cost_explorer_integration.py +478 -495
  54. runbooks/common/mcp_integration.py +63 -74
  55. runbooks/common/memory_optimization.py +140 -118
  56. runbooks/common/module_cli_base.py +37 -58
  57. runbooks/common/organizations_client.py +176 -194
  58. runbooks/common/patterns.py +204 -0
  59. runbooks/common/performance_monitoring.py +67 -71
  60. runbooks/common/performance_optimization_engine.py +283 -274
  61. runbooks/common/profile_utils.py +248 -39
  62. runbooks/common/rich_utils.py +643 -92
  63. runbooks/common/sre_performance_suite.py +177 -186
  64. runbooks/enterprise/__init__.py +1 -1
  65. runbooks/enterprise/logging.py +144 -106
  66. runbooks/enterprise/security.py +187 -204
  67. runbooks/enterprise/validation.py +43 -56
  68. runbooks/finops/__init__.py +29 -33
  69. runbooks/finops/account_resolver.py +1 -1
  70. runbooks/finops/advanced_optimization_engine.py +980 -0
  71. runbooks/finops/automation_core.py +268 -231
  72. runbooks/finops/business_case_config.py +184 -179
  73. runbooks/finops/cli.py +660 -139
  74. runbooks/finops/commvault_ec2_analysis.py +157 -164
  75. runbooks/finops/compute_cost_optimizer.py +336 -320
  76. runbooks/finops/config.py +20 -20
  77. runbooks/finops/cost_optimizer.py +488 -622
  78. runbooks/finops/cost_processor.py +332 -214
  79. runbooks/finops/dashboard_runner.py +1006 -172
  80. runbooks/finops/ebs_cost_optimizer.py +991 -657
  81. runbooks/finops/elastic_ip_optimizer.py +317 -257
  82. runbooks/finops/enhanced_mcp_integration.py +340 -0
  83. runbooks/finops/enhanced_progress.py +40 -37
  84. runbooks/finops/enhanced_trend_visualization.py +3 -2
  85. runbooks/finops/enterprise_wrappers.py +230 -292
  86. runbooks/finops/executive_export.py +203 -160
  87. runbooks/finops/helpers.py +130 -288
  88. runbooks/finops/iam_guidance.py +1 -1
  89. runbooks/finops/infrastructure/__init__.py +80 -0
  90. runbooks/finops/infrastructure/commands.py +506 -0
  91. runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
  92. runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
  93. runbooks/finops/markdown_exporter.py +338 -175
  94. runbooks/finops/mcp_validator.py +1952 -0
  95. runbooks/finops/nat_gateway_optimizer.py +1513 -482
  96. runbooks/finops/network_cost_optimizer.py +657 -587
  97. runbooks/finops/notebook_utils.py +226 -188
  98. runbooks/finops/optimization_engine.py +1136 -0
  99. runbooks/finops/optimizer.py +25 -29
  100. runbooks/finops/rds_snapshot_optimizer.py +367 -411
  101. runbooks/finops/reservation_optimizer.py +427 -363
  102. runbooks/finops/scenario_cli_integration.py +77 -78
  103. runbooks/finops/scenarios.py +1278 -439
  104. runbooks/finops/schemas.py +218 -182
  105. runbooks/finops/snapshot_manager.py +2289 -0
  106. runbooks/finops/tests/test_finops_dashboard.py +3 -3
  107. runbooks/finops/tests/test_reference_images_validation.py +2 -2
  108. runbooks/finops/tests/test_single_account_features.py +17 -17
  109. runbooks/finops/tests/validate_test_suite.py +1 -1
  110. runbooks/finops/types.py +3 -3
  111. runbooks/finops/validation_framework.py +263 -269
  112. runbooks/finops/vpc_cleanup_exporter.py +191 -146
  113. runbooks/finops/vpc_cleanup_optimizer.py +593 -575
  114. runbooks/finops/workspaces_analyzer.py +171 -182
  115. runbooks/hitl/enhanced_workflow_engine.py +1 -1
  116. runbooks/integration/__init__.py +89 -0
  117. runbooks/integration/mcp_integration.py +1920 -0
  118. runbooks/inventory/CLAUDE.md +816 -0
  119. runbooks/inventory/README.md +3 -3
  120. runbooks/inventory/Tests/common_test_data.py +30 -30
  121. runbooks/inventory/__init__.py +2 -2
  122. runbooks/inventory/cloud_foundations_integration.py +144 -149
  123. runbooks/inventory/collectors/aws_comprehensive.py +28 -11
  124. runbooks/inventory/collectors/aws_networking.py +111 -101
  125. runbooks/inventory/collectors/base.py +4 -0
  126. runbooks/inventory/core/collector.py +495 -313
  127. runbooks/inventory/discovery.md +2 -2
  128. runbooks/inventory/drift_detection_cli.py +69 -96
  129. runbooks/inventory/find_ec2_security_groups.py +1 -1
  130. runbooks/inventory/inventory_mcp_cli.py +48 -46
  131. runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
  132. runbooks/inventory/mcp_inventory_validator.py +549 -465
  133. runbooks/inventory/mcp_vpc_validator.py +359 -442
  134. runbooks/inventory/organizations_discovery.py +56 -52
  135. runbooks/inventory/rich_inventory_display.py +33 -32
  136. runbooks/inventory/unified_validation_engine.py +278 -251
  137. runbooks/inventory/vpc_analyzer.py +733 -696
  138. runbooks/inventory/vpc_architecture_validator.py +293 -348
  139. runbooks/inventory/vpc_dependency_analyzer.py +382 -378
  140. runbooks/inventory/vpc_flow_analyzer.py +3 -3
  141. runbooks/main.py +152 -9147
  142. runbooks/main_final.py +91 -60
  143. runbooks/main_minimal.py +22 -10
  144. runbooks/main_optimized.py +131 -100
  145. runbooks/main_ultra_minimal.py +7 -2
  146. runbooks/mcp/__init__.py +36 -0
  147. runbooks/mcp/integration.py +679 -0
  148. runbooks/metrics/dora_metrics_engine.py +2 -2
  149. runbooks/monitoring/performance_monitor.py +9 -4
  150. runbooks/operate/dynamodb_operations.py +3 -1
  151. runbooks/operate/ec2_operations.py +145 -137
  152. runbooks/operate/iam_operations.py +146 -152
  153. runbooks/operate/mcp_integration.py +1 -1
  154. runbooks/operate/networking_cost_heatmap.py +33 -10
  155. runbooks/operate/privatelink_operations.py +1 -1
  156. runbooks/operate/rds_operations.py +223 -254
  157. runbooks/operate/s3_operations.py +107 -118
  158. runbooks/operate/vpc_endpoints.py +1 -1
  159. runbooks/operate/vpc_operations.py +648 -618
  160. runbooks/remediation/base.py +1 -1
  161. runbooks/remediation/commons.py +10 -7
  162. runbooks/remediation/commvault_ec2_analysis.py +71 -67
  163. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
  164. runbooks/remediation/multi_account.py +24 -21
  165. runbooks/remediation/rds_snapshot_list.py +91 -65
  166. runbooks/remediation/remediation_cli.py +92 -146
  167. runbooks/remediation/universal_account_discovery.py +83 -79
  168. runbooks/remediation/workspaces_list.py +49 -44
  169. runbooks/security/__init__.py +19 -0
  170. runbooks/security/assessment_runner.py +1150 -0
  171. runbooks/security/baseline_checker.py +812 -0
  172. runbooks/security/cloudops_automation_security_validator.py +509 -535
  173. runbooks/security/compliance_automation_engine.py +17 -17
  174. runbooks/security/config/__init__.py +2 -2
  175. runbooks/security/config/compliance_config.py +50 -50
  176. runbooks/security/config_template_generator.py +63 -76
  177. runbooks/security/enterprise_security_framework.py +1 -1
  178. runbooks/security/executive_security_dashboard.py +519 -508
  179. runbooks/security/integration_test_enterprise_security.py +5 -3
  180. runbooks/security/multi_account_security_controls.py +959 -1210
  181. runbooks/security/real_time_security_monitor.py +422 -444
  182. runbooks/security/run_script.py +1 -1
  183. runbooks/security/security_baseline_tester.py +1 -1
  184. runbooks/security/security_cli.py +143 -112
  185. runbooks/security/test_2way_validation.py +439 -0
  186. runbooks/security/two_way_validation_framework.py +852 -0
  187. runbooks/sre/mcp_reliability_engine.py +6 -6
  188. runbooks/sre/production_monitoring_framework.py +167 -177
  189. runbooks/tdd/__init__.py +15 -0
  190. runbooks/tdd/cli.py +1071 -0
  191. runbooks/utils/__init__.py +14 -17
  192. runbooks/utils/logger.py +7 -2
  193. runbooks/utils/version_validator.py +51 -48
  194. runbooks/validation/__init__.py +6 -6
  195. runbooks/validation/cli.py +9 -3
  196. runbooks/validation/comprehensive_2way_validator.py +754 -708
  197. runbooks/validation/mcp_validator.py +906 -228
  198. runbooks/validation/terraform_citations_validator.py +104 -115
  199. runbooks/validation/terraform_drift_detector.py +447 -451
  200. runbooks/vpc/README.md +617 -0
  201. runbooks/vpc/__init__.py +8 -1
  202. runbooks/vpc/analyzer.py +577 -0
  203. runbooks/vpc/cleanup_wrapper.py +476 -413
  204. runbooks/vpc/cli_cloudtrail_commands.py +339 -0
  205. runbooks/vpc/cli_mcp_validation_commands.py +480 -0
  206. runbooks/vpc/cloudtrail_audit_integration.py +717 -0
  207. runbooks/vpc/config.py +92 -97
  208. runbooks/vpc/cost_engine.py +411 -148
  209. runbooks/vpc/cost_explorer_integration.py +553 -0
  210. runbooks/vpc/cross_account_session.py +101 -106
  211. runbooks/vpc/enhanced_mcp_validation.py +917 -0
  212. runbooks/vpc/eni_gate_validator.py +961 -0
  213. runbooks/vpc/heatmap_engine.py +190 -162
  214. runbooks/vpc/mcp_no_eni_validator.py +681 -640
  215. runbooks/vpc/nat_gateway_optimizer.py +358 -0
  216. runbooks/vpc/networking_wrapper.py +15 -8
  217. runbooks/vpc/pdca_remediation_planner.py +528 -0
  218. runbooks/vpc/performance_optimized_analyzer.py +219 -231
  219. runbooks/vpc/runbooks_adapter.py +1167 -241
  220. runbooks/vpc/tdd_red_phase_stubs.py +601 -0
  221. runbooks/vpc/test_data_loader.py +358 -0
  222. runbooks/vpc/tests/conftest.py +314 -4
  223. runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
  224. runbooks/vpc/tests/test_cost_engine.py +0 -2
  225. runbooks/vpc/topology_generator.py +326 -0
  226. runbooks/vpc/unified_scenarios.py +1302 -1129
  227. runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
  228. runbooks-1.1.5.dist-info/METADATA +328 -0
  229. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/RECORD +233 -200
  230. runbooks/finops/README.md +0 -414
  231. runbooks/finops/accuracy_cross_validator.py +0 -647
  232. runbooks/finops/business_cases.py +0 -950
  233. runbooks/finops/dashboard_router.py +0 -922
  234. runbooks/finops/ebs_optimizer.py +0 -956
  235. runbooks/finops/embedded_mcp_validator.py +0 -1629
  236. runbooks/finops/enhanced_dashboard_runner.py +0 -527
  237. runbooks/finops/finops_dashboard.py +0 -584
  238. runbooks/finops/finops_scenarios.py +0 -1218
  239. runbooks/finops/legacy_migration.py +0 -730
  240. runbooks/finops/multi_dashboard.py +0 -1519
  241. runbooks/finops/single_dashboard.py +0 -1113
  242. runbooks/finops/unlimited_scenarios.py +0 -393
  243. runbooks-1.1.3.dist-info/METADATA +0 -799
  244. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
  245. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
  246. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
  247. {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -6,7 +6,7 @@ This module provides export functionality for VPC cleanup analysis results,
6
6
  leveraging the existing markdown_exporter infrastructure with VPC-specific formatting.
7
7
 
8
8
  Author: CloudOps Runbooks Team
9
- Version: 0.9.9
9
+ Version: latest version
10
10
  """
11
11
 
12
12
  import csv
@@ -15,317 +15,362 @@ import os
15
15
  from datetime import datetime
16
16
  from typing import Any, Dict, List
17
17
 
18
- from .markdown_exporter import MarkdownExporter
19
18
  from runbooks.common.rich_utils import console
20
19
 
20
+ from .markdown_exporter import MarkdownExporter
21
+
22
+
23
+ class VPCCleanupExporter:
24
+ """VPC Cleanup results exporter class."""
25
+
26
+ def __init__(self, output_dir: str = "./"):
27
+ """Initialize VPC cleanup exporter."""
28
+ self.output_dir = output_dir
29
+
30
+ def export_results(self, vpc_result: Any, export_formats: List[str]) -> Dict[str, str]:
31
+ """Export VPC cleanup results in specified formats."""
32
+ return export_vpc_cleanup_results(vpc_result, export_formats, self.output_dir)
33
+
21
34
 
22
35
  def _format_tags_for_display(tags_dict: Dict[str, str]) -> str:
23
36
  """Format tags for display with priority order, emphasizing ownership tags."""
24
37
  if not tags_dict:
25
38
  return "No tags"
26
-
39
+
27
40
  # Enhanced priority keys with focus on ownership and approvals
28
- priority_keys = ['Name', 'Owner', 'BusinessOwner', 'TechnicalOwner', 'Team', 'Contact',
29
- 'Environment', 'Project', 'CostCenter', 'CreatedBy', 'ManagedBy']
41
+ priority_keys = [
42
+ "Name",
43
+ "Owner",
44
+ "BusinessOwner",
45
+ "TechnicalOwner",
46
+ "Team",
47
+ "Contact",
48
+ "Environment",
49
+ "Project",
50
+ "CostCenter",
51
+ "CreatedBy",
52
+ "ManagedBy",
53
+ ]
30
54
  relevant_tags = []
31
-
55
+
32
56
  for key in priority_keys:
33
57
  if key in tags_dict and tags_dict[key]:
34
58
  relevant_tags.append(f"{key}:{tags_dict[key]}")
35
-
59
+
36
60
  # Add CloudFormation/Terraform tags for IaC detection
37
- iac_keys = ['aws:cloudformation:stack-name', 'terraform:module', 'cdktf:stack', 'pulumi:project']
61
+ iac_keys = ["aws:cloudformation:stack-name", "terraform:module", "cdktf:stack", "pulumi:project"]
38
62
  for key in iac_keys:
39
63
  if key in tags_dict and tags_dict[key] and len(relevant_tags) < 6:
40
64
  relevant_tags.append(f"IaC:{tags_dict[key]}")
41
-
65
+
42
66
  # Add other important tags
43
67
  for key, value in tags_dict.items():
44
68
  if key not in priority_keys + iac_keys and value and len(relevant_tags) < 5:
45
69
  relevant_tags.append(f"{key}:{value}")
46
-
70
+
47
71
  return "; ".join(relevant_tags) if relevant_tags else f"({len(tags_dict)} tags)"
48
72
 
49
73
 
50
74
  def export_vpc_cleanup_results(vpc_result: Any, export_formats: List[str], output_dir: str = "./") -> Dict[str, str]:
51
75
  """
52
76
  Export VPC cleanup results in multiple formats.
53
-
77
+
54
78
  Args:
55
79
  vpc_result: VPC cleanup analysis result object
56
80
  export_formats: List of formats to export (markdown, csv, json, pdf)
57
81
  output_dir: Directory to save exported files
58
-
82
+
59
83
  Returns:
60
84
  Dict mapping format to exported filename
61
85
  """
62
86
  results = {}
63
-
87
+
64
88
  # Extract VPC candidates from result - use correct attribute name
65
- vpc_candidates = getattr(vpc_result, 'cleanup_candidates', [])
89
+ vpc_candidates = getattr(vpc_result, "cleanup_candidates", [])
66
90
  if not vpc_candidates:
67
91
  # Fallback to other possible attribute names
68
- vpc_candidates = getattr(vpc_result, 'vpc_candidates', [])
69
-
70
- if 'markdown' in export_formats:
92
+ vpc_candidates = getattr(vpc_result, "vpc_candidates", [])
93
+
94
+ if "markdown" in export_formats:
71
95
  try:
72
96
  exporter = MarkdownExporter()
73
97
  markdown_filename = exporter.export_vpc_analysis_to_file(
74
- vpc_candidates,
75
- filename="vpc-cleanup-candidates.md",
76
- output_dir=output_dir
98
+ vpc_candidates, filename="vpc-cleanup-candidates.md", output_dir=output_dir
77
99
  )
78
- results['markdown'] = markdown_filename
100
+ results["markdown"] = markdown_filename
79
101
  except Exception as e:
80
102
  console.print(f"[yellow]Warning: Markdown export failed: {e}[/yellow]")
81
- results['markdown'] = None
82
-
103
+ results["markdown"] = None
104
+
83
105
  # Real implementations for other formats
84
- if 'csv' in export_formats:
106
+ if "csv" in export_formats:
85
107
  try:
86
108
  csv_filename = _export_vpc_candidates_csv(vpc_candidates, output_dir)
87
- results['csv'] = csv_filename
109
+ results["csv"] = csv_filename
88
110
  except Exception as e:
89
111
  print(f"Warning: CSV export failed: {e}")
90
- results['csv'] = None
91
-
92
- if 'json' in export_formats:
112
+ results["csv"] = None
113
+
114
+ if "json" in export_formats:
93
115
  try:
94
116
  json_filename = _export_vpc_candidates_json(vpc_candidates, output_dir)
95
- results['json'] = json_filename
117
+ results["json"] = json_filename
96
118
  except Exception as e:
97
119
  print(f"Warning: JSON export failed: {e}")
98
- results['json'] = None
99
-
100
- if 'pdf' in export_formats:
120
+ results["json"] = None
121
+
122
+ if "pdf" in export_formats:
101
123
  try:
102
124
  pdf_filename = _export_vpc_candidates_pdf(vpc_candidates, output_dir)
103
- results['pdf'] = pdf_filename
125
+ results["pdf"] = pdf_filename
104
126
  except Exception as e:
105
127
  print(f"Warning: PDF export failed: {e}")
106
- results['pdf'] = None
107
-
128
+ results["pdf"] = None
129
+
108
130
  return results
109
131
 
110
132
 
111
133
  def _export_vpc_candidates_csv(vpc_candidates: List[Any], output_dir: str) -> str:
112
134
  """Export VPC candidates to CSV format with all 15 columns."""
113
135
  filename = os.path.join(output_dir, "vpc-cleanup-candidates.csv")
114
-
136
+
115
137
  # 15-column headers for comprehensive VPC analysis
116
138
  headers = [
117
- "Account_ID", "VPC_ID", "VPC_Name", "CIDR_Block", "Overlapping",
118
- "Is_Default", "ENI_Count", "Tags", "Flow_Logs", "TGW/Peering",
119
- "LBs_Present", "IaC", "Timeline", "Decision", "Owners/Approvals", "Notes"
139
+ "Account_ID",
140
+ "VPC_ID",
141
+ "VPC_Name",
142
+ "CIDR_Block",
143
+ "Overlapping",
144
+ "Is_Default",
145
+ "ENI_Count",
146
+ "Tags",
147
+ "Flow_Logs",
148
+ "TGW/Peering",
149
+ "LBs_Present",
150
+ "IaC",
151
+ "Timeline",
152
+ "Decision",
153
+ "Owners/Approvals",
154
+ "Notes",
120
155
  ]
121
-
122
- with open(filename, 'w', newline='', encoding='utf-8') as csvfile:
156
+
157
+ with open(filename, "w", newline="", encoding="utf-8") as csvfile:
123
158
  writer = csv.writer(csvfile)
124
159
  writer.writerow(headers)
125
-
160
+
126
161
  for candidate in vpc_candidates:
127
162
  # Extract data with enhanced tag and owner handling
128
- tags_dict = getattr(candidate, 'tags', {}) or {}
129
-
163
+ tags_dict = getattr(candidate, "tags", {}) or {}
164
+
130
165
  # Use enhanced tag formatting function
131
166
  tags_str = _format_tags_for_display(tags_dict)
132
-
133
- load_balancers = getattr(candidate, 'load_balancers', []) or []
167
+
168
+ load_balancers = getattr(candidate, "load_balancers", []) or []
134
169
  lbs_present = "Yes" if load_balancers else "No"
135
-
170
+
136
171
  # Enhanced owner extraction from multiple sources
137
- owners = getattr(candidate, 'owners_approvals', []) or []
138
-
172
+ owners = getattr(candidate, "owners_approvals", []) or []
173
+
139
174
  # Extract owners from tags with enhanced logic
140
175
  if not owners and tags_dict:
141
- owner_keys = ['Owner', 'BusinessOwner', 'TechnicalOwner', 'Team', 'Contact', 'CreatedBy', 'ManagedBy']
176
+ owner_keys = ["Owner", "BusinessOwner", "TechnicalOwner", "Team", "Contact", "CreatedBy", "ManagedBy"]
142
177
  for key in owner_keys:
143
178
  if key in tags_dict and tags_dict[key]:
144
179
  value = tags_dict[key]
145
- if 'business' in key.lower() or 'manager' in value.lower():
180
+ if "business" in key.lower() or "manager" in value.lower():
146
181
  owners.append(f"{value} (Business)")
147
- elif 'technical' in key.lower() or 'engineer' in value.lower():
182
+ elif "technical" in key.lower() or "engineer" in value.lower():
148
183
  owners.append(f"{value} (Technical)")
149
- elif 'team' in key.lower():
184
+ elif "team" in key.lower():
150
185
  owners.append(f"{value} (Team)")
151
186
  else:
152
187
  owners.append(f"{value} ({key})")
153
-
188
+
154
189
  # For default VPCs, add system indicator
155
- is_default = getattr(candidate, 'is_default', False)
190
+ is_default = getattr(candidate, "is_default", False)
156
191
  if is_default and not owners:
157
192
  owners.append("System Default")
158
-
193
+
159
194
  if owners:
160
195
  owners_str = "; ".join(owners)
161
196
  else:
162
197
  # Enhanced fallback for CSV
163
- if getattr(candidate, 'is_default', False):
198
+ if getattr(candidate, "is_default", False):
164
199
  owners_str = "System Default VPC"
165
- elif getattr(candidate, 'iac_detected', False):
200
+ elif getattr(candidate, "iac_detected", False):
166
201
  owners_str = "IaC Managed"
167
202
  else:
168
203
  owners_str = "No owner tags found"
169
-
204
+
170
205
  row = [
171
- getattr(candidate, 'account_id', 'Unknown'),
172
- getattr(candidate, 'vpc_id', ''),
173
- getattr(candidate, 'vpc_name', 'Unnamed'),
174
- getattr(candidate, 'cidr_block', ''),
206
+ getattr(candidate, "account_id", "Unknown"),
207
+ getattr(candidate, "vpc_id", ""),
208
+ getattr(candidate, "vpc_name", "Unnamed"),
209
+ getattr(candidate, "cidr_block", ""),
175
210
  "No", # Overlapping analysis would need CIDR comparison
176
- "Yes" if getattr(candidate, 'is_default', False) else "No",
177
- getattr(candidate, 'dependency_analysis', {}).eni_count if hasattr(candidate, 'dependency_analysis') else 0,
211
+ "Yes" if getattr(candidate, "is_default", False) else "No",
212
+ getattr(candidate, "dependency_analysis", {}).eni_count
213
+ if hasattr(candidate, "dependency_analysis")
214
+ else 0,
178
215
  tags_str,
179
- "Yes" if getattr(candidate, 'flow_logs_enabled', False) else "No",
216
+ "Yes" if getattr(candidate, "flow_logs_enabled", False) else "No",
180
217
  "No", # TGW/Peering analysis placeholder
181
218
  lbs_present,
182
- "Yes" if getattr(candidate, 'iac_detected', False) else "No",
219
+ "Yes" if getattr(candidate, "iac_detected", False) else "No",
183
220
  "Unknown", # Timeline analysis placeholder
184
- getattr(candidate, 'cleanup_recommendation', 'unknown'),
221
+ getattr(candidate, "cleanup_recommendation", "unknown"),
185
222
  owners_str,
186
- "Generated by CloudOps Runbooks VPC Module"
223
+ "Generated by CloudOps Runbooks VPC Module",
187
224
  ]
188
225
  writer.writerow(row)
189
-
226
+
190
227
  return filename
191
228
 
192
229
 
193
230
  def _export_vpc_candidates_json(vpc_candidates: List[Any], output_dir: str) -> str:
194
231
  """Export VPC candidates to JSON format with full data structure."""
195
232
  filename = os.path.join(output_dir, "vpc-cleanup-candidates.json")
196
-
233
+
197
234
  # Convert candidates to serializable format
198
235
  candidates_data = []
199
236
  for candidate in vpc_candidates:
200
237
  candidate_dict = {
201
- "account_id": getattr(candidate, 'account_id', 'Unknown'),
202
- "vpc_id": getattr(candidate, 'vpc_id', ''),
203
- "vpc_name": getattr(candidate, 'vpc_name', 'Unnamed'),
204
- "cidr_block": getattr(candidate, 'cidr_block', ''),
205
- "region": getattr(candidate, 'region', 'unknown'),
206
- "is_default": getattr(candidate, 'is_default', False),
207
- "state": getattr(candidate, 'state', 'unknown'),
208
- "tags": getattr(candidate, 'tags', {}) or {},
209
- "tags_summary": _format_tags_for_display(getattr(candidate, 'tags', {}) or {}),
210
- "flow_logs_enabled": getattr(candidate, 'flow_logs_enabled', False),
211
- "load_balancers": getattr(candidate, 'load_balancers', []) or [],
212
- "iac_detected": getattr(candidate, 'iac_detected', False),
213
- "owners_approvals": getattr(candidate, 'owners_approvals', []) or [],
214
- "cleanup_bucket": getattr(candidate, 'cleanup_bucket', 'unknown'),
215
- "cleanup_recommendation": getattr(candidate, 'cleanup_recommendation', 'unknown'),
216
- "risk_assessment": getattr(candidate, 'risk_assessment', 'unknown'),
217
- "business_impact": getattr(candidate, 'business_impact', 'unknown')
238
+ "account_id": getattr(candidate, "account_id", "Unknown"),
239
+ "vpc_id": getattr(candidate, "vpc_id", ""),
240
+ "vpc_name": getattr(candidate, "vpc_name", "Unnamed"),
241
+ "cidr_block": getattr(candidate, "cidr_block", ""),
242
+ "region": getattr(candidate, "region", "unknown"),
243
+ "is_default": getattr(candidate, "is_default", False),
244
+ "state": getattr(candidate, "state", "unknown"),
245
+ "tags": getattr(candidate, "tags", {}) or {},
246
+ "tags_summary": _format_tags_for_display(getattr(candidate, "tags", {}) or {}),
247
+ "flow_logs_enabled": getattr(candidate, "flow_logs_enabled", False),
248
+ "load_balancers": getattr(candidate, "load_balancers", []) or [],
249
+ "iac_detected": getattr(candidate, "iac_detected", False),
250
+ "owners_approvals": getattr(candidate, "owners_approvals", []) or [],
251
+ "cleanup_bucket": getattr(candidate, "cleanup_bucket", "unknown"),
252
+ "cleanup_recommendation": getattr(candidate, "cleanup_recommendation", "unknown"),
253
+ "risk_assessment": getattr(candidate, "risk_assessment", "unknown"),
254
+ "business_impact": getattr(candidate, "business_impact", "unknown"),
218
255
  }
219
-
256
+
220
257
  # Add dependency analysis if available
221
- if hasattr(candidate, 'dependency_analysis') and candidate.dependency_analysis:
258
+ if hasattr(candidate, "dependency_analysis") and candidate.dependency_analysis:
222
259
  dep_analysis = candidate.dependency_analysis
223
260
  candidate_dict["dependency_analysis"] = {
224
- "eni_count": getattr(dep_analysis, 'eni_count', 0),
225
- "route_tables": getattr(dep_analysis, 'route_tables', []),
226
- "security_groups": getattr(dep_analysis, 'security_groups', []),
227
- "internet_gateways": getattr(dep_analysis, 'internet_gateways', []),
228
- "nat_gateways": getattr(dep_analysis, 'nat_gateways', []),
229
- "vpc_endpoints": getattr(dep_analysis, 'vpc_endpoints', []),
230
- "peering_connections": getattr(dep_analysis, 'peering_connections', []),
231
- "dependency_risk_level": getattr(dep_analysis, 'dependency_risk_level', 'unknown')
261
+ "eni_count": getattr(dep_analysis, "eni_count", 0),
262
+ "route_tables": getattr(dep_analysis, "route_tables", []),
263
+ "security_groups": getattr(dep_analysis, "security_groups", []),
264
+ "internet_gateways": getattr(dep_analysis, "internet_gateways", []),
265
+ "nat_gateways": getattr(dep_analysis, "nat_gateways", []),
266
+ "vpc_endpoints": getattr(dep_analysis, "vpc_endpoints", []),
267
+ "peering_connections": getattr(dep_analysis, "peering_connections", []),
268
+ "dependency_risk_level": getattr(dep_analysis, "dependency_risk_level", "unknown"),
232
269
  }
233
-
270
+
234
271
  candidates_data.append(candidate_dict)
235
-
272
+
236
273
  # Create export metadata
237
274
  export_data = {
238
275
  "metadata": {
239
276
  "export_timestamp": datetime.now().isoformat(),
240
277
  "total_candidates": len(candidates_data),
241
- "generator": "CloudOps Runbooks VPC Module v0.9.9"
278
+ "generator": "CloudOps Runbooks VPC Module latest version",
242
279
  },
243
- "vpc_candidates": candidates_data
280
+ "vpc_candidates": candidates_data,
244
281
  }
245
-
246
- with open(filename, 'w', encoding='utf-8') as jsonfile:
282
+
283
+ with open(filename, "w", encoding="utf-8") as jsonfile:
247
284
  json.dump(export_data, jsonfile, indent=2, ensure_ascii=False)
248
-
285
+
249
286
  return filename
250
287
 
251
288
 
252
289
  def _export_vpc_candidates_pdf(vpc_candidates: List[Any], output_dir: str) -> str:
253
290
  """Export VPC candidates to PDF format for executive presentation."""
254
291
  filename = os.path.join(output_dir, "vpc-cleanup-candidates.pdf")
255
-
292
+
256
293
  try:
257
294
  # Try to use reportlab for PDF generation
258
295
  from reportlab.lib import colors
259
- from reportlab.lib.pagesizes import letter, A4
260
- from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
296
+ from reportlab.lib.pagesizes import A4, letter
261
297
  from reportlab.lib.styles import getSampleStyleSheet
262
-
298
+ from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle
299
+
263
300
  doc = SimpleDocTemplate(filename, pagesize=A4)
264
301
  styles = getSampleStyleSheet()
265
302
  story = []
266
-
303
+
267
304
  # Title
268
- title = Paragraph("VPC Cleanup Analysis Report", styles['Title'])
305
+ title = Paragraph("VPC Cleanup Analysis Report", styles["Title"])
269
306
  story.append(title)
270
307
  story.append(Spacer(1, 20))
271
-
308
+
272
309
  # Summary
273
310
  summary_text = f"""
274
- <b>Generated:</b> {datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}<br/>
311
+ <b>Generated:</b> {datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC")}<br/>
275
312
  <b>Total VPC Candidates:</b> {len(vpc_candidates)}<br/>
276
- <b>Analysis Source:</b> CloudOps Runbooks VPC Module v0.9.9
313
+ <b>Analysis Source:</b> CloudOps Runbooks VPC Module latest version
277
314
  """
278
- summary = Paragraph(summary_text, styles['Normal'])
315
+ summary = Paragraph(summary_text, styles["Normal"])
279
316
  story.append(summary)
280
317
  story.append(Spacer(1, 20))
281
-
318
+
282
319
  # Create table data
283
- table_data = [
284
- ["Account ID", "VPC ID", "VPC Name", "CIDR", "Default", "ENI Count", "Decision"]
285
- ]
286
-
320
+ table_data = [["Account ID", "VPC ID", "VPC Name", "CIDR", "Default", "ENI Count", "Decision"]]
321
+
287
322
  for candidate in vpc_candidates:
288
323
  row = [
289
- str(getattr(candidate, 'account_id', 'Unknown'))[:15], # Truncate for PDF width
290
- str(getattr(candidate, 'vpc_id', ''))[:20],
291
- str(getattr(candidate, 'vpc_name', 'Unnamed'))[:15],
292
- str(getattr(candidate, 'cidr_block', ''))[:15],
293
- "Yes" if getattr(candidate, 'is_default', False) else "No",
294
- str(getattr(candidate, 'dependency_analysis', {}).eni_count if hasattr(candidate, 'dependency_analysis') else 0),
295
- str(getattr(candidate, 'cleanup_recommendation', 'unknown'))[:10]
324
+ str(getattr(candidate, "account_id", "Unknown"))[:15], # Truncate for PDF width
325
+ str(getattr(candidate, "vpc_id", ""))[:20],
326
+ str(getattr(candidate, "vpc_name", "Unnamed"))[:15],
327
+ str(getattr(candidate, "cidr_block", ""))[:15],
328
+ "Yes" if getattr(candidate, "is_default", False) else "No",
329
+ str(
330
+ getattr(candidate, "dependency_analysis", {}).eni_count
331
+ if hasattr(candidate, "dependency_analysis")
332
+ else 0
333
+ ),
334
+ str(getattr(candidate, "cleanup_recommendation", "unknown"))[:10],
296
335
  ]
297
336
  table_data.append(row)
298
-
337
+
299
338
  # Create table
300
339
  table = Table(table_data)
301
- table.setStyle(TableStyle([
302
- ('BACKGROUND', (0, 0), (-1, 0), colors.grey),
303
- ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
304
- ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
305
- ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
306
- ('FONTSIZE', (0, 0), (-1, 0), 10),
307
- ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
308
- ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
309
- ('FONTSIZE', (0, 1), (-1, -1), 8),
310
- ('GRID', (0, 0), (-1, -1), 1, colors.black)
311
- ]))
312
-
340
+ table.setStyle(
341
+ TableStyle(
342
+ [
343
+ ("BACKGROUND", (0, 0), (-1, 0), colors.grey),
344
+ ("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
345
+ ("ALIGN", (0, 0), (-1, -1), "CENTER"),
346
+ ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
347
+ ("FONTSIZE", (0, 0), (-1, 0), 10),
348
+ ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
349
+ ("BACKGROUND", (0, 1), (-1, -1), colors.beige),
350
+ ("FONTSIZE", (0, 1), (-1, -1), 8),
351
+ ("GRID", (0, 0), (-1, -1), 1, colors.black),
352
+ ]
353
+ )
354
+ )
355
+
313
356
  story.append(table)
314
357
  doc.build(story)
315
-
358
+
316
359
  except ImportError:
317
360
  # Fallback: create a simple text-based PDF placeholder
318
- with open(filename, 'w', encoding='utf-8') as f:
361
+ with open(filename, "w", encoding="utf-8") as f:
319
362
  f.write("VPC Cleanup Analysis Report (PDF)\n")
320
363
  f.write("=" * 40 + "\n\n")
321
364
  f.write(f"Generated: {datetime.now().isoformat()}\n")
322
365
  f.write(f"Total VPC Candidates: {len(vpc_candidates)}\n\n")
323
-
366
+
324
367
  for i, candidate in enumerate(vpc_candidates, 1):
325
368
  f.write(f"{i}. VPC {getattr(candidate, 'vpc_id', 'Unknown')}\n")
326
369
  f.write(f" Account: {getattr(candidate, 'account_id', 'Unknown')}\n")
327
370
  f.write(f" CIDR: {getattr(candidate, 'cidr_block', 'Unknown')}\n")
328
- f.write(f" ENI Count: {getattr(candidate, 'dependency_analysis', {}).eni_count if hasattr(candidate, 'dependency_analysis') else 0}\n")
371
+ f.write(
372
+ f" ENI Count: {getattr(candidate, 'dependency_analysis', {}).eni_count if hasattr(candidate, 'dependency_analysis') else 0}\n"
373
+ )
329
374
  f.write(f" Decision: {getattr(candidate, 'cleanup_recommendation', 'unknown')}\n\n")
330
-
331
- return filename
375
+
376
+ return filename