runbooks 0.9.5__py3-none-any.whl → 0.9.7__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/_platform/__init__.py +19 -0
- runbooks/_platform/core/runbooks_wrapper.py +478 -0
- runbooks/cloudops/cost_optimizer.py +330 -0
- runbooks/cloudops/interfaces.py +3 -3
- runbooks/finops/README.md +1 -1
- runbooks/finops/automation_core.py +643 -0
- runbooks/finops/business_cases.py +414 -16
- runbooks/finops/cli.py +23 -0
- runbooks/finops/compute_cost_optimizer.py +865 -0
- runbooks/finops/ebs_cost_optimizer.py +718 -0
- runbooks/finops/ebs_optimizer.py +909 -0
- runbooks/finops/elastic_ip_optimizer.py +675 -0
- runbooks/finops/embedded_mcp_validator.py +330 -14
- runbooks/finops/enterprise_wrappers.py +827 -0
- runbooks/finops/legacy_migration.py +730 -0
- runbooks/finops/nat_gateway_optimizer.py +1160 -0
- runbooks/finops/network_cost_optimizer.py +1387 -0
- runbooks/finops/notebook_utils.py +596 -0
- runbooks/finops/reservation_optimizer.py +956 -0
- runbooks/finops/validation_framework.py +753 -0
- runbooks/finops/workspaces_analyzer.py +593 -0
- runbooks/inventory/__init__.py +7 -0
- runbooks/inventory/collectors/aws_networking.py +357 -6
- runbooks/inventory/mcp_vpc_validator.py +1091 -0
- runbooks/inventory/vpc_analyzer.py +1107 -0
- runbooks/inventory/vpc_architecture_validator.py +939 -0
- runbooks/inventory/vpc_dependency_analyzer.py +845 -0
- runbooks/main.py +425 -39
- runbooks/operate/vpc_operations.py +1479 -16
- runbooks/remediation/commvault_ec2_analysis.py +5 -4
- runbooks/remediation/dynamodb_optimize.py +2 -2
- runbooks/remediation/rds_instance_list.py +1 -1
- runbooks/remediation/rds_snapshot_list.py +5 -4
- runbooks/remediation/workspaces_list.py +2 -2
- runbooks/security/compliance_automation.py +2 -2
- runbooks/vpc/tests/test_config.py +2 -2
- {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/METADATA +1 -1
- {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/RECORD +43 -24
- {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/WHEEL +0 -0
- {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/entry_points.txt +0 -0
- {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/licenses/LICENSE +0 -0
- {runbooks-0.9.5.dist-info → runbooks-0.9.7.dist-info}/top_level.txt +0 -0
runbooks/main.py
CHANGED
@@ -5348,9 +5348,9 @@ def emergency_response(ctx, spike_threshold, target_savings, analysis_days, max_
|
|
5348
5348
|
|
5349
5349
|
# Export reports if requested
|
5350
5350
|
if export_reports:
|
5351
|
-
exported = result.export_reports('
|
5351
|
+
exported = result.export_reports('./tmp/emergency-cost-reports')
|
5352
5352
|
if exported.get('json'):
|
5353
|
-
print_success(f"📊 Executive reports exported to:
|
5353
|
+
print_success(f"📊 Executive reports exported to: ./tmp/emergency-cost-reports")
|
5354
5354
|
|
5355
5355
|
# Exit with success/failure status
|
5356
5356
|
if result.success:
|
@@ -5549,7 +5549,7 @@ def cost_optimization():
|
|
5549
5549
|
@click.option("--analyze", is_flag=True, help="Perform detailed cost analysis")
|
5550
5550
|
@click.option("--calculate-savings", is_flag=True, help="Calculate cost savings for cleanup")
|
5551
5551
|
@click.option("--unused-days", default=180, help="Days threshold for considering WorkSpace unused (JIRA FinOps-24)")
|
5552
|
-
@click.option("--output-file", default="
|
5552
|
+
@click.option("--output-file", default="./tmp/workspaces_cost_analysis.csv", help="Output CSV file path")
|
5553
5553
|
def workspaces(profile, region, dry_run, analyze, calculate_savings, unused_days, output_file):
|
5554
5554
|
"""
|
5555
5555
|
FinOps-24: WorkSpaces cleanup analysis for $12,518 annual savings.
|
@@ -5598,7 +5598,7 @@ def workspaces(profile, region, dry_run, analyze, calculate_savings, unused_days
|
|
5598
5598
|
@click.option("--older-than", default=90, help="Focus on snapshots older than X days (JIRA FinOps-23)")
|
5599
5599
|
@click.option("--calculate-savings", is_flag=True, help="Calculate detailed cost savings analysis")
|
5600
5600
|
@click.option("--analyze", is_flag=True, help="Perform comprehensive cost analysis")
|
5601
|
-
@click.option("--output-file", default="
|
5601
|
+
@click.option("--output-file", default="./tmp/rds_snapshots_cost_analysis.csv", help="Output CSV file path")
|
5602
5602
|
def rds_snapshots(profile, region, dry_run, manual_only, older_than, calculate_savings, analyze, output_file):
|
5603
5603
|
"""
|
5604
5604
|
FinOps-23: RDS manual snapshots analysis for $5K-24K annual savings.
|
@@ -5645,7 +5645,7 @@ def rds_snapshots(profile, region, dry_run, manual_only, older_than, calculate_s
|
|
5645
5645
|
@common_aws_options
|
5646
5646
|
@click.option("--account", default="637423383469", help="Commvault backup account ID (JIRA FinOps-25)")
|
5647
5647
|
@click.option("--investigate-utilization", is_flag=True, help="Investigate EC2 utilization patterns")
|
5648
|
-
@click.option("--output-file", default="
|
5648
|
+
@click.option("--output-file", default="./tmp/commvault_ec2_analysis.csv", help="Output CSV file path")
|
5649
5649
|
def commvault_ec2(profile, region, dry_run, account, investigate_utilization, output_file):
|
5650
5650
|
"""
|
5651
5651
|
FinOps-25: Commvault EC2 investigation for cost optimization.
|
@@ -5688,7 +5688,7 @@ def commvault_ec2(profile, region, dry_run, account, investigate_utilization, ou
|
|
5688
5688
|
@cost_optimization.command()
|
5689
5689
|
@common_aws_options
|
5690
5690
|
@click.option("--all-scenarios", is_flag=True, help="Run all JIRA cost optimization scenarios")
|
5691
|
-
@click.option("--output-dir", default="
|
5691
|
+
@click.option("--output-dir", default="./tmp/cost_optimization_reports", help="Directory for all reports")
|
5692
5692
|
def comprehensive_analysis(profile, region, dry_run, all_scenarios, output_dir):
|
5693
5693
|
"""
|
5694
5694
|
Comprehensive analysis of all JIRA cost optimization scenarios.
|
@@ -5850,8 +5850,8 @@ def _parse_profiles_parameter(profiles_tuple):
|
|
5850
5850
|
)
|
5851
5851
|
@click.option(
|
5852
5852
|
"--scenario",
|
5853
|
-
type=click.Choice(["workspaces", "snapshots", "commvault"], case_sensitive=False),
|
5854
|
-
help="Business scenario analysis: workspaces (FinOps-24: $13,020 savings), snapshots (FinOps-23: $119,700 savings), commvault (FinOps-25: investigation)"
|
5853
|
+
type=click.Choice(["workspaces", "snapshots", "commvault", "nat-gateway", "elastic-ip", "ebs"], case_sensitive=False),
|
5854
|
+
help="Business scenario analysis: workspaces (FinOps-24: $13,020 savings), snapshots (FinOps-23: $119,700 savings), commvault (FinOps-25: investigation), nat-gateway (FinOps-26: $8K-$12K potential), elastic-ip (FinOps-EIP: $3.65/month direct savings), ebs (FinOps-EBS: 15-20% storage optimization)"
|
5855
5855
|
)
|
5856
5856
|
@click.pass_context
|
5857
5857
|
def finops(
|
@@ -5895,6 +5895,9 @@ def finops(
|
|
5895
5895
|
runbooks finops --scenario workspaces # FinOps-24: WorkSpaces cleanup ($13,020 annual)
|
5896
5896
|
runbooks finops --scenario snapshots # FinOps-23: RDS snapshots ($119,700 annual)
|
5897
5897
|
runbooks finops --scenario commvault # FinOps-25: EC2 investigation framework
|
5898
|
+
runbooks finops --scenario nat-gateway # FinOps-26: NAT Gateway optimization ($8K-$12K potential)
|
5899
|
+
runbooks finops --scenario elastic-ip # FinOps-EIP: Elastic IP cleanup ($3.65/month per EIP)
|
5900
|
+
runbooks finops --scenario ebs # FinOps-EBS: Storage optimization (15-20% cost reduction)
|
5898
5901
|
|
5899
5902
|
GENERAL ANALYTICS:
|
5900
5903
|
runbooks finops --audit --csv --report-name audit_report
|
@@ -5914,20 +5917,199 @@ def finops(
|
|
5914
5917
|
print_info(f"Executing scenario: {scenario.upper()}")
|
5915
5918
|
|
5916
5919
|
try:
|
5920
|
+
# Import CloudOps cost optimizer for enhanced JIRA scenario integration
|
5921
|
+
from runbooks.cloudops.cost_optimizer import CostOptimizer
|
5922
|
+
from runbooks.cloudops.models import ExecutionMode
|
5923
|
+
import asyncio
|
5924
|
+
|
5925
|
+
# Initialize CloudOps cost optimizer with enterprise patterns
|
5926
|
+
execution_mode = ExecutionMode.ANALYSIS if dry_run else ExecutionMode.EXECUTION
|
5927
|
+
cost_optimizer = CostOptimizer(
|
5928
|
+
profile=primary_profile or "default",
|
5929
|
+
region=region or "us-east-1",
|
5930
|
+
execution_mode=execution_mode
|
5931
|
+
)
|
5932
|
+
|
5917
5933
|
if scenario.lower() == "workspaces":
|
5918
5934
|
print_info("FinOps-24: WorkSpaces cleanup analysis ($13,020 annual savings - 104% target achievement)")
|
5919
|
-
|
5920
|
-
|
5935
|
+
print_info("🚀 Enhanced with CloudOps enterprise integration")
|
5936
|
+
|
5937
|
+
# Use CloudOps cost optimizer for enterprise-grade analysis
|
5938
|
+
workspaces_result = asyncio.run(cost_optimizer.optimize_workspaces(
|
5939
|
+
usage_threshold_days=180, # 6 months as per JIRA requirement
|
5940
|
+
dry_run=dry_run
|
5941
|
+
))
|
5942
|
+
|
5943
|
+
# Convert to legacy format for backward compatibility
|
5944
|
+
results = {
|
5945
|
+
"scenario": "FinOps-24",
|
5946
|
+
"business_case": "WorkSpaces Cleanup",
|
5947
|
+
"annual_savings": workspaces_result.annual_savings,
|
5948
|
+
"monthly_savings": workspaces_result.total_monthly_savings,
|
5949
|
+
"affected_resources": workspaces_result.affected_resources,
|
5950
|
+
"success": workspaces_result.success,
|
5951
|
+
"execution_mode": workspaces_result.execution_mode.value,
|
5952
|
+
"risk_level": workspaces_result.resource_impacts[0].risk_level.value if workspaces_result.resource_impacts else "LOW"
|
5953
|
+
}
|
5921
5954
|
|
5922
5955
|
elif scenario.lower() == "snapshots":
|
5923
5956
|
print_info("FinOps-23: RDS snapshots optimization ($119,700 annual savings - 498% target achievement)")
|
5924
|
-
|
5925
|
-
|
5957
|
+
print_info("🚀 Enhanced with CloudOps enterprise integration")
|
5958
|
+
|
5959
|
+
# Use CloudOps cost optimizer for enterprise-grade analysis
|
5960
|
+
snapshots_result = asyncio.run(cost_optimizer.optimize_rds_snapshots(
|
5961
|
+
snapshot_age_threshold_days=90, # 3 months threshold
|
5962
|
+
dry_run=dry_run
|
5963
|
+
))
|
5964
|
+
|
5965
|
+
# Convert to legacy format for backward compatibility
|
5966
|
+
results = {
|
5967
|
+
"scenario": "FinOps-23",
|
5968
|
+
"business_case": "RDS Snapshots Cleanup",
|
5969
|
+
"annual_savings": snapshots_result.annual_savings,
|
5970
|
+
"monthly_savings": snapshots_result.total_monthly_savings,
|
5971
|
+
"affected_resources": snapshots_result.affected_resources,
|
5972
|
+
"success": snapshots_result.success,
|
5973
|
+
"execution_mode": snapshots_result.execution_mode.value,
|
5974
|
+
"risk_level": snapshots_result.resource_impacts[0].risk_level.value if snapshots_result.resource_impacts else "MEDIUM"
|
5975
|
+
}
|
5926
5976
|
|
5927
5977
|
elif scenario.lower() == "commvault":
|
5928
5978
|
print_info("FinOps-25: Commvault EC2 investigation framework (Real AWS integration)")
|
5929
|
-
|
5930
|
-
|
5979
|
+
print_info("🚀 Enhanced with CloudOps enterprise integration")
|
5980
|
+
|
5981
|
+
# Use CloudOps cost optimizer for enterprise-grade investigation
|
5982
|
+
commvault_result = asyncio.run(cost_optimizer.investigate_commvault_ec2(
|
5983
|
+
account_id="637423383469", # From JIRA specification
|
5984
|
+
dry_run=True # Always dry-run for investigations
|
5985
|
+
))
|
5986
|
+
|
5987
|
+
# Convert to legacy format for backward compatibility
|
5988
|
+
results = {
|
5989
|
+
"scenario": "FinOps-25",
|
5990
|
+
"business_case": "Commvault EC2 Investigation",
|
5991
|
+
"annual_savings": commvault_result.annual_savings,
|
5992
|
+
"monthly_savings": commvault_result.total_monthly_savings,
|
5993
|
+
"affected_resources": commvault_result.affected_resources,
|
5994
|
+
"success": commvault_result.success,
|
5995
|
+
"execution_mode": commvault_result.execution_mode.value,
|
5996
|
+
"risk_level": commvault_result.resource_impacts[0].risk_level.value if commvault_result.resource_impacts else "HIGH",
|
5997
|
+
"investigation_status": "Framework Established"
|
5998
|
+
}
|
5999
|
+
|
6000
|
+
elif scenario.lower() == "nat-gateway":
|
6001
|
+
print_info("FinOps-26: NAT Gateway cost optimization ($8K-$12K potential annual savings)")
|
6002
|
+
print_info("🚀 Enterprise multi-region analysis with network dependency validation")
|
6003
|
+
|
6004
|
+
# Use dedicated NAT Gateway optimizer for specialized analysis
|
6005
|
+
from runbooks.finops.nat_gateway_optimizer import NATGatewayOptimizer
|
6006
|
+
|
6007
|
+
nat_optimizer = NATGatewayOptimizer(
|
6008
|
+
profile_name=primary_profile or "default",
|
6009
|
+
regions=regions or ["us-east-1", "us-west-2", "eu-west-1"]
|
6010
|
+
)
|
6011
|
+
|
6012
|
+
nat_result = asyncio.run(nat_optimizer.analyze_nat_gateways(dry_run=dry_run))
|
6013
|
+
|
6014
|
+
# Convert to legacy format for backward compatibility
|
6015
|
+
results = {
|
6016
|
+
"scenario": "FinOps-26",
|
6017
|
+
"business_case": "NAT Gateway Cost Optimization",
|
6018
|
+
"annual_savings": nat_result.potential_annual_savings,
|
6019
|
+
"monthly_savings": nat_result.potential_monthly_savings,
|
6020
|
+
"total_nat_gateways": nat_result.total_nat_gateways,
|
6021
|
+
"analyzed_regions": nat_result.analyzed_regions,
|
6022
|
+
"current_annual_cost": nat_result.total_annual_cost,
|
6023
|
+
"execution_time": nat_result.execution_time_seconds,
|
6024
|
+
"mcp_validation_accuracy": nat_result.mcp_validation_accuracy,
|
6025
|
+
"success": True,
|
6026
|
+
"risk_level": "LOW", # READ-ONLY analysis
|
6027
|
+
"optimization_summary": {
|
6028
|
+
"decommission_candidates": len([r for r in nat_result.optimization_results if r.optimization_recommendation == "decommission"]),
|
6029
|
+
"investigation_candidates": len([r for r in nat_result.optimization_results if r.optimization_recommendation == "investigate"]),
|
6030
|
+
"retain_recommendations": len([r for r in nat_result.optimization_results if r.optimization_recommendation == "retain"])
|
6031
|
+
}
|
6032
|
+
}
|
6033
|
+
|
6034
|
+
elif scenario.lower() == "elastic-ip":
|
6035
|
+
print_info("FinOps-EIP: Elastic IP cost optimization ($3.65/month per unattached EIP)")
|
6036
|
+
print_info("🚀 Enterprise multi-region analysis with DNS dependency validation")
|
6037
|
+
|
6038
|
+
# Use dedicated Elastic IP optimizer for specialized analysis
|
6039
|
+
from runbooks.finops.elastic_ip_optimizer import ElasticIPOptimizer
|
6040
|
+
|
6041
|
+
eip_optimizer = ElasticIPOptimizer(
|
6042
|
+
profile_name=primary_profile or "default",
|
6043
|
+
regions=regions or ["us-east-1", "us-west-2", "eu-west-1", "us-east-2"]
|
6044
|
+
)
|
6045
|
+
|
6046
|
+
eip_result = asyncio.run(eip_optimizer.analyze_elastic_ips(dry_run=dry_run))
|
6047
|
+
|
6048
|
+
# Convert to legacy format for backward compatibility
|
6049
|
+
results = {
|
6050
|
+
"scenario": "FinOps-EIP",
|
6051
|
+
"business_case": "Elastic IP Cost Optimization",
|
6052
|
+
"annual_savings": eip_result.potential_annual_savings,
|
6053
|
+
"monthly_savings": eip_result.potential_monthly_savings,
|
6054
|
+
"total_elastic_ips": eip_result.total_elastic_ips,
|
6055
|
+
"attached_elastic_ips": eip_result.attached_elastic_ips,
|
6056
|
+
"unattached_elastic_ips": eip_result.unattached_elastic_ips,
|
6057
|
+
"analyzed_regions": eip_result.analyzed_regions,
|
6058
|
+
"current_annual_cost": eip_result.total_annual_cost,
|
6059
|
+
"execution_time": eip_result.execution_time_seconds,
|
6060
|
+
"mcp_validation_accuracy": eip_result.mcp_validation_accuracy,
|
6061
|
+
"success": True,
|
6062
|
+
"risk_level": "LOW", # READ-ONLY analysis
|
6063
|
+
"optimization_summary": {
|
6064
|
+
"release_candidates": len([r for r in eip_result.optimization_results if r.optimization_recommendation == "release"]),
|
6065
|
+
"investigation_candidates": len([r for r in eip_result.optimization_results if r.optimization_recommendation == "investigate"]),
|
6066
|
+
"retain_recommendations": len([r for r in eip_result.optimization_results if r.optimization_recommendation == "retain"])
|
6067
|
+
}
|
6068
|
+
}
|
6069
|
+
|
6070
|
+
elif scenario.lower() == "ebs":
|
6071
|
+
print_info("FinOps-EBS: EBS Volume storage optimization (15-20% cost reduction potential)")
|
6072
|
+
print_info("🚀 Enterprise comprehensive analysis: GP2→GP3 + Usage + Orphaned cleanup")
|
6073
|
+
|
6074
|
+
# Use dedicated EBS optimizer for specialized analysis
|
6075
|
+
from runbooks.finops.ebs_optimizer import EBSOptimizer
|
6076
|
+
|
6077
|
+
ebs_optimizer = EBSOptimizer(
|
6078
|
+
profile_name=primary_profile or "default",
|
6079
|
+
regions=regions or ["us-east-1", "us-west-2", "eu-west-1"]
|
6080
|
+
)
|
6081
|
+
|
6082
|
+
ebs_result = asyncio.run(ebs_optimizer.analyze_ebs_volumes(dry_run=dry_run))
|
6083
|
+
|
6084
|
+
# Convert to legacy format for backward compatibility
|
6085
|
+
results = {
|
6086
|
+
"scenario": "FinOps-EBS",
|
6087
|
+
"business_case": "EBS Volume Storage Optimization",
|
6088
|
+
"annual_savings": ebs_result.total_potential_annual_savings,
|
6089
|
+
"monthly_savings": ebs_result.total_potential_monthly_savings,
|
6090
|
+
"total_volumes": ebs_result.total_volumes,
|
6091
|
+
"gp2_volumes": ebs_result.gp2_volumes,
|
6092
|
+
"gp3_eligible_volumes": ebs_result.gp3_eligible_volumes,
|
6093
|
+
"low_usage_volumes": ebs_result.low_usage_volumes,
|
6094
|
+
"orphaned_volumes": ebs_result.orphaned_volumes,
|
6095
|
+
"analyzed_regions": ebs_result.analyzed_regions,
|
6096
|
+
"current_annual_cost": ebs_result.total_annual_cost,
|
6097
|
+
"execution_time": ebs_result.execution_time_seconds,
|
6098
|
+
"mcp_validation_accuracy": ebs_result.mcp_validation_accuracy,
|
6099
|
+
"success": True,
|
6100
|
+
"risk_level": "LOW", # READ-ONLY analysis
|
6101
|
+
"optimization_breakdown": {
|
6102
|
+
"gp3_conversion_savings": ebs_result.gp3_potential_annual_savings,
|
6103
|
+
"low_usage_savings": ebs_result.low_usage_potential_annual_savings,
|
6104
|
+
"orphaned_cleanup_savings": ebs_result.orphaned_potential_annual_savings
|
6105
|
+
},
|
6106
|
+
"optimization_summary": {
|
6107
|
+
"gp3_convert_candidates": len([r for r in ebs_result.optimization_results if r.optimization_recommendation == "gp3_convert"]),
|
6108
|
+
"usage_investigation_candidates": len([r for r in ebs_result.optimization_results if r.optimization_recommendation == "investigate_usage"]),
|
6109
|
+
"orphaned_cleanup_candidates": len([r for r in ebs_result.optimization_results if r.optimization_recommendation == "cleanup_orphaned"]),
|
6110
|
+
"retain_recommendations": len([r for r in ebs_result.optimization_results if r.optimization_recommendation == "retain"])
|
6111
|
+
}
|
6112
|
+
}
|
5931
6113
|
|
5932
6114
|
# Handle output file if report_name specified
|
5933
6115
|
if report_name:
|
@@ -6222,6 +6404,185 @@ def finops_mcp_validation(profile, target_accuracy):
|
|
6222
6404
|
raise click.Abort()
|
6223
6405
|
|
6224
6406
|
|
6407
|
+
@main.command("nat-gateway")
|
6408
|
+
@click.option('--profile', help='AWS profile name (3-tier priority: User > Environment > Default)')
|
6409
|
+
@click.option('--regions', multiple=True, help='AWS regions to analyze (space-separated)')
|
6410
|
+
@click.option('--dry-run/--no-dry-run', default=True, help='Execute in dry-run mode (READ-ONLY analysis)')
|
6411
|
+
@click.option('--export-format', type=click.Choice(['json', 'csv', 'markdown']),
|
6412
|
+
default='json', help='Export format for results')
|
6413
|
+
@click.option('--output-file', help='Output file path for results export')
|
6414
|
+
@click.option('--usage-threshold-days', type=int, default=7,
|
6415
|
+
help='CloudWatch analysis period in days')
|
6416
|
+
def nat_gateway_optimizer_cmd(profile, regions, dry_run, export_format, output_file, usage_threshold_days):
|
6417
|
+
"""
|
6418
|
+
NAT Gateway Cost Optimizer - Enterprise Multi-Region Analysis
|
6419
|
+
|
6420
|
+
Part of $132,720+ annual savings methodology targeting $8K-$12K NAT Gateway optimization.
|
6421
|
+
|
6422
|
+
SAFETY: READ-ONLY analysis only - no resource modifications.
|
6423
|
+
|
6424
|
+
UNIFIED CLI: Use 'runbooks finops --scenario nat-gateway' for integrated workflow.
|
6425
|
+
|
6426
|
+
Examples:
|
6427
|
+
runbooks nat-gateway --analyze
|
6428
|
+
runbooks nat-gateway --profile my-profile --regions us-east-1 us-west-2
|
6429
|
+
runbooks nat-gateway --export-format csv --output-file nat_analysis.csv
|
6430
|
+
"""
|
6431
|
+
try:
|
6432
|
+
from runbooks.finops.nat_gateway_optimizer import NATGatewayOptimizer
|
6433
|
+
import asyncio
|
6434
|
+
|
6435
|
+
# Initialize optimizer
|
6436
|
+
optimizer = NATGatewayOptimizer(
|
6437
|
+
profile_name=profile,
|
6438
|
+
regions=list(regions) if regions else None
|
6439
|
+
)
|
6440
|
+
|
6441
|
+
# Execute analysis
|
6442
|
+
results = asyncio.run(optimizer.analyze_nat_gateways(dry_run=dry_run))
|
6443
|
+
|
6444
|
+
# Export results if requested
|
6445
|
+
if output_file or export_format != 'json':
|
6446
|
+
optimizer.export_results(results, output_file, export_format)
|
6447
|
+
|
6448
|
+
# Display final success message
|
6449
|
+
from runbooks.common.rich_utils import print_success, print_info, format_cost
|
6450
|
+
if results.potential_annual_savings > 0:
|
6451
|
+
print_success(f"Analysis complete: {format_cost(results.potential_annual_savings)} potential annual savings identified")
|
6452
|
+
else:
|
6453
|
+
print_info("Analysis complete: All NAT Gateways are optimally configured")
|
6454
|
+
|
6455
|
+
except KeyboardInterrupt:
|
6456
|
+
console.print("[yellow]Analysis interrupted by user[/yellow]")
|
6457
|
+
raise click.Abort()
|
6458
|
+
except Exception as e:
|
6459
|
+
console.print(f"[red]NAT Gateway analysis failed: {e}[/red]")
|
6460
|
+
raise click.Abort()
|
6461
|
+
|
6462
|
+
|
6463
|
+
@main.command("elastic-ip")
|
6464
|
+
@click.option('--profile', help='AWS profile name (3-tier priority: User > Environment > Default)')
|
6465
|
+
@click.option('--regions', multiple=True, help='AWS regions to analyze (space-separated)')
|
6466
|
+
@click.option('--dry-run/--no-dry-run', default=True, help='Execute in dry-run mode (READ-ONLY analysis)')
|
6467
|
+
@click.option('--export-format', type=click.Choice(['json', 'csv', 'markdown']),
|
6468
|
+
default='json', help='Export format for results')
|
6469
|
+
@click.option('--output-file', help='Output file path for results export')
|
6470
|
+
def elastic_ip_optimizer_cmd(profile, regions, dry_run, export_format, output_file):
|
6471
|
+
"""
|
6472
|
+
Elastic IP Cost Optimizer - Enterprise Multi-Region Analysis
|
6473
|
+
|
6474
|
+
Part of $132,720+ annual savings methodology targeting direct cost elimination.
|
6475
|
+
|
6476
|
+
SAFETY: READ-ONLY analysis only - no resource modifications.
|
6477
|
+
|
6478
|
+
UNIFIED CLI: Use 'runbooks finops --scenario elastic-ip' for integrated workflow.
|
6479
|
+
|
6480
|
+
Examples:
|
6481
|
+
runbooks elastic-ip --cleanup
|
6482
|
+
runbooks elastic-ip --profile my-profile --regions us-east-1 us-west-2
|
6483
|
+
runbooks elastic-ip --export-format csv --output-file eip_analysis.csv
|
6484
|
+
"""
|
6485
|
+
try:
|
6486
|
+
from runbooks.finops.elastic_ip_optimizer import ElasticIPOptimizer
|
6487
|
+
|
6488
|
+
# Initialize optimizer
|
6489
|
+
optimizer = ElasticIPOptimizer(
|
6490
|
+
profile_name=profile,
|
6491
|
+
regions=list(regions) if regions else None
|
6492
|
+
)
|
6493
|
+
|
6494
|
+
# Execute analysis
|
6495
|
+
results = asyncio.run(optimizer.analyze_elastic_ips(dry_run=dry_run))
|
6496
|
+
|
6497
|
+
# Export results if requested
|
6498
|
+
if output_file or export_format != 'json':
|
6499
|
+
optimizer.export_results(results, output_file, export_format)
|
6500
|
+
|
6501
|
+
# Display final success message
|
6502
|
+
from runbooks.common.rich_utils import print_success, print_info, format_cost
|
6503
|
+
if results.potential_annual_savings > 0:
|
6504
|
+
print_success(f"Analysis complete: {format_cost(results.potential_annual_savings)} potential annual savings identified")
|
6505
|
+
else:
|
6506
|
+
print_info("Analysis complete: All Elastic IPs are optimally configured")
|
6507
|
+
|
6508
|
+
except KeyboardInterrupt:
|
6509
|
+
console.print("[yellow]Analysis interrupted by user[/yellow]")
|
6510
|
+
raise click.Abort()
|
6511
|
+
except Exception as e:
|
6512
|
+
console.print(f"[red]Elastic IP analysis failed: {e}[/red]")
|
6513
|
+
raise click.Abort()
|
6514
|
+
|
6515
|
+
|
6516
|
+
@main.command("ebs")
|
6517
|
+
@click.option('--profile', help='AWS profile name (3-tier priority: User > Environment > Default)')
|
6518
|
+
@click.option('--regions', multiple=True, help='AWS regions to analyze (space-separated)')
|
6519
|
+
@click.option('--dry-run/--no-dry-run', default=True, help='Execute in dry-run mode (READ-ONLY analysis)')
|
6520
|
+
@click.option('--export-format', type=click.Choice(['json', 'csv', 'markdown']),
|
6521
|
+
default='json', help='Export format for results')
|
6522
|
+
@click.option('--output-file', help='Output file path for results export')
|
6523
|
+
@click.option('--usage-threshold-days', type=int, default=7,
|
6524
|
+
help='CloudWatch analysis period in days')
|
6525
|
+
def ebs_optimizer_cmd(profile, regions, dry_run, export_format, output_file, usage_threshold_days):
|
6526
|
+
"""
|
6527
|
+
EBS Volume Optimizer - Enterprise Multi-Region Storage Analysis
|
6528
|
+
|
6529
|
+
Comprehensive EBS storage cost optimization combining 3 strategies:
|
6530
|
+
• GP2→GP3 conversion analysis (15-20% storage cost reduction)
|
6531
|
+
• Low usage volume detection via CloudWatch metrics
|
6532
|
+
• Orphaned volume cleanup from stopped/terminated instances
|
6533
|
+
|
6534
|
+
Part of $132,720+ annual savings methodology completing Tier 1 High-Value engine.
|
6535
|
+
|
6536
|
+
SAFETY: READ-ONLY analysis only - no resource modifications.
|
6537
|
+
|
6538
|
+
UNIFIED CLI: Use 'runbooks finops --scenario ebs' for integrated workflow.
|
6539
|
+
|
6540
|
+
Examples:
|
6541
|
+
runbooks ebs --optimize
|
6542
|
+
runbooks ebs --profile my-profile --regions us-east-1 us-west-2
|
6543
|
+
runbooks ebs --export-format csv --output-file ebs_analysis.csv
|
6544
|
+
"""
|
6545
|
+
try:
|
6546
|
+
from runbooks.finops.ebs_optimizer import EBSOptimizer
|
6547
|
+
import asyncio
|
6548
|
+
|
6549
|
+
# Initialize optimizer
|
6550
|
+
optimizer = EBSOptimizer(
|
6551
|
+
profile_name=profile,
|
6552
|
+
regions=list(regions) if regions else None
|
6553
|
+
)
|
6554
|
+
|
6555
|
+
# Execute comprehensive analysis
|
6556
|
+
results = asyncio.run(optimizer.analyze_ebs_volumes(dry_run=dry_run))
|
6557
|
+
|
6558
|
+
# Export results if requested
|
6559
|
+
if output_file or export_format != 'json':
|
6560
|
+
optimizer.export_results(results, output_file, export_format)
|
6561
|
+
|
6562
|
+
# Display final success message
|
6563
|
+
from runbooks.common.rich_utils import print_success, print_info, format_cost
|
6564
|
+
if results.total_potential_annual_savings > 0:
|
6565
|
+
savings_breakdown = []
|
6566
|
+
if results.gp3_potential_annual_savings > 0:
|
6567
|
+
savings_breakdown.append(f"GP2→GP3: {format_cost(results.gp3_potential_annual_savings)}")
|
6568
|
+
if results.low_usage_potential_annual_savings > 0:
|
6569
|
+
savings_breakdown.append(f"Usage: {format_cost(results.low_usage_potential_annual_savings)}")
|
6570
|
+
if results.orphaned_potential_annual_savings > 0:
|
6571
|
+
savings_breakdown.append(f"Orphaned: {format_cost(results.orphaned_potential_annual_savings)}")
|
6572
|
+
|
6573
|
+
print_success(f"Analysis complete: {format_cost(results.total_potential_annual_savings)} potential annual savings")
|
6574
|
+
print_info(f"Optimization strategies: {' | '.join(savings_breakdown)}")
|
6575
|
+
else:
|
6576
|
+
print_info("Analysis complete: All EBS volumes are optimally configured")
|
6577
|
+
|
6578
|
+
except KeyboardInterrupt:
|
6579
|
+
console.print("[yellow]Analysis interrupted by user[/yellow]")
|
6580
|
+
raise click.Abort()
|
6581
|
+
except Exception as e:
|
6582
|
+
console.print(f"[red]EBS optimization analysis failed: {e}[/red]")
|
6583
|
+
raise click.Abort()
|
6584
|
+
|
6585
|
+
|
6225
6586
|
# ============================================================================
|
6226
6587
|
# HELPER FUNCTIONS
|
6227
6588
|
# ============================================================================
|
@@ -6931,44 +7292,69 @@ def vpc(ctx):
|
|
6931
7292
|
|
6932
7293
|
@vpc.command()
|
6933
7294
|
@common_aws_options
|
6934
|
-
@click.option("--
|
6935
|
-
@click.option("--
|
6936
|
-
@click.option("--
|
7295
|
+
@click.option("--vpc-ids", multiple=True, help="Specific VPC IDs to analyze (space-separated)")
|
7296
|
+
@click.option("--output-dir", default="./awso_evidence", help="Output directory for evidence")
|
7297
|
+
@click.option("--generate-evidence", is_flag=True, default=True, help="Generate AWSO-05 evidence bundle")
|
6937
7298
|
@click.pass_context
|
6938
|
-
def analyze(ctx, profile, region, dry_run,
|
7299
|
+
def analyze(ctx, profile, region, dry_run, vpc_ids, output_dir, generate_evidence):
|
6939
7300
|
"""
|
6940
|
-
🔍
|
7301
|
+
🔍 Comprehensive VPC analysis with AWSO-05 integration
|
7302
|
+
|
7303
|
+
Migrated from VPC module with enhanced capabilities:
|
7304
|
+
- Complete VPC topology discovery
|
7305
|
+
- 12-step AWSO-05 dependency analysis
|
7306
|
+
- ENI gate validation for workload protection
|
7307
|
+
- Evidence bundle generation for compliance
|
6941
7308
|
|
6942
7309
|
Examples:
|
6943
|
-
runbooks vpc analyze --profile prod
|
6944
|
-
runbooks vpc analyze --
|
7310
|
+
runbooks vpc analyze --profile prod
|
7311
|
+
runbooks vpc analyze --vpc-ids vpc-123 vpc-456 --generate-evidence
|
7312
|
+
runbooks vpc analyze --output-dir ./custom_evidence
|
6945
7313
|
"""
|
6946
|
-
console.print("[cyan]🔍 VPC
|
7314
|
+
console.print("[cyan]🔍 VPC Analysis - Enhanced with VPC Module Integration[/cyan]")
|
6947
7315
|
|
6948
7316
|
try:
|
6949
|
-
from runbooks.
|
7317
|
+
from runbooks.operate.vpc_operations import VPCOperations
|
7318
|
+
from runbooks.inventory.vpc_analyzer import VPCAnalyzer
|
6950
7319
|
|
6951
|
-
# Initialize
|
6952
|
-
|
6953
|
-
|
6954
|
-
|
7320
|
+
# Initialize VPC operations with analyzer integration
|
7321
|
+
vpc_ops = VPCOperations(profile=profile, region=region, dry_run=dry_run)
|
7322
|
+
|
7323
|
+
# Convert tuple to list for VPC IDs
|
7324
|
+
vpc_id_list = list(vpc_ids) if vpc_ids else None
|
6955
7325
|
|
6956
|
-
|
6957
|
-
|
6958
|
-
|
7326
|
+
console.print(f"\n🔍 Starting comprehensive VPC analysis...")
|
7327
|
+
if vpc_id_list:
|
7328
|
+
console.print(f"Analyzing specific VPCs: {', '.join(vpc_id_list)}")
|
7329
|
+
else:
|
7330
|
+
console.print("Analyzing all VPCs in region")
|
7331
|
+
console.print(f"📊 Analysis includes: topology discovery, cost analysis, AWSO-05 compliance")
|
6959
7332
|
|
6960
|
-
#
|
6961
|
-
|
6962
|
-
|
7333
|
+
# Execute integrated VPC analysis workflow
|
7334
|
+
results = vpc_ops.execute_integrated_vpc_analysis(
|
7335
|
+
vpc_ids=vpc_id_list,
|
7336
|
+
generate_evidence=generate_evidence
|
7337
|
+
)
|
6963
7338
|
|
6964
|
-
#
|
6965
|
-
|
6966
|
-
|
6967
|
-
|
6968
|
-
|
7339
|
+
# Display results summary
|
7340
|
+
summary = results['analysis_summary']
|
7341
|
+
console.print(f"\n✅ VPC Analysis Complete!")
|
7342
|
+
console.print(f"📊 Resources discovered: {summary['total_resources']}")
|
7343
|
+
console.print(f"💰 Monthly network cost: ${summary['estimated_monthly_cost']:.2f}")
|
7344
|
+
|
7345
|
+
if summary['default_vpcs_found'] > 0:
|
7346
|
+
console.print(f"🚨 Default VPCs found: {summary['default_vpcs_found']} (security risk)")
|
7347
|
+
|
7348
|
+
if summary['eni_gate_warnings'] > 0:
|
7349
|
+
console.print(f"⚠️ ENI warnings: {summary['eni_gate_warnings']} (workload protection)")
|
7350
|
+
|
7351
|
+
console.print(f"🎯 Cleanup readiness: {summary['cleanup_readiness']}")
|
7352
|
+
|
7353
|
+
if results.get('evidence_files'):
|
7354
|
+
console.print(f"📋 Evidence bundle: {len(results['evidence_files'])} files in {output_dir}")
|
6969
7355
|
|
6970
7356
|
except Exception as e:
|
6971
|
-
console.print(f"[red]❌ Error: {e}[/red]")
|
7357
|
+
console.print(f"[red]❌ VPC Analysis Error: {e}[/red]")
|
6972
7358
|
logger.error(f"VPC analysis failed: {e}")
|
6973
7359
|
sys.exit(1)
|
6974
7360
|
|