runbooks 1.0.2__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 +9 -4
  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.2.dist-info → runbooks-1.1.0.dist-info}/METADATA +15 -15
  43. {runbooks-1.0.2.dist-info → runbooks-1.1.0.dist-info}/RECORD +47 -31
  44. {runbooks-1.0.2.dist-info → runbooks-1.1.0.dist-info}/WHEEL +0 -0
  45. {runbooks-1.0.2.dist-info → runbooks-1.1.0.dist-info}/entry_points.txt +0 -0
  46. {runbooks-1.0.2.dist-info → runbooks-1.1.0.dist-info}/licenses/LICENSE +0 -0
  47. {runbooks-1.0.2.dist-info → runbooks-1.1.0.dist-info}/top_level.txt +0 -0
@@ -19,8 +19,35 @@ try:
19
19
  from loguru import logger as loguru_logger
20
20
  _HAS_LOGURU = True
21
21
  except ImportError:
22
+ # Create a mock loguru-like object for compatibility
22
23
  import logging
23
- loguru_logger = logging.getLogger(__name__)
24
+
25
+ class MockLoguru:
26
+ def __init__(self):
27
+ self.logger = logging.getLogger(__name__)
28
+
29
+ def remove(self, *args, **kwargs):
30
+ pass # No-op for standard logging
31
+
32
+ def add(self, *args, **kwargs):
33
+ pass # No-op for standard logging
34
+
35
+ def bind(self, **kwargs):
36
+ return self # Return self for chaining
37
+
38
+ def info(self, message, *args, **kwargs):
39
+ self.logger.info(message, *args)
40
+
41
+ def warning(self, message, *args, **kwargs):
42
+ self.logger.warning(message, *args)
43
+
44
+ def error(self, message, *args, **kwargs):
45
+ self.logger.error(message, *args)
46
+
47
+ def debug(self, message, *args, **kwargs):
48
+ self.logger.debug(message, *args)
49
+
50
+ loguru_logger = MockLoguru()
24
51
  _HAS_LOGURU = False
25
52
 
26
53
  # Rich CLI integration
@@ -103,7 +130,8 @@ class EnterpriseRichLogger:
103
130
 
104
131
  def _setup_loguru_logging(self, enable_console: bool, enable_file: bool, enable_audit: bool) -> None:
105
132
  """Setup Loguru-based logging."""
106
- # Remove default handler
133
+ global loguru_logger
134
+ # Remove default handler (MockLoguru handles this gracefully)
107
135
  loguru_logger.remove()
108
136
 
109
137
  # Console handler
@@ -0,0 +1,177 @@
1
+ """
2
+ Enterprise Validation Module - Enhanced Logging and Validation
3
+
4
+ This module provides enterprise-grade logging and validation capabilities
5
+ for the CloudOps Runbooks framework.
6
+
7
+ Features:
8
+ - Enhanced structured logging with performance monitoring
9
+ - Cross-module validation utilities
10
+ - Rich CLI integration with enterprise UX standards
11
+ - Enterprise compliance validation
12
+ """
13
+
14
+ import logging
15
+ from typing import Any, Dict, List, Optional
16
+ from rich.console import Console
17
+ from rich.logging import RichHandler
18
+
19
+ # Rich console for enterprise logging
20
+ console = Console()
21
+
22
+ class EnhancedLogging:
23
+ """Enhanced logging capabilities for enterprise operations."""
24
+
25
+ def __init__(self, module_name: str = "runbooks"):
26
+ self.module_name = module_name
27
+ self.logger = self._setup_enhanced_logger()
28
+
29
+ def _setup_enhanced_logger(self) -> logging.Logger:
30
+ """Setup enhanced logger with Rich integration."""
31
+ logger = logging.getLogger(f"runbooks.{self.module_name}")
32
+
33
+ # Skip if already configured
34
+ if logger.handlers:
35
+ return logger
36
+
37
+ logger.setLevel(logging.INFO)
38
+
39
+ # Rich handler for beautiful console output
40
+ rich_handler = RichHandler(
41
+ console=console,
42
+ show_time=True,
43
+ show_path=True,
44
+ rich_tracebacks=True
45
+ )
46
+
47
+ formatter = logging.Formatter(
48
+ fmt="[%(name)s] %(message)s",
49
+ datefmt="[%X]"
50
+ )
51
+ rich_handler.setFormatter(formatter)
52
+
53
+ logger.addHandler(rich_handler)
54
+ logger.propagate = False
55
+
56
+ return logger
57
+
58
+ def info(self, message: str, **kwargs) -> None:
59
+ """Log info message with Rich formatting."""
60
+ self.logger.info(message, **kwargs)
61
+
62
+ def warning(self, message: str, **kwargs) -> None:
63
+ """Log warning message with Rich formatting."""
64
+ self.logger.warning(message, **kwargs)
65
+
66
+ def error(self, message: str, **kwargs) -> None:
67
+ """Log error message with Rich formatting."""
68
+ self.logger.error(message, **kwargs)
69
+
70
+ def debug(self, message: str, **kwargs) -> None:
71
+ """Log debug message with Rich formatting."""
72
+ self.logger.debug(message, **kwargs)
73
+
74
+
75
+ class ConfigValidator:
76
+ """Configuration validation utilities."""
77
+
78
+ @staticmethod
79
+ def validate_aws_profile(profile: str) -> bool:
80
+ """Validate AWS profile configuration."""
81
+ if not profile or not isinstance(profile, str):
82
+ return False
83
+ return len(profile.strip()) > 0
84
+
85
+ @staticmethod
86
+ def validate_region(region: str) -> bool:
87
+ """Validate AWS region format."""
88
+ if not region or not isinstance(region, str):
89
+ return False
90
+ # Basic AWS region format validation
91
+ return len(region.split('-')) >= 3
92
+
93
+
94
+ class InputValidator:
95
+ """Input validation utilities."""
96
+
97
+ @staticmethod
98
+ def validate_account_id(account_id: str) -> bool:
99
+ """Validate AWS account ID format."""
100
+ if not account_id or not isinstance(account_id, str):
101
+ return False
102
+ return account_id.isdigit() and len(account_id) == 12
103
+
104
+ @staticmethod
105
+ def validate_instance_id(instance_id: str) -> bool:
106
+ """Validate EC2 instance ID format."""
107
+ if not instance_id or not isinstance(instance_id, str):
108
+ return False
109
+ return instance_id.startswith('i-') and len(instance_id) >= 10
110
+
111
+
112
+ class TypeValidator:
113
+ """Type validation utilities."""
114
+
115
+ @staticmethod
116
+ def validate_list_of_strings(value: Any) -> bool:
117
+ """Validate that value is a list of strings."""
118
+ if not isinstance(value, list):
119
+ return False
120
+ return all(isinstance(item, str) for item in value)
121
+
122
+ @staticmethod
123
+ def validate_dict(value: Any, required_keys: Optional[List[str]] = None) -> bool:
124
+ """Validate dictionary structure."""
125
+ if not isinstance(value, dict):
126
+ return False
127
+
128
+ if required_keys:
129
+ return all(key in value for key in required_keys)
130
+
131
+ return True
132
+
133
+
134
+ def validate_configuration(config: Dict[str, Any]) -> Dict[str, Any]:
135
+ """Validate configuration dictionary."""
136
+ validator = ConfigValidator()
137
+ errors = []
138
+
139
+ # Validate profile if present
140
+ if 'profile' in config:
141
+ if not validator.validate_aws_profile(config['profile']):
142
+ errors.append("Invalid AWS profile configuration")
143
+
144
+ # Validate region if present
145
+ if 'region' in config:
146
+ if not validator.validate_region(config['region']):
147
+ errors.append("Invalid AWS region format")
148
+
149
+ return {
150
+ 'valid': len(errors) == 0,
151
+ 'errors': errors
152
+ }
153
+
154
+
155
+ def validate_user_input(user_input: Dict[str, Any]) -> Dict[str, Any]:
156
+ """Validate user input data."""
157
+ validator = InputValidator()
158
+ errors = []
159
+
160
+ # Validate account ID if present
161
+ if 'account_id' in user_input:
162
+ if not validator.validate_account_id(user_input['account_id']):
163
+ errors.append("Invalid AWS account ID format")
164
+
165
+ # Validate instance ID if present
166
+ if 'instance_id' in user_input:
167
+ if not validator.validate_instance_id(user_input['instance_id']):
168
+ errors.append("Invalid EC2 instance ID format")
169
+
170
+ return {
171
+ 'valid': len(errors) == 0,
172
+ 'errors': errors
173
+ }
174
+
175
+
176
+ # Create default enhanced logger
177
+ enhanced_logger = EnhancedLogging("enterprise")