|
| 1 | +--- |
| 2 | +name: optimize-dynamodb |
| 3 | +description: "Analyze DynamoDB tables for cost optimization opportunities. Triggers on: optimize DynamoDB, DynamoDB cost analysis, reduce DynamoDB costs, DynamoDB capacity mode, on-demand vs provisioned, table class analysis, unused GSI, DynamoDB utilization, right-size DynamoDB." |
| 4 | +license: Apache-2.0 |
| 5 | +metadata: |
| 6 | + tags: aws, dynamodb, cost-optimization, capacity, provisioned, on-demand, table-class, utilization, gsi |
| 7 | + dependencies: python>=3.9, boto3 |
| 8 | +--- |
| 9 | + |
| 10 | +# DynamoDB Cost Optimizer |
| 11 | + |
| 12 | +Scripts are fully self-contained — they fetch pricing, metrics, and costs from AWS |
| 13 | +via boto3 and return only a small summary. Execute them, do NOT reimplement the logic. |
| 14 | + |
| 15 | +## Prerequisites |
| 16 | + |
| 17 | +Before running any scripts, detect the Python command: |
| 18 | + |
| 19 | +1. Run `python --version`. If it returns Python 3.9+, use `python` for all scripts. |
| 20 | +2. If not, try `python3 --version`. If 3.9+, use `python3` for all scripts. |
| 21 | +3. If neither works, tell the user to install Python 3. |
| 22 | +4. Run `<python> -c "import boto3"`. If it fails, tell the user: `pip install boto3`. |
| 23 | +5. AWS credentials configured with: `dynamodb:DescribeTable`, `dynamodb:ListTables`, |
| 24 | + `dynamodb:DescribeContinuousBackups`, `cloudwatch:GetMetricData`, `pricing:GetProducts`, |
| 25 | + `ce:GetCostAndUsage` |
| 26 | + |
| 27 | +## Workflow |
| 28 | + |
| 29 | +### Step 1: Region |
| 30 | + |
| 31 | +Ask user for AWS region(s). Default: `us-east-1`. Supports multiple regions. |
| 32 | + |
| 33 | +### Step 2: Run Analysis |
| 34 | + |
| 35 | +Use the batch script to analyze tables. It auto-discovers all tables when `tables` is omitted. |
| 36 | +Pricing is fetched automatically per region — no need to pass it. |
| 37 | + |
| 38 | +Script: `scripts/analyze_all.py` |
| 39 | + |
| 40 | +IMPORTANT: Run the script from the user's current working directory using the absolute path |
| 41 | +to the script. This ensures the report is saved locally. |
| 42 | + |
| 43 | +Example: |
| 44 | +`python3 /path/to/skill/scripts/analyze_all.py '{"region":"REGION","days":14}'` |
| 45 | + |
| 46 | +All tables in a region: |
| 47 | +`{"region":"REGION","days":14}` |
| 48 | + |
| 49 | +Specific tables: |
| 50 | +`{"region":"REGION","tables":["table1","table2"],"days":14}` |
| 51 | + |
| 52 | +Multi-region: |
| 53 | +`{"regions":{"us-east-1":["t1","t2"],"eu-west-1":["t3"]},"days":14}` |
| 54 | + |
| 55 | +This runs all four analyzers (capacity mode, table class, utilization, unused GSIs) |
| 56 | +with parallel execution (10 concurrent by default). One command, one approval. |
| 57 | + |
| 58 | +Individual scripts are also available if the user only wants one type of analysis. |
| 59 | +These require a `prices` object — use `scripts/get_pricing.py REGION` to fetch it first: |
| 60 | + |
| 61 | +- `scripts/capacity_mode.py` — Input: `{"region":"REGION","tableName":"TABLE","days":14,"prices":PRICING}` |
| 62 | +- `scripts/table_class.py` — Input: `{"region":"REGION","tableName":"TABLE","days":14,"prices":PRICING}` |
| 63 | +- `scripts/utilization.py` — Input: `{"region":"REGION","tableName":"TABLE","days":14,"prices":PRICING}` |
| 64 | +- `scripts/unused_gsi.py` — Input: `{"region":"REGION","tableName":"TABLE","days":14}` |
| 65 | + |
| 66 | +### Step 3: Present Results |
| 67 | + |
| 68 | +The script outputs a summary line and saves the full report to `dynamodb-cost-report.md` |
| 69 | +in the user's current working directory. |
| 70 | + |
| 71 | +DO NOT read or summarize the report file. Simply display the script's output, which |
| 72 | +includes the summary and file path. The user can open the file themselves if needed. |
| 73 | + |
| 74 | +After displaying the output, ask if the user wants CLI commands for any recommendations. |
| 75 | + |
| 76 | +### Step 4: Generate Actions |
| 77 | + |
| 78 | +For accepted recommendations: |
| 79 | + |
| 80 | +```bash |
| 81 | +# Switch to on-demand |
| 82 | +aws dynamodb update-table --table-name TABLE --billing-mode PAY_PER_REQUEST |
| 83 | + |
| 84 | +# Switch to provisioned |
| 85 | +aws dynamodb update-table --table-name TABLE --billing-mode PROVISIONED \ |
| 86 | + --provisioned-throughput ReadCapacityUnits=RCU,WriteCapacityUnits=WCU |
| 87 | + |
| 88 | +# Change table class |
| 89 | +aws dynamodb update-table --table-name TABLE --table-class STANDARD_INFREQUENT_ACCESS |
| 90 | + |
| 91 | +# Delete unused GSI |
| 92 | +aws dynamodb update-table --table-name TABLE \ |
| 93 | + --global-secondary-index-updates '[{"Delete":{"IndexName":"GSI_NAME"}}]' |
| 94 | +``` |
| 95 | + |
| 96 | +DO NOT execute update commands without explicit user confirmation. |
| 97 | + |
| 98 | +## Error Handling |
| 99 | + |
| 100 | +- Script fails → show error output, DO NOT reimplement logic. |
| 101 | +- Reserved capacity detected → table class script handles this, reports it. |
| 102 | +- ON_DEMAND table → utilization script handles this, reports it. |
| 103 | +- CloudWatch throttling → scripts retry with exponential backoff (up to 5 retries). |
| 104 | +- Per-table errors → reported in the output, other tables still analyzed. |
| 105 | +- AWS credentials missing → scripts exit with clear error message. |
0 commit comments