runbooks 1.0.3__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. runbooks/__init__.py +10 -5
  2. runbooks/__init__.py.backup +134 -0
  3. runbooks/__init___optimized.py +110 -0
  4. runbooks/cloudops/base.py +56 -3
  5. runbooks/cloudops/cost_optimizer.py +496 -42
  6. runbooks/common/aws_pricing.py +236 -80
  7. runbooks/common/business_logic.py +485 -0
  8. runbooks/common/cli_decorators.py +219 -0
  9. runbooks/common/error_handling.py +424 -0
  10. runbooks/common/lazy_loader.py +186 -0
  11. runbooks/common/module_cli_base.py +378 -0
  12. runbooks/common/performance_monitoring.py +512 -0
  13. runbooks/common/profile_utils.py +133 -6
  14. runbooks/enterprise/logging.py +30 -2
  15. runbooks/enterprise/validation.py +177 -0
  16. runbooks/finops/README.md +311 -236
  17. runbooks/finops/aws_client.py +1 -1
  18. runbooks/finops/business_case_config.py +723 -19
  19. runbooks/finops/cli.py +136 -0
  20. runbooks/finops/commvault_ec2_analysis.py +25 -9
  21. runbooks/finops/config.py +272 -0
  22. runbooks/finops/dashboard_runner.py +136 -23
  23. runbooks/finops/ebs_cost_optimizer.py +39 -40
  24. runbooks/finops/enhanced_trend_visualization.py +7 -2
  25. runbooks/finops/enterprise_wrappers.py +45 -18
  26. runbooks/finops/finops_dashboard.py +50 -25
  27. runbooks/finops/finops_scenarios.py +22 -7
  28. runbooks/finops/helpers.py +115 -2
  29. runbooks/finops/multi_dashboard.py +7 -5
  30. runbooks/finops/optimizer.py +97 -6
  31. runbooks/finops/scenario_cli_integration.py +247 -0
  32. runbooks/finops/scenarios.py +12 -1
  33. runbooks/finops/unlimited_scenarios.py +393 -0
  34. runbooks/finops/validation_framework.py +19 -7
  35. runbooks/finops/workspaces_analyzer.py +1 -5
  36. runbooks/inventory/mcp_inventory_validator.py +2 -1
  37. runbooks/main.py +132 -94
  38. runbooks/main_final.py +358 -0
  39. runbooks/main_minimal.py +84 -0
  40. runbooks/main_optimized.py +493 -0
  41. runbooks/main_ultra_minimal.py +47 -0
  42. {runbooks-1.0.3.dist-info → runbooks-1.1.0.dist-info}/METADATA +1 -1
  43. {runbooks-1.0.3.dist-info → runbooks-1.1.0.dist-info}/RECORD +47 -31
  44. {runbooks-1.0.3.dist-info → runbooks-1.1.0.dist-info}/WHEEL +0 -0
  45. {runbooks-1.0.3.dist-info → runbooks-1.1.0.dist-info}/entry_points.txt +0 -0
  46. {runbooks-1.0.3.dist-info → runbooks-1.1.0.dist-info}/licenses/LICENSE +0 -0
  47. {runbooks-1.0.3.dist-info → runbooks-1.1.0.dist-info}/top_level.txt +0 -0
runbooks/main.py CHANGED
@@ -104,7 +104,18 @@ from runbooks.common.rich_utils import console, create_table, print_banner, prin
104
104
  from runbooks.config import load_config, save_config
105
105
  from runbooks.inventory.core.collector import InventoryCollector
106
106
  from runbooks.utils import setup_logging, setup_enhanced_logging
107
- from runbooks.finops.business_case_config import get_business_case_config, format_business_achievement
107
+ # PERFORMANCE FIX: Lazy load business case config to avoid MCP initialization
108
+ # from runbooks.finops.business_case_config import get_business_case_config, format_business_achievement
109
+
110
+ def lazy_get_business_case_config():
111
+ """Lazy load business case config only when needed."""
112
+ from runbooks.finops.business_case_config import get_business_case_config
113
+ return get_business_case_config
114
+
115
+ def lazy_format_business_achievement():
116
+ """Lazy load business achievement formatter only when needed."""
117
+ from runbooks.finops.business_case_config import format_business_achievement
118
+ return format_business_achievement
108
119
 
109
120
  console = Console()
110
121
 
@@ -6093,7 +6104,7 @@ def comprehensive_analysis(profile, region, dry_run, all_scenarios, output_dir):
6093
6104
  console.print(f"\n[blue]📊 Scenario 3: Commvault EC2 Investigation (FinOps-25)[/blue]")
6094
6105
  ctx.invoke(commvault_ec2,
6095
6106
  profile=profile, region=region, dry_run=dry_run,
6096
- account="637423383469", investigate_utilization=True,
6107
+ account=get_account_id_for_context(profile), investigate_utilization=True,
6097
6108
  output_file=f"{output_dir}/commvault_ec2_analysis.csv")
6098
6109
 
6099
6110
  # Summary report
@@ -6110,7 +6121,7 @@ def comprehensive_analysis(profile, region, dry_run, all_scenarios, output_dir):
6110
6121
  )
6111
6122
 
6112
6123
  # Use dynamic configuration for summary table
6113
- config = get_business_case_config()
6124
+ config = lazy_get_business_case_config()()
6114
6125
  workspaces_scenario = config.get_scenario('workspaces')
6115
6126
  rds_scenario = config.get_scenario('rds-snapshots')
6116
6127
  backup_scenario = config.get_scenario('backup-investigation')
@@ -6198,43 +6209,22 @@ def _parse_profiles_parameter(profiles_tuple):
6198
6209
  @click.option(
6199
6210
  "--export-markdown", "--markdown", is_flag=True, help="Generate Rich-styled markdown export with 10-column format"
6200
6211
  )
6201
- @click.option(
6202
- "--profile-display-length",
6203
- type=int,
6204
- help="Maximum characters for profile name display (optional, no truncation if not specified)",
6205
- )
6206
- @click.option(
6207
- "--service-name-length",
6208
- type=int,
6209
- help="Maximum characters for service name display (optional, no truncation if not specified)",
6210
- )
6211
- @click.option(
6212
- "--max-services-text",
6213
- type=int,
6214
- help="Maximum number of services in text summaries (optional, no limit if not specified)",
6215
- )
6216
- @click.option(
6217
- "--high-cost-threshold", type=float, default=5000, help="High cost threshold for highlighting (default: 5000)"
6218
- )
6219
- @click.option(
6220
- "--medium-cost-threshold", type=float, default=1000, help="Medium cost threshold for highlighting (default: 1000)"
6221
- )
6222
6212
  @click.option(
6223
6213
  "--validate", is_flag=True, help="Enable MCP cross-validation with real-time AWS API comparison for enterprise accuracy verification"
6224
6214
  )
6225
6215
  @click.option(
6226
- "--tech-focus", is_flag=True, help="Focus on technical analysis (UnblendedCost) for DevOps and SRE teams"
6216
+ "--unblended", is_flag=True, help="AWS Cost Explorer UnblendedCost analysis for technical teams (DevOps/SRE focus)"
6227
6217
  )
6228
6218
  @click.option(
6229
- "--financial-focus", is_flag=True, help="Focus on financial reporting (AmortizedCost) for Finance and Executive teams"
6219
+ "--amortized", is_flag=True, help="AWS Cost Explorer AmortizedCost analysis for financial teams (Finance/Executive focus)"
6230
6220
  )
6231
6221
  @click.option(
6232
- "--dual-metrics", is_flag=True, default=True, help="Show both technical and financial metrics (default behavior)"
6222
+ "--dual-metrics", is_flag=True, default=True, help="Show both UnblendedCost and AmortizedCost metrics (comprehensive analysis, default)"
6233
6223
  )
6234
6224
  @click.option(
6235
- "--scenario",
6236
- type=click.Choice(["workspaces", "snapshots", "commvault", "nat-gateway", "elastic-ip", "ebs", "vpc-cleanup"], case_sensitive=False),
6237
- help="Business scenario analysis with dynamic configuration - use 'runbooks finops --help-scenarios' for current scenario details"
6225
+ "--scenario",
6226
+ type=str,
6227
+ help="Business scenario: workspaces, snapshots, commvault, nat-gateway, elastic-ip, ebs, vpc-cleanup"
6238
6228
  )
6239
6229
  @click.pass_context
6240
6230
  def finops(
@@ -6257,41 +6247,41 @@ def finops(
6257
6247
  json,
6258
6248
  pdf,
6259
6249
  export_markdown,
6260
- profile_display_length,
6261
- service_name_length,
6262
- max_services_text,
6263
- high_cost_threshold,
6264
- medium_cost_threshold,
6265
6250
  validate,
6266
- tech_focus,
6267
- financial_focus,
6251
+ unblended,
6252
+ amortized,
6268
6253
  dual_metrics,
6269
6254
  scenario,
6270
6255
  ):
6271
6256
  """
6272
- AWS FinOps - Cost and usage analytics with dual-metric system.
6273
-
6274
- Comprehensive cost analysis supporting both UnblendedCost (technical)
6275
- and AmortizedCost (financial) perspectives for enterprise reporting.
6276
-
6277
- BUSINESS SCENARIOS (Dynamic Configuration):
6278
- runbooks finops --scenario workspaces # WorkSpaces Resource Optimization
6279
- runbooks finops --scenario snapshots # RDS Storage Optimization
6280
- runbooks finops --scenario commvault # Backup Infrastructure Analysis
6281
- runbooks finops --scenario nat-gateway # Network Gateway Optimization
6282
- runbooks finops --scenario elastic-ip # IP Address Resource Management
6283
- runbooks finops --scenario ebs # Storage Volume Optimization
6284
- runbooks finops --scenario vpc-cleanup # Network Infrastructure Cleanup
6285
-
6286
- Use --help-scenarios to see current configured targets and savings ranges.
6287
-
6288
- GENERAL ANALYTICS:
6289
- runbooks finops --audit --csv --report-name audit_report
6290
- runbooks finops --trend --json --report-name cost_trend
6291
- runbooks finops --time-range 30 --pdf --report-name monthly_costs
6292
- runbooks finops --tech-focus --profile my-profile # Technical teams
6293
- runbooks finops --financial-focus --pdf --report-name exec_report # Finance teams
6294
- runbooks finops --dual-metrics --csv --json # Comprehensive analysis (default)
6257
+ AWS FinOps - Cost and usage analytics.
6258
+
6259
+ 📊 DEFAULT DASHBOARD:
6260
+ runbooks finops --profile BILLING_PROFILE
6261
+
6262
+ 🎯 BUSINESS SCENARIOS:
6263
+ runbooks finops --scenario workspaces --profile PROFILE # WorkSpaces optimization
6264
+ runbooks finops --scenario snapshots --profile PROFILE # RDS snapshots cleanup
6265
+ runbooks finops --scenario commvault --profile PROFILE # Backup analysis
6266
+ runbooks finops --scenario nat-gateway --profile PROFILE # NAT Gateway optimization
6267
+ runbooks finops --scenario elastic-ip --profile PROFILE # Elastic IP management
6268
+ runbooks finops --scenario ebs --profile PROFILE # EBS optimization
6269
+ runbooks finops --scenario vpc-cleanup --profile PROFILE # VPC cleanup
6270
+
6271
+ 📊 ANALYTICS MODES:
6272
+ runbooks finops --audit --profile PROFILE # Cost anomaly analysis
6273
+ runbooks finops --trend --profile PROFILE # 6-month trend analysis
6274
+ runbooks finops --unblended --profile PROFILE # Technical cost view (DevOps/SRE)
6275
+ runbooks finops --amortized --profile PROFILE # Financial cost view (Finance)
6276
+
6277
+ 📄 EXPORTS:
6278
+ runbooks finops --csv --json --pdf --profile PROFILE # Multiple formats
6279
+ runbooks finops --report-name monthly --pdf --profile PROFILE
6280
+
6281
+ 🌍 MULTIPLE PROFILES/REGIONS:
6282
+ runbooks finops --profiles PROF1 PROF2 --regions us-east-1 eu-west-1
6283
+
6284
+ ⚠️ STATUS: Some business scenarios may require additional CloudOps dependencies.
6295
6285
  """
6296
6286
 
6297
6287
  # Handle group behavior: if no subcommand invoked, execute main functionality
@@ -6302,14 +6292,54 @@ def finops(
6302
6292
  # Subcommand will handle execution
6303
6293
  return
6304
6294
 
6295
+ # Removed broken --help-scenarios logic - use main --help instead
6296
+
6305
6297
  # Business Scenario Dispatch Logic (Strategic Objective #1: Unified CLI)
6306
6298
  if scenario:
6307
- from runbooks.common.rich_utils import console, print_header, print_success, print_info
6299
+ from runbooks.common.rich_utils import console, print_header, print_success, print_info, print_error
6308
6300
 
6301
+ # PHASE 2 PRIORITY 1: Unlimited Scenario Expansion Framework
6302
+ # Dynamic scenario validation (replaces hardcoded choice list)
6303
+ from runbooks.finops.unlimited_scenarios import get_dynamic_scenario_choices
6304
+ valid_scenarios = get_dynamic_scenario_choices()
6305
+
6306
+ if scenario not in valid_scenarios:
6307
+ print_error(f"Unknown scenario: '{scenario}'")
6308
+ print_info("Available scenarios:")
6309
+ for valid_scenario in valid_scenarios:
6310
+ config = lazy_get_business_case_config()()
6311
+ scenario_obj = config.get_scenario(valid_scenario)
6312
+ if scenario_obj:
6313
+ print_info(f" {valid_scenario} - {scenario_obj.display_name} ({scenario_obj.savings_range_display})")
6314
+ else:
6315
+ print_info(f" {valid_scenario}")
6316
+ print_info("\nUse 'runbooks finops --help-scenarios' for comprehensive scenario information")
6317
+ return
6318
+
6309
6319
  # Unified scenario dispatcher with enterprise Rich CLI formatting
6310
6320
  print_header("FinOps Business Scenarios", "Manager Priority Cost Optimization")
6311
- print_info(f"Executing scenario: {scenario.upper()}")
6312
-
6321
+ print_success(f" Scenario validated: {scenario.upper()}")
6322
+
6323
+ # Display unlimited expansion capability info
6324
+ from runbooks.finops.unlimited_scenarios import discover_scenarios_summary
6325
+ summary = discover_scenarios_summary()
6326
+ if summary["scenario_discovery"]["environment_discovered"] > 0:
6327
+ print_info(f"🚀 Unlimited expansion: {summary['scenario_discovery']['environment_discovered']} environment-discovered scenarios active")
6328
+
6329
+ # Validate and suggest optimal parameters for scenario
6330
+ from runbooks.finops.scenario_cli_integration import validate_and_suggest_parameters
6331
+ cli_params = {
6332
+ 'time_range': time_range,
6333
+ 'unblended': unblended,
6334
+ 'amortized': amortized,
6335
+ 'dual_metrics': dual_metrics,
6336
+ 'pdf': pdf,
6337
+ 'csv': csv,
6338
+ 'json': json,
6339
+ 'export_markdown': export_markdown
6340
+ }
6341
+ validate_and_suggest_parameters(scenario, cli_params)
6342
+
6313
6343
  try:
6314
6344
  # Import CloudOps cost optimizer for enhanced JIRA scenario integration
6315
6345
  from runbooks.cloudops.cost_optimizer import CostOptimizer
@@ -6327,7 +6357,7 @@ def finops(
6327
6357
  )
6328
6358
 
6329
6359
  if scenario.lower() == "workspaces":
6330
- config = get_business_case_config()
6360
+ config = lazy_get_business_case_config()()
6331
6361
  workspaces_scenario = config.get_scenario('workspaces')
6332
6362
  scenario_info = f"{workspaces_scenario.display_name} ({workspaces_scenario.savings_range_display})" if workspaces_scenario else "WorkSpaces Resource Optimization"
6333
6363
  print_info(f"{scenario_info}")
@@ -6352,7 +6382,7 @@ def finops(
6352
6382
  }
6353
6383
 
6354
6384
  elif scenario.lower() == "snapshots":
6355
- config = get_business_case_config()
6385
+ config = lazy_get_business_case_config()()
6356
6386
  rds_scenario = config.get_scenario('rds-snapshots')
6357
6387
  scenario_info = f"{rds_scenario.display_name} ({rds_scenario.savings_range_display})" if rds_scenario else "RDS Storage Optimization"
6358
6388
  print_info(f"{scenario_info}")
@@ -6377,15 +6407,17 @@ def finops(
6377
6407
  }
6378
6408
 
6379
6409
  elif scenario.lower() == "commvault":
6380
- config = get_business_case_config()
6410
+ config = lazy_get_business_case_config()()
6381
6411
  backup_scenario = config.get_scenario('backup-investigation')
6382
6412
  scenario_info = f"{backup_scenario.display_name}" if backup_scenario else "Backup Infrastructure Analysis"
6383
6413
  print_info(f"{scenario_info} (Real AWS integration)")
6384
6414
  print_info("🚀 Enhanced with CloudOps enterprise integration")
6385
6415
 
6386
6416
  # Use CloudOps cost optimizer for enterprise-grade investigation
6417
+ # Dynamically resolve account ID from current AWS profile context
6418
+ current_account_id = get_account_id_for_context(profile if profile != "default" else "default")
6387
6419
  commvault_result = asyncio.run(cost_optimizer.investigate_commvault_ec2(
6388
- account_id="637423383469", # From JIRA specification
6420
+ account_id=current_account_id, # Dynamic account resolution
6389
6421
  dry_run=True # Always dry-run for investigations
6390
6422
  ))
6391
6423
 
@@ -6403,7 +6435,7 @@ def finops(
6403
6435
  }
6404
6436
 
6405
6437
  elif scenario.lower() == "nat-gateway":
6406
- config = get_business_case_config()
6438
+ config = lazy_get_business_case_config()()
6407
6439
  nat_scenario = config.get_scenario('nat-gateway')
6408
6440
  scenario_info = f"{nat_scenario.display_name} ({nat_scenario.savings_range_display})" if nat_scenario else "Network Gateway Optimization"
6409
6441
  print_info(f"{scenario_info}")
@@ -6441,7 +6473,7 @@ def finops(
6441
6473
  }
6442
6474
 
6443
6475
  elif scenario.lower() == "elastic-ip":
6444
- config = get_business_case_config()
6476
+ config = lazy_get_business_case_config()()
6445
6477
  eip_scenario = config.get_scenario('elastic-ip')
6446
6478
  scenario_info = f"{eip_scenario.display_name} ({eip_scenario.savings_range_display})" if eip_scenario else "IP Address Resource Management"
6447
6479
  print_info(f"{scenario_info}")
@@ -6481,7 +6513,7 @@ def finops(
6481
6513
  }
6482
6514
 
6483
6515
  elif scenario.lower() == "ebs":
6484
- config = get_business_case_config()
6516
+ config = lazy_get_business_case_config()()
6485
6517
  ebs_scenario = config.get_scenario('ebs-optimization')
6486
6518
  scenario_info = f"{ebs_scenario.display_name}" if ebs_scenario else "Storage Volume Optimization (15-20% cost reduction potential)"
6487
6519
  print_info(f"{scenario_info}")
@@ -6529,7 +6561,7 @@ def finops(
6529
6561
  }
6530
6562
 
6531
6563
  elif scenario.lower() == "vpc-cleanup":
6532
- config = get_business_case_config()
6564
+ config = lazy_get_business_case_config()()
6533
6565
  vpc_scenario = config.get_scenario('vpc-cleanup')
6534
6566
  scenario_info = f"{vpc_scenario.display_name} ({vpc_scenario.savings_range_display})" if vpc_scenario else "Network Infrastructure Cleanup"
6535
6567
  print_info(f"{scenario_info}")
@@ -6671,16 +6703,19 @@ def finops(
6671
6703
  report_name = f"finops_multi_format_export"
6672
6704
  click.echo(click.style(f"📝 Auto-generated report name: {report_name}", fg="blue"))
6673
6705
 
6674
- # Dual-Metric Configuration Logic (Enterprise Enhancement)
6706
+ # AWS Terminology Alignment: Dual-Metric Configuration Logic (Enhanced Enterprise Implementation)
6675
6707
  metric_config = "dual" # Default comprehensive analysis
6676
- if tech_focus:
6708
+
6709
+
6710
+ # AWS native parameter processing
6711
+ if unblended:
6677
6712
  metric_config = "technical"
6678
- click.echo(click.style("🔧 Technical Focus: UnblendedCost analysis for DevOps/SRE teams", fg="bright_blue", bold=True))
6679
- elif financial_focus:
6680
- metric_config = "financial"
6681
- click.echo(click.style("📊 Financial Focus: AmortizedCost analysis for Finance/Executive teams", fg="bright_green", bold=True))
6713
+ click.echo(click.style("🔧 AWS UnblendedCost Analysis: Technical cost view for DevOps/SRE teams", fg="bright_blue", bold=True))
6714
+ elif amortized:
6715
+ metric_config = "financial"
6716
+ click.echo(click.style("📊 AWS AmortizedCost Analysis: Financial reporting view for Finance/Executive teams", fg="bright_green", bold=True))
6682
6717
  else:
6683
- click.echo(click.style("💰 Dual-Metrics: Both technical and financial perspectives (default)", fg="bright_cyan", bold=True))
6718
+ click.echo(click.style("💰 Dual-Metrics: Both AWS UnblendedCost and AmortizedCost analysis (comprehensive, default)", fg="bright_cyan", bold=True))
6684
6719
 
6685
6720
  # Report name logic (separate from metric config)
6686
6721
  if report_types and not report_name:
@@ -6746,17 +6781,12 @@ def finops(
6746
6781
  audit=audit,
6747
6782
  export_markdown=export_markdown, # Add export_markdown parameter
6748
6783
  config_file=None, # Not exposed in Click interface yet
6749
- # Display configuration parameters
6750
- profile_display_length=profile_display_length,
6751
- service_name_length=service_name_length,
6752
- max_services_text=max_services_text,
6753
- high_cost_threshold=high_cost_threshold,
6754
- medium_cost_threshold=medium_cost_threshold,
6784
+ # Display configuration parameters now managed via API-only config
6755
6785
  validate=validate,
6756
- # Dual-Metric Configuration (Enterprise Enhancement)
6786
+ # AWS Terminology Alignment: Dual-Metric Configuration (Enterprise Enhancement)
6757
6787
  metric_config=metric_config,
6758
- tech_focus=tech_focus,
6759
- financial_focus=financial_focus,
6788
+ unblended=unblended,
6789
+ amortized=amortized,
6760
6790
  dual_metrics=dual_metrics,
6761
6791
  )
6762
6792
  # Route to appropriate dashboard implementation
@@ -6777,8 +6807,11 @@ def finops(
6777
6807
  @click.option("--output", type=click.Choice(["json", "csv", "pdf", "html"]), help="Output format")
6778
6808
  def dashboard(profile, region, dry_run, output):
6779
6809
  """
6780
- FinOps cost analytics dashboard.
6781
-
6810
+ FinOps cost analytics dashboard (same as 'runbooks finops' default).
6811
+
6812
+ 📊 This command provides identical functionality to running 'runbooks finops' without parameters.
6813
+ Both commands launch the interactive cost dashboard with business scenario overview.
6814
+
6782
6815
  Interactive cost analysis with Rich CLI formatting and enterprise-grade reporting.
6783
6816
  """
6784
6817
  from runbooks.common.rich_utils import console, print_header
@@ -6885,21 +6918,26 @@ def finops_23_rds_snapshots(profile, output_file):
6885
6918
 
6886
6919
  @main.command("finops-25")
6887
6920
  @click.option('--profile', help='AWS profile name')
6888
- @click.option('--account-id', default='637423383469', help='Commvault account ID')
6921
+ @click.option('--account-id', help='Account ID for analysis (uses current AWS account if not specified)')
6889
6922
  @click.option('--output-file', help='Save results to file')
6890
6923
  def finops_25_commvault(profile, account_id, output_file):
6891
6924
  """FinOps-25: Commvault EC2 investigation framework (Real AWS integration).
6892
-
6925
+
6893
6926
  UNIFIED CLI: Use 'runbooks finops --scenario commvault' for new unified interface.
6894
6927
  """
6895
6928
  from runbooks.common.rich_utils import console, print_warning, print_info
6896
-
6929
+
6897
6930
  print_warning("Legacy command detected! Consider using unified interface:")
6898
6931
  print_info("runbooks finops --scenario commvault --profile [PROFILE]")
6899
-
6932
+
6933
+ # Resolve account ID dynamically if not provided
6934
+ if not account_id:
6935
+ account_id = get_account_id_for_context(profile or "default")
6936
+ console.print(f"[dim]Using current AWS account: {account_id}[/dim]")
6937
+
6900
6938
  try:
6901
6939
  from runbooks.finops.finops_scenarios import investigate_finops_25_commvault
6902
- results = investigate_finops_25_commvault(profile)
6940
+ results = investigate_finops_25_commvault(profile, account_id=account_id)
6903
6941
 
6904
6942
  if output_file:
6905
6943
  import json