aws-inventory-manager 0.2.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.

Potentially problematic release.


This version of aws-inventory-manager might be problematic. Click here for more details.

Files changed (65) hide show
  1. aws_inventory_manager-0.2.0.dist-info/METADATA +508 -0
  2. aws_inventory_manager-0.2.0.dist-info/RECORD +65 -0
  3. aws_inventory_manager-0.2.0.dist-info/WHEEL +5 -0
  4. aws_inventory_manager-0.2.0.dist-info/entry_points.txt +2 -0
  5. aws_inventory_manager-0.2.0.dist-info/licenses/LICENSE +21 -0
  6. aws_inventory_manager-0.2.0.dist-info/top_level.txt +1 -0
  7. src/__init__.py +3 -0
  8. src/aws/__init__.py +11 -0
  9. src/aws/client.py +128 -0
  10. src/aws/credentials.py +191 -0
  11. src/aws/rate_limiter.py +177 -0
  12. src/cli/__init__.py +5 -0
  13. src/cli/config.py +130 -0
  14. src/cli/main.py +1450 -0
  15. src/cost/__init__.py +5 -0
  16. src/cost/analyzer.py +226 -0
  17. src/cost/explorer.py +209 -0
  18. src/cost/reporter.py +237 -0
  19. src/delta/__init__.py +5 -0
  20. src/delta/calculator.py +180 -0
  21. src/delta/reporter.py +225 -0
  22. src/models/__init__.py +17 -0
  23. src/models/cost_report.py +87 -0
  24. src/models/delta_report.py +111 -0
  25. src/models/inventory.py +124 -0
  26. src/models/resource.py +99 -0
  27. src/models/snapshot.py +108 -0
  28. src/snapshot/__init__.py +6 -0
  29. src/snapshot/capturer.py +347 -0
  30. src/snapshot/filter.py +245 -0
  31. src/snapshot/inventory_storage.py +264 -0
  32. src/snapshot/resource_collectors/__init__.py +5 -0
  33. src/snapshot/resource_collectors/apigateway.py +140 -0
  34. src/snapshot/resource_collectors/backup.py +136 -0
  35. src/snapshot/resource_collectors/base.py +81 -0
  36. src/snapshot/resource_collectors/cloudformation.py +55 -0
  37. src/snapshot/resource_collectors/cloudwatch.py +109 -0
  38. src/snapshot/resource_collectors/codebuild.py +69 -0
  39. src/snapshot/resource_collectors/codepipeline.py +82 -0
  40. src/snapshot/resource_collectors/dynamodb.py +65 -0
  41. src/snapshot/resource_collectors/ec2.py +240 -0
  42. src/snapshot/resource_collectors/ecs.py +215 -0
  43. src/snapshot/resource_collectors/eks.py +200 -0
  44. src/snapshot/resource_collectors/elb.py +126 -0
  45. src/snapshot/resource_collectors/eventbridge.py +156 -0
  46. src/snapshot/resource_collectors/iam.py +188 -0
  47. src/snapshot/resource_collectors/kms.py +111 -0
  48. src/snapshot/resource_collectors/lambda_func.py +112 -0
  49. src/snapshot/resource_collectors/rds.py +109 -0
  50. src/snapshot/resource_collectors/route53.py +86 -0
  51. src/snapshot/resource_collectors/s3.py +105 -0
  52. src/snapshot/resource_collectors/secretsmanager.py +70 -0
  53. src/snapshot/resource_collectors/sns.py +68 -0
  54. src/snapshot/resource_collectors/sqs.py +72 -0
  55. src/snapshot/resource_collectors/ssm.py +160 -0
  56. src/snapshot/resource_collectors/stepfunctions.py +74 -0
  57. src/snapshot/resource_collectors/vpcendpoints.py +79 -0
  58. src/snapshot/resource_collectors/waf.py +159 -0
  59. src/snapshot/storage.py +259 -0
  60. src/utils/__init__.py +12 -0
  61. src/utils/export.py +87 -0
  62. src/utils/hash.py +60 -0
  63. src/utils/logging.py +63 -0
  64. src/utils/paths.py +51 -0
  65. src/utils/progress.py +41 -0
src/utils/hash.py ADDED
@@ -0,0 +1,60 @@
1
+ """Configuration hashing utility for change detection."""
2
+
3
+ import hashlib
4
+ import json
5
+ from typing import Any, Dict, Set
6
+
7
+ # Attributes to exclude from hashing (volatile data)
8
+ EXCLUDE_ATTRIBUTES: Set[str] = {
9
+ "ResponseMetadata",
10
+ "LastModifiedDate",
11
+ "CreatedDate",
12
+ "CreateDate",
13
+ "State",
14
+ "Status",
15
+ "RequestId",
16
+ "VersionId",
17
+ "LastUpdateTime",
18
+ "LastUpdatedTime",
19
+ "ModifiedTime",
20
+ }
21
+
22
+
23
+ def compute_config_hash(resource_data: Dict[str, Any]) -> str:
24
+ """Compute stable SHA256 hash of resource configuration.
25
+
26
+ This hash is used for change detection. Volatile attributes
27
+ (timestamps, states, etc.) are excluded to prevent false positives.
28
+
29
+ Args:
30
+ resource_data: Resource configuration dictionary
31
+
32
+ Returns:
33
+ 64-character SHA256 hex string
34
+ """
35
+ # Deep copy and remove excluded attributes
36
+ clean_data = _remove_volatile_attributes(resource_data, EXCLUDE_ATTRIBUTES)
37
+
38
+ # Normalize: sort keys for deterministic JSON
39
+ normalized = json.dumps(clean_data, sort_keys=True, default=str)
40
+
41
+ # Hash
42
+ return hashlib.sha256(normalized.encode()).hexdigest()
43
+
44
+
45
+ def _remove_volatile_attributes(data: Any, exclude_set: Set[str]) -> Any:
46
+ """Recursively remove excluded attributes from nested dict/list.
47
+
48
+ Args:
49
+ data: Data structure to clean (dict, list, or primitive)
50
+ exclude_set: Set of attribute names to exclude
51
+
52
+ Returns:
53
+ Cleaned data structure
54
+ """
55
+ if isinstance(data, dict):
56
+ return {k: _remove_volatile_attributes(v, exclude_set) for k, v in data.items() if k not in exclude_set}
57
+ elif isinstance(data, list):
58
+ return [_remove_volatile_attributes(item, exclude_set) for item in data]
59
+ else:
60
+ return data
src/utils/logging.py ADDED
@@ -0,0 +1,63 @@
1
+ """Logging configuration for AWS Baseline Snapshot tool."""
2
+
3
+ import logging
4
+ import sys
5
+ from typing import Optional
6
+
7
+
8
+ def setup_logging(level: str = "INFO", log_file: Optional[str] = None, verbose: bool = False) -> None:
9
+ """Configure logging for the application.
10
+
11
+ Args:
12
+ level: Log level (DEBUG, INFO, WARN, ERROR)
13
+ log_file: Optional log file path
14
+ verbose: If True, show detailed logs; if False, suppress all but critical
15
+ """
16
+ # Convert string level to logging constant
17
+ numeric_level = getattr(logging, level.upper(), logging.INFO)
18
+
19
+ # In non-verbose mode, suppress all logs except CRITICAL
20
+ # User will only see styled Rich console output
21
+ if not verbose:
22
+ numeric_level = logging.CRITICAL
23
+
24
+ # Create formatter
25
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
26
+
27
+ # Configure root logger
28
+ root_logger = logging.getLogger()
29
+ root_logger.setLevel(numeric_level)
30
+
31
+ # Remove existing handlers
32
+ for handler in root_logger.handlers[:]:
33
+ root_logger.removeHandler(handler)
34
+
35
+ # Console handler (only add if verbose or log_file specified)
36
+ if verbose or log_file:
37
+ console_handler = logging.StreamHandler(sys.stderr)
38
+ console_handler.setLevel(numeric_level)
39
+ console_handler.setFormatter(formatter)
40
+ root_logger.addHandler(console_handler)
41
+
42
+ # File handler (if specified)
43
+ if log_file:
44
+ file_handler = logging.FileHandler(log_file)
45
+ file_handler.setLevel(logging.DEBUG) # Always log everything to file
46
+ file_handler.setFormatter(formatter)
47
+ root_logger.addHandler(file_handler)
48
+
49
+ # Suppress noisy third-party loggers
50
+ logging.getLogger("boto3").setLevel(logging.CRITICAL)
51
+ logging.getLogger("botocore").setLevel(logging.CRITICAL)
52
+ logging.getLogger("urllib3").setLevel(logging.CRITICAL)
53
+ logging.getLogger("s3transfer").setLevel(logging.CRITICAL)
54
+
55
+ # Suppress internal module logs unless verbose
56
+ if not verbose:
57
+ logging.getLogger("src").setLevel(logging.CRITICAL)
58
+ logging.getLogger("src.snapshot").setLevel(logging.CRITICAL)
59
+ logging.getLogger("src.snapshot.resource_collectors").setLevel(logging.CRITICAL)
60
+ logging.getLogger("src.snapshot.capturer").setLevel(logging.CRITICAL)
61
+ logging.getLogger("src.snapshot.storage").setLevel(logging.CRITICAL)
62
+ logging.getLogger("src.aws").setLevel(logging.CRITICAL)
63
+ logging.getLogger("src.aws.credentials").setLevel(logging.CRITICAL)
src/utils/paths.py ADDED
@@ -0,0 +1,51 @@
1
+ """Path resolution utilities for snapshot storage."""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Optional, Union
6
+
7
+
8
+ def get_snapshot_storage_path(custom_path: Optional[Union[str, Path]] = None) -> Path:
9
+ """Resolve snapshot storage path with precedence: parameter > env var > default.
10
+
11
+ Precedence order:
12
+ 1. custom_path parameter (if provided)
13
+ 2. AWS_INVENTORY_STORAGE_PATH environment variable (if set)
14
+ 3. ~/.snapshots (default)
15
+
16
+ Args:
17
+ custom_path: Optional custom path override
18
+
19
+ Returns:
20
+ Resolved Path object for snapshot storage
21
+
22
+ Examples:
23
+ # Use default
24
+ >>> get_snapshot_storage_path()
25
+ Path.home() / '.snapshots'
26
+
27
+ # Use environment variable
28
+ >>> os.environ['AWS_INVENTORY_STORAGE_PATH'] = '/data/snapshots'
29
+ >>> get_snapshot_storage_path()
30
+ Path('/data/snapshots')
31
+
32
+ # Use parameter (highest priority)
33
+ >>> get_snapshot_storage_path('/custom/path')
34
+ Path('/custom/path')
35
+ """
36
+ # Priority 1: Custom path parameter (but not empty string)
37
+ if custom_path:
38
+ # Handle both str and Path types
39
+ if isinstance(custom_path, str):
40
+ if custom_path.strip():
41
+ return Path(custom_path).expanduser().resolve()
42
+ else: # Path object
43
+ return custom_path.expanduser().resolve()
44
+
45
+ # Priority 2: Environment variable
46
+ env_path = os.getenv("AWS_INVENTORY_STORAGE_PATH")
47
+ if env_path:
48
+ return Path(env_path).expanduser().resolve()
49
+
50
+ # Priority 3: Default to ~/.snapshots
51
+ return Path.home() / ".snapshots"
src/utils/progress.py ADDED
@@ -0,0 +1,41 @@
1
+ """Progress indicator utilities using Rich library."""
2
+
3
+ from contextlib import contextmanager
4
+
5
+ from rich.progress import (
6
+ BarColumn,
7
+ Progress,
8
+ SpinnerColumn,
9
+ TaskProgressColumn,
10
+ TextColumn,
11
+ TimeRemainingColumn,
12
+ )
13
+
14
+
15
+ @contextmanager
16
+ def create_progress():
17
+ """Create a Rich progress context for tracking operations.
18
+
19
+ Yields:
20
+ Progress instance configured for multi-task tracking
21
+ """
22
+ with Progress(
23
+ SpinnerColumn(),
24
+ TextColumn("[progress.description]{task.description}"),
25
+ BarColumn(),
26
+ TaskProgressColumn(),
27
+ TimeRemainingColumn(),
28
+ ) as progress:
29
+ yield progress
30
+
31
+
32
+ def create_spinner_progress():
33
+ """Create a simple spinner progress for indeterminate operations.
34
+
35
+ Returns:
36
+ Progress instance with spinner
37
+ """
38
+ return Progress(
39
+ SpinnerColumn(),
40
+ TextColumn("[progress.description]{task.description}"),
41
+ )