runbooks 0.7.7__py3-none-any.whl → 0.9.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 (157) hide show
  1. runbooks/__init__.py +1 -1
  2. runbooks/base.py +2 -2
  3. runbooks/cfat/README.md +12 -1
  4. runbooks/cfat/__init__.py +8 -4
  5. runbooks/cfat/assessment/collectors.py +171 -14
  6. runbooks/cfat/assessment/compliance.py +546 -522
  7. runbooks/cfat/assessment/runner.py +129 -10
  8. runbooks/cfat/models.py +6 -2
  9. runbooks/common/__init__.py +152 -0
  10. runbooks/common/accuracy_validator.py +1039 -0
  11. runbooks/common/context_logger.py +440 -0
  12. runbooks/common/cross_module_integration.py +594 -0
  13. runbooks/common/enhanced_exception_handler.py +1108 -0
  14. runbooks/common/enterprise_audit_integration.py +634 -0
  15. runbooks/common/logger.py +14 -0
  16. runbooks/common/mcp_integration.py +539 -0
  17. runbooks/common/performance_monitor.py +387 -0
  18. runbooks/common/profile_utils.py +216 -0
  19. runbooks/common/rich_utils.py +622 -0
  20. runbooks/enterprise/__init__.py +68 -0
  21. runbooks/enterprise/error_handling.py +411 -0
  22. runbooks/enterprise/logging.py +439 -0
  23. runbooks/enterprise/multi_tenant.py +583 -0
  24. runbooks/feedback/user_feedback_collector.py +440 -0
  25. runbooks/finops/README.md +129 -14
  26. runbooks/finops/__init__.py +22 -3
  27. runbooks/finops/account_resolver.py +279 -0
  28. runbooks/finops/accuracy_cross_validator.py +638 -0
  29. runbooks/finops/aws_client.py +721 -36
  30. runbooks/finops/budget_integration.py +313 -0
  31. runbooks/finops/cli.py +90 -33
  32. runbooks/finops/cost_processor.py +211 -37
  33. runbooks/finops/dashboard_router.py +900 -0
  34. runbooks/finops/dashboard_runner.py +1334 -399
  35. runbooks/finops/embedded_mcp_validator.py +288 -0
  36. runbooks/finops/enhanced_dashboard_runner.py +526 -0
  37. runbooks/finops/enhanced_progress.py +327 -0
  38. runbooks/finops/enhanced_trend_visualization.py +423 -0
  39. runbooks/finops/finops_dashboard.py +41 -0
  40. runbooks/finops/helpers.py +639 -323
  41. runbooks/finops/iam_guidance.py +400 -0
  42. runbooks/finops/markdown_exporter.py +466 -0
  43. runbooks/finops/multi_dashboard.py +1502 -0
  44. runbooks/finops/optimizer.py +396 -395
  45. runbooks/finops/profile_processor.py +2 -2
  46. runbooks/finops/runbooks.inventory.organizations_discovery.log +0 -0
  47. runbooks/finops/runbooks.security.report_generator.log +0 -0
  48. runbooks/finops/runbooks.security.run_script.log +0 -0
  49. runbooks/finops/runbooks.security.security_export.log +0 -0
  50. runbooks/finops/service_mapping.py +195 -0
  51. runbooks/finops/single_dashboard.py +710 -0
  52. runbooks/finops/tests/__init__.py +19 -0
  53. runbooks/finops/tests/results_test_finops_dashboard.xml +1 -0
  54. runbooks/finops/tests/run_comprehensive_tests.py +421 -0
  55. runbooks/finops/tests/run_tests.py +305 -0
  56. runbooks/finops/tests/test_finops_dashboard.py +705 -0
  57. runbooks/finops/tests/test_integration.py +477 -0
  58. runbooks/finops/tests/test_performance.py +380 -0
  59. runbooks/finops/tests/test_performance_benchmarks.py +500 -0
  60. runbooks/finops/tests/test_reference_images_validation.py +867 -0
  61. runbooks/finops/tests/test_single_account_features.py +715 -0
  62. runbooks/finops/tests/validate_test_suite.py +220 -0
  63. runbooks/finops/types.py +1 -1
  64. runbooks/hitl/enhanced_workflow_engine.py +725 -0
  65. runbooks/inventory/README.md +12 -1
  66. runbooks/inventory/artifacts/scale-optimize-status.txt +12 -0
  67. runbooks/inventory/collectors/aws_comprehensive.py +192 -185
  68. runbooks/inventory/collectors/enterprise_scale.py +281 -0
  69. runbooks/inventory/core/collector.py +299 -12
  70. runbooks/inventory/list_ec2_instances.py +21 -20
  71. runbooks/inventory/list_ssm_parameters.py +31 -3
  72. runbooks/inventory/organizations_discovery.py +1315 -0
  73. runbooks/inventory/rich_inventory_display.py +360 -0
  74. runbooks/inventory/run_on_multi_accounts.py +32 -16
  75. runbooks/inventory/runbooks.security.report_generator.log +0 -0
  76. runbooks/inventory/runbooks.security.run_script.log +0 -0
  77. runbooks/inventory/vpc_flow_analyzer.py +1030 -0
  78. runbooks/main.py +4171 -1615
  79. runbooks/metrics/dora_metrics_engine.py +1293 -0
  80. runbooks/monitoring/performance_monitor.py +433 -0
  81. runbooks/operate/README.md +394 -0
  82. runbooks/operate/__init__.py +2 -2
  83. runbooks/operate/base.py +291 -11
  84. runbooks/operate/deployment_framework.py +1032 -0
  85. runbooks/operate/deployment_validator.py +853 -0
  86. runbooks/operate/dynamodb_operations.py +10 -6
  87. runbooks/operate/ec2_operations.py +321 -11
  88. runbooks/operate/executive_dashboard.py +779 -0
  89. runbooks/operate/mcp_integration.py +750 -0
  90. runbooks/operate/nat_gateway_operations.py +1120 -0
  91. runbooks/operate/networking_cost_heatmap.py +685 -0
  92. runbooks/operate/privatelink_operations.py +940 -0
  93. runbooks/operate/s3_operations.py +10 -6
  94. runbooks/operate/vpc_endpoints.py +644 -0
  95. runbooks/operate/vpc_operations.py +1038 -0
  96. runbooks/remediation/README.md +489 -13
  97. runbooks/remediation/__init__.py +2 -2
  98. runbooks/remediation/acm_remediation.py +1 -1
  99. runbooks/remediation/base.py +1 -1
  100. runbooks/remediation/cloudtrail_remediation.py +1 -1
  101. runbooks/remediation/cognito_remediation.py +1 -1
  102. runbooks/remediation/commons.py +8 -4
  103. runbooks/remediation/dynamodb_remediation.py +1 -1
  104. runbooks/remediation/ec2_remediation.py +1 -1
  105. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -1
  106. runbooks/remediation/kms_enable_key_rotation.py +1 -1
  107. runbooks/remediation/kms_remediation.py +1 -1
  108. runbooks/remediation/lambda_remediation.py +1 -1
  109. runbooks/remediation/multi_account.py +1 -1
  110. runbooks/remediation/rds_remediation.py +1 -1
  111. runbooks/remediation/s3_block_public_access.py +1 -1
  112. runbooks/remediation/s3_enable_access_logging.py +1 -1
  113. runbooks/remediation/s3_encryption.py +1 -1
  114. runbooks/remediation/s3_remediation.py +1 -1
  115. runbooks/remediation/vpc_remediation.py +475 -0
  116. runbooks/security/ENTERPRISE_SECURITY_FRAMEWORK.md +506 -0
  117. runbooks/security/README.md +12 -1
  118. runbooks/security/__init__.py +166 -33
  119. runbooks/security/compliance_automation.py +634 -0
  120. runbooks/security/compliance_automation_engine.py +1021 -0
  121. runbooks/security/enterprise_security_framework.py +931 -0
  122. runbooks/security/enterprise_security_policies.json +293 -0
  123. runbooks/security/integration_test_enterprise_security.py +879 -0
  124. runbooks/security/module_security_integrator.py +641 -0
  125. runbooks/security/report_generator.py +10 -0
  126. runbooks/security/run_script.py +27 -5
  127. runbooks/security/security_baseline_tester.py +153 -27
  128. runbooks/security/security_export.py +456 -0
  129. runbooks/sre/README.md +472 -0
  130. runbooks/sre/__init__.py +33 -0
  131. runbooks/sre/mcp_reliability_engine.py +1049 -0
  132. runbooks/sre/performance_optimization_engine.py +1032 -0
  133. runbooks/sre/reliability_monitoring_framework.py +1011 -0
  134. runbooks/validation/__init__.py +10 -0
  135. runbooks/validation/benchmark.py +489 -0
  136. runbooks/validation/cli.py +368 -0
  137. runbooks/validation/mcp_validator.py +797 -0
  138. runbooks/vpc/README.md +478 -0
  139. runbooks/vpc/__init__.py +38 -0
  140. runbooks/vpc/config.py +212 -0
  141. runbooks/vpc/cost_engine.py +347 -0
  142. runbooks/vpc/heatmap_engine.py +605 -0
  143. runbooks/vpc/manager_interface.py +649 -0
  144. runbooks/vpc/networking_wrapper.py +1289 -0
  145. runbooks/vpc/rich_formatters.py +693 -0
  146. runbooks/vpc/tests/__init__.py +5 -0
  147. runbooks/vpc/tests/conftest.py +356 -0
  148. runbooks/vpc/tests/test_cli_integration.py +530 -0
  149. runbooks/vpc/tests/test_config.py +458 -0
  150. runbooks/vpc/tests/test_cost_engine.py +479 -0
  151. runbooks/vpc/tests/test_networking_wrapper.py +512 -0
  152. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/METADATA +175 -65
  153. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/RECORD +157 -60
  154. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/entry_points.txt +1 -1
  155. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/WHEEL +0 -0
  156. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/licenses/LICENSE +0 -0
  157. {runbooks-0.7.7.dist-info → runbooks-0.9.0.dist-info}/top_level.txt +0 -0
runbooks/operate/base.py CHANGED
@@ -6,19 +6,40 @@ ensuring consistent patterns, safety features, and enterprise-grade reliability
6
6
  across all service-specific operations.
7
7
  """
8
8
 
9
+ import asyncio
10
+ import time
9
11
  from abc import ABC, abstractmethod
10
12
  from dataclasses import dataclass, field
11
13
  from datetime import datetime
12
14
  from enum import Enum
13
- from typing import Any, Dict, List, Optional, Union
15
+ from typing import Any, Callable, Dict, List, Optional, Union
14
16
 
15
17
  import boto3
16
18
  from botocore.exceptions import ClientError, NoCredentialsError
17
19
  from loguru import logger
18
-
20
+ from rich.console import Console
21
+ from rich.panel import Panel
22
+ from rich.progress import Progress, SpinnerColumn, TextColumn
23
+ from rich.table import Table
24
+
25
+ from runbooks.common.cross_module_integration import DataFlowType, EnterpriseCrossModuleIntegrator
26
+ from runbooks.common.mcp_integration import EnterpriseMCPIntegrator, MCPOperationType
27
+ from runbooks.common.profile_utils import create_operational_session, get_profile_for_operation
28
+ from runbooks.common.rich_utils import print_error, print_info, print_success, print_warning
19
29
  from runbooks.inventory.models.account import AWSAccount
20
30
  from runbooks.inventory.utils.aws_helpers import aws_api_retry, get_boto3_session
21
31
 
32
+ # Enterprise 4-Profile Architecture - Proven FinOps Patterns
33
+ ENTERPRISE_PROFILES = {
34
+ "BILLING_PROFILE": "ams-admin-Billing-ReadOnlyAccess-909135376185",
35
+ "MANAGEMENT_PROFILE": "ams-admin-ReadOnlyAccess-909135376185",
36
+ "CENTRALISED_OPS_PROFILE": "ams-centralised-ops-ReadOnlyAccess-335083429030",
37
+ "SINGLE_ACCOUNT_PROFILE": "ams-shared-services-non-prod-ReadOnlyAccess-499201730520",
38
+ }
39
+
40
+ # Rich console instance for consistent formatting
41
+ console = Console()
42
+
22
43
 
23
44
  class OperationStatus(Enum):
24
45
  """Status of an AWS operation."""
@@ -118,19 +139,36 @@ class BaseOperation(ABC):
118
139
 
119
140
  def __init__(self, profile: Optional[str] = None, region: Optional[str] = None, dry_run: bool = False):
120
141
  """
121
- Initialize base operation class.
142
+ Initialize base operation class with enterprise patterns.
122
143
 
123
144
  Args:
124
- profile: AWS profile name for authentication
145
+ profile: AWS profile name for authentication (supports ENTERPRISE_PROFILES)
125
146
  region: AWS region for operations
126
147
  dry_run: Enable dry-run mode for safe testing
127
148
  """
128
- self.profile = profile
149
+ # Support enterprise profile shortcuts
150
+ if profile in ENTERPRISE_PROFILES:
151
+ self.profile = ENTERPRISE_PROFILES[profile]
152
+ console.print(f"[blue]Using enterprise profile: {profile} -> {self.profile}[/blue]")
153
+ else:
154
+ self.profile = profile
155
+
129
156
  self.region = region or "us-east-1"
130
157
  self.dry_run = dry_run
131
158
  self._session = None
132
159
  self._clients = {}
133
160
 
161
+ # Performance benchmarking
162
+ self._operation_start_time = None
163
+ self._performance_target = 2.0 # <2s target for operate operations
164
+
165
+ # Phase 4: MCP Integration Framework
166
+ self.mcp_integrator = EnterpriseMCPIntegrator(self.profile)
167
+ self.cross_module_integrator = EnterpriseCrossModuleIntegrator(self.profile)
168
+ self.enable_mcp_validation = True
169
+
170
+ print_info(f"BaseOperation initialized with MCP integration for {self.service_name or 'unknown'} service")
171
+
134
172
  @property
135
173
  def session(self) -> boto3.Session:
136
174
  """Get or create AWS session."""
@@ -185,7 +223,7 @@ class BaseOperation(ABC):
185
223
 
186
224
  def confirm_operation(self, context: OperationContext, resource_id: str, operation_type: str) -> bool:
187
225
  """
188
- Request user confirmation for destructive operations.
226
+ Request user confirmation for destructive operations with Rich CLI.
189
227
 
190
228
  Args:
191
229
  context: Operation context
@@ -196,15 +234,27 @@ class BaseOperation(ABC):
196
234
  True if operation is confirmed
197
235
  """
198
236
  if context.dry_run:
199
- logger.info(f"[DRY-RUN] Would perform {operation_type} on {resource_id}")
237
+ console.print(
238
+ Panel(
239
+ f"[yellow]Would perform {operation_type} on {resource_id}[/yellow]",
240
+ title="🏃 DRY-RUN MODE",
241
+ border_style="yellow",
242
+ )
243
+ )
200
244
  return True
201
245
 
202
246
  if context.force or not self.requires_confirmation:
203
247
  return True
204
248
 
205
- # In a real implementation, this would integrate with CLI for confirmation
206
- logger.warning(
207
- f"Destructive operation: {operation_type} on {resource_id} in account {context.account.account_id}"
249
+ # Rich CLI confirmation display
250
+ console.print(
251
+ Panel(
252
+ f"[red]⚠️ Destructive operation: {operation_type}[/red]\n"
253
+ f"[white]Resource: {resource_id}[/white]\n"
254
+ f"[white]Account: {context.account.account_id}[/white]",
255
+ title="🚨 CONFIRMATION REQUIRED",
256
+ border_style="red",
257
+ )
208
258
  )
209
259
  return True # Simplified for this implementation
210
260
 
@@ -307,5 +357,235 @@ class BaseOperation(ABC):
307
357
  List of historical operation results
308
358
  """
309
359
  # In a real implementation, this would query a database or log store
310
- logger.info(f"Operation history requested for {resource_id or 'all resources'}")
360
+ console.print(f"[blue]📊 Operation history requested for {resource_id or 'all resources'}[/blue]")
311
361
  return []
362
+
363
+ def start_performance_benchmark(self) -> None:
364
+ """Start performance timing for operation benchmarking."""
365
+ self._operation_start_time = time.time()
366
+
367
+ def end_performance_benchmark(self, operation_name: str) -> float:
368
+ """
369
+ End performance timing and display results.
370
+
371
+ Args:
372
+ operation_name: Name of the operation for reporting
373
+
374
+ Returns:
375
+ Elapsed time in seconds
376
+ """
377
+ if self._operation_start_time is None:
378
+ return 0.0
379
+
380
+ elapsed_time = time.time() - self._operation_start_time
381
+
382
+ # Performance validation against target
383
+ if elapsed_time <= self._performance_target:
384
+ console.print(
385
+ f"[green]⚡ {operation_name} completed in {elapsed_time:.2f}s (target: {self._performance_target}s) ✅[/green]"
386
+ )
387
+ else:
388
+ console.print(
389
+ f"[yellow]⚠️ {operation_name} completed in {elapsed_time:.2f}s (exceeded target: {self._performance_target}s)[/yellow]"
390
+ )
391
+
392
+ self._operation_start_time = None
393
+ return elapsed_time
394
+
395
+ def display_operation_summary(self, results: List[OperationResult]) -> None:
396
+ """
397
+ Display operation summary using Rich table formatting.
398
+
399
+ Args:
400
+ results: List of operation results to summarize
401
+ """
402
+ if not results:
403
+ console.print("[yellow]No operations to display[/yellow]")
404
+ return
405
+
406
+ table = Table(title="🔧 Operation Summary")
407
+ table.add_column("Operation", style="cyan")
408
+ table.add_column("Resource", style="magenta")
409
+ table.add_column("Status", style="green")
410
+ table.add_column("Duration", style="blue")
411
+
412
+ success_count = 0
413
+ total_count = len(results)
414
+
415
+ for result in results:
416
+ status_icon = "✅" if result.success else "❌"
417
+ status_text = f"{status_icon} {result.status.value}"
418
+
419
+ duration = "N/A"
420
+ if result.completed_at and result.started_at:
421
+ elapsed = (result.completed_at - result.started_at).total_seconds()
422
+ duration = f"{elapsed:.2f}s"
423
+
424
+ if result.success:
425
+ success_count += 1
426
+
427
+ table.add_row(result.operation_type, result.resource_id, status_text, duration)
428
+
429
+ console.print(table)
430
+
431
+ # Success rate summary
432
+ success_rate = (success_count / total_count) * 100 if total_count > 0 else 0
433
+ if success_rate >= 95:
434
+ console.print(
435
+ f"[green]🎯 Success Rate: {success_rate:.1f}% ({success_count}/{total_count}) - Excellent![/green]"
436
+ )
437
+ elif success_rate >= 90:
438
+ console.print(
439
+ f"[yellow]📊 Success Rate: {success_rate:.1f}% ({success_count}/{total_count}) - Good[/yellow]"
440
+ )
441
+ else:
442
+ console.print(
443
+ f"[red]⚠️ Success Rate: {success_rate:.1f}% ({success_count}/{total_count}) - Needs Attention[/red]"
444
+ )
445
+
446
+ # Phase 4: MCP Integration Methods
447
+ async def validate_operation_with_mcp(self, operation_data: Dict[str, Any]) -> Dict[str, Any]:
448
+ """
449
+ Validate operation results using MCP integration.
450
+
451
+ Args:
452
+ operation_data: Operation results to validate
453
+
454
+ Returns:
455
+ Dictionary containing validation results
456
+ """
457
+ try:
458
+ if not self.enable_mcp_validation:
459
+ return {"validation_skipped": True, "reason": "MCP validation disabled"}
460
+
461
+ print_info("Validating operation results with MCP integration")
462
+
463
+ validation_result = await self.mcp_integrator.validate_operate_operations(operation_data)
464
+
465
+ if validation_result.success:
466
+ print_success(f"Operation MCP validation passed: {validation_result.accuracy_score}% accuracy")
467
+ else:
468
+ print_warning("Operation MCP validation encountered issues")
469
+
470
+ return validation_result.to_dict()
471
+
472
+ except Exception as e:
473
+ print_error(f"MCP validation failed: {str(e)[:50]}...")
474
+ return {"validation_error": str(e), "validation_failed": True}
475
+
476
+ async def prepare_data_for_finops_analysis(self, operation_results: List[OperationResult]) -> Dict[str, Any]:
477
+ """
478
+ Prepare operation results for FinOps cost analysis integration.
479
+
480
+ Args:
481
+ operation_results: List of operation results
482
+
483
+ Returns:
484
+ Dictionary formatted for FinOps module consumption
485
+ """
486
+ try:
487
+ print_info("Preparing operation data for FinOps analysis")
488
+
489
+ # Convert operation results to data flow format
490
+ operation_data = {
491
+ "operations": [
492
+ {
493
+ "id": result.operation_id,
494
+ "type": result.operation_type,
495
+ "resource_id": result.resource_id,
496
+ "resource_type": result.resource_type,
497
+ "account_id": result.account_id,
498
+ "region": result.region,
499
+ "success": result.success,
500
+ "started_at": result.started_at.isoformat(),
501
+ "completed_at": result.completed_at.isoformat() if result.completed_at else None,
502
+ "metadata": result.metadata,
503
+ }
504
+ for result in operation_results
505
+ ]
506
+ }
507
+
508
+ data_flow_result = await self.cross_module_integrator.execute_data_flow(
509
+ flow_type=DataFlowType.OPERATE_TO_FINOPS, source_data=operation_data
510
+ )
511
+
512
+ if data_flow_result.success:
513
+ print_success("Operate → FinOps data flow completed successfully")
514
+ return data_flow_result.transformed_data
515
+ else:
516
+ print_error(f"Data flow failed: {', '.join(data_flow_result.error_details)}")
517
+ return {}
518
+
519
+ except Exception as e:
520
+ print_error(f"Failed to prepare data for FinOps analysis: {str(e)}")
521
+ return {}
522
+
523
+ def execute_operation_with_validation(
524
+ self, context: OperationContext, operation_func: Callable, *args, **kwargs
525
+ ) -> List[OperationResult]:
526
+ """
527
+ Execute operation with automatic MCP validation and performance tracking.
528
+
529
+ Args:
530
+ context: Operation context
531
+ operation_func: Operation function to execute
532
+ *args: Arguments for operation function
533
+ **kwargs: Keyword arguments for operation function
534
+
535
+ Returns:
536
+ List of operation results with MCP validation
537
+ """
538
+ self.start_performance_benchmark()
539
+
540
+ try:
541
+ # Execute the operation
542
+ results = operation_func(context, *args, **kwargs)
543
+
544
+ # Add MCP validation asynchronously if enabled
545
+ if self.enable_mcp_validation and results:
546
+ try:
547
+ operation_data = {
548
+ "operations": [result.__dict__ for result in results],
549
+ "context": context.__dict__,
550
+ }
551
+
552
+ validation_result = asyncio.run(self.validate_operation_with_mcp(operation_data))
553
+
554
+ # Add validation results to operation metadata
555
+ for result in results:
556
+ result.metadata["mcp_validation"] = validation_result
557
+
558
+ except Exception as e:
559
+ print_warning(f"MCP validation failed: {str(e)[:50]}... - operation completed without validation")
560
+
561
+ # End performance benchmark
562
+ elapsed_time = self.end_performance_benchmark(f"{context.operation_type} operation")
563
+
564
+ # Add performance metrics to results
565
+ for result in results:
566
+ result.metadata["performance_seconds"] = elapsed_time
567
+ result.metadata["performance_target_met"] = elapsed_time <= self._performance_target
568
+
569
+ return results
570
+
571
+ except Exception as e:
572
+ self.end_performance_benchmark(f"{context.operation_type} operation (failed)")
573
+ raise e
574
+
575
+ def get_mcp_integration_status(self) -> Dict[str, Any]:
576
+ """
577
+ Get current MCP integration status and configuration.
578
+
579
+ Returns:
580
+ Dictionary containing MCP integration details
581
+ """
582
+ return {
583
+ "service_name": self.service_name,
584
+ "mcp_validation_enabled": self.enable_mcp_validation,
585
+ "mcp_integrator_initialized": self.mcp_integrator is not None,
586
+ "cross_module_integrator_initialized": self.cross_module_integrator is not None,
587
+ "supported_operations": list(self.supported_operations),
588
+ "performance_target_seconds": self._performance_target,
589
+ "profile": self.profile,
590
+ "region": self.region,
591
+ }