runbooks 1.1.4__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.
- runbooks/__init__.py +31 -2
- runbooks/__init___optimized.py +18 -4
- runbooks/_platform/__init__.py +1 -5
- runbooks/_platform/core/runbooks_wrapper.py +141 -138
- runbooks/aws2/accuracy_validator.py +812 -0
- runbooks/base.py +7 -0
- runbooks/cfat/assessment/compliance.py +1 -1
- runbooks/cfat/assessment/runner.py +1 -0
- runbooks/cfat/cloud_foundations_assessment.py +227 -239
- runbooks/cli/__init__.py +1 -1
- runbooks/cli/commands/cfat.py +64 -23
- runbooks/cli/commands/finops.py +1005 -54
- runbooks/cli/commands/inventory.py +138 -35
- runbooks/cli/commands/operate.py +9 -36
- runbooks/cli/commands/security.py +42 -18
- runbooks/cli/commands/validation.py +432 -18
- runbooks/cli/commands/vpc.py +81 -17
- runbooks/cli/registry.py +22 -10
- runbooks/cloudops/__init__.py +20 -27
- runbooks/cloudops/base.py +96 -107
- runbooks/cloudops/cost_optimizer.py +544 -542
- runbooks/cloudops/infrastructure_optimizer.py +5 -4
- runbooks/cloudops/interfaces.py +224 -225
- runbooks/cloudops/lifecycle_manager.py +5 -4
- runbooks/cloudops/mcp_cost_validation.py +252 -235
- runbooks/cloudops/models.py +78 -53
- runbooks/cloudops/monitoring_automation.py +5 -4
- runbooks/cloudops/notebook_framework.py +177 -213
- runbooks/cloudops/security_enforcer.py +125 -159
- runbooks/common/accuracy_validator.py +11 -0
- runbooks/common/aws_pricing.py +349 -326
- runbooks/common/aws_pricing_api.py +211 -212
- runbooks/common/aws_profile_manager.py +40 -36
- runbooks/common/aws_utils.py +74 -79
- runbooks/common/business_logic.py +126 -104
- runbooks/common/cli_decorators.py +36 -60
- runbooks/common/comprehensive_cost_explorer_integration.py +455 -463
- runbooks/common/cross_account_manager.py +197 -204
- runbooks/common/date_utils.py +27 -39
- runbooks/common/decorators.py +29 -19
- runbooks/common/dry_run_examples.py +173 -208
- runbooks/common/dry_run_framework.py +157 -155
- runbooks/common/enhanced_exception_handler.py +15 -4
- runbooks/common/enhanced_logging_example.py +50 -64
- runbooks/common/enhanced_logging_integration_example.py +65 -37
- runbooks/common/env_utils.py +16 -16
- runbooks/common/error_handling.py +40 -38
- runbooks/common/lazy_loader.py +41 -23
- runbooks/common/logging_integration_helper.py +79 -86
- runbooks/common/mcp_cost_explorer_integration.py +476 -493
- runbooks/common/mcp_integration.py +63 -74
- runbooks/common/memory_optimization.py +140 -118
- runbooks/common/module_cli_base.py +37 -58
- runbooks/common/organizations_client.py +175 -193
- runbooks/common/patterns.py +23 -25
- runbooks/common/performance_monitoring.py +67 -71
- runbooks/common/performance_optimization_engine.py +283 -274
- runbooks/common/profile_utils.py +111 -37
- runbooks/common/rich_utils.py +201 -141
- runbooks/common/sre_performance_suite.py +177 -186
- runbooks/enterprise/__init__.py +1 -1
- runbooks/enterprise/logging.py +144 -106
- runbooks/enterprise/security.py +187 -204
- runbooks/enterprise/validation.py +43 -56
- runbooks/finops/__init__.py +26 -30
- runbooks/finops/account_resolver.py +1 -1
- runbooks/finops/advanced_optimization_engine.py +980 -0
- runbooks/finops/automation_core.py +268 -231
- runbooks/finops/business_case_config.py +184 -179
- runbooks/finops/cli.py +660 -139
- runbooks/finops/commvault_ec2_analysis.py +157 -164
- runbooks/finops/compute_cost_optimizer.py +336 -320
- runbooks/finops/config.py +20 -20
- runbooks/finops/cost_optimizer.py +484 -618
- runbooks/finops/cost_processor.py +332 -214
- runbooks/finops/dashboard_runner.py +1006 -172
- runbooks/finops/ebs_cost_optimizer.py +991 -657
- runbooks/finops/elastic_ip_optimizer.py +317 -257
- runbooks/finops/enhanced_mcp_integration.py +340 -0
- runbooks/finops/enhanced_progress.py +32 -29
- runbooks/finops/enhanced_trend_visualization.py +3 -2
- runbooks/finops/enterprise_wrappers.py +223 -285
- runbooks/finops/executive_export.py +203 -160
- runbooks/finops/helpers.py +130 -288
- runbooks/finops/iam_guidance.py +1 -1
- runbooks/finops/infrastructure/__init__.py +80 -0
- runbooks/finops/infrastructure/commands.py +506 -0
- runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
- runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
- runbooks/finops/markdown_exporter.py +337 -174
- runbooks/finops/mcp_validator.py +1952 -0
- runbooks/finops/nat_gateway_optimizer.py +1512 -481
- runbooks/finops/network_cost_optimizer.py +657 -587
- runbooks/finops/notebook_utils.py +226 -188
- runbooks/finops/optimization_engine.py +1136 -0
- runbooks/finops/optimizer.py +19 -23
- runbooks/finops/rds_snapshot_optimizer.py +367 -411
- runbooks/finops/reservation_optimizer.py +427 -363
- runbooks/finops/scenario_cli_integration.py +64 -65
- runbooks/finops/scenarios.py +1277 -438
- runbooks/finops/schemas.py +218 -182
- runbooks/finops/snapshot_manager.py +2289 -0
- runbooks/finops/types.py +3 -3
- runbooks/finops/validation_framework.py +259 -265
- runbooks/finops/vpc_cleanup_exporter.py +189 -144
- runbooks/finops/vpc_cleanup_optimizer.py +591 -573
- runbooks/finops/workspaces_analyzer.py +171 -182
- runbooks/integration/__init__.py +89 -0
- runbooks/integration/mcp_integration.py +1920 -0
- runbooks/inventory/CLAUDE.md +816 -0
- runbooks/inventory/__init__.py +2 -2
- runbooks/inventory/cloud_foundations_integration.py +144 -149
- runbooks/inventory/collectors/aws_comprehensive.py +1 -1
- runbooks/inventory/collectors/aws_networking.py +109 -99
- runbooks/inventory/collectors/base.py +4 -0
- runbooks/inventory/core/collector.py +495 -313
- runbooks/inventory/drift_detection_cli.py +69 -96
- runbooks/inventory/inventory_mcp_cli.py +48 -46
- runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
- runbooks/inventory/mcp_inventory_validator.py +549 -465
- runbooks/inventory/mcp_vpc_validator.py +359 -442
- runbooks/inventory/organizations_discovery.py +55 -51
- runbooks/inventory/rich_inventory_display.py +33 -32
- runbooks/inventory/unified_validation_engine.py +278 -251
- runbooks/inventory/vpc_analyzer.py +732 -695
- runbooks/inventory/vpc_architecture_validator.py +293 -348
- runbooks/inventory/vpc_dependency_analyzer.py +382 -378
- runbooks/inventory/vpc_flow_analyzer.py +1 -1
- runbooks/main.py +49 -34
- runbooks/main_final.py +91 -60
- runbooks/main_minimal.py +22 -10
- runbooks/main_optimized.py +131 -100
- runbooks/main_ultra_minimal.py +7 -2
- runbooks/mcp/__init__.py +36 -0
- runbooks/mcp/integration.py +679 -0
- runbooks/monitoring/performance_monitor.py +9 -4
- runbooks/operate/dynamodb_operations.py +3 -1
- runbooks/operate/ec2_operations.py +145 -137
- runbooks/operate/iam_operations.py +146 -152
- runbooks/operate/networking_cost_heatmap.py +29 -8
- runbooks/operate/rds_operations.py +223 -254
- runbooks/operate/s3_operations.py +107 -118
- runbooks/operate/vpc_operations.py +646 -616
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/commons.py +10 -7
- runbooks/remediation/commvault_ec2_analysis.py +70 -66
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
- runbooks/remediation/multi_account.py +24 -21
- runbooks/remediation/rds_snapshot_list.py +86 -60
- runbooks/remediation/remediation_cli.py +92 -146
- runbooks/remediation/universal_account_discovery.py +83 -79
- runbooks/remediation/workspaces_list.py +46 -41
- runbooks/security/__init__.py +19 -0
- runbooks/security/assessment_runner.py +1150 -0
- runbooks/security/baseline_checker.py +812 -0
- runbooks/security/cloudops_automation_security_validator.py +509 -535
- runbooks/security/compliance_automation_engine.py +17 -17
- runbooks/security/config/__init__.py +2 -2
- runbooks/security/config/compliance_config.py +50 -50
- runbooks/security/config_template_generator.py +63 -76
- runbooks/security/enterprise_security_framework.py +1 -1
- runbooks/security/executive_security_dashboard.py +519 -508
- runbooks/security/multi_account_security_controls.py +959 -1210
- runbooks/security/real_time_security_monitor.py +422 -444
- runbooks/security/security_baseline_tester.py +1 -1
- runbooks/security/security_cli.py +143 -112
- runbooks/security/test_2way_validation.py +439 -0
- runbooks/security/two_way_validation_framework.py +852 -0
- runbooks/sre/production_monitoring_framework.py +167 -177
- runbooks/tdd/__init__.py +15 -0
- runbooks/tdd/cli.py +1071 -0
- runbooks/utils/__init__.py +14 -17
- runbooks/utils/logger.py +7 -2
- runbooks/utils/version_validator.py +50 -47
- runbooks/validation/__init__.py +6 -6
- runbooks/validation/cli.py +9 -3
- runbooks/validation/comprehensive_2way_validator.py +745 -704
- runbooks/validation/mcp_validator.py +906 -228
- runbooks/validation/terraform_citations_validator.py +104 -115
- runbooks/validation/terraform_drift_detector.py +447 -451
- runbooks/vpc/README.md +617 -0
- runbooks/vpc/__init__.py +8 -1
- runbooks/vpc/analyzer.py +577 -0
- runbooks/vpc/cleanup_wrapper.py +476 -413
- runbooks/vpc/cli_cloudtrail_commands.py +339 -0
- runbooks/vpc/cli_mcp_validation_commands.py +480 -0
- runbooks/vpc/cloudtrail_audit_integration.py +717 -0
- runbooks/vpc/config.py +92 -97
- runbooks/vpc/cost_engine.py +411 -148
- runbooks/vpc/cost_explorer_integration.py +553 -0
- runbooks/vpc/cross_account_session.py +101 -106
- runbooks/vpc/enhanced_mcp_validation.py +917 -0
- runbooks/vpc/eni_gate_validator.py +961 -0
- runbooks/vpc/heatmap_engine.py +185 -160
- runbooks/vpc/mcp_no_eni_validator.py +680 -639
- runbooks/vpc/nat_gateway_optimizer.py +358 -0
- runbooks/vpc/networking_wrapper.py +15 -8
- runbooks/vpc/pdca_remediation_planner.py +528 -0
- runbooks/vpc/performance_optimized_analyzer.py +219 -231
- runbooks/vpc/runbooks_adapter.py +1167 -241
- runbooks/vpc/tdd_red_phase_stubs.py +601 -0
- runbooks/vpc/test_data_loader.py +358 -0
- runbooks/vpc/tests/conftest.py +314 -4
- runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
- runbooks/vpc/tests/test_cost_engine.py +0 -2
- runbooks/vpc/topology_generator.py +326 -0
- runbooks/vpc/unified_scenarios.py +1297 -1124
- runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
- runbooks-1.1.5.dist-info/METADATA +328 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/RECORD +214 -193
- runbooks/finops/README.md +0 -414
- runbooks/finops/accuracy_cross_validator.py +0 -647
- runbooks/finops/business_cases.py +0 -950
- runbooks/finops/dashboard_router.py +0 -922
- runbooks/finops/ebs_optimizer.py +0 -973
- runbooks/finops/embedded_mcp_validator.py +0 -1629
- runbooks/finops/enhanced_dashboard_runner.py +0 -527
- runbooks/finops/finops_dashboard.py +0 -584
- runbooks/finops/finops_scenarios.py +0 -1218
- runbooks/finops/legacy_migration.py +0 -730
- runbooks/finops/multi_dashboard.py +0 -1519
- runbooks/finops/single_dashboard.py +0 -1113
- runbooks/finops/unlimited_scenarios.py +0 -393
- runbooks-1.1.4.dist-info/METADATA +0 -800
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
- {runbooks-1.1.4.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -11,7 +11,7 @@ Strategic Alignment:
|
|
11
11
|
|
12
12
|
Features:
|
13
13
|
- Real-time AWS API cross-validation
|
14
|
-
- Terraform state drift detection
|
14
|
+
- Terraform state drift detection
|
15
15
|
- Rich CLI enterprise UX with visual indicators
|
16
16
|
- Evidence-based drift reporting
|
17
17
|
- Profile override priority system
|
@@ -34,7 +34,7 @@ from ..common.rich_utils import console, print_error, print_info, print_success
|
|
34
34
|
from .mcp_inventory_validator import (
|
35
35
|
create_inventory_mcp_validator,
|
36
36
|
generate_drift_report,
|
37
|
-
validate_inventory_results_with_mcp
|
37
|
+
validate_inventory_results_with_mcp,
|
38
38
|
)
|
39
39
|
|
40
40
|
|
@@ -45,46 +45,32 @@ def drift():
|
|
45
45
|
|
46
46
|
|
47
47
|
@drift.command("detect")
|
48
|
-
@click.option(
|
49
|
-
|
50
|
-
help="AWS profile to use (overrides environment variables)"
|
51
|
-
)
|
52
|
-
@click.option(
|
53
|
-
"--profiles",
|
54
|
-
help="Comma-separated list of AWS profiles for multi-account analysis"
|
55
|
-
)
|
48
|
+
@click.option("--profile", help="AWS profile to use (overrides environment variables)")
|
49
|
+
@click.option("--profiles", help="Comma-separated list of AWS profiles for multi-account analysis")
|
56
50
|
@click.option(
|
57
51
|
"--terraform-dir",
|
58
52
|
default="/Volumes/Working/1xOps/CloudOps-Runbooks/terraform-aws",
|
59
|
-
help="Path to terraform configuration directory"
|
53
|
+
help="Path to terraform configuration directory",
|
60
54
|
)
|
61
55
|
@click.option(
|
62
56
|
"--report-format",
|
63
57
|
type=click.Choice(["console", "json", "csv"]),
|
64
58
|
default="console",
|
65
|
-
help="Output format for drift report"
|
66
|
-
)
|
67
|
-
@click.option(
|
68
|
-
"--output-file",
|
69
|
-
help="File path to save drift report (optional)"
|
70
|
-
)
|
71
|
-
@click.option(
|
72
|
-
"--threshold",
|
73
|
-
type=float,
|
74
|
-
default=99.5,
|
75
|
-
help="Accuracy threshold for drift detection (default: 99.5%)"
|
59
|
+
help="Output format for drift report",
|
76
60
|
)
|
61
|
+
@click.option("--output-file", help="File path to save drift report (optional)")
|
62
|
+
@click.option("--threshold", type=float, default=99.5, help="Accuracy threshold for drift detection (default: 99.5%)")
|
77
63
|
def detect_drift(
|
78
64
|
profile: Optional[str],
|
79
|
-
profiles: Optional[str],
|
65
|
+
profiles: Optional[str],
|
80
66
|
terraform_dir: str,
|
81
67
|
report_format: str,
|
82
68
|
output_file: Optional[str],
|
83
|
-
threshold: float
|
69
|
+
threshold: float,
|
84
70
|
):
|
85
71
|
"""
|
86
72
|
Detect infrastructure drift using 3-way validation.
|
87
|
-
|
73
|
+
|
88
74
|
Compares inventory collection results against AWS API and terraform state
|
89
75
|
to identify discrepancies and provide actionable recommendations.
|
90
76
|
"""
|
@@ -98,9 +84,9 @@ def detect_drift(
|
|
98
84
|
# Use operational profile as default
|
99
85
|
default_profile = get_profile_for_operation("operational", None)
|
100
86
|
profile_list = [default_profile]
|
101
|
-
|
87
|
+
|
102
88
|
print_info(f"Starting drift detection for {len(profile_list)} profile(s)")
|
103
|
-
|
89
|
+
|
104
90
|
# Validate all profiles
|
105
91
|
valid_profiles = []
|
106
92
|
for prof in profile_list:
|
@@ -108,99 +94,83 @@ def detect_drift(
|
|
108
94
|
valid_profiles.append(prof)
|
109
95
|
else:
|
110
96
|
print_error(f"Profile '{prof}' validation failed - skipping")
|
111
|
-
|
97
|
+
|
112
98
|
if not valid_profiles:
|
113
99
|
print_error("No valid profiles available for drift detection")
|
114
100
|
return
|
115
|
-
|
101
|
+
|
116
102
|
# Create validator with terraform integration
|
117
|
-
validator = create_inventory_mcp_validator(
|
118
|
-
|
119
|
-
terraform_directory=terraform_dir
|
120
|
-
)
|
121
|
-
|
103
|
+
validator = create_inventory_mcp_validator(profiles=valid_profiles, terraform_directory=terraform_dir)
|
104
|
+
|
122
105
|
# Set custom threshold if provided
|
123
106
|
validator.validation_threshold = threshold
|
124
|
-
|
107
|
+
|
125
108
|
console.print(f"[blue]🔍 Initializing drift detection...[/]")
|
126
109
|
console.print(f"[dim]Terraform directory: {terraform_dir}[/]")
|
127
110
|
console.print(f"[dim]Accuracy threshold: {threshold}%[/]")
|
128
|
-
|
111
|
+
|
129
112
|
# For demonstration, create mock inventory data
|
130
113
|
# In practice, this would come from actual inventory collection
|
131
114
|
mock_inventory = _create_mock_inventory_data(valid_profiles)
|
132
|
-
|
115
|
+
|
133
116
|
# Perform enhanced validation with drift detection
|
134
117
|
validation_results = validator.validate_inventory_data(mock_inventory)
|
135
|
-
|
118
|
+
|
136
119
|
# Generate summary results
|
137
120
|
overall_accuracy = validation_results.get("total_accuracy", 0)
|
138
121
|
terraform_integration = validation_results.get("terraform_integration", {})
|
139
|
-
|
122
|
+
|
140
123
|
if validation_results.get("passed_validation", False):
|
141
124
|
print_success(f"✅ Drift detection completed: {overall_accuracy:.1f}% accuracy")
|
142
125
|
else:
|
143
126
|
console.print(f"[yellow]🔄 Infrastructure drift detected: {overall_accuracy:.1f}% accuracy[/]")
|
144
|
-
|
127
|
+
|
145
128
|
# Display terraform integration status
|
146
129
|
if terraform_integration.get("enabled", False):
|
147
130
|
tf_files = terraform_integration.get("state_files_discovered", 0)
|
148
131
|
print_info(f"Terraform integration: {tf_files} configuration files analyzed")
|
149
|
-
|
132
|
+
|
150
133
|
drift_analysis = terraform_integration.get("drift_analysis", {})
|
151
134
|
if drift_analysis:
|
152
135
|
drift_pct = drift_analysis.get("drift_percentage", 0)
|
153
136
|
tf_coverage = drift_analysis.get("terraform_coverage_percentage", 0)
|
154
137
|
console.print(f"[dim]📊 {drift_pct:.1f}% of accounts have drift detected[/]")
|
155
138
|
console.print(f"[dim]🎯 {tf_coverage:.1f}% of accounts have terraform coverage[/]")
|
156
|
-
|
139
|
+
|
157
140
|
# Generate and export report if requested
|
158
141
|
if output_file or report_format != "console":
|
159
142
|
drift_report = generate_drift_report(valid_profiles, mock_inventory, terraform_dir)
|
160
|
-
|
143
|
+
|
161
144
|
if output_file:
|
162
145
|
_export_drift_report(drift_report, output_file, report_format)
|
163
146
|
print_success(f"Drift report exported to: {output_file}")
|
164
|
-
|
147
|
+
|
165
148
|
print_info("Drift detection analysis complete")
|
166
|
-
|
149
|
+
|
167
150
|
except Exception as e:
|
168
151
|
print_error(f"Drift detection failed: {str(e)}")
|
169
152
|
raise click.Abort()
|
170
153
|
|
171
154
|
|
172
155
|
@drift.command("report")
|
173
|
-
@click.option(
|
174
|
-
"--profile",
|
175
|
-
help="AWS profile to use for single-account analysis"
|
176
|
-
)
|
156
|
+
@click.option("--profile", help="AWS profile to use for single-account analysis")
|
177
157
|
@click.option(
|
178
158
|
"--terraform-dir",
|
179
159
|
default="/Volumes/Working/1xOps/CloudOps-Runbooks/terraform-aws",
|
180
|
-
help="Path to terraform configuration directory"
|
160
|
+
help="Path to terraform configuration directory",
|
181
161
|
)
|
182
162
|
@click.option(
|
183
163
|
"--format",
|
184
164
|
"report_format",
|
185
165
|
type=click.Choice(["json", "csv", "markdown"]),
|
186
166
|
default="json",
|
187
|
-
help="Report output format"
|
167
|
+
help="Report output format",
|
188
168
|
)
|
189
|
-
@click.option(
|
190
|
-
|
191
|
-
"output_file",
|
192
|
-
required=True,
|
193
|
-
help="Output file path for drift report"
|
194
|
-
)
|
195
|
-
def generate_report(
|
196
|
-
profile: Optional[str],
|
197
|
-
terraform_dir: str,
|
198
|
-
report_format: str,
|
199
|
-
output_file: str
|
200
|
-
):
|
169
|
+
@click.option("--output", "output_file", required=True, help="Output file path for drift report")
|
170
|
+
def generate_report(profile: Optional[str], terraform_dir: str, report_format: str, output_file: str):
|
201
171
|
"""
|
202
172
|
Generate comprehensive infrastructure drift report.
|
203
|
-
|
173
|
+
|
204
174
|
Creates detailed drift analysis report with actionable recommendations
|
205
175
|
for infrastructure as code management and compliance.
|
206
176
|
"""
|
@@ -208,35 +178,35 @@ def generate_report(
|
|
208
178
|
# Use default profile if none specified
|
209
179
|
if not profile:
|
210
180
|
profile = get_profile_for_operation("operational", None)
|
211
|
-
|
181
|
+
|
212
182
|
print_info(f"Generating drift report for profile: {profile}")
|
213
|
-
|
183
|
+
|
214
184
|
# Validate profile
|
215
185
|
if not validate_profile_access(profile, "drift-reporting"):
|
216
186
|
print_error(f"Profile '{profile}' validation failed")
|
217
187
|
return
|
218
|
-
|
188
|
+
|
219
189
|
# Create mock inventory for demonstration
|
220
190
|
mock_inventory = _create_mock_inventory_data([profile])
|
221
|
-
|
191
|
+
|
222
192
|
# Generate comprehensive drift report
|
223
193
|
drift_report = generate_drift_report([profile], mock_inventory, terraform_dir)
|
224
|
-
|
194
|
+
|
225
195
|
# Export report
|
226
196
|
_export_drift_report(drift_report, output_file, report_format)
|
227
|
-
|
197
|
+
|
228
198
|
print_success(f"Drift report generated: {output_file}")
|
229
|
-
|
199
|
+
|
230
200
|
# Display summary
|
231
201
|
accounts_analyzed = drift_report.get("accounts_analyzed", 0)
|
232
202
|
overall_accuracy = drift_report.get("overall_accuracy", 0)
|
233
203
|
drift_detected = drift_report.get("drift_detected", False)
|
234
|
-
|
204
|
+
|
235
205
|
console.print(f"[dim]📊 Analysis Summary:[/]")
|
236
206
|
console.print(f"[dim] Accounts analyzed: {accounts_analyzed}[/]")
|
237
207
|
console.print(f"[dim] Overall accuracy: {overall_accuracy:.1f}%[/]")
|
238
208
|
console.print(f"[dim] Drift detected: {'Yes' if drift_detected else 'No'}[/]")
|
239
|
-
|
209
|
+
|
240
210
|
except Exception as e:
|
241
211
|
print_error(f"Report generation failed: {str(e)}")
|
242
212
|
raise click.Abort()
|
@@ -245,7 +215,7 @@ def generate_report(
|
|
245
215
|
def _create_mock_inventory_data(profiles: List[str]) -> dict:
|
246
216
|
"""Create mock inventory data for demonstration purposes."""
|
247
217
|
mock_data = {}
|
248
|
-
|
218
|
+
|
249
219
|
for profile in profiles:
|
250
220
|
mock_data[profile] = {
|
251
221
|
"resource_counts": {
|
@@ -258,12 +228,12 @@ def _create_mock_inventory_data(profiles: List[str]) -> dict:
|
|
258
228
|
"cloudformation": 4,
|
259
229
|
"elbv2": 1,
|
260
230
|
"route53": 2,
|
261
|
-
"sns": 3
|
231
|
+
"sns": 3,
|
262
232
|
},
|
263
233
|
"regions": ["us-east-1", "us-west-2", "ap-southeast-2"],
|
264
|
-
"collection_timestamp": "2024-09-10T12:00:00Z"
|
234
|
+
"collection_timestamp": "2024-09-10T12:00:00Z",
|
265
235
|
}
|
266
|
-
|
236
|
+
|
267
237
|
return mock_data
|
268
238
|
|
269
239
|
|
@@ -271,50 +241,53 @@ def _export_drift_report(report_data: dict, output_file: str, format_type: str)
|
|
271
241
|
"""Export drift report to specified format."""
|
272
242
|
import json
|
273
243
|
from pathlib import Path
|
274
|
-
|
244
|
+
|
275
245
|
output_path = Path(output_file)
|
276
246
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
277
|
-
|
247
|
+
|
278
248
|
if format_type == "json":
|
279
|
-
with open(output_path,
|
249
|
+
with open(output_path, "w") as f:
|
280
250
|
json.dump(report_data, f, indent=2, default=str)
|
281
251
|
elif format_type == "csv":
|
282
252
|
# Create CSV summary
|
283
253
|
import csv
|
284
|
-
|
254
|
+
|
255
|
+
with open(output_path, "w", newline="") as f:
|
285
256
|
writer = csv.writer(f)
|
286
|
-
writer.writerow([
|
287
|
-
|
257
|
+
writer.writerow(["Account ID", "Profile", "Accuracy %", "Drift Detected", "Terraform Coverage"])
|
258
|
+
|
288
259
|
for account in report_data.get("detailed_analysis", []):
|
289
|
-
writer.writerow(
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
260
|
+
writer.writerow(
|
261
|
+
[
|
262
|
+
account.get("account_id", "Unknown"),
|
263
|
+
account.get("profile", "Unknown"),
|
264
|
+
f"{account.get('accuracy_percent', 0):.1f}",
|
265
|
+
"Yes" if account.get("drift_summary", {}).get("drift_detected", 0) > 0 else "No",
|
266
|
+
"Yes" if account.get("terraform_coverage", False) else "No",
|
267
|
+
]
|
268
|
+
)
|
296
269
|
elif format_type == "markdown":
|
297
270
|
# Create markdown report
|
298
|
-
with open(output_path,
|
271
|
+
with open(output_path, "w") as f:
|
299
272
|
f.write("# Infrastructure Drift Analysis Report\n\n")
|
300
273
|
f.write(f"**Generated:** {report_data.get('generated_timestamp', 'Unknown')}\n\n")
|
301
|
-
|
274
|
+
|
302
275
|
terraform_info = report_data.get("terraform_integration", {})
|
303
276
|
f.write(f"**Terraform Integration:** {terraform_info.get('enabled', False)}\n")
|
304
277
|
f.write(f"**State Files Discovered:** {terraform_info.get('state_files_discovered', 0)}\n\n")
|
305
|
-
|
278
|
+
|
306
279
|
f.write("## Summary\n\n")
|
307
280
|
f.write(f"- **Accounts Analyzed:** {report_data.get('accounts_analyzed', 0)}\n")
|
308
281
|
f.write(f"- **Overall Accuracy:** {report_data.get('overall_accuracy', 0):.1f}%\n")
|
309
282
|
f.write(f"- **Drift Detected:** {'Yes' if report_data.get('drift_detected', False) else 'No'}\n\n")
|
310
|
-
|
283
|
+
|
311
284
|
f.write("## Detailed Analysis\n\n")
|
312
285
|
for account in report_data.get("detailed_analysis", []):
|
313
286
|
f.write(f"### Account: {account.get('account_id', 'Unknown')}\n\n")
|
314
287
|
f.write(f"- **Profile:** {account.get('profile', 'Unknown')}\n")
|
315
288
|
f.write(f"- **Accuracy:** {account.get('accuracy_percent', 0):.1f}%\n")
|
316
289
|
f.write(f"- **Terraform Coverage:** {'Yes' if account.get('terraform_coverage', False) else 'No'}\n\n")
|
317
|
-
|
290
|
+
|
318
291
|
recommendations = account.get("recommendations", [])
|
319
292
|
if recommendations:
|
320
293
|
f.write("**Recommendations:**\n")
|
@@ -324,4 +297,4 @@ def _export_drift_report(report_data: dict, output_file: str, format_type: str)
|
|
324
297
|
|
325
298
|
|
326
299
|
if __name__ == "__main__":
|
327
|
-
drift()
|
300
|
+
drift()
|
@@ -25,22 +25,28 @@ from .mcp_inventory_validator import create_inventory_mcp_validator
|
|
25
25
|
|
26
26
|
|
27
27
|
@click.command()
|
28
|
-
@click.option(
|
29
|
-
@click.option(
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
@click.option("--profile", help="AWS profile name (takes precedence over environment variables)")
|
29
|
+
@click.option(
|
30
|
+
"--resource-types",
|
31
|
+
multiple=True,
|
32
|
+
type=click.Choice(["ec2", "s3", "rds", "lambda", "vpc", "iam", "cloudformation"]),
|
33
|
+
default=["ec2", "s3", "vpc"],
|
34
|
+
help="Resource types to validate",
|
35
|
+
)
|
36
|
+
@click.option("--test-mode", is_flag=True, default=True, help="Run in test mode with sample data")
|
37
|
+
@click.option(
|
38
|
+
"--real-validation",
|
39
|
+
is_flag=True,
|
40
|
+
default=False,
|
41
|
+
help="Run validation against real AWS APIs (requires valid profiles)",
|
42
|
+
)
|
37
43
|
def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], test_mode: bool, real_validation: bool):
|
38
44
|
"""
|
39
45
|
Test inventory MCP validation functionality.
|
40
|
-
|
46
|
+
|
41
47
|
This command demonstrates inventory MCP validation integration
|
42
48
|
following proven enterprise patterns from FinOps module success.
|
43
|
-
|
49
|
+
|
44
50
|
Examples:
|
45
51
|
runbooks inventory validate-mcp --profile my-profile --resource-types ec2,s3
|
46
52
|
runbooks inventory validate-mcp --test-mode --resource-types ec2,vpc,rds
|
@@ -48,7 +54,9 @@ def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], te
|
|
48
54
|
"""
|
49
55
|
try:
|
50
56
|
console.print(f"[blue]🔍 Inventory MCP Validation Test[/blue]")
|
51
|
-
console.print(
|
57
|
+
console.print(
|
58
|
+
f"[dim]Profile: {profile or 'environment fallback'} | Resources: {', '.join(resource_types)} | Test mode: {test_mode}[/dim]"
|
59
|
+
)
|
52
60
|
|
53
61
|
# Apply profile priority system following proven patterns
|
54
62
|
operational_profile = get_profile_for_operation("operational", profile)
|
@@ -61,7 +69,7 @@ def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], te
|
|
61
69
|
if test_mode and not real_validation:
|
62
70
|
# Test mode: Use sample data to demonstrate validation
|
63
71
|
print_info("Running test mode with sample inventory data")
|
64
|
-
|
72
|
+
|
65
73
|
# Create sample inventory data for testing
|
66
74
|
sample_inventory = {
|
67
75
|
operational_profile: {
|
@@ -72,89 +80,83 @@ def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], te
|
|
72
80
|
"lambda": 12,
|
73
81
|
"vpc": 4,
|
74
82
|
"iam": 25,
|
75
|
-
"cloudformation": 6
|
83
|
+
"cloudformation": 6,
|
76
84
|
},
|
77
|
-
"regions": ["us-east-1", "us-west-2"]
|
85
|
+
"regions": ["us-east-1", "us-west-2"],
|
78
86
|
}
|
79
87
|
}
|
80
|
-
|
88
|
+
|
81
89
|
# Filter to requested resource types
|
82
90
|
filtered_inventory = {
|
83
91
|
operational_profile: {
|
84
92
|
"resource_counts": {
|
85
|
-
rt: sample_inventory[operational_profile]["resource_counts"].get(rt, 0)
|
86
|
-
for rt in resource_types
|
93
|
+
rt: sample_inventory[operational_profile]["resource_counts"].get(rt, 0) for rt in resource_types
|
87
94
|
},
|
88
|
-
"regions": sample_inventory[operational_profile]["regions"]
|
95
|
+
"regions": sample_inventory[operational_profile]["regions"],
|
89
96
|
}
|
90
97
|
}
|
91
|
-
|
92
|
-
print_info(
|
93
|
-
|
98
|
+
|
99
|
+
print_info(
|
100
|
+
f"Testing validation with sample resource counts: {filtered_inventory[operational_profile]['resource_counts']}"
|
101
|
+
)
|
102
|
+
|
94
103
|
# Note: In test mode, this will compare sample data against real AWS APIs
|
95
104
|
# This demonstrates the validation mechanism without requiring mock data
|
96
105
|
validation_results = validator.validate_inventory_data(filtered_inventory)
|
97
|
-
|
106
|
+
|
98
107
|
elif real_validation:
|
99
108
|
# Real validation mode: Requires actual inventory collection
|
100
109
|
print_warning("Real validation mode requires actual inventory collection")
|
101
110
|
print_info("This would typically be called from the main inventory collector")
|
102
|
-
|
111
|
+
|
103
112
|
# For demonstration, we'll validate empty inventory (should show 0 vs actual counts)
|
104
113
|
empty_inventory = {
|
105
|
-
operational_profile: {
|
106
|
-
"resource_counts": {rt: 0 for rt in resource_types},
|
107
|
-
"regions": ["us-east-1"]
|
108
|
-
}
|
114
|
+
operational_profile: {"resource_counts": {rt: 0 for rt in resource_types}, "regions": ["us-east-1"]}
|
109
115
|
}
|
110
|
-
|
116
|
+
|
111
117
|
print_info("Validating empty inventory against real AWS APIs (demonstrates detection capability)")
|
112
118
|
validation_results = validator.validate_inventory_data(empty_inventory)
|
113
|
-
|
119
|
+
|
114
120
|
else:
|
115
121
|
# Resource count validation only
|
116
122
|
print_info("Running resource count validation test")
|
117
|
-
|
118
|
-
sample_counts = {
|
119
|
-
|
120
|
-
"s3": 5,
|
121
|
-
"vpc": 2
|
122
|
-
}
|
123
|
-
|
123
|
+
|
124
|
+
sample_counts = {"ec2": 10, "s3": 5, "vpc": 2}
|
125
|
+
|
124
126
|
# Filter to requested resource types
|
125
127
|
test_counts = {rt: sample_counts.get(rt, 0) for rt in resource_types if rt in sample_counts}
|
126
|
-
|
128
|
+
|
127
129
|
validation_results = validator.validate_resource_counts(test_counts)
|
128
130
|
|
129
131
|
# Display results summary
|
130
132
|
console.print(f"\n[bright_cyan]📊 Validation Test Results Summary[/]")
|
131
|
-
|
133
|
+
|
132
134
|
if isinstance(validation_results, dict):
|
133
135
|
if "total_accuracy" in validation_results:
|
134
136
|
accuracy = validation_results.get("total_accuracy", 0)
|
135
137
|
passed = validation_results.get("passed_validation", False)
|
136
|
-
|
138
|
+
|
137
139
|
if passed:
|
138
140
|
print_success(f"✅ Test validation completed: {accuracy:.1f}% accuracy")
|
139
141
|
else:
|
140
142
|
print_warning(f"⚠️ Test validation: {accuracy:.1f}% accuracy (target: ≥99.5%)")
|
141
|
-
|
143
|
+
|
142
144
|
profiles_validated = validation_results.get("profiles_validated", 0)
|
143
145
|
console.print(f"[dim]Profiles validated: {profiles_validated}[/dim]")
|
144
|
-
|
146
|
+
|
145
147
|
# Show resource summary if available
|
146
148
|
resource_summary = validation_results.get("resource_validation_summary", {})
|
147
149
|
if resource_summary:
|
148
150
|
console.print(f"[dim]Resource types validated: {len(resource_summary)}[/dim]")
|
149
|
-
|
151
|
+
|
150
152
|
elif "validated_count" in validation_results:
|
151
153
|
validated_count = validation_results.get("validated_count", 0)
|
152
154
|
passed_count = validation_results.get("passed_count", 0)
|
153
155
|
print_info(f"Resource count validation: {passed_count}/{validated_count} passed")
|
154
|
-
|
156
|
+
|
155
157
|
else:
|
156
158
|
print_info("Validation completed - see detailed output above")
|
157
|
-
|
159
|
+
|
158
160
|
# Integration guidance
|
159
161
|
console.print(f"\n[bright_cyan]💡 Integration Information[/]")
|
160
162
|
console.print(f"[dim]This MCP validator is automatically integrated into:[/dim]")
|
@@ -168,4 +170,4 @@ def validate_inventory_mcp(profile: Optional[str], resource_types: List[str], te
|
|
168
170
|
|
169
171
|
|
170
172
|
if __name__ == "__main__":
|
171
|
-
validate_inventory_mcp()
|
173
|
+
validate_inventory_mcp()
|