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.
- 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/WEIGHT_CONFIG_README.md +1 -1
- runbooks/cfat/assessment/compliance.py +8 -8
- runbooks/cfat/assessment/runner.py +1 -0
- runbooks/cfat/cloud_foundations_assessment.py +227 -239
- runbooks/cfat/models.py +6 -2
- runbooks/cfat/tests/__init__.py +6 -1
- runbooks/cli/__init__.py +13 -0
- runbooks/cli/commands/cfat.py +274 -0
- runbooks/cli/commands/finops.py +1164 -0
- runbooks/cli/commands/inventory.py +379 -0
- runbooks/cli/commands/operate.py +239 -0
- runbooks/cli/commands/security.py +248 -0
- runbooks/cli/commands/validation.py +825 -0
- runbooks/cli/commands/vpc.py +310 -0
- runbooks/cli/registry.py +107 -0
- runbooks/cloudops/__init__.py +23 -30
- runbooks/cloudops/base.py +96 -107
- runbooks/cloudops/cost_optimizer.py +549 -547
- runbooks/cloudops/infrastructure_optimizer.py +5 -4
- runbooks/cloudops/interfaces.py +226 -227
- 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 +179 -215
- 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 +341 -0
- runbooks/common/aws_utils.py +75 -80
- runbooks/common/business_logic.py +127 -105
- runbooks/common/cli_decorators.py +36 -60
- runbooks/common/comprehensive_cost_explorer_integration.py +456 -464
- runbooks/common/cross_account_manager.py +198 -205
- runbooks/common/date_utils.py +27 -39
- runbooks/common/decorators.py +235 -0
- 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 +478 -495
- 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 +176 -194
- runbooks/common/patterns.py +204 -0
- runbooks/common/performance_monitoring.py +67 -71
- runbooks/common/performance_optimization_engine.py +283 -274
- runbooks/common/profile_utils.py +248 -39
- runbooks/common/rich_utils.py +643 -92
- 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 +29 -33
- 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 +488 -622
- 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 +40 -37
- runbooks/finops/enhanced_trend_visualization.py +3 -2
- runbooks/finops/enterprise_wrappers.py +230 -292
- 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 +338 -175
- runbooks/finops/mcp_validator.py +1952 -0
- runbooks/finops/nat_gateway_optimizer.py +1513 -482
- 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 +25 -29
- runbooks/finops/rds_snapshot_optimizer.py +367 -411
- runbooks/finops/reservation_optimizer.py +427 -363
- runbooks/finops/scenario_cli_integration.py +77 -78
- runbooks/finops/scenarios.py +1278 -439
- runbooks/finops/schemas.py +218 -182
- runbooks/finops/snapshot_manager.py +2289 -0
- runbooks/finops/tests/test_finops_dashboard.py +3 -3
- runbooks/finops/tests/test_reference_images_validation.py +2 -2
- runbooks/finops/tests/test_single_account_features.py +17 -17
- runbooks/finops/tests/validate_test_suite.py +1 -1
- runbooks/finops/types.py +3 -3
- runbooks/finops/validation_framework.py +263 -269
- runbooks/finops/vpc_cleanup_exporter.py +191 -146
- runbooks/finops/vpc_cleanup_optimizer.py +593 -575
- runbooks/finops/workspaces_analyzer.py +171 -182
- runbooks/hitl/enhanced_workflow_engine.py +1 -1
- runbooks/integration/__init__.py +89 -0
- runbooks/integration/mcp_integration.py +1920 -0
- runbooks/inventory/CLAUDE.md +816 -0
- runbooks/inventory/README.md +3 -3
- runbooks/inventory/Tests/common_test_data.py +30 -30
- runbooks/inventory/__init__.py +2 -2
- runbooks/inventory/cloud_foundations_integration.py +144 -149
- runbooks/inventory/collectors/aws_comprehensive.py +28 -11
- runbooks/inventory/collectors/aws_networking.py +111 -101
- runbooks/inventory/collectors/base.py +4 -0
- runbooks/inventory/core/collector.py +495 -313
- runbooks/inventory/discovery.md +2 -2
- runbooks/inventory/drift_detection_cli.py +69 -96
- runbooks/inventory/find_ec2_security_groups.py +1 -1
- 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 +56 -52
- runbooks/inventory/rich_inventory_display.py +33 -32
- runbooks/inventory/unified_validation_engine.py +278 -251
- runbooks/inventory/vpc_analyzer.py +733 -696
- runbooks/inventory/vpc_architecture_validator.py +293 -348
- runbooks/inventory/vpc_dependency_analyzer.py +382 -378
- runbooks/inventory/vpc_flow_analyzer.py +3 -3
- runbooks/main.py +152 -9147
- 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/metrics/dora_metrics_engine.py +2 -2
- 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/mcp_integration.py +1 -1
- runbooks/operate/networking_cost_heatmap.py +33 -10
- runbooks/operate/privatelink_operations.py +1 -1
- runbooks/operate/rds_operations.py +223 -254
- runbooks/operate/s3_operations.py +107 -118
- runbooks/operate/vpc_endpoints.py +1 -1
- runbooks/operate/vpc_operations.py +648 -618
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/commons.py +10 -7
- runbooks/remediation/commvault_ec2_analysis.py +71 -67
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
- runbooks/remediation/multi_account.py +24 -21
- runbooks/remediation/rds_snapshot_list.py +91 -65
- runbooks/remediation/remediation_cli.py +92 -146
- runbooks/remediation/universal_account_discovery.py +83 -79
- runbooks/remediation/workspaces_list.py +49 -44
- 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/integration_test_enterprise_security.py +5 -3
- runbooks/security/multi_account_security_controls.py +959 -1210
- runbooks/security/real_time_security_monitor.py +422 -444
- runbooks/security/run_script.py +1 -1
- 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/mcp_reliability_engine.py +6 -6
- 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 +51 -48
- runbooks/validation/__init__.py +6 -6
- runbooks/validation/cli.py +9 -3
- runbooks/validation/comprehensive_2way_validator.py +754 -708
- 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 +190 -162
- runbooks/vpc/mcp_no_eni_validator.py +681 -640
- 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 +1302 -1129
- runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
- runbooks-1.1.5.dist-info/METADATA +328 -0
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/RECORD +233 -200
- 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 -956
- 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.3.dist-info/METADATA +0 -799
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1136 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
FinOps Unified Optimization Engine - Enterprise Cost Optimization Platform
|
4
|
+
|
5
|
+
Strategic Framework: Consolidated optimization engine implementing strategy pattern for
|
6
|
+
comprehensive AWS cost optimization following enterprise safety-first principles.
|
7
|
+
|
8
|
+
UNIFIED CAPABILITIES (Strategy Pattern Implementation):
|
9
|
+
- EC2 Instance Optimization (idle detection, rightsizing, reservation analysis)
|
10
|
+
- EBS Volume Optimization (GP2→GP3 conversion, orphaned volumes, low usage detection)
|
11
|
+
- NAT Gateway Optimization (usage analysis, cost reduction, VPC endpoint alternatives)
|
12
|
+
- Network Cost Optimization (data transfer, Transit Gateway, VPC endpoint strategy)
|
13
|
+
- Reserved Instance Optimization (multi-service RI recommendations, ROI analysis)
|
14
|
+
- Elastic IP Optimization (unused EIP detection and cleanup)
|
15
|
+
- RDS Snapshot Optimization (automated cleanup, lifecycle management)
|
16
|
+
- Compute Cost Optimization (auto-scaling, spot instance recommendations)
|
17
|
+
- VPC Cleanup Optimization (unused resources, security group cleanup)
|
18
|
+
- General Resource Optimization (tagging, lifecycle policies, automation)
|
19
|
+
- Cost Analysis & Reporting (consolidated savings projections, executive reporting)
|
20
|
+
|
21
|
+
Technical Foundation: Strategy pattern with enterprise MCP validation targeting $79,922+ annual savings
|
22
|
+
Business Impact: Systematic cost optimization across all AWS services with evidence-based recommendations
|
23
|
+
Strategic Alignment: FAANG SDLC with comprehensive audit trails and safety-first implementation
|
24
|
+
|
25
|
+
Author: CloudOps Runbooks Team
|
26
|
+
Version: 2.0.0 - Unified Strategy Pattern Implementation
|
27
|
+
"""
|
28
|
+
|
29
|
+
import asyncio
|
30
|
+
import logging
|
31
|
+
import time
|
32
|
+
from abc import ABC, abstractmethod
|
33
|
+
from dataclasses import dataclass
|
34
|
+
from datetime import datetime, timedelta
|
35
|
+
from enum import Enum
|
36
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
37
|
+
|
38
|
+
import boto3
|
39
|
+
from botocore.exceptions import ClientError, NoCredentialsError
|
40
|
+
from pydantic import BaseModel, Field
|
41
|
+
|
42
|
+
from ..common.aws_profile_manager import AWSProfileManager
|
43
|
+
from ..common.profile_utils import get_profile_for_operation
|
44
|
+
from ..common.rich_utils import (
|
45
|
+
STATUS_INDICATORS,
|
46
|
+
console,
|
47
|
+
create_panel,
|
48
|
+
create_progress_bar,
|
49
|
+
create_table,
|
50
|
+
format_cost,
|
51
|
+
print_error,
|
52
|
+
print_header,
|
53
|
+
print_info,
|
54
|
+
print_success,
|
55
|
+
print_warning,
|
56
|
+
)
|
57
|
+
from .mcp_validator import EmbeddedMCPValidator
|
58
|
+
|
59
|
+
logger = logging.getLogger(__name__)
|
60
|
+
|
61
|
+
|
62
|
+
class OptimizationDepth(str, Enum):
|
63
|
+
"""Analysis depth levels for optimization engine."""
|
64
|
+
|
65
|
+
BASIC = "basic"
|
66
|
+
COMPREHENSIVE = "comprehensive"
|
67
|
+
ENTERPRISE = "enterprise"
|
68
|
+
|
69
|
+
|
70
|
+
class OptimizationStrategy(str, Enum):
|
71
|
+
"""Unified optimization strategies available in the engine."""
|
72
|
+
|
73
|
+
# Compute optimizations
|
74
|
+
EC2_IDLE_DETECTION = "ec2_idle_detection"
|
75
|
+
EC2_RIGHTSIZING = "ec2_rightsizing"
|
76
|
+
COMPUTE_COST_OPTIMIZATION = "compute_cost_optimization"
|
77
|
+
|
78
|
+
# Storage optimizations
|
79
|
+
EBS_GP2_TO_GP3_CONVERSION = "ebs_gp2_to_gp3"
|
80
|
+
EBS_ORPHANED_VOLUMES = "ebs_orphaned_volumes"
|
81
|
+
EBS_LOW_USAGE = "ebs_low_usage"
|
82
|
+
RDS_SNAPSHOT_CLEANUP = "rds_snapshot_cleanup"
|
83
|
+
|
84
|
+
# Network optimizations
|
85
|
+
NAT_GATEWAY_OPTIMIZATION = "nat_gateway_optimization"
|
86
|
+
ELASTIC_IP_OPTIMIZATION = "elastic_ip_optimization"
|
87
|
+
NETWORK_COST_OPTIMIZATION = "network_cost_optimization"
|
88
|
+
VPC_CLEANUP_OPTIMIZATION = "vpc_cleanup_optimization"
|
89
|
+
|
90
|
+
# Financial optimizations
|
91
|
+
RESERVED_INSTANCE_OPTIMIZATION = "reserved_instance_optimization"
|
92
|
+
|
93
|
+
# Cross-cutting optimizations
|
94
|
+
COMPREHENSIVE_COST_ANALYSIS = "comprehensive_cost_analysis"
|
95
|
+
|
96
|
+
# Legacy resource types (for backward compatibility)
|
97
|
+
EC2 = "ec2"
|
98
|
+
S3 = "s3"
|
99
|
+
RDS = "rds"
|
100
|
+
LAMBDA = "lambda"
|
101
|
+
VPC = "vpc"
|
102
|
+
EBS = "ebs"
|
103
|
+
|
104
|
+
|
105
|
+
class ResourceType(str, Enum):
|
106
|
+
"""Supported resource types for optimization (legacy support)."""
|
107
|
+
|
108
|
+
EC2 = "ec2"
|
109
|
+
S3 = "s3"
|
110
|
+
RDS = "rds"
|
111
|
+
LAMBDA = "lambda"
|
112
|
+
VPC = "vpc"
|
113
|
+
EBS = "ebs"
|
114
|
+
|
115
|
+
|
116
|
+
# Strategy Pattern Base Classes
|
117
|
+
class OptimizationStrategyBase(ABC):
|
118
|
+
"""Abstract base class for optimization strategies."""
|
119
|
+
|
120
|
+
def __init__(self, session: boto3.Session, region: str, profile: str):
|
121
|
+
self.session = session
|
122
|
+
self.region = region
|
123
|
+
self.profile = profile
|
124
|
+
self.logger = logging.getLogger(f"{__name__}.{self.__class__.__name__}")
|
125
|
+
|
126
|
+
@abstractmethod
|
127
|
+
async def analyze(self, **kwargs) -> "OptimizationResults":
|
128
|
+
"""Execute optimization analysis for this strategy."""
|
129
|
+
pass
|
130
|
+
|
131
|
+
@abstractmethod
|
132
|
+
def get_strategy_name(self) -> str:
|
133
|
+
"""Return the name of this optimization strategy."""
|
134
|
+
pass
|
135
|
+
|
136
|
+
@abstractmethod
|
137
|
+
def get_estimated_savings_range(self) -> Tuple[float, float]:
|
138
|
+
"""Return estimated savings range (min, max) for this strategy."""
|
139
|
+
pass
|
140
|
+
|
141
|
+
|
142
|
+
@dataclass
|
143
|
+
class UsageMetrics:
|
144
|
+
"""Unified usage metrics across all optimization strategies."""
|
145
|
+
|
146
|
+
resource_id: str
|
147
|
+
resource_type: str
|
148
|
+
region: str
|
149
|
+
utilization_percentage: float = 0.0
|
150
|
+
active_connections: float = 0.0
|
151
|
+
data_transfer_gb: float = 0.0
|
152
|
+
read_operations: float = 0.0
|
153
|
+
write_operations: float = 0.0
|
154
|
+
idle_time_percentage: float = 0.0
|
155
|
+
analysis_period_days: int = 7
|
156
|
+
is_underutilized: bool = False
|
157
|
+
|
158
|
+
|
159
|
+
class OptimizationRecommendation(BaseModel):
|
160
|
+
"""Enhanced optimization recommendation with strategy context."""
|
161
|
+
|
162
|
+
resource_id: str
|
163
|
+
resource_type: str
|
164
|
+
region: str
|
165
|
+
optimization_strategy: str
|
166
|
+
current_cost_monthly: float
|
167
|
+
projected_savings_monthly: float
|
168
|
+
projected_savings_annual: float
|
169
|
+
confidence_level: str = "HIGH" # HIGH, MEDIUM, LOW
|
170
|
+
risk_assessment: str = "LOW" # LOW, MEDIUM, HIGH
|
171
|
+
implementation_effort: str = "LOW" # LOW, MEDIUM, HIGH
|
172
|
+
recommendation_type: str = "optimize" # optimize, resize, terminate, migrate, convert
|
173
|
+
detailed_recommendation: str = ""
|
174
|
+
implementation_steps: List[str] = Field(default_factory=list)
|
175
|
+
business_impact: str = ""
|
176
|
+
technical_details: Dict[str, Any] = Field(default_factory=dict)
|
177
|
+
usage_metrics: Optional[UsageMetrics] = None
|
178
|
+
tags: Dict[str, str] = Field(default_factory=dict)
|
179
|
+
|
180
|
+
# ROI and financial analysis
|
181
|
+
break_even_months: Optional[float] = None
|
182
|
+
roi_percentage: Optional[float] = None
|
183
|
+
upfront_cost: float = 0.0
|
184
|
+
|
185
|
+
|
186
|
+
class OptimizationResults(BaseModel):
|
187
|
+
"""Enhanced optimization analysis results with strategy context."""
|
188
|
+
|
189
|
+
optimization_strategies: List[str] = Field(default_factory=list)
|
190
|
+
analysis_depth: str = "comprehensive"
|
191
|
+
savings_target: float = 0.3
|
192
|
+
total_current_monthly_cost: float = 0.0
|
193
|
+
total_projected_monthly_savings: float = 0.0
|
194
|
+
total_projected_annual_savings: float = 0.0
|
195
|
+
roi_percentage: float = 0.0
|
196
|
+
analysis_timestamp: datetime = Field(default_factory=datetime.now)
|
197
|
+
recommendations: List[OptimizationRecommendation] = Field(default_factory=list)
|
198
|
+
summary_statistics: Dict[str, Any] = Field(default_factory=dict)
|
199
|
+
risk_assessment_summary: str = ""
|
200
|
+
implementation_timeline: str = ""
|
201
|
+
mcp_validation_results: Dict[str, Any] = Field(default_factory=dict)
|
202
|
+
|
203
|
+
# Strategy-specific results
|
204
|
+
strategy_results: Dict[str, Dict[str, Any]] = Field(default_factory=dict)
|
205
|
+
cross_strategy_synergies: List[str] = Field(default_factory=list)
|
206
|
+
implementation_priority_order: List[str] = Field(default_factory=list)
|
207
|
+
|
208
|
+
|
209
|
+
# Concrete Optimization Strategy Implementations
|
210
|
+
class EC2IdleDetectionStrategy(OptimizationStrategyBase):
|
211
|
+
"""EC2 idle instance detection and stopping strategy."""
|
212
|
+
|
213
|
+
def get_strategy_name(self) -> str:
|
214
|
+
return "EC2 Idle Instance Detection"
|
215
|
+
|
216
|
+
def get_estimated_savings_range(self) -> Tuple[float, float]:
|
217
|
+
return (5000.0, 25000.0) # Monthly savings range
|
218
|
+
|
219
|
+
async def analyze(
|
220
|
+
self, idle_cpu_threshold: int = 5, idle_duration_hours: int = 168, **kwargs
|
221
|
+
) -> OptimizationResults:
|
222
|
+
"""Analyze EC2 instances for idle patterns and optimization opportunities."""
|
223
|
+
print_info(
|
224
|
+
f"🖥️ Analyzing EC2 instances for idle patterns (CPU < {idle_cpu_threshold}% for {idle_duration_hours}h)"
|
225
|
+
)
|
226
|
+
|
227
|
+
recommendations = []
|
228
|
+
total_current_cost = 0.0
|
229
|
+
total_savings = 0.0
|
230
|
+
|
231
|
+
try:
|
232
|
+
ec2_client = self.session.client("ec2", region_name=self.region)
|
233
|
+
cloudwatch_client = self.session.client("cloudwatch", region_name=self.region)
|
234
|
+
|
235
|
+
# Get all running instances
|
236
|
+
response = ec2_client.describe_instances(Filters=[{"Name": "instance-state-name", "Values": ["running"]}])
|
237
|
+
|
238
|
+
instances = []
|
239
|
+
for reservation in response["Reservations"]:
|
240
|
+
instances.extend(reservation["Instances"])
|
241
|
+
|
242
|
+
with create_progress_bar() as progress:
|
243
|
+
task = progress.add_task("Analyzing EC2 instances...", total=len(instances))
|
244
|
+
|
245
|
+
for instance in instances:
|
246
|
+
instance_id = instance["InstanceId"]
|
247
|
+
instance_type = instance.get("InstanceType", "unknown")
|
248
|
+
|
249
|
+
# Analyze CPU utilization
|
250
|
+
usage_metrics = await self._get_instance_usage_metrics(
|
251
|
+
cloudwatch_client, instance_id, idle_duration_hours
|
252
|
+
)
|
253
|
+
|
254
|
+
if usage_metrics.utilization_percentage < idle_cpu_threshold:
|
255
|
+
monthly_cost = self._estimate_instance_monthly_cost(instance_type)
|
256
|
+
total_current_cost += monthly_cost
|
257
|
+
|
258
|
+
if usage_metrics.utilization_percentage < 2:
|
259
|
+
# Very low utilization - recommend termination
|
260
|
+
projected_savings = monthly_cost * 0.95
|
261
|
+
recommendation_type = "terminate"
|
262
|
+
detailed_rec = f"Instance shows {usage_metrics.utilization_percentage:.1f}% CPU utilization. Consider termination."
|
263
|
+
risk = "LOW"
|
264
|
+
else:
|
265
|
+
# Low utilization - recommend downsizing
|
266
|
+
projected_savings = monthly_cost * 0.40
|
267
|
+
recommendation_type = "resize"
|
268
|
+
detailed_rec = f"Instance shows {usage_metrics.utilization_percentage:.1f}% CPU utilization. Consider downsizing."
|
269
|
+
risk = "MEDIUM"
|
270
|
+
|
271
|
+
total_savings += projected_savings
|
272
|
+
|
273
|
+
tags = {tag["Key"]: tag["Value"] for tag in instance.get("Tags", [])}
|
274
|
+
|
275
|
+
recommendation = OptimizationRecommendation(
|
276
|
+
resource_id=instance_id,
|
277
|
+
resource_type="ec2",
|
278
|
+
region=self.region,
|
279
|
+
optimization_strategy="ec2_idle_detection",
|
280
|
+
current_cost_monthly=monthly_cost,
|
281
|
+
projected_savings_monthly=projected_savings,
|
282
|
+
projected_savings_annual=projected_savings * 12,
|
283
|
+
confidence_level="HIGH",
|
284
|
+
risk_assessment=risk,
|
285
|
+
implementation_effort="MEDIUM",
|
286
|
+
recommendation_type=recommendation_type,
|
287
|
+
detailed_recommendation=detailed_rec,
|
288
|
+
implementation_steps=self._get_implementation_steps(recommendation_type),
|
289
|
+
business_impact=f"Potential annual savings: {format_cost(projected_savings * 12)}",
|
290
|
+
technical_details={
|
291
|
+
"instance_type": instance_type,
|
292
|
+
"avg_cpu": usage_metrics.utilization_percentage,
|
293
|
+
},
|
294
|
+
usage_metrics=usage_metrics,
|
295
|
+
tags=tags,
|
296
|
+
)
|
297
|
+
recommendations.append(recommendation)
|
298
|
+
|
299
|
+
progress.update(task, advance=1)
|
300
|
+
|
301
|
+
return OptimizationResults(
|
302
|
+
optimization_strategies=["ec2_idle_detection"],
|
303
|
+
total_current_monthly_cost=total_current_cost,
|
304
|
+
total_projected_monthly_savings=total_savings,
|
305
|
+
total_projected_annual_savings=total_savings * 12,
|
306
|
+
roi_percentage=(total_savings / total_current_cost * 100) if total_current_cost > 0 else 0,
|
307
|
+
recommendations=recommendations,
|
308
|
+
summary_statistics={
|
309
|
+
"instances_analyzed": len(instances),
|
310
|
+
"idle_instances_found": len(recommendations),
|
311
|
+
"average_savings_per_instance": total_savings / len(recommendations) if recommendations else 0,
|
312
|
+
"strategy": "ec2_idle_detection",
|
313
|
+
},
|
314
|
+
)
|
315
|
+
|
316
|
+
except Exception as e:
|
317
|
+
self.logger.error(f"EC2 idle detection analysis failed: {e}")
|
318
|
+
raise
|
319
|
+
|
320
|
+
async def _get_instance_usage_metrics(self, cloudwatch_client, instance_id: str, hours: int) -> UsageMetrics:
|
321
|
+
"""Get CloudWatch metrics for instance utilization analysis."""
|
322
|
+
try:
|
323
|
+
end_time = datetime.utcnow()
|
324
|
+
start_time = end_time - timedelta(hours=hours)
|
325
|
+
|
326
|
+
response = cloudwatch_client.get_metric_statistics(
|
327
|
+
Namespace="AWS/EC2",
|
328
|
+
MetricName="CPUUtilization",
|
329
|
+
Dimensions=[{"Name": "InstanceId", "Value": instance_id}],
|
330
|
+
StartTime=start_time,
|
331
|
+
EndTime=end_time,
|
332
|
+
Period=3600, # 1 hour intervals
|
333
|
+
Statistics=["Average"],
|
334
|
+
)
|
335
|
+
|
336
|
+
datapoints = response.get("Datapoints", [])
|
337
|
+
avg_cpu = sum(dp["Average"] for dp in datapoints) / len(datapoints) if datapoints else 0
|
338
|
+
|
339
|
+
return UsageMetrics(
|
340
|
+
resource_id=instance_id,
|
341
|
+
resource_type="ec2",
|
342
|
+
region=self.region,
|
343
|
+
utilization_percentage=avg_cpu,
|
344
|
+
analysis_period_days=hours // 24,
|
345
|
+
is_underutilized=avg_cpu < 20,
|
346
|
+
)
|
347
|
+
|
348
|
+
except Exception as e:
|
349
|
+
self.logger.warning(f"Could not get metrics for instance {instance_id}: {e}")
|
350
|
+
return UsageMetrics(
|
351
|
+
resource_id=instance_id,
|
352
|
+
resource_type="ec2",
|
353
|
+
region=self.region,
|
354
|
+
utilization_percentage=50.0, # Default safe assumption
|
355
|
+
analysis_period_days=7,
|
356
|
+
is_underutilized=False,
|
357
|
+
)
|
358
|
+
|
359
|
+
def _estimate_instance_monthly_cost(self, instance_type: str) -> float:
|
360
|
+
"""Estimate monthly cost for EC2 instance type."""
|
361
|
+
cost_estimates = {
|
362
|
+
"t2.nano": 4.50,
|
363
|
+
"t2.micro": 8.50,
|
364
|
+
"t2.small": 17.00,
|
365
|
+
"t2.medium": 34.00,
|
366
|
+
"t2.large": 68.00,
|
367
|
+
"t3.nano": 3.80,
|
368
|
+
"t3.micro": 7.60,
|
369
|
+
"t3.small": 15.20,
|
370
|
+
"t3.medium": 30.40,
|
371
|
+
"t3.large": 60.80,
|
372
|
+
"t3.xlarge": 121.60,
|
373
|
+
"t3.2xlarge": 243.20,
|
374
|
+
"m5.large": 70.00,
|
375
|
+
"m5.xlarge": 140.00,
|
376
|
+
"m5.2xlarge": 280.00,
|
377
|
+
"m5.4xlarge": 560.00,
|
378
|
+
"c5.large": 62.00,
|
379
|
+
"c5.xlarge": 124.00,
|
380
|
+
"c5.2xlarge": 248.00,
|
381
|
+
"c5.4xlarge": 496.00,
|
382
|
+
"r5.large": 116.80,
|
383
|
+
"r5.xlarge": 233.60,
|
384
|
+
"r5.2xlarge": 467.20,
|
385
|
+
}
|
386
|
+
return cost_estimates.get(instance_type, 75.00) # Default estimate
|
387
|
+
|
388
|
+
def _get_implementation_steps(self, recommendation_type: str) -> List[str]:
|
389
|
+
"""Get implementation steps based on recommendation type."""
|
390
|
+
if recommendation_type == "terminate":
|
391
|
+
return [
|
392
|
+
"1. Verify instance is not critical for operations",
|
393
|
+
"2. Create backup/snapshot if needed",
|
394
|
+
"3. Stop instance during maintenance window",
|
395
|
+
"4. Monitor for 48 hours to ensure no impact",
|
396
|
+
"5. Terminate if no issues detected",
|
397
|
+
]
|
398
|
+
else: # resize
|
399
|
+
return [
|
400
|
+
"1. Analyze memory and network utilization patterns",
|
401
|
+
"2. Identify appropriate smaller instance type",
|
402
|
+
"3. Schedule downtime for resize operation",
|
403
|
+
"4. Create AMI backup before resize",
|
404
|
+
"5. Resize instance and monitor performance",
|
405
|
+
]
|
406
|
+
|
407
|
+
|
408
|
+
class EBSOptimizationStrategy(OptimizationStrategyBase):
|
409
|
+
"""EBS volume optimization strategy (GP2→GP3 conversion, orphaned volumes)."""
|
410
|
+
|
411
|
+
def get_strategy_name(self) -> str:
|
412
|
+
return "EBS Volume Optimization"
|
413
|
+
|
414
|
+
def get_estimated_savings_range(self) -> Tuple[float, float]:
|
415
|
+
return (2000.0, 15000.0) # Monthly savings range
|
416
|
+
|
417
|
+
async def analyze(self, **kwargs) -> OptimizationResults:
|
418
|
+
"""Analyze EBS volumes for optimization opportunities."""
|
419
|
+
print_info("💾 Analyzing EBS volumes for optimization opportunities")
|
420
|
+
|
421
|
+
recommendations = []
|
422
|
+
total_current_cost = 0.0
|
423
|
+
total_savings = 0.0
|
424
|
+
|
425
|
+
try:
|
426
|
+
ec2_client = self.session.client("ec2", region_name=self.region)
|
427
|
+
|
428
|
+
# Get all EBS volumes
|
429
|
+
paginator = ec2_client.get_paginator("describe_volumes")
|
430
|
+
volumes = []
|
431
|
+
|
432
|
+
for page in paginator.paginate():
|
433
|
+
volumes.extend(page["Volumes"])
|
434
|
+
|
435
|
+
with create_progress_bar() as progress:
|
436
|
+
task = progress.add_task("Analyzing EBS volumes...", total=len(volumes))
|
437
|
+
|
438
|
+
for volume in volumes:
|
439
|
+
volume_id = volume["VolumeId"]
|
440
|
+
volume_type = volume.get("VolumeType", "gp2")
|
441
|
+
size_gb = volume.get("Size", 0)
|
442
|
+
state = volume.get("State", "unknown")
|
443
|
+
|
444
|
+
monthly_cost = self._estimate_ebs_monthly_cost(volume_type, size_gb)
|
445
|
+
total_current_cost += monthly_cost
|
446
|
+
|
447
|
+
# Check for GP2→GP3 conversion opportunity
|
448
|
+
if volume_type == "gp2" and size_gb >= 1:
|
449
|
+
gp3_savings = monthly_cost * 0.20 # 20% savings
|
450
|
+
total_savings += gp3_savings
|
451
|
+
|
452
|
+
tags = {tag["Key"]: tag["Value"] for tag in volume.get("Tags", [])}
|
453
|
+
|
454
|
+
recommendation = OptimizationRecommendation(
|
455
|
+
resource_id=volume_id,
|
456
|
+
resource_type="ebs",
|
457
|
+
region=self.region,
|
458
|
+
optimization_strategy="ebs_gp2_to_gp3",
|
459
|
+
current_cost_monthly=monthly_cost,
|
460
|
+
projected_savings_monthly=gp3_savings,
|
461
|
+
projected_savings_annual=gp3_savings * 12,
|
462
|
+
confidence_level="HIGH",
|
463
|
+
risk_assessment="LOW",
|
464
|
+
implementation_effort="LOW",
|
465
|
+
recommendation_type="convert",
|
466
|
+
detailed_recommendation=f"Convert GP2 volume ({size_gb}GB) to GP3 for 20% cost reduction",
|
467
|
+
implementation_steps=[
|
468
|
+
"1. Create snapshot for backup",
|
469
|
+
"2. Modify volume type to GP3",
|
470
|
+
"3. Monitor performance after conversion",
|
471
|
+
"4. Adjust IOPS if needed",
|
472
|
+
],
|
473
|
+
business_impact=f"Potential annual savings: {format_cost(gp3_savings * 12)}",
|
474
|
+
technical_details={
|
475
|
+
"current_type": volume_type,
|
476
|
+
"target_type": "gp3",
|
477
|
+
"size_gb": size_gb,
|
478
|
+
"state": state,
|
479
|
+
},
|
480
|
+
tags=tags,
|
481
|
+
)
|
482
|
+
recommendations.append(recommendation)
|
483
|
+
|
484
|
+
# Check for orphaned volumes
|
485
|
+
if state == "available" and not volume.get("Attachments"):
|
486
|
+
orphan_savings = monthly_cost * 0.95 # 95% savings by deletion
|
487
|
+
total_savings += orphan_savings
|
488
|
+
|
489
|
+
tags = {tag["Key"]: tag["Value"] for tag in volume.get("Tags", [])}
|
490
|
+
|
491
|
+
recommendation = OptimizationRecommendation(
|
492
|
+
resource_id=volume_id,
|
493
|
+
resource_type="ebs",
|
494
|
+
region=self.region,
|
495
|
+
optimization_strategy="ebs_orphaned_volumes",
|
496
|
+
current_cost_monthly=monthly_cost,
|
497
|
+
projected_savings_monthly=orphan_savings,
|
498
|
+
projected_savings_annual=orphan_savings * 12,
|
499
|
+
confidence_level="HIGH",
|
500
|
+
risk_assessment="MEDIUM",
|
501
|
+
implementation_effort="LOW",
|
502
|
+
recommendation_type="terminate",
|
503
|
+
detailed_recommendation=f"Orphaned volume ({size_gb}GB {volume_type}) not attached to any instance",
|
504
|
+
implementation_steps=[
|
505
|
+
"1. Verify volume is not needed for recovery",
|
506
|
+
"2. Create snapshot if data needs to be preserved",
|
507
|
+
"3. Delete orphaned volume",
|
508
|
+
"4. Update documentation",
|
509
|
+
],
|
510
|
+
business_impact=f"Potential annual savings: {format_cost(orphan_savings * 12)}",
|
511
|
+
technical_details={
|
512
|
+
"volume_type": volume_type,
|
513
|
+
"size_gb": size_gb,
|
514
|
+
"state": state,
|
515
|
+
"orphaned": True,
|
516
|
+
},
|
517
|
+
tags=tags,
|
518
|
+
)
|
519
|
+
recommendations.append(recommendation)
|
520
|
+
|
521
|
+
progress.update(task, advance=1)
|
522
|
+
|
523
|
+
return OptimizationResults(
|
524
|
+
optimization_strategies=["ebs_gp2_to_gp3", "ebs_orphaned_volumes"],
|
525
|
+
total_current_monthly_cost=total_current_cost,
|
526
|
+
total_projected_monthly_savings=total_savings,
|
527
|
+
total_projected_annual_savings=total_savings * 12,
|
528
|
+
roi_percentage=(total_savings / total_current_cost * 100) if total_current_cost > 0 else 0,
|
529
|
+
recommendations=recommendations,
|
530
|
+
summary_statistics={
|
531
|
+
"volumes_analyzed": len(volumes),
|
532
|
+
"optimization_opportunities": len(recommendations),
|
533
|
+
"gp2_to_gp3_candidates": len(
|
534
|
+
[r for r in recommendations if r.optimization_strategy == "ebs_gp2_to_gp3"]
|
535
|
+
),
|
536
|
+
"orphaned_volumes": len(
|
537
|
+
[r for r in recommendations if r.optimization_strategy == "ebs_orphaned_volumes"]
|
538
|
+
),
|
539
|
+
"strategy": "ebs_optimization",
|
540
|
+
},
|
541
|
+
)
|
542
|
+
|
543
|
+
except Exception as e:
|
544
|
+
self.logger.error(f"EBS optimization analysis failed: {e}")
|
545
|
+
raise
|
546
|
+
|
547
|
+
def _estimate_ebs_monthly_cost(self, volume_type: str, size_gb: int) -> float:
|
548
|
+
"""Estimate monthly cost for EBS volume."""
|
549
|
+
cost_per_gb = {
|
550
|
+
"gp3": 0.08,
|
551
|
+
"gp2": 0.10,
|
552
|
+
"io1": 0.125,
|
553
|
+
"io2": 0.125,
|
554
|
+
"st1": 0.045,
|
555
|
+
"sc1": 0.025,
|
556
|
+
"standard": 0.05,
|
557
|
+
}
|
558
|
+
rate = cost_per_gb.get(volume_type, 0.08)
|
559
|
+
return size_gb * rate
|
560
|
+
|
561
|
+
|
562
|
+
class NATGatewayOptimizationStrategy(OptimizationStrategyBase):
|
563
|
+
"""NAT Gateway optimization strategy focusing on unused/underutilized gateways."""
|
564
|
+
|
565
|
+
def get_strategy_name(self) -> str:
|
566
|
+
return "NAT Gateway Optimization"
|
567
|
+
|
568
|
+
def get_estimated_savings_range(self) -> Tuple[float, float]:
|
569
|
+
return (1000.0, 8000.0) # Monthly savings range
|
570
|
+
|
571
|
+
async def analyze(self, analysis_days: int = 7, **kwargs) -> OptimizationResults:
|
572
|
+
"""Analyze NAT Gateways for optimization opportunities."""
|
573
|
+
print_info(f"🌐 Analyzing NAT Gateways for optimization opportunities ({analysis_days} day analysis)")
|
574
|
+
|
575
|
+
recommendations = []
|
576
|
+
total_current_cost = 0.0
|
577
|
+
total_savings = 0.0
|
578
|
+
|
579
|
+
try:
|
580
|
+
ec2_client = self.session.client("ec2", region_name=self.region)
|
581
|
+
cloudwatch_client = self.session.client("cloudwatch", region_name=self.region)
|
582
|
+
|
583
|
+
# Get all NAT Gateways
|
584
|
+
response = ec2_client.describe_nat_gateways()
|
585
|
+
nat_gateways = [ng for ng in response.get("NatGateways", []) if ng.get("State") == "available"]
|
586
|
+
|
587
|
+
with create_progress_bar() as progress:
|
588
|
+
task = progress.add_task("Analyzing NAT Gateways...", total=len(nat_gateways))
|
589
|
+
|
590
|
+
for nat_gateway in nat_gateways:
|
591
|
+
nat_gateway_id = nat_gateway.get("NatGatewayId")
|
592
|
+
vpc_id = nat_gateway.get("VpcId", "")
|
593
|
+
|
594
|
+
# Estimate monthly cost (base cost + data processing)
|
595
|
+
monthly_cost = 45.0 # Base NAT Gateway cost
|
596
|
+
total_current_cost += monthly_cost
|
597
|
+
|
598
|
+
# Get usage metrics
|
599
|
+
usage_metrics = await self._get_nat_gateway_usage_metrics(
|
600
|
+
cloudwatch_client, nat_gateway_id, analysis_days
|
601
|
+
)
|
602
|
+
|
603
|
+
# Check if NAT Gateway is underutilized
|
604
|
+
if usage_metrics.active_connections < 10 and usage_metrics.data_transfer_gb < 1.0:
|
605
|
+
savings = monthly_cost * 0.90 # 90% savings by removal
|
606
|
+
total_savings += savings
|
607
|
+
|
608
|
+
tags = {tag["Key"]: tag["Value"] for tag in nat_gateway.get("Tags", [])}
|
609
|
+
|
610
|
+
recommendation = OptimizationRecommendation(
|
611
|
+
resource_id=nat_gateway_id,
|
612
|
+
resource_type="nat_gateway",
|
613
|
+
region=self.region,
|
614
|
+
optimization_strategy="nat_gateway_optimization",
|
615
|
+
current_cost_monthly=monthly_cost,
|
616
|
+
projected_savings_monthly=savings,
|
617
|
+
projected_savings_annual=savings * 12,
|
618
|
+
confidence_level="MEDIUM",
|
619
|
+
risk_assessment="MEDIUM",
|
620
|
+
implementation_effort="MEDIUM",
|
621
|
+
recommendation_type="terminate",
|
622
|
+
detailed_recommendation=f"NAT Gateway shows minimal usage: {usage_metrics.active_connections:.0f} connections, {usage_metrics.data_transfer_gb:.1f}GB data transfer",
|
623
|
+
implementation_steps=[
|
624
|
+
"1. Review routing tables and dependencies",
|
625
|
+
"2. Analyze traffic patterns over 30 days",
|
626
|
+
"3. Consider VPC endpoint alternatives",
|
627
|
+
"4. Plan removal during maintenance window",
|
628
|
+
"5. Monitor connectivity after removal",
|
629
|
+
],
|
630
|
+
business_impact=f"Potential annual savings: {format_cost(savings * 12)}",
|
631
|
+
technical_details={
|
632
|
+
"vpc_id": vpc_id,
|
633
|
+
"active_connections": usage_metrics.active_connections,
|
634
|
+
"data_transfer_gb": usage_metrics.data_transfer_gb,
|
635
|
+
},
|
636
|
+
usage_metrics=usage_metrics,
|
637
|
+
tags=tags,
|
638
|
+
)
|
639
|
+
recommendations.append(recommendation)
|
640
|
+
|
641
|
+
progress.update(task, advance=1)
|
642
|
+
|
643
|
+
return OptimizationResults(
|
644
|
+
optimization_strategies=["nat_gateway_optimization"],
|
645
|
+
total_current_monthly_cost=total_current_cost,
|
646
|
+
total_projected_monthly_savings=total_savings,
|
647
|
+
total_projected_annual_savings=total_savings * 12,
|
648
|
+
roi_percentage=(total_savings / total_current_cost * 100) if total_current_cost > 0 else 0,
|
649
|
+
recommendations=recommendations,
|
650
|
+
summary_statistics={
|
651
|
+
"nat_gateways_analyzed": len(nat_gateways),
|
652
|
+
"optimization_opportunities": len(recommendations),
|
653
|
+
"strategy": "nat_gateway_optimization",
|
654
|
+
},
|
655
|
+
)
|
656
|
+
|
657
|
+
except Exception as e:
|
658
|
+
self.logger.error(f"NAT Gateway optimization analysis failed: {e}")
|
659
|
+
raise
|
660
|
+
|
661
|
+
async def _get_nat_gateway_usage_metrics(self, cloudwatch_client, nat_gateway_id: str, days: int) -> UsageMetrics:
|
662
|
+
"""Get CloudWatch metrics for NAT Gateway utilization analysis."""
|
663
|
+
try:
|
664
|
+
end_time = datetime.utcnow()
|
665
|
+
start_time = end_time - timedelta(days=days)
|
666
|
+
|
667
|
+
# Get ActiveConnectionCount
|
668
|
+
connections_response = cloudwatch_client.get_metric_statistics(
|
669
|
+
Namespace="AWS/NATGateway",
|
670
|
+
MetricName="ActiveConnectionCount",
|
671
|
+
Dimensions=[{"Name": "NatGatewayId", "Value": nat_gateway_id}],
|
672
|
+
StartTime=start_time,
|
673
|
+
EndTime=end_time,
|
674
|
+
Period=86400, # Daily
|
675
|
+
Statistics=["Average"],
|
676
|
+
)
|
677
|
+
|
678
|
+
# Get BytesOutToDestination for data transfer
|
679
|
+
bytes_response = cloudwatch_client.get_metric_statistics(
|
680
|
+
Namespace="AWS/NATGateway",
|
681
|
+
MetricName="BytesOutToDestination",
|
682
|
+
Dimensions=[{"Name": "NatGatewayId", "Value": nat_gateway_id}],
|
683
|
+
StartTime=start_time,
|
684
|
+
EndTime=end_time,
|
685
|
+
Period=86400, # Daily
|
686
|
+
Statistics=["Sum"],
|
687
|
+
)
|
688
|
+
|
689
|
+
connections_datapoints = connections_response.get("Datapoints", [])
|
690
|
+
bytes_datapoints = bytes_response.get("Datapoints", [])
|
691
|
+
|
692
|
+
avg_connections = (
|
693
|
+
sum(dp["Average"] for dp in connections_datapoints) / len(connections_datapoints)
|
694
|
+
if connections_datapoints
|
695
|
+
else 0
|
696
|
+
)
|
697
|
+
total_bytes = sum(dp["Sum"] for dp in bytes_datapoints)
|
698
|
+
total_gb = total_bytes / (1024**3) if total_bytes > 0 else 0
|
699
|
+
|
700
|
+
return UsageMetrics(
|
701
|
+
resource_id=nat_gateway_id,
|
702
|
+
resource_type="nat_gateway",
|
703
|
+
region=self.region,
|
704
|
+
active_connections=avg_connections,
|
705
|
+
data_transfer_gb=total_gb,
|
706
|
+
analysis_period_days=days,
|
707
|
+
is_underutilized=avg_connections < 10 and total_gb < 1.0,
|
708
|
+
)
|
709
|
+
|
710
|
+
except Exception as e:
|
711
|
+
self.logger.warning(f"Could not get metrics for NAT Gateway {nat_gateway_id}: {e}")
|
712
|
+
return UsageMetrics(
|
713
|
+
resource_id=nat_gateway_id,
|
714
|
+
resource_type="nat_gateway",
|
715
|
+
region=self.region,
|
716
|
+
active_connections=50.0, # Default safe assumption
|
717
|
+
data_transfer_gb=10.0,
|
718
|
+
analysis_period_days=days,
|
719
|
+
is_underutilized=False,
|
720
|
+
)
|
721
|
+
|
722
|
+
|
723
|
+
class UnifiedOptimizationEngine:
|
724
|
+
"""
|
725
|
+
Unified Enterprise Optimization Engine implementing strategy pattern.
|
726
|
+
|
727
|
+
Provides comprehensive cost optimization analysis across all AWS resource types
|
728
|
+
using a unified strategy pattern approach with enterprise-grade validation.
|
729
|
+
"""
|
730
|
+
|
731
|
+
def __init__(
|
732
|
+
self,
|
733
|
+
profile: Optional[str] = None,
|
734
|
+
region: Optional[str] = None,
|
735
|
+
optimization_strategies: Optional[List[str]] = None,
|
736
|
+
savings_target: float = 0.3,
|
737
|
+
analysis_depth: str = "comprehensive",
|
738
|
+
):
|
739
|
+
"""
|
740
|
+
Initialize UnifiedOptimizationEngine with strategy pattern.
|
741
|
+
|
742
|
+
Args:
|
743
|
+
profile: AWS profile name (uses ProfileManager for resolution)
|
744
|
+
region: AWS region for analysis
|
745
|
+
optimization_strategies: List of optimization strategies to run
|
746
|
+
savings_target: Target savings percentage (0.1-0.8)
|
747
|
+
analysis_depth: Analysis depth level
|
748
|
+
"""
|
749
|
+
self.profile_manager = AWSProfileManager(profile)
|
750
|
+
self.profile = self.profile_manager.profile
|
751
|
+
self.region = region or "us-east-1"
|
752
|
+
self.savings_target = max(0.1, min(0.8, savings_target))
|
753
|
+
self.analysis_depth = OptimizationDepth(analysis_depth)
|
754
|
+
|
755
|
+
# Initialize AWS session through ProfileManager
|
756
|
+
self.session = self.profile_manager.get_session(self.region)
|
757
|
+
self.account_id = self.profile_manager.get_account_id(self.region)
|
758
|
+
|
759
|
+
# Initialize MCP validator for accuracy validation
|
760
|
+
profiles_list = [self.profile] if self.profile else ["default"]
|
761
|
+
self.mcp_validator = EmbeddedMCPValidator(profiles=profiles_list)
|
762
|
+
|
763
|
+
# Available optimization strategies
|
764
|
+
self.available_strategies = {
|
765
|
+
OptimizationStrategy.EC2_IDLE_DETECTION: EC2IdleDetectionStrategy,
|
766
|
+
OptimizationStrategy.EBS_GP2_TO_GP3_CONVERSION: EBSOptimizationStrategy,
|
767
|
+
OptimizationStrategy.EBS_ORPHANED_VOLUMES: EBSOptimizationStrategy,
|
768
|
+
OptimizationStrategy.NAT_GATEWAY_OPTIMIZATION: NATGatewayOptimizationStrategy,
|
769
|
+
# Legacy support
|
770
|
+
OptimizationStrategy.EC2: EC2IdleDetectionStrategy,
|
771
|
+
OptimizationStrategy.EBS: EBSOptimizationStrategy,
|
772
|
+
OptimizationStrategy.VPC: NATGatewayOptimizationStrategy,
|
773
|
+
}
|
774
|
+
|
775
|
+
# Set optimization strategies to run
|
776
|
+
if optimization_strategies:
|
777
|
+
self.strategies_to_run = [OptimizationStrategy(s) for s in optimization_strategies]
|
778
|
+
else:
|
779
|
+
# Default comprehensive analysis
|
780
|
+
self.strategies_to_run = [
|
781
|
+
OptimizationStrategy.EC2_IDLE_DETECTION,
|
782
|
+
OptimizationStrategy.EBS_GP2_TO_GP3_CONVERSION,
|
783
|
+
OptimizationStrategy.NAT_GATEWAY_OPTIMIZATION,
|
784
|
+
]
|
785
|
+
|
786
|
+
async def analyze_optimization_opportunities(self, **kwargs) -> OptimizationResults:
|
787
|
+
"""
|
788
|
+
Execute comprehensive optimization analysis using strategy pattern.
|
789
|
+
|
790
|
+
Returns:
|
791
|
+
OptimizationResults: Consolidated optimization analysis with recommendations
|
792
|
+
"""
|
793
|
+
print_header("Unified FinOps Optimization Engine", "v2.0.0")
|
794
|
+
|
795
|
+
console.print(
|
796
|
+
f"[cyan]🎯 Optimization Strategies:[/cyan] {', '.join([s.value for s in self.strategies_to_run])}"
|
797
|
+
)
|
798
|
+
console.print(f"[cyan]📊 Savings Target:[/cyan] {self.savings_target:.1%}")
|
799
|
+
console.print(f"[cyan]🔍 Analysis Depth:[/cyan] {self.analysis_depth.value}")
|
800
|
+
console.print(f"[cyan]🏷️ AWS Profile:[/cyan] {self.profile}")
|
801
|
+
console.print(f"[cyan]🌍 Region:[/cyan] {self.region}")
|
802
|
+
console.print()
|
803
|
+
|
804
|
+
all_recommendations = []
|
805
|
+
total_current_cost = 0.0
|
806
|
+
total_savings = 0.0
|
807
|
+
strategy_results = {}
|
808
|
+
|
809
|
+
try:
|
810
|
+
for strategy in self.strategies_to_run:
|
811
|
+
if strategy in self.available_strategies:
|
812
|
+
strategy_class = self.available_strategies[strategy]
|
813
|
+
strategy_instance = strategy_class(self.session, self.region, self.profile)
|
814
|
+
|
815
|
+
print_info(f"🔍 Executing strategy: {strategy_instance.get_strategy_name()}")
|
816
|
+
|
817
|
+
# Execute strategy analysis
|
818
|
+
strategy_result = await strategy_instance.analyze(**kwargs)
|
819
|
+
|
820
|
+
# Accumulate results
|
821
|
+
all_recommendations.extend(strategy_result.recommendations)
|
822
|
+
total_current_cost += strategy_result.total_current_monthly_cost
|
823
|
+
total_savings += strategy_result.total_projected_monthly_savings
|
824
|
+
|
825
|
+
# Store strategy-specific results
|
826
|
+
strategy_results[strategy.value] = {
|
827
|
+
"recommendations_count": len(strategy_result.recommendations),
|
828
|
+
"monthly_savings": strategy_result.total_projected_monthly_savings,
|
829
|
+
"annual_savings": strategy_result.total_projected_annual_savings,
|
830
|
+
"roi_percentage": strategy_result.roi_percentage,
|
831
|
+
"summary_statistics": strategy_result.summary_statistics,
|
832
|
+
}
|
833
|
+
|
834
|
+
print_success(
|
835
|
+
f"✅ {strategy_instance.get_strategy_name()}: {len(strategy_result.recommendations)} opportunities, ${strategy_result.total_projected_monthly_savings:.2f}/month savings"
|
836
|
+
)
|
837
|
+
|
838
|
+
# Consolidate results
|
839
|
+
consolidated_results = OptimizationResults(
|
840
|
+
optimization_strategies=[s.value for s in self.strategies_to_run],
|
841
|
+
analysis_depth=self.analysis_depth.value,
|
842
|
+
savings_target=self.savings_target,
|
843
|
+
total_current_monthly_cost=total_current_cost,
|
844
|
+
total_projected_monthly_savings=total_savings,
|
845
|
+
total_projected_annual_savings=total_savings * 12,
|
846
|
+
roi_percentage=(total_savings / total_current_cost * 100) if total_current_cost > 0 else 0,
|
847
|
+
recommendations=all_recommendations,
|
848
|
+
strategy_results=strategy_results,
|
849
|
+
)
|
850
|
+
|
851
|
+
# Enhanced validation for enterprise accuracy
|
852
|
+
if self.analysis_depth == OptimizationDepth.ENTERPRISE:
|
853
|
+
consolidated_results = await self._enhance_with_mcp_validation(consolidated_results)
|
854
|
+
|
855
|
+
# Generate cross-strategy synergies
|
856
|
+
consolidated_results.cross_strategy_synergies = self._identify_synergies(all_recommendations)
|
857
|
+
consolidated_results.implementation_priority_order = self._prioritize_implementation(all_recommendations)
|
858
|
+
|
859
|
+
# Generate summary statistics
|
860
|
+
consolidated_results.summary_statistics = {
|
861
|
+
"total_resources_analyzed": sum(
|
862
|
+
r.get("summary_statistics", {}).get("instances_analyzed", 0)
|
863
|
+
+ r.get("summary_statistics", {}).get("volumes_analyzed", 0)
|
864
|
+
+ r.get("summary_statistics", {}).get("nat_gateways_analyzed", 0)
|
865
|
+
for r in strategy_results.values()
|
866
|
+
),
|
867
|
+
"total_optimization_opportunities": len(all_recommendations),
|
868
|
+
"strategies_executed": len(self.strategies_to_run),
|
869
|
+
"average_monthly_savings_per_opportunity": total_savings / len(all_recommendations)
|
870
|
+
if all_recommendations
|
871
|
+
else 0,
|
872
|
+
"target_achievement_percentage": (total_savings / total_current_cost) / self.savings_target * 100
|
873
|
+
if total_current_cost > 0
|
874
|
+
else 0,
|
875
|
+
}
|
876
|
+
|
877
|
+
# Display consolidated summary
|
878
|
+
self._display_unified_optimization_summary(consolidated_results)
|
879
|
+
|
880
|
+
return consolidated_results
|
881
|
+
|
882
|
+
except ClientError as e:
|
883
|
+
error_code = e.response["Error"]["Code"]
|
884
|
+
if error_code == "UnauthorizedOperation":
|
885
|
+
print_error(f"AWS permissions error: {e}")
|
886
|
+
print_info("Ensure your AWS profile has the necessary permissions for optimization analysis")
|
887
|
+
else:
|
888
|
+
print_error(f"AWS API error: {e}")
|
889
|
+
raise
|
890
|
+
except Exception as e:
|
891
|
+
print_error(f"Unified optimization analysis failed: {e}")
|
892
|
+
raise
|
893
|
+
|
894
|
+
def _identify_synergies(self, recommendations: List[OptimizationRecommendation]) -> List[str]:
|
895
|
+
"""Identify cross-strategy synergies and opportunities."""
|
896
|
+
synergies = []
|
897
|
+
|
898
|
+
# Group recommendations by resource type
|
899
|
+
ec2_recs = [r for r in recommendations if r.resource_type == "ec2"]
|
900
|
+
ebs_recs = [r for r in recommendations if r.resource_type == "ebs"]
|
901
|
+
nat_recs = [r for r in recommendations if r.resource_type == "nat_gateway"]
|
902
|
+
|
903
|
+
if ec2_recs and ebs_recs:
|
904
|
+
synergies.append("EC2 instance termination creates opportunities for orphaned EBS volume cleanup")
|
905
|
+
|
906
|
+
if nat_recs and len(nat_recs) > 1:
|
907
|
+
synergies.append("Multiple NAT Gateway optimizations can enable VPC consolidation strategies")
|
908
|
+
|
909
|
+
if len(ec2_recs) > 5:
|
910
|
+
synergies.append("Large-scale EC2 optimization creates opportunities for Reserved Instance analysis")
|
911
|
+
|
912
|
+
return synergies
|
913
|
+
|
914
|
+
def _prioritize_implementation(self, recommendations: List[OptimizationRecommendation]) -> List[str]:
|
915
|
+
"""Prioritize implementation order based on risk and savings."""
|
916
|
+
# Sort by risk (LOW first) and savings (HIGH first)
|
917
|
+
risk_priority = {"LOW": 3, "MEDIUM": 2, "HIGH": 1}
|
918
|
+
|
919
|
+
sorted_recs = sorted(
|
920
|
+
recommendations, key=lambda r: (risk_priority.get(r.risk_assessment, 1), -r.projected_savings_annual)
|
921
|
+
)
|
922
|
+
|
923
|
+
return [f"{r.optimization_strategy}: {r.resource_id}" for r in sorted_recs[:10]] # Top 10 priorities
|
924
|
+
|
925
|
+
async def _enhance_with_mcp_validation(self, results: OptimizationResults) -> OptimizationResults:
|
926
|
+
"""Enhance optimization results with MCP validation for enterprise accuracy."""
|
927
|
+
print_info("🔍 Performing MCP validation for enterprise accuracy...")
|
928
|
+
|
929
|
+
try:
|
930
|
+
# Perform MCP validation on cost calculations
|
931
|
+
validation_results = self.mcp_validator.validate_cost_data(
|
932
|
+
{
|
933
|
+
"total_current_cost": results.total_current_monthly_cost,
|
934
|
+
"projected_savings": results.total_projected_monthly_savings,
|
935
|
+
"recommendations_count": len(results.recommendations),
|
936
|
+
"strategies_count": len(results.optimization_strategies),
|
937
|
+
}
|
938
|
+
)
|
939
|
+
|
940
|
+
results.mcp_validation_results = validation_results
|
941
|
+
|
942
|
+
# Update confidence levels based on validation
|
943
|
+
if validation_results.get("accuracy_percentage", 0) >= 99.5:
|
944
|
+
print_success("✅ MCP validation passed: ≥99.5% accuracy achieved")
|
945
|
+
# Boost confidence levels
|
946
|
+
for recommendation in results.recommendations:
|
947
|
+
if recommendation.confidence_level == "MEDIUM":
|
948
|
+
recommendation.confidence_level = "HIGH"
|
949
|
+
else:
|
950
|
+
print_warning("⚠️ MCP validation below threshold, adjusting confidence levels")
|
951
|
+
# Lower confidence levels
|
952
|
+
for recommendation in results.recommendations:
|
953
|
+
if recommendation.confidence_level == "HIGH":
|
954
|
+
recommendation.confidence_level = "MEDIUM"
|
955
|
+
|
956
|
+
except Exception as e:
|
957
|
+
print_warning(f"MCP validation failed: {e}")
|
958
|
+
results.mcp_validation_results = {"error": str(e), "accuracy_percentage": 0.0}
|
959
|
+
|
960
|
+
return results
|
961
|
+
|
962
|
+
def _display_unified_optimization_summary(self, results: OptimizationResults) -> None:
|
963
|
+
"""Display unified optimization summary with strategy breakdown."""
|
964
|
+
print_header("Unified Optimization Analysis Summary", "Executive Report")
|
965
|
+
|
966
|
+
# Strategy breakdown table
|
967
|
+
strategy_table = create_table(
|
968
|
+
title="Strategy Performance Summary",
|
969
|
+
columns=[
|
970
|
+
{"name": "Strategy", "style": "cyan", "min_width": 30},
|
971
|
+
{"name": "Opportunities", "style": "green", "min_width": 15},
|
972
|
+
{"name": "Monthly Savings", "style": "yellow", "min_width": 18},
|
973
|
+
{"name": "Annual Savings", "style": "red", "min_width": 18},
|
974
|
+
],
|
975
|
+
)
|
976
|
+
|
977
|
+
for strategy_name, strategy_data in results.strategy_results.items():
|
978
|
+
strategy_table.add_row(
|
979
|
+
strategy_name.replace("_", " ").title(),
|
980
|
+
str(strategy_data["recommendations_count"]),
|
981
|
+
format_cost(strategy_data["monthly_savings"]),
|
982
|
+
format_cost(strategy_data["annual_savings"]),
|
983
|
+
)
|
984
|
+
|
985
|
+
console.print(strategy_table)
|
986
|
+
console.print()
|
987
|
+
|
988
|
+
# Consolidated summary
|
989
|
+
summary_table = create_table(
|
990
|
+
title="Consolidated Optimization Summary",
|
991
|
+
columns=[
|
992
|
+
{"name": "Metric", "style": "cyan", "min_width": 25},
|
993
|
+
{"name": "Value", "style": "green", "min_width": 20},
|
994
|
+
{"name": "Impact", "style": "yellow", "min_width": 30},
|
995
|
+
],
|
996
|
+
)
|
997
|
+
|
998
|
+
summary_table.add_row(
|
999
|
+
"Total Current Monthly Cost",
|
1000
|
+
format_cost(results.total_current_monthly_cost),
|
1001
|
+
"Baseline spending across analyzed resources",
|
1002
|
+
)
|
1003
|
+
summary_table.add_row(
|
1004
|
+
"Total Projected Monthly Savings",
|
1005
|
+
format_cost(results.total_projected_monthly_savings),
|
1006
|
+
f"{(results.total_projected_monthly_savings / results.total_current_monthly_cost * 100):.1f}% cost reduction"
|
1007
|
+
if results.total_current_monthly_cost > 0
|
1008
|
+
else "N/A",
|
1009
|
+
)
|
1010
|
+
summary_table.add_row(
|
1011
|
+
"Total Projected Annual Savings",
|
1012
|
+
format_cost(results.total_projected_annual_savings),
|
1013
|
+
f"Target: {results.savings_target:.1%} achievement: {(results.total_projected_monthly_savings / results.total_current_monthly_cost) / results.savings_target * 100:.1f}%"
|
1014
|
+
if results.total_current_monthly_cost > 0
|
1015
|
+
else "N/A",
|
1016
|
+
)
|
1017
|
+
summary_table.add_row(
|
1018
|
+
"Total Optimization Opportunities",
|
1019
|
+
str(len(results.recommendations)),
|
1020
|
+
f"Across {len(results.optimization_strategies)} strategies",
|
1021
|
+
)
|
1022
|
+
summary_table.add_row(
|
1023
|
+
"Implementation ROI", f"{results.roi_percentage:.1f}%", "Return on optimization investment"
|
1024
|
+
)
|
1025
|
+
|
1026
|
+
console.print(summary_table)
|
1027
|
+
console.print()
|
1028
|
+
|
1029
|
+
# Cross-strategy synergies
|
1030
|
+
if results.cross_strategy_synergies:
|
1031
|
+
synergies_panel = create_panel(
|
1032
|
+
"\n".join([f"• {synergy}" for synergy in results.cross_strategy_synergies]),
|
1033
|
+
title="🔗 Cross-Strategy Synergies",
|
1034
|
+
)
|
1035
|
+
console.print(synergies_panel)
|
1036
|
+
console.print()
|
1037
|
+
|
1038
|
+
# Implementation priorities
|
1039
|
+
if results.implementation_priority_order:
|
1040
|
+
priorities_panel = create_panel(
|
1041
|
+
"\n".join(
|
1042
|
+
[f"{i + 1}. {priority}" for i, priority in enumerate(results.implementation_priority_order[:5])]
|
1043
|
+
),
|
1044
|
+
title="📋 Top Implementation Priorities",
|
1045
|
+
)
|
1046
|
+
console.print(priorities_panel)
|
1047
|
+
console.print()
|
1048
|
+
|
1049
|
+
# MCP validation results
|
1050
|
+
if results.mcp_validation_results:
|
1051
|
+
accuracy = results.mcp_validation_results.get("accuracy_percentage", 0)
|
1052
|
+
if accuracy >= 99.5:
|
1053
|
+
validation_status = f"✅ {accuracy:.1f}% accuracy (Enterprise threshold met)"
|
1054
|
+
validation_style = "green"
|
1055
|
+
else:
|
1056
|
+
validation_status = f"⚠️ {accuracy:.1f}% accuracy (Below enterprise threshold)"
|
1057
|
+
validation_style = "yellow"
|
1058
|
+
|
1059
|
+
validation_panel = create_panel(
|
1060
|
+
validation_status, title="MCP Validation Results", border_style=validation_style
|
1061
|
+
)
|
1062
|
+
console.print(validation_panel)
|
1063
|
+
console.print()
|
1064
|
+
|
1065
|
+
# Implementation guidance
|
1066
|
+
print_info("📋 Next Steps:")
|
1067
|
+
console.print("1. Review detailed recommendations by strategy")
|
1068
|
+
console.print("2. Prioritize implementation based on risk and ROI")
|
1069
|
+
console.print("3. Plan rollout during maintenance windows")
|
1070
|
+
console.print("4. Monitor cost impact and performance metrics")
|
1071
|
+
console.print()
|
1072
|
+
|
1073
|
+
if results.recommendations:
|
1074
|
+
print_success(f"🎯 Analysis complete: {len(results.recommendations)} optimization opportunities identified")
|
1075
|
+
print_info(f"💰 Potential annual savings: {format_cost(results.total_projected_annual_savings)}")
|
1076
|
+
else:
|
1077
|
+
print_info("✨ No immediate optimization opportunities identified")
|
1078
|
+
console.print("This indicates efficient resource utilization across analyzed strategies")
|
1079
|
+
|
1080
|
+
|
1081
|
+
# Legacy ResourceOptimizer class for backward compatibility
|
1082
|
+
class ResourceOptimizer(UnifiedOptimizationEngine):
|
1083
|
+
"""
|
1084
|
+
Legacy ResourceOptimizer class for backward compatibility.
|
1085
|
+
Redirects to UnifiedOptimizationEngine with appropriate strategy mapping.
|
1086
|
+
"""
|
1087
|
+
|
1088
|
+
def __init__(
|
1089
|
+
self,
|
1090
|
+
profile: Optional[str] = None,
|
1091
|
+
region: Optional[str] = None,
|
1092
|
+
resource_type: str = "ec2",
|
1093
|
+
savings_target: float = 0.3,
|
1094
|
+
analysis_depth: str = "comprehensive",
|
1095
|
+
):
|
1096
|
+
"""
|
1097
|
+
Initialize ResourceOptimizer with backward compatibility.
|
1098
|
+
"""
|
1099
|
+
# Map legacy resource types to strategies
|
1100
|
+
strategy_mapping = {
|
1101
|
+
"ec2": [OptimizationStrategy.EC2_IDLE_DETECTION],
|
1102
|
+
"ebs": [OptimizationStrategy.EBS_GP2_TO_GP3_CONVERSION],
|
1103
|
+
"vpc": [OptimizationStrategy.NAT_GATEWAY_OPTIMIZATION],
|
1104
|
+
"s3": [], # Placeholder for future S3 strategies
|
1105
|
+
"rds": [], # Placeholder for future RDS strategies
|
1106
|
+
"lambda": [], # Placeholder for future Lambda strategies
|
1107
|
+
}
|
1108
|
+
|
1109
|
+
strategies = strategy_mapping.get(resource_type, [OptimizationStrategy.EC2_IDLE_DETECTION])
|
1110
|
+
|
1111
|
+
super().__init__(
|
1112
|
+
profile=profile,
|
1113
|
+
region=region,
|
1114
|
+
optimization_strategies=[s.value for s in strategies] if strategies else None,
|
1115
|
+
savings_target=savings_target,
|
1116
|
+
analysis_depth=analysis_depth,
|
1117
|
+
)
|
1118
|
+
|
1119
|
+
# Store legacy attributes for compatibility
|
1120
|
+
self.resource_type = ResourceType(resource_type)
|
1121
|
+
|
1122
|
+
async def analyze_optimization_opportunities(self, **kwargs) -> OptimizationResults:
|
1123
|
+
"""
|
1124
|
+
Execute comprehensive optimization analysis for specified resource type.
|
1125
|
+
Redirects to the unified strategy-based analysis.
|
1126
|
+
|
1127
|
+
Returns:
|
1128
|
+
OptimizationResults: Complete optimization analysis with recommendations
|
1129
|
+
"""
|
1130
|
+
print_info(f"🔄 Legacy mode: redirecting {self.resource_type.value} analysis to unified strategy engine")
|
1131
|
+
|
1132
|
+
# Use the parent class's unified analysis method
|
1133
|
+
return await super().analyze_optimization_opportunities(**kwargs)
|
1134
|
+
|
1135
|
+
|
1136
|
+
# End of UnifiedOptimizationEngine implementation
|