runbooks 0.7.0__py3-none-any.whl → 0.7.6__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 (132) hide show
  1. runbooks/__init__.py +87 -37
  2. runbooks/cfat/README.md +300 -49
  3. runbooks/cfat/__init__.py +2 -2
  4. runbooks/finops/__init__.py +1 -1
  5. runbooks/finops/cli.py +1 -1
  6. runbooks/inventory/collectors/__init__.py +8 -0
  7. runbooks/inventory/collectors/aws_management.py +791 -0
  8. runbooks/inventory/collectors/aws_networking.py +3 -3
  9. runbooks/main.py +3389 -782
  10. runbooks/operate/__init__.py +207 -0
  11. runbooks/operate/base.py +311 -0
  12. runbooks/operate/cloudformation_operations.py +619 -0
  13. runbooks/operate/cloudwatch_operations.py +496 -0
  14. runbooks/operate/dynamodb_operations.py +812 -0
  15. runbooks/operate/ec2_operations.py +926 -0
  16. runbooks/operate/iam_operations.py +569 -0
  17. runbooks/operate/s3_operations.py +1211 -0
  18. runbooks/operate/tagging_operations.py +655 -0
  19. runbooks/remediation/CLAUDE.md +100 -0
  20. runbooks/remediation/DOME9.md +218 -0
  21. runbooks/remediation/README.md +26 -0
  22. runbooks/remediation/Tests/__init__.py +0 -0
  23. runbooks/remediation/Tests/update_policy.py +74 -0
  24. runbooks/remediation/__init__.py +95 -0
  25. runbooks/remediation/acm_cert_expired_unused.py +98 -0
  26. runbooks/remediation/acm_remediation.py +875 -0
  27. runbooks/remediation/api_gateway_list.py +167 -0
  28. runbooks/remediation/base.py +643 -0
  29. runbooks/remediation/cloudtrail_remediation.py +908 -0
  30. runbooks/remediation/cloudtrail_s3_modifications.py +296 -0
  31. runbooks/remediation/cognito_active_users.py +78 -0
  32. runbooks/remediation/cognito_remediation.py +856 -0
  33. runbooks/remediation/cognito_user_password_reset.py +163 -0
  34. runbooks/remediation/commons.py +455 -0
  35. runbooks/remediation/dynamodb_optimize.py +155 -0
  36. runbooks/remediation/dynamodb_remediation.py +744 -0
  37. runbooks/remediation/dynamodb_server_side_encryption.py +108 -0
  38. runbooks/remediation/ec2_public_ips.py +134 -0
  39. runbooks/remediation/ec2_remediation.py +892 -0
  40. runbooks/remediation/ec2_subnet_disable_auto_ip_assignment.py +72 -0
  41. runbooks/remediation/ec2_unattached_ebs_volumes.py +448 -0
  42. runbooks/remediation/ec2_unused_security_groups.py +202 -0
  43. runbooks/remediation/kms_enable_key_rotation.py +651 -0
  44. runbooks/remediation/kms_remediation.py +717 -0
  45. runbooks/remediation/lambda_list.py +243 -0
  46. runbooks/remediation/lambda_remediation.py +971 -0
  47. runbooks/remediation/multi_account.py +569 -0
  48. runbooks/remediation/rds_instance_list.py +199 -0
  49. runbooks/remediation/rds_remediation.py +873 -0
  50. runbooks/remediation/rds_snapshot_list.py +192 -0
  51. runbooks/remediation/requirements.txt +118 -0
  52. runbooks/remediation/s3_block_public_access.py +159 -0
  53. runbooks/remediation/s3_bucket_public_access.py +143 -0
  54. runbooks/remediation/s3_disable_static_website_hosting.py +74 -0
  55. runbooks/remediation/s3_downloader.py +215 -0
  56. runbooks/remediation/s3_enable_access_logging.py +562 -0
  57. runbooks/remediation/s3_encryption.py +526 -0
  58. runbooks/remediation/s3_force_ssl_secure_policy.py +143 -0
  59. runbooks/remediation/s3_list.py +141 -0
  60. runbooks/remediation/s3_object_search.py +201 -0
  61. runbooks/remediation/s3_remediation.py +816 -0
  62. runbooks/remediation/scan_for_phrase.py +425 -0
  63. runbooks/remediation/workspaces_list.py +220 -0
  64. runbooks/security/__init__.py +9 -10
  65. runbooks/security/security_baseline_tester.py +4 -2
  66. runbooks-0.7.6.dist-info/METADATA +608 -0
  67. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/RECORD +84 -76
  68. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/entry_points.txt +0 -1
  69. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/top_level.txt +0 -1
  70. jupyter-agent/.env +0 -2
  71. jupyter-agent/.env.template +0 -2
  72. jupyter-agent/.gitattributes +0 -35
  73. jupyter-agent/.gradio/certificate.pem +0 -31
  74. jupyter-agent/README.md +0 -16
  75. jupyter-agent/__main__.log +0 -8
  76. jupyter-agent/app.py +0 -256
  77. jupyter-agent/cloudops-agent.png +0 -0
  78. jupyter-agent/ds-system-prompt.txt +0 -154
  79. jupyter-agent/jupyter-agent.png +0 -0
  80. jupyter-agent/llama3_template.jinja +0 -123
  81. jupyter-agent/requirements.txt +0 -9
  82. jupyter-agent/tmp/4ojbs8a02ir/jupyter-agent.ipynb +0 -68
  83. jupyter-agent/tmp/cm5iasgpm3p/jupyter-agent.ipynb +0 -91
  84. jupyter-agent/tmp/crqbsseag5/jupyter-agent.ipynb +0 -91
  85. jupyter-agent/tmp/hohanq1u097/jupyter-agent.ipynb +0 -57
  86. jupyter-agent/tmp/jns1sam29wm/jupyter-agent.ipynb +0 -53
  87. jupyter-agent/tmp/jupyter-agent.ipynb +0 -27
  88. jupyter-agent/utils.py +0 -409
  89. runbooks/aws/__init__.py +0 -58
  90. runbooks/aws/dynamodb_operations.py +0 -231
  91. runbooks/aws/ec2_copy_image_cross-region.py +0 -195
  92. runbooks/aws/ec2_describe_instances.py +0 -202
  93. runbooks/aws/ec2_ebs_snapshots_delete.py +0 -186
  94. runbooks/aws/ec2_run_instances.py +0 -213
  95. runbooks/aws/ec2_start_stop_instances.py +0 -212
  96. runbooks/aws/ec2_terminate_instances.py +0 -143
  97. runbooks/aws/ec2_unused_eips.py +0 -196
  98. runbooks/aws/ec2_unused_volumes.py +0 -188
  99. runbooks/aws/s3_create_bucket.py +0 -142
  100. runbooks/aws/s3_list_buckets.py +0 -152
  101. runbooks/aws/s3_list_objects.py +0 -156
  102. runbooks/aws/s3_object_operations.py +0 -183
  103. runbooks/aws/tagging_lambda_handler.py +0 -183
  104. runbooks/inventory/FAILED_SCRIPTS_TROUBLESHOOTING.md +0 -619
  105. runbooks/inventory/PASSED_SCRIPTS_GUIDE.md +0 -738
  106. runbooks/inventory/aws_organization.png +0 -0
  107. runbooks/inventory/cfn_move_stack_instances.py +0 -1526
  108. runbooks/inventory/delete_s3_buckets_objects.py +0 -169
  109. runbooks/inventory/lockdown_cfn_stackset_role.py +0 -224
  110. runbooks/inventory/update_aws_actions.py +0 -173
  111. runbooks/inventory/update_cfn_stacksets.py +0 -1215
  112. runbooks/inventory/update_cloudwatch_logs_retention_policy.py +0 -294
  113. runbooks/inventory/update_iam_roles_cross_accounts.py +0 -478
  114. runbooks/inventory/update_s3_public_access_block.py +0 -539
  115. runbooks/organizations/__init__.py +0 -12
  116. runbooks/organizations/manager.py +0 -374
  117. runbooks-0.7.0.dist-info/METADATA +0 -375
  118. /runbooks/inventory/{tests → Tests}/common_test_data.py +0 -0
  119. /runbooks/inventory/{tests → Tests}/common_test_functions.py +0 -0
  120. /runbooks/inventory/{tests → Tests}/script_test_data.py +0 -0
  121. /runbooks/inventory/{tests → Tests}/setup.py +0 -0
  122. /runbooks/inventory/{tests → Tests}/src.py +0 -0
  123. /runbooks/inventory/{tests/test_inventory_modules.py → Tests/test_Inventory_Modules.py} +0 -0
  124. /runbooks/inventory/{tests → Tests}/test_cfn_describe_stacks.py +0 -0
  125. /runbooks/inventory/{tests → Tests}/test_ec2_describe_instances.py +0 -0
  126. /runbooks/inventory/{tests → Tests}/test_lambda_list_functions.py +0 -0
  127. /runbooks/inventory/{tests → Tests}/test_moto_integration_example.py +0 -0
  128. /runbooks/inventory/{tests → Tests}/test_org_list_accounts.py +0 -0
  129. /runbooks/inventory/{Inventory_Modules.py → inventory_modules.py} +0 -0
  130. /runbooks/{aws → operate}/tags.json +0 -0
  131. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/WHEEL +0 -0
  132. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,155 @@
1
+ """
2
+ DynamoDB Cost Optimization - Analyze and optimize table settings for cost savings.
3
+ """
4
+
5
+ import logging
6
+ from datetime import datetime, timedelta
7
+ from functools import lru_cache
8
+
9
+ import click
10
+ from botocore.exceptions import ClientError
11
+
12
+ from .commons import display_aws_account_info, get_client, list_tables, write_to_csv
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @lru_cache(maxsize=32)
18
+ def get_table_details(table_name):
19
+ """Get DynamoDB table details with error handling."""
20
+ try:
21
+ dynamodb = get_client("dynamodb")
22
+ return dynamodb.describe_table(TableName=table_name)["Table"]
23
+ except ClientError as e:
24
+ logger.error(f"Failed to get table details for {table_name}: {e}")
25
+ raise
26
+
27
+
28
+ def update_table_billing_mode(table_name, billing_mode):
29
+ """Update DynamoDB table billing mode."""
30
+ try:
31
+ dynamodb = get_client("dynamodb")
32
+ dynamodb.update_table(TableName=table_name, BillingMode=billing_mode)
33
+ logger.info(f"Updated {table_name} to {billing_mode} billing mode")
34
+ except ClientError as e:
35
+ logger.error(f"Failed to update {table_name} billing mode: {e}")
36
+ raise
37
+
38
+
39
+ @lru_cache(maxsize=32)
40
+ def analyze_table(table_name):
41
+ """Analyze table usage patterns and suggest cost optimizations."""
42
+ try:
43
+ table_details = get_table_details(table_name)
44
+
45
+ # Get basic table info
46
+ billing_mode_summary = table_details.get("BillingModeSummary", {})
47
+ billing_mode = billing_mode_summary.get("BillingMode", "PROVISIONED")
48
+ table_size_bytes = table_details.get("TableSizeBytes", 0)
49
+ table_item_count = table_details.get("ItemCount", 0)
50
+
51
+ # Get CloudWatch metrics for last 7 days
52
+ end_time = datetime.utcnow()
53
+ start_time = end_time - timedelta(days=7)
54
+
55
+ try:
56
+ cloudwatch = get_client("cloudwatch")
57
+ metrics = cloudwatch.get_metric_statistics(
58
+ Namespace="AWS/DynamoDB",
59
+ MetricName="ConsumedReadCapacityUnits",
60
+ Dimensions=[{"Name": "TableName", "Value": table_name}],
61
+ StartTime=start_time,
62
+ EndTime=end_time,
63
+ Period=86400, # Daily resolution
64
+ Statistics=["Average"],
65
+ )
66
+
67
+ # Calculate average RCU usage
68
+ datapoints = metrics.get("Datapoints", [])
69
+ average_rcu = sum(dp["Average"] for dp in datapoints) / len(datapoints) if datapoints else 0
70
+
71
+ except ClientError as e:
72
+ logger.warning(f"Could not get CloudWatch metrics for {table_name}: {e}")
73
+ average_rcu = 0
74
+
75
+ # Get provisioned capacity if applicable
76
+ provisioned_rcu = None
77
+ if billing_mode == "PROVISIONED" and "ProvisionedThroughput" in table_details:
78
+ provisioned_rcu = table_details["ProvisionedThroughput"].get("ReadCapacityUnits", 0)
79
+
80
+ # Build analysis result
81
+ analysis = {
82
+ "Table": table_name,
83
+ "Billing Mode": billing_mode,
84
+ "Table Size": f"{table_size_bytes / (1024**3):.2f} GB" if table_size_bytes else "0 GB",
85
+ "Item Count": table_item_count,
86
+ "Average RCU": round(average_rcu, 2),
87
+ "Provisioned RCU": provisioned_rcu,
88
+ "Recommendations": [],
89
+ }
90
+
91
+ # Generate recommendations
92
+ if billing_mode == "PROVISIONED" and provisioned_rcu and average_rcu < 0.9 * provisioned_rcu:
93
+ analysis["Recommendations"].append("Consider lowering provisioned RCU to match actual usage")
94
+
95
+ if average_rcu > 1000:
96
+ analysis["Recommendations"].append("Consider enabling DynamoDB Accelerator (DAX) for high read workloads")
97
+
98
+ # Storage optimization for large, infrequently accessed tables
99
+ if table_size_bytes > 10 * (1024**3) and table_item_count > 0 and average_rcu / table_item_count < 0.1:
100
+ table_class = table_details.get("TableClassSummary", {}).get("TableClass", "STANDARD")
101
+ if table_class != "STANDARD_INFREQUENT_ACCESS":
102
+ analysis["Recommendations"].append("Consider STANDARD_INFREQUENT_ACCESS for storage cost savings")
103
+
104
+ return analysis
105
+
106
+ except Exception as e:
107
+ logger.error(f"Failed to analyze table {table_name}: {e}")
108
+ return {
109
+ "Table": table_name,
110
+ "Error": str(e),
111
+ "Recommendations": ["Unable to analyze - check table permissions"],
112
+ }
113
+
114
+
115
+ @click.command()
116
+ @click.option("--apply", "-a", is_flag=True, help="Apply suggested optimizations")
117
+ @click.option("--output", "-o", default="/tmp/dynamodb_analysis.csv", help="Output CSV file path")
118
+ def dynamodb_analyze(apply=False, output="/tmp/dynamodb_analysis.csv"):
119
+ """Analyze DynamoDB tables and suggest cost optimizations."""
120
+ logger.info(f"Analyzing DynamoDB tables in {display_aws_account_info()}")
121
+
122
+ try:
123
+ table_names = list_tables()
124
+ if not table_names:
125
+ logger.info("No DynamoDB tables found")
126
+ return
127
+
128
+ logger.info(f"Found {len(table_names)} tables to analyze")
129
+
130
+ # Analyze each table
131
+ results = []
132
+ for table_name in table_names:
133
+ logger.info(f"Analyzing table: {table_name}")
134
+ result = analyze_table(table_name)
135
+ results.append(result)
136
+
137
+ # Log recommendations
138
+ if result.get("Recommendations"):
139
+ for rec in result["Recommendations"]:
140
+ logger.info(f" Recommendation: {rec}")
141
+ else:
142
+ logger.info(" No optimization recommendations")
143
+
144
+ # Save results to CSV
145
+ write_to_csv(results, output)
146
+ logger.info(f"Analysis results saved to: {output}")
147
+
148
+ # Apply optimizations if requested
149
+ if apply:
150
+ logger.info("Apply functionality not yet implemented")
151
+ # TODO: Implement safe optimization application
152
+
153
+ except Exception as e:
154
+ logger.error(f"Failed to analyze DynamoDB tables: {e}")
155
+ raise