cdk-cost-analyzer 0.1.1
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.
- package/.cdk-cost-analyzer-cache/metadata.json +12 -0
- package/.gitlab-ci.yml +214 -0
- package/.husky/pre-commit +12 -0
- package/.kiro/hooks/accessibility-audit.kiro.hook +18 -0
- package/.kiro/hooks/api-schema-validation.kiro.hook +21 -0
- package/.kiro/hooks/auto-test-on-save.kiro.hook +19 -0
- package/.kiro/hooks/cdk-synth-on-change.kiro.hook +20 -0
- package/.kiro/hooks/code-coverage-check.kiro.hook +14 -0
- package/.kiro/hooks/commit-message-helper.kiro.hook +14 -0
- package/.kiro/hooks/dependency-update-check.kiro.hook +14 -0
- package/.kiro/hooks/env-file-validation.kiro.hook +18 -0
- package/.kiro/hooks/lint-and-format-on-save.kiro.hook +21 -0
- package/.kiro/hooks/mcp-config-validation.kiro.hook +17 -0
- package/.kiro/hooks/mcp-server-test.kiro.hook +14 -0
- package/.kiro/hooks/performance-analysis.kiro.hook +14 -0
- package/.kiro/hooks/readme-spell-check.kiro.hook +14 -0
- package/.kiro/hooks/security-scan-on-dependency-change.kiro.hook +21 -0
- package/.kiro/hooks/translation-update.kiro.hook +18 -0
- package/.kiro/hooks/update-documentation.kiro.hook +18 -0
- package/.kiro/settings/mcp.json +20 -0
- package/.kiro/specs/cdk-cost-analyzer/design.md +620 -0
- package/.kiro/specs/cdk-cost-analyzer/requirements.md +183 -0
- package/.kiro/specs/cdk-cost-analyzer/tasks.md +357 -0
- package/.kiro/specs/github-actions-ci/design.md +281 -0
- package/.kiro/specs/github-actions-ci/requirements.md +86 -0
- package/.kiro/specs/github-actions-ci/tasks.md +115 -0
- package/.kiro/specs/nlb-calculator-test-coverage/design.md +190 -0
- package/.kiro/specs/nlb-calculator-test-coverage/requirements.md +84 -0
- package/.kiro/specs/nlb-calculator-test-coverage/tasks.md +150 -0
- package/.kiro/specs/production-readiness/design.md +1213 -0
- package/.kiro/specs/production-readiness/requirements.md +312 -0
- package/.kiro/specs/production-readiness/tasks.md +269 -0
- package/.kiro/specs/repository-cleanup/design.md +283 -0
- package/.kiro/specs/repository-cleanup/requirements.md +74 -0
- package/.kiro/specs/repository-cleanup/tasks.md +64 -0
- package/.kiro/steering/aws-cli-best-practices.md +41 -0
- package/.kiro/steering/cdk-best-practices.md +49 -0
- package/.kiro/steering/development-standards.md +54 -0
- package/.kiro/steering/docker-best-practices.md +34 -0
- package/.kiro/steering/documentation-style.md +151 -0
- package/.kiro/steering/git-best-practices.md +37 -0
- package/.kiro/steering/mcp-best-practices.md +95 -0
- package/.kiro/steering/python-best-practices.md +48 -0
- package/.kiro/steering/react-best-practices.md +44 -0
- package/.kiro/steering/security-best-practices.md +41 -0
- package/.kiro/steering/testing-best-practices.md +59 -0
- package/.kiro/steering/typescript-best-practices.md +40 -0
- package/CHANGELOG.md +49 -0
- package/CONTRIBUTING.md +258 -0
- package/LICENSE +19 -0
- package/README.md +480 -0
- package/SECURITY.md +117 -0
- package/dist/api/index.d.ts +11 -0
- package/dist/api/index.js +65 -0
- package/dist/api/types.d.ts +15 -0
- package/dist/api/types.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +262 -0
- package/dist/config/ConfigManager.d.ts +40 -0
- package/dist/config/ConfigManager.js +238 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +19 -0
- package/dist/config/types.d.ts +72 -0
- package/dist/config/types.js +15 -0
- package/dist/diff/DiffEngine.d.ts +7 -0
- package/dist/diff/DiffEngine.js +73 -0
- package/dist/diff/index.d.ts +2 -0
- package/dist/diff/index.js +21 -0
- package/dist/diff/types.d.ts +20 -0
- package/dist/diff/types.js +3 -0
- package/dist/integrations/GitLabIntegration.d.ts +7 -0
- package/dist/integrations/GitLabIntegration.js +45 -0
- package/dist/integrations/index.d.ts +2 -0
- package/dist/integrations/index.js +21 -0
- package/dist/integrations/types.d.ts +11 -0
- package/dist/integrations/types.js +13 -0
- package/dist/parser/TemplateParser.d.ts +8 -0
- package/dist/parser/TemplateParser.js +75 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +22 -0
- package/dist/parser/types.d.ts +30 -0
- package/dist/parser/types.js +3 -0
- package/dist/pipeline/PipelineOrchestrator.d.ts +23 -0
- package/dist/pipeline/PipelineOrchestrator.js +191 -0
- package/dist/pipeline/index.d.ts +2 -0
- package/dist/pipeline/index.js +19 -0
- package/dist/pipeline/types.d.ts +41 -0
- package/dist/pipeline/types.js +13 -0
- package/dist/pricing/CacheManager.d.ts +75 -0
- package/dist/pricing/CacheManager.js +195 -0
- package/dist/pricing/PricingClient.d.ts +17 -0
- package/dist/pricing/PricingClient.js +122 -0
- package/dist/pricing/PricingService.d.ts +16 -0
- package/dist/pricing/PricingService.js +149 -0
- package/dist/pricing/calculators/ALBCalculator.d.ts +16 -0
- package/dist/pricing/calculators/ALBCalculator.js +163 -0
- package/dist/pricing/calculators/APIGatewayCalculator.d.ts +10 -0
- package/dist/pricing/calculators/APIGatewayCalculator.js +177 -0
- package/dist/pricing/calculators/CloudFrontCalculator.d.ts +59 -0
- package/dist/pricing/calculators/CloudFrontCalculator.js +151 -0
- package/dist/pricing/calculators/DynamoDBCalculator.d.ts +9 -0
- package/dist/pricing/calculators/DynamoDBCalculator.js +146 -0
- package/dist/pricing/calculators/EC2Calculator.d.ts +7 -0
- package/dist/pricing/calculators/EC2Calculator.js +80 -0
- package/dist/pricing/calculators/ECSCalculator.d.ts +9 -0
- package/dist/pricing/calculators/ECSCalculator.js +116 -0
- package/dist/pricing/calculators/ElastiCacheCalculator.d.ts +8 -0
- package/dist/pricing/calculators/ElastiCacheCalculator.js +106 -0
- package/dist/pricing/calculators/LambdaCalculator.d.ts +13 -0
- package/dist/pricing/calculators/LambdaCalculator.js +111 -0
- package/dist/pricing/calculators/NLBCalculator.d.ts +16 -0
- package/dist/pricing/calculators/NLBCalculator.js +138 -0
- package/dist/pricing/calculators/NatGatewayCalculator.d.ts +12 -0
- package/dist/pricing/calculators/NatGatewayCalculator.js +116 -0
- package/dist/pricing/calculators/RDSCalculator.d.ts +9 -0
- package/dist/pricing/calculators/RDSCalculator.js +103 -0
- package/dist/pricing/calculators/S3Calculator.d.ts +8 -0
- package/dist/pricing/calculators/S3Calculator.js +68 -0
- package/dist/pricing/calculators/VPCEndpointCalculator.d.ts +12 -0
- package/dist/pricing/calculators/VPCEndpointCalculator.js +129 -0
- package/dist/pricing/index.d.ts +10 -0
- package/dist/pricing/index.js +37 -0
- package/dist/pricing/types.d.ts +53 -0
- package/dist/pricing/types.js +22 -0
- package/dist/releasetag.txt +1 -0
- package/dist/reporter/Reporter.d.ts +18 -0
- package/dist/reporter/Reporter.js +412 -0
- package/dist/reporter/index.d.ts +2 -0
- package/dist/reporter/index.js +21 -0
- package/dist/reporter/types.d.ts +72 -0
- package/dist/reporter/types.js +3 -0
- package/dist/synthesis/SynthesisOrchestrator.d.ts +26 -0
- package/dist/synthesis/SynthesisOrchestrator.js +243 -0
- package/dist/synthesis/index.d.ts +2 -0
- package/dist/synthesis/index.js +19 -0
- package/dist/synthesis/types.d.ts +17 -0
- package/dist/synthesis/types.js +13 -0
- package/dist/threshold/ThresholdEnforcer.d.ts +29 -0
- package/dist/threshold/ThresholdEnforcer.js +143 -0
- package/dist/threshold/index.d.ts +2 -0
- package/dist/threshold/index.js +19 -0
- package/dist/threshold/types.d.ts +15 -0
- package/dist/threshold/types.js +17 -0
- package/docs/CALCULATORS.md +820 -0
- package/docs/CI_CD.md +608 -0
- package/docs/CONFIGURATION.md +407 -0
- package/docs/DEVELOPMENT.md +387 -0
- package/docs/RELEASE.md +223 -0
- package/docs/TROUBLESHOOTING.md +847 -0
- package/examples/.cdk-cost-analyzer.yml +85 -0
- package/examples/.gitlab-ci.yml +125 -0
- package/examples/api-usage.js +26 -0
- package/examples/complex/base.json +16 -0
- package/examples/complex/target.json +29 -0
- package/examples/monorepo/.gitlab-ci.yml +251 -0
- package/examples/monorepo/README.md +341 -0
- package/examples/monorepo/package.json +27 -0
- package/examples/monorepo/packages/backend-infra/.cdk-cost-analyzer.yml +34 -0
- package/examples/monorepo/packages/backend-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/backend-infra/cdk.json +7 -0
- package/examples/monorepo/packages/backend-infra/lib/backend-stack.ts +128 -0
- package/examples/monorepo/packages/backend-infra/package.json +30 -0
- package/examples/monorepo/packages/backend-infra/tsconfig.json +11 -0
- package/examples/monorepo/packages/data-infra/.cdk-cost-analyzer.yml +38 -0
- package/examples/monorepo/packages/data-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/data-infra/cdk.json +7 -0
- package/examples/monorepo/packages/data-infra/lib/data-stack.ts +121 -0
- package/examples/monorepo/packages/data-infra/package.json +30 -0
- package/examples/monorepo/packages/data-infra/tsconfig.json +11 -0
- package/examples/monorepo/packages/frontend-infra/.cdk-cost-analyzer.yml +31 -0
- package/examples/monorepo/packages/frontend-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/frontend-infra/cdk.json +7 -0
- package/examples/monorepo/packages/frontend-infra/lib/frontend-stack.ts +60 -0
- package/examples/monorepo/packages/frontend-infra/package.json +30 -0
- package/examples/monorepo/packages/frontend-infra/tsconfig.json +11 -0
- package/examples/monorepo/tsconfig.json +35 -0
- package/examples/multi-stack/.cdk-cost-analyzer.yml +72 -0
- package/examples/multi-stack/.gitlab-ci.yml +184 -0
- package/examples/multi-stack/README.md +279 -0
- package/examples/multi-stack/bin/app.ts +36 -0
- package/examples/multi-stack/cdk.json +72 -0
- package/examples/multi-stack/lib/compute-stack.ts +128 -0
- package/examples/multi-stack/lib/networking-stack.ts +69 -0
- package/examples/multi-stack/lib/storage-stack.ts +141 -0
- package/examples/multi-stack/package-lock.json +4437 -0
- package/examples/multi-stack/package.json +42 -0
- package/examples/multi-stack/tsconfig.json +34 -0
- package/examples/simple/base.json +8 -0
- package/examples/simple/target.json +14 -0
- package/examples/single-stack/.NVP +0 -0
- package/examples/single-stack/.cdk-cost-analyzer.yml +52 -0
- package/examples/single-stack/.gitlab-ci.yml +126 -0
- package/examples/single-stack/README.md +184 -0
- package/examples/single-stack/UeK +0 -0
- package/examples/single-stack/bin/app.ts +16 -0
- package/examples/single-stack/cdk.json +72 -0
- package/examples/single-stack/lib/infrastructure-stack.ts +119 -0
- package/examples/single-stack/package-lock.json +4443 -0
- package/examples/single-stack/package.json +38 -0
- package/examples/single-stack/tsconfig.json +34 -0
- package/package.json +139 -0
- package/test-cdk-project/README-COMPUTE.md +141 -0
- package/test-cdk-project/README.md +95 -0
- package/test-cdk-project/app-with-compute.js +102 -0
- package/test-cdk-project/app.js +81 -0
- package/test-cdk-project/cdk-compute.json +3 -0
- package/test-cdk-project/cdk.context.json +7 -0
- package/test-cdk-project/cdk.json +3 -0
- package/test-cdk-project/cdk.out/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out/TestStack.template.json +115 -0
- package/test-cdk-project/cdk.out/cdk.out +1 -0
- package/test-cdk-project/cdk.out/manifest.json +503 -0
- package/test-cdk-project/cdk.out/tree.json +1 -0
- package/test-cdk-project/cdk.out.base/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out.base/TestStack.template.json +115 -0
- package/test-cdk-project/cdk.out.base/cdk.out +1 -0
- package/test-cdk-project/cdk.out.base/manifest.json +503 -0
- package/test-cdk-project/cdk.out.base/tree.json +1 -0
- package/test-cdk-project/cdk.out.target/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out.target/TestStack.template.json +183 -0
- package/test-cdk-project/cdk.out.target/cdk.out +1 -0
- package/test-cdk-project/cdk.out.target/manifest.json +521 -0
- package/test-cdk-project/cdk.out.target/tree.json +1 -0
- package/test-cdk-project/package-lock.json +422 -0
- package/test-cdk-project/package.json +17 -0
- package/tools/workflows/README.md +102 -0
- package/tools/workflows/validate-workflows.js +109 -0
- package/tools/workflows/workflow-utils.ts +181 -0
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
# Design Document
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The CDK Cost Analyzer is a TypeScript package that compares CloudFormation templates and calculates AWS resource cost differences. The system parses template JSON/YAML, identifies resource changes, queries AWS Pricing API for current costs, and generates formatted cost reports.
|
|
6
|
+
|
|
7
|
+
The Phase 1 MVP architecture focuses on simplicity and core functionality, with a modular design that allows Phase 2 enhancements to be added incrementally.
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
### High-Level Architecture
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─────────────────┐
|
|
15
|
+
│ CLI / API │ Entry points
|
|
16
|
+
└────────┬────────┘
|
|
17
|
+
│
|
|
18
|
+
┌────────▼────────┐
|
|
19
|
+
│ Cost Analyzer │ Main orchestration
|
|
20
|
+
└────────┬────────┘
|
|
21
|
+
│
|
|
22
|
+
┌────┴────┬──────────┬──────────┐
|
|
23
|
+
│ │ │ │
|
|
24
|
+
┌───▼───┐ ┌──▼──┐ ┌────▼────┐ ┌──▼──────┐
|
|
25
|
+
│Parser │ │Diff │ │Pricing │ │Reporter │
|
|
26
|
+
│ │ │ │ │Service │ │ │
|
|
27
|
+
└───────┘ └─────┘ └─────────┘ └─────────┘
|
|
28
|
+
│
|
|
29
|
+
┌────▼────┐
|
|
30
|
+
│AWS API │
|
|
31
|
+
└─────────┘
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Component Responsibilities
|
|
35
|
+
|
|
36
|
+
1. **CLI**: Command-line interface for terminal usage
|
|
37
|
+
2. **API**: Programmatic interface for code integration
|
|
38
|
+
3. **Cost Analyzer**: Orchestrates the analysis workflow
|
|
39
|
+
4. **Parser**: Parses CloudFormation templates (JSON/YAML)
|
|
40
|
+
5. **Diff Engine**: Identifies added, removed, and modified resources
|
|
41
|
+
6. **Pricing Service**: Fetches AWS pricing data and calculates costs
|
|
42
|
+
7. **Reporter**: Formats and outputs cost reports
|
|
43
|
+
|
|
44
|
+
## Components and Interfaces
|
|
45
|
+
|
|
46
|
+
### 1. Template Parser
|
|
47
|
+
|
|
48
|
+
**Purpose**: Parse CloudFormation templates from JSON or YAML format
|
|
49
|
+
|
|
50
|
+
**Interface**:
|
|
51
|
+
```typescript
|
|
52
|
+
interface TemplateParser {
|
|
53
|
+
parse(content: string): CloudFormationTemplate;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface CloudFormationTemplate {
|
|
57
|
+
Resources: Record<string, Resource>;
|
|
58
|
+
Metadata?: Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface Resource {
|
|
62
|
+
Type: string;
|
|
63
|
+
Properties: Record<string, unknown>;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Implementation Notes**:
|
|
68
|
+
- Support both JSON and YAML formats
|
|
69
|
+
- Use existing libraries (js-yaml for YAML parsing)
|
|
70
|
+
- Validate template structure
|
|
71
|
+
- Extract resource definitions
|
|
72
|
+
|
|
73
|
+
### 2. Diff Engine
|
|
74
|
+
|
|
75
|
+
**Purpose**: Compare two templates and identify resource changes
|
|
76
|
+
|
|
77
|
+
**Interface**:
|
|
78
|
+
```typescript
|
|
79
|
+
interface DiffEngine {
|
|
80
|
+
diff(base: CloudFormationTemplate, target: CloudFormationTemplate): ResourceDiff;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface ResourceDiff {
|
|
84
|
+
added: Resource[];
|
|
85
|
+
removed: Resource[];
|
|
86
|
+
modified: ModifiedResource[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface ModifiedResource {
|
|
90
|
+
logicalId: string;
|
|
91
|
+
type: string;
|
|
92
|
+
oldProperties: Record<string, unknown>;
|
|
93
|
+
newProperties: Record<string, unknown>;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Implementation Notes**:
|
|
98
|
+
- Compare resources by logical ID
|
|
99
|
+
- Identify added resources (in target, not in base)
|
|
100
|
+
- Identify removed resources (in base, not in target)
|
|
101
|
+
- Identify modified resources (in both, but properties differ)
|
|
102
|
+
- Deep comparison of resource properties
|
|
103
|
+
|
|
104
|
+
### 3. Pricing Service
|
|
105
|
+
|
|
106
|
+
**Purpose**: Fetch AWS pricing data and calculate resource costs
|
|
107
|
+
|
|
108
|
+
**Interface**:
|
|
109
|
+
```typescript
|
|
110
|
+
interface PricingService {
|
|
111
|
+
getResourceCost(resource: Resource, region: string): Promise<MonthlyCost>;
|
|
112
|
+
getCostDelta(diff: ResourceDiff, region: string): Promise<CostDelta>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface MonthlyCost {
|
|
116
|
+
amount: number;
|
|
117
|
+
currency: string;
|
|
118
|
+
confidence: 'high' | 'medium' | 'low' | 'unknown';
|
|
119
|
+
assumptions: string[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface CostDelta {
|
|
123
|
+
totalDelta: number;
|
|
124
|
+
addedCosts: ResourceCost[];
|
|
125
|
+
removedCosts: ResourceCost[];
|
|
126
|
+
modifiedCosts: ModifiedResourceCost[];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
interface ResourceCost {
|
|
130
|
+
logicalId: string;
|
|
131
|
+
type: string;
|
|
132
|
+
monthlyCost: MonthlyCost;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface ModifiedResourceCost extends ResourceCost {
|
|
136
|
+
oldMonthlyCost: MonthlyCost;
|
|
137
|
+
newMonthlyCost: MonthlyCost;
|
|
138
|
+
costDelta: number;
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Implementation Notes**:
|
|
143
|
+
- Use AWS SDK Pricing API client
|
|
144
|
+
- Implement resource-specific cost calculators for EC2, S3, Lambda, RDS
|
|
145
|
+
- Cache pricing data to reduce API calls
|
|
146
|
+
- Handle pricing API failures with retries
|
|
147
|
+
- Return confidence levels based on data availability
|
|
148
|
+
- Document assumptions for usage-based pricing
|
|
149
|
+
|
|
150
|
+
### 4. Resource Cost Calculators
|
|
151
|
+
|
|
152
|
+
**Purpose**: Calculate costs for specific AWS resource types
|
|
153
|
+
|
|
154
|
+
**Interface**:
|
|
155
|
+
```typescript
|
|
156
|
+
interface ResourceCostCalculator {
|
|
157
|
+
supports(resourceType: string): boolean;
|
|
158
|
+
calculateCost(resource: Resource, region: string, pricingData: PricingData): MonthlyCost;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Implementations**:
|
|
163
|
+
- **EC2Calculator**: Calculate costs based on instance type, region
|
|
164
|
+
- **S3Calculator**: Estimate storage costs with default assumptions (e.g., 100GB)
|
|
165
|
+
- **LambdaCalculator**: Estimate based on memory and default invocations (e.g., 1M/month)
|
|
166
|
+
- **RDSCalculator**: Calculate based on instance class, engine, storage
|
|
167
|
+
|
|
168
|
+
### 5. Reporter
|
|
169
|
+
|
|
170
|
+
**Purpose**: Format cost analysis results for output
|
|
171
|
+
|
|
172
|
+
**Interface**:
|
|
173
|
+
```typescript
|
|
174
|
+
interface Reporter {
|
|
175
|
+
generateReport(costDelta: CostDelta, format: ReportFormat): string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
type ReportFormat = 'text' | 'json' | 'markdown';
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Implementation Notes**:
|
|
182
|
+
- Text format: Human-readable console output
|
|
183
|
+
- JSON format: Structured data for programmatic use
|
|
184
|
+
- Markdown format: For documentation and MR comments (Phase 2)
|
|
185
|
+
- Include summary section with total delta
|
|
186
|
+
- Group resources by category (added/removed/modified)
|
|
187
|
+
- Sort by cost impact (highest first)
|
|
188
|
+
- Format currency with proper symbols and decimals
|
|
189
|
+
|
|
190
|
+
### 6. CLI Interface
|
|
191
|
+
|
|
192
|
+
**Purpose**: Provide command-line access to cost analysis
|
|
193
|
+
|
|
194
|
+
**Interface**:
|
|
195
|
+
```bash
|
|
196
|
+
cdk-cost-analyzer <base-template> <target-template> [options]
|
|
197
|
+
|
|
198
|
+
Options:
|
|
199
|
+
--region <region> AWS region (default: eu-central-1)
|
|
200
|
+
--format <format> Output format: text|json|markdown (default: text)
|
|
201
|
+
--help Show help
|
|
202
|
+
--version Show version
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Implementation Notes**:
|
|
206
|
+
- Use commander or yargs for CLI parsing
|
|
207
|
+
- Read template files from filesystem
|
|
208
|
+
- Output to stdout
|
|
209
|
+
- Exit with code 0 on success, non-zero on error
|
|
210
|
+
- Display errors to stderr
|
|
211
|
+
|
|
212
|
+
### 7. Programmatic API
|
|
213
|
+
|
|
214
|
+
**Purpose**: Provide TypeScript/JavaScript API for integration
|
|
215
|
+
|
|
216
|
+
**Interface**:
|
|
217
|
+
```typescript
|
|
218
|
+
export async function analyzeCosts(options: AnalyzeOptions): Promise<CostAnalysisResult>;
|
|
219
|
+
|
|
220
|
+
interface AnalyzeOptions {
|
|
221
|
+
baseTemplate: string; // Template content or file path
|
|
222
|
+
targetTemplate: string; // Template content or file path
|
|
223
|
+
region?: string; // Default: 'eu-central-1'
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
interface CostAnalysisResult {
|
|
227
|
+
totalDelta: number;
|
|
228
|
+
currency: string;
|
|
229
|
+
addedResources: ResourceCost[];
|
|
230
|
+
removedResources: ResourceCost[];
|
|
231
|
+
modifiedResources: ModifiedResourceCost[];
|
|
232
|
+
summary: string;
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Data Models
|
|
237
|
+
|
|
238
|
+
### CloudFormation Template Structure
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
interface CloudFormationTemplate {
|
|
242
|
+
AWSTemplateFormatVersion?: string;
|
|
243
|
+
Description?: string;
|
|
244
|
+
Metadata?: Record<string, unknown>;
|
|
245
|
+
Parameters?: Record<string, Parameter>;
|
|
246
|
+
Resources: Record<string, Resource>;
|
|
247
|
+
Outputs?: Record<string, Output>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
interface Resource {
|
|
251
|
+
Type: string; // e.g., "AWS::EC2::Instance"
|
|
252
|
+
Properties: Record<string, unknown>;
|
|
253
|
+
DependsOn?: string | string[];
|
|
254
|
+
Metadata?: Record<string, unknown>;
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Pricing Data Structure
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
interface PricingData {
|
|
262
|
+
serviceCode: string;
|
|
263
|
+
region: string;
|
|
264
|
+
products: PricingProduct[];
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
interface PricingProduct {
|
|
268
|
+
sku: string;
|
|
269
|
+
productFamily: string;
|
|
270
|
+
attributes: Record<string, string>;
|
|
271
|
+
pricing: {
|
|
272
|
+
onDemand?: {
|
|
273
|
+
pricePerUnit: number;
|
|
274
|
+
unit: string;
|
|
275
|
+
};
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Cost Calculation Assumptions
|
|
281
|
+
|
|
282
|
+
For resources with usage-based pricing, the following default assumptions are used:
|
|
283
|
+
|
|
284
|
+
- **S3 Buckets**: 100 GB standard storage, 10,000 GET requests/month
|
|
285
|
+
- **Lambda Functions**: 1 million invocations/month, average 1-second duration
|
|
286
|
+
- **RDS Instances**: 100 GB storage, single-AZ deployment
|
|
287
|
+
- **EC2 Instances**: 730 hours/month (full month), on-demand pricing
|
|
288
|
+
|
|
289
|
+
These assumptions can be documented in the cost report and made configurable in Phase 2.
|
|
290
|
+
|
|
291
|
+
## Correct
|
|
292
|
+
ness Properties
|
|
293
|
+
|
|
294
|
+
*A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
|
|
295
|
+
|
|
296
|
+
Property 1: Template parsing succeeds for valid templates
|
|
297
|
+
*For any* valid CloudFormation template (JSON or YAML), the parser should successfully parse it without throwing errors and return a structured template object.
|
|
298
|
+
**Validates: Requirements 1.1**
|
|
299
|
+
|
|
300
|
+
Property 2: Diff engine correctly categorizes resources
|
|
301
|
+
*For any* pair of CloudFormation templates with known differences, the diff engine should correctly identify all added resources (in target but not base), removed resources (in base but not target), and modified resources (in both with different properties).
|
|
302
|
+
**Validates: Requirements 1.2**
|
|
303
|
+
|
|
304
|
+
Property 3: Cost calculation produces valid results
|
|
305
|
+
*For any* supported resource type, the cost calculator should return a non-negative cost value with a valid currency code and confidence level.
|
|
306
|
+
**Validates: Requirements 1.3**
|
|
307
|
+
|
|
308
|
+
Property 4: Total cost delta equals sum of individual costs
|
|
309
|
+
*For any* cost analysis result, the total cost delta should equal the sum of all added resource costs minus the sum of all removed resource costs plus the sum of all modified resource cost deltas.
|
|
310
|
+
**Validates: Requirements 1.4**
|
|
311
|
+
|
|
312
|
+
Property 5: Resources appear in exactly one category
|
|
313
|
+
*For any* cost report, each resource should appear in exactly one category (added, removed, or modified), and all resources from the diff should appear in the report.
|
|
314
|
+
**Validates: Requirements 1.5**
|
|
315
|
+
|
|
316
|
+
Property 6: EC2 costs vary by instance type and region
|
|
317
|
+
*For any* two EC2 instances with different instance types or regions, their calculated costs should differ (unless they happen to have identical pricing).
|
|
318
|
+
**Validates: Requirements 2.1**
|
|
319
|
+
|
|
320
|
+
Property 7: S3 buckets receive cost estimates
|
|
321
|
+
*For any* S3 bucket resource, the cost calculator should return a cost estimate greater than zero based on default storage assumptions.
|
|
322
|
+
**Validates: Requirements 2.2**
|
|
323
|
+
|
|
324
|
+
Property 8: Lambda costs scale with memory configuration
|
|
325
|
+
*For any* two Lambda functions where one has higher memory allocation than the other, the higher memory function should have equal or higher estimated cost.
|
|
326
|
+
**Validates: Requirements 2.3**
|
|
327
|
+
|
|
328
|
+
Property 9: RDS costs are calculated for all engine types
|
|
329
|
+
*For any* RDS instance resource with a valid engine type, the cost calculator should return a cost estimate greater than zero.
|
|
330
|
+
**Validates: Requirements 2.4**
|
|
331
|
+
|
|
332
|
+
Property 10: Unsupported resources don't cause failures
|
|
333
|
+
*For any* template containing unsupported resource types, the analysis should complete successfully, marking unsupported resources as having unknown costs without throwing errors.
|
|
334
|
+
**Validates: Requirements 2.5**
|
|
335
|
+
|
|
336
|
+
Property 11: CLI accepts valid template file paths
|
|
337
|
+
*For any* valid file paths pointing to CloudFormation templates, the CLI should accept them as arguments and proceed with analysis.
|
|
338
|
+
**Validates: Requirements 3.2**
|
|
339
|
+
|
|
340
|
+
Property 12: CLI region flag overrides default
|
|
341
|
+
*For any* valid AWS region provided via the --region flag, the analysis should use that region instead of the default eu-central-1.
|
|
342
|
+
**Validates: Requirements 3.3**
|
|
343
|
+
|
|
344
|
+
Property 13: Successful analysis outputs to stdout
|
|
345
|
+
*For any* successful cost analysis via CLI, the formatted report should be written to stdout and the process should exit with code 0.
|
|
346
|
+
**Validates: Requirements 3.4**
|
|
347
|
+
|
|
348
|
+
Property 14: Invalid inputs cause non-zero exit
|
|
349
|
+
*For any* invalid template file (missing, malformed, or unreadable), the CLI should exit with a non-zero status code and write an error message to stderr.
|
|
350
|
+
**Validates: Requirements 3.5**
|
|
351
|
+
|
|
352
|
+
Property 15: API returns structured results
|
|
353
|
+
*For any* successful analysis via the programmatic API, the return value should be an object containing totalDelta, currency, addedResources, removedResources, modifiedResources, and summary fields.
|
|
354
|
+
**Validates: Requirements 4.3**
|
|
355
|
+
|
|
356
|
+
Property 16: API throws errors for invalid inputs
|
|
357
|
+
*For any* invalid input (malformed templates, invalid region), the API should throw a descriptive error rather than returning undefined or crashing.
|
|
358
|
+
**Validates: Requirements 4.4**
|
|
359
|
+
|
|
360
|
+
Property 17: Pricing queries include region filter
|
|
361
|
+
*For any* cost calculation, the AWS Pricing API queries should include the specified region as a filter parameter.
|
|
362
|
+
**Validates: Requirements 5.2**
|
|
363
|
+
|
|
364
|
+
Property 18: Failed pricing calls trigger retries
|
|
365
|
+
*For any* transient pricing API failure, the system should retry the request up to 3 times with exponential backoff before giving up.
|
|
366
|
+
**Validates: Requirements 5.3**
|
|
367
|
+
|
|
368
|
+
Property 19: Cache is used when API fails
|
|
369
|
+
*For any* pricing API failure where cached data exists for the requested resource and region, the system should use the cached data instead of marking the cost as unknown.
|
|
370
|
+
**Validates: Requirements 5.4**
|
|
371
|
+
|
|
372
|
+
Property 20: Unavailable pricing results in unknown cost
|
|
373
|
+
*For any* resource where pricing data cannot be retrieved (API fails and no cache exists), the resource should be marked with confidence level 'unknown' and cost calculation should continue.
|
|
374
|
+
**Validates: Requirements 5.5**
|
|
375
|
+
|
|
376
|
+
Property 21: Reports contain all required resource fields
|
|
377
|
+
*For any* resource listed in a cost report, the entry should include the resource's logical ID, type, and estimated monthly cost.
|
|
378
|
+
**Validates: Requirements 6.2**
|
|
379
|
+
|
|
380
|
+
Property 22: Currency values are consistently formatted
|
|
381
|
+
*For any* cost value displayed in a report, it should be formatted with exactly two decimal places and include the appropriate currency symbol.
|
|
382
|
+
**Validates: Requirements 6.3**
|
|
383
|
+
|
|
384
|
+
Property 23: Positive deltas have plus sign prefix
|
|
385
|
+
*For any* cost delta greater than zero in a report, the formatted value should include a plus sign (+) prefix.
|
|
386
|
+
**Validates: Requirements 6.4**
|
|
387
|
+
|
|
388
|
+
Property 24: Negative deltas have minus sign prefix
|
|
389
|
+
*For any* cost delta less than zero in a report, the formatted value should include a minus sign (-) prefix.
|
|
390
|
+
**Validates: Requirements 6.5**
|
|
391
|
+
|
|
392
|
+
## Error Handling
|
|
393
|
+
|
|
394
|
+
### Error Categories
|
|
395
|
+
|
|
396
|
+
1. **Input Errors**
|
|
397
|
+
- Invalid template syntax (JSON/YAML parsing errors)
|
|
398
|
+
- Missing required template fields
|
|
399
|
+
- Invalid file paths
|
|
400
|
+
- Invalid region codes
|
|
401
|
+
|
|
402
|
+
2. **API Errors**
|
|
403
|
+
- AWS Pricing API failures
|
|
404
|
+
- Network timeouts
|
|
405
|
+
- Authentication errors
|
|
406
|
+
- Rate limiting
|
|
407
|
+
|
|
408
|
+
3. **Calculation Errors**
|
|
409
|
+
- Unsupported resource types
|
|
410
|
+
- Missing pricing data
|
|
411
|
+
- Invalid resource configurations
|
|
412
|
+
|
|
413
|
+
### Error Handling Strategy
|
|
414
|
+
|
|
415
|
+
**Input Errors**: Fail fast with clear error messages
|
|
416
|
+
- Validate inputs early in the process
|
|
417
|
+
- Provide specific error messages indicating what's wrong
|
|
418
|
+
- Exit with non-zero status code (CLI) or throw typed exceptions (API)
|
|
419
|
+
|
|
420
|
+
**API Errors**: Retry with fallback
|
|
421
|
+
- Implement exponential backoff for transient failures
|
|
422
|
+
- Fall back to cached pricing data when available
|
|
423
|
+
- Continue analysis with "unknown" costs if pricing unavailable
|
|
424
|
+
- Log warnings for partial failures
|
|
425
|
+
|
|
426
|
+
**Calculation Errors**: Graceful degradation
|
|
427
|
+
- Mark unsupported resources as "unknown" cost
|
|
428
|
+
- Continue processing other resources
|
|
429
|
+
- Include warnings in the report
|
|
430
|
+
- Document assumptions and limitations
|
|
431
|
+
|
|
432
|
+
### Error Types
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
class TemplateParseError extends Error {
|
|
436
|
+
constructor(message: string, public templatePath?: string) {
|
|
437
|
+
super(message);
|
|
438
|
+
this.name = 'TemplateParseError';
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
class PricingAPIError extends Error {
|
|
443
|
+
constructor(message: string, public retryable: boolean = true) {
|
|
444
|
+
super(message);
|
|
445
|
+
this.name = 'PricingAPIError';
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
class UnsupportedResourceError extends Error {
|
|
450
|
+
constructor(public resourceType: string) {
|
|
451
|
+
super(`Resource type ${resourceType} is not supported`);
|
|
452
|
+
this.name = 'UnsupportedResourceError';
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Testing Strategy
|
|
458
|
+
|
|
459
|
+
### Unit Testing
|
|
460
|
+
|
|
461
|
+
Unit tests will verify specific behaviors and edge cases:
|
|
462
|
+
|
|
463
|
+
**Template Parser Tests**:
|
|
464
|
+
- Parse valid JSON templates
|
|
465
|
+
- Parse valid YAML templates
|
|
466
|
+
- Handle malformed JSON/YAML
|
|
467
|
+
- Handle missing Resources section
|
|
468
|
+
- Handle empty templates
|
|
469
|
+
|
|
470
|
+
**Diff Engine Tests**:
|
|
471
|
+
- Identify added resources
|
|
472
|
+
- Identify removed resources
|
|
473
|
+
- Identify modified resources
|
|
474
|
+
- Handle identical templates (no changes)
|
|
475
|
+
- Handle completely different templates
|
|
476
|
+
|
|
477
|
+
**Cost Calculator Tests**:
|
|
478
|
+
- Calculate EC2 costs for specific instance types
|
|
479
|
+
- Calculate S3 costs with default assumptions
|
|
480
|
+
- Calculate Lambda costs with different memory settings
|
|
481
|
+
- Calculate RDS costs for different engines
|
|
482
|
+
- Handle unsupported resource types
|
|
483
|
+
|
|
484
|
+
**Reporter Tests**:
|
|
485
|
+
- Format text reports correctly
|
|
486
|
+
- Format JSON reports correctly
|
|
487
|
+
- Format currency values
|
|
488
|
+
- Format positive/negative deltas
|
|
489
|
+
- Sort resources by cost impact
|
|
490
|
+
|
|
491
|
+
**CLI Tests**:
|
|
492
|
+
- Parse command-line arguments
|
|
493
|
+
- Handle missing files
|
|
494
|
+
- Handle invalid regions
|
|
495
|
+
- Exit with correct status codes
|
|
496
|
+
- Output to stdout/stderr appropriately
|
|
497
|
+
|
|
498
|
+
### Property-Based Testing
|
|
499
|
+
|
|
500
|
+
Property-based tests will verify universal properties across many inputs using a PBT library (fast-check for TypeScript):
|
|
501
|
+
|
|
502
|
+
**Template Parsing Properties**:
|
|
503
|
+
- Property 1: Template parsing succeeds for valid templates (Requirements 1.1)
|
|
504
|
+
- Property 10: Unsupported resources don't cause failures (Requirements 2.5)
|
|
505
|
+
|
|
506
|
+
**Diff Engine Properties**:
|
|
507
|
+
- Property 2: Diff engine correctly categorizes resources (Requirements 1.2)
|
|
508
|
+
- Property 5: Resources appear in exactly one category (Requirements 1.5)
|
|
509
|
+
|
|
510
|
+
**Cost Calculation Properties**:
|
|
511
|
+
- Property 3: Cost calculation produces valid results (Requirements 1.3)
|
|
512
|
+
- Property 4: Total cost delta equals sum of individual costs (Requirements 1.4)
|
|
513
|
+
- Property 6: EC2 costs vary by instance type and region (Requirements 2.1)
|
|
514
|
+
- Property 8: Lambda costs scale with memory configuration (Requirements 2.3)
|
|
515
|
+
|
|
516
|
+
**API Properties**:
|
|
517
|
+
- Property 15: API returns structured results (Requirements 4.3)
|
|
518
|
+
- Property 16: API throws errors for invalid inputs (Requirements 4.4)
|
|
519
|
+
|
|
520
|
+
**Pricing Service Properties**:
|
|
521
|
+
- Property 17: Pricing queries include region filter (Requirements 5.2)
|
|
522
|
+
- Property 18: Failed pricing calls trigger retries (Requirements 5.3)
|
|
523
|
+
- Property 19: Cache is used when API fails (Requirements 5.4)
|
|
524
|
+
- Property 20: Unavailable pricing results in unknown cost (Requirements 5.5)
|
|
525
|
+
|
|
526
|
+
**Reporter Properties**:
|
|
527
|
+
- Property 21: Reports contain all required resource fields (Requirements 6.2)
|
|
528
|
+
- Property 22: Currency values are consistently formatted (Requirements 6.3)
|
|
529
|
+
- Property 23: Positive deltas have plus sign prefix (Requirements 6.4)
|
|
530
|
+
- Property 24: Negative deltas have minus sign prefix (Requirements 6.5)
|
|
531
|
+
|
|
532
|
+
**Testing Configuration**:
|
|
533
|
+
- Each property-based test will run a minimum of 100 iterations
|
|
534
|
+
- Each test will be tagged with a comment referencing the design document property
|
|
535
|
+
- Tag format: `// Feature: cdk-cost-analyzer, Property {number}: {property_text}`
|
|
536
|
+
|
|
537
|
+
### Integration Testing
|
|
538
|
+
|
|
539
|
+
Integration tests will verify end-to-end workflows:
|
|
540
|
+
|
|
541
|
+
- Complete CLI workflow with real template files
|
|
542
|
+
- Complete API workflow with programmatic calls
|
|
543
|
+
- AWS Pricing API integration (with mocked responses)
|
|
544
|
+
- Error handling across component boundaries
|
|
545
|
+
|
|
546
|
+
### Test Data
|
|
547
|
+
|
|
548
|
+
**Sample Templates**:
|
|
549
|
+
- Minimal valid template (single resource)
|
|
550
|
+
- Complex template (multiple resource types)
|
|
551
|
+
- Template with EC2 instances
|
|
552
|
+
- Template with S3 buckets
|
|
553
|
+
- Template with Lambda functions
|
|
554
|
+
- Template with RDS instances
|
|
555
|
+
- Template with unsupported resources
|
|
556
|
+
- Malformed templates (invalid JSON/YAML)
|
|
557
|
+
|
|
558
|
+
**Pricing Data**:
|
|
559
|
+
- Mock pricing responses for each supported resource type
|
|
560
|
+
- Mock pricing responses for different regions
|
|
561
|
+
- Mock error responses for API failures
|
|
562
|
+
|
|
563
|
+
## Dependencies
|
|
564
|
+
|
|
565
|
+
### Production Dependencies
|
|
566
|
+
|
|
567
|
+
- **aws-sdk** (v3): AWS Pricing API client
|
|
568
|
+
- **js-yaml**: YAML template parsing
|
|
569
|
+
- **commander**: CLI argument parsing
|
|
570
|
+
|
|
571
|
+
### Development Dependencies
|
|
572
|
+
|
|
573
|
+
- **typescript**: TypeScript compiler
|
|
574
|
+
- **fast-check**: Property-based testing library
|
|
575
|
+
- **vitest**: Unit testing framework
|
|
576
|
+
- **@types/node**: Node.js type definitions
|
|
577
|
+
- **@types/js-yaml**: js-yaml type definitions
|
|
578
|
+
|
|
579
|
+
### Dependency Justification
|
|
580
|
+
|
|
581
|
+
- **aws-sdk**: Required for AWS Pricing API integration
|
|
582
|
+
- **js-yaml**: Standard library for YAML parsing, widely used and maintained
|
|
583
|
+
- **commander**: Popular CLI framework with good TypeScript support
|
|
584
|
+
- **fast-check**: Leading property-based testing library for TypeScript
|
|
585
|
+
- **vitest**: Fast, modern testing framework with excellent TypeScript support
|
|
586
|
+
|
|
587
|
+
## Implementation Notes
|
|
588
|
+
|
|
589
|
+
### Phase 1 Scope
|
|
590
|
+
|
|
591
|
+
The MVP implementation will focus on:
|
|
592
|
+
1. Core template parsing and diffing
|
|
593
|
+
2. Basic cost calculation for EC2, S3, Lambda, RDS
|
|
594
|
+
3. Simple CLI and programmatic API
|
|
595
|
+
4. Text and JSON report formats
|
|
596
|
+
5. AWS Pricing API integration with retry logic
|
|
597
|
+
|
|
598
|
+
### Phase 2 Considerations
|
|
599
|
+
|
|
600
|
+
The design supports future enhancements:
|
|
601
|
+
- GitLab integration can be added as a separate module
|
|
602
|
+
- Additional resource calculators can be registered
|
|
603
|
+
- Markdown report format for MR comments
|
|
604
|
+
- CDK synthesis can be added before parsing
|
|
605
|
+
- Historical tracking can use the existing data structures
|
|
606
|
+
|
|
607
|
+
### Performance Considerations
|
|
608
|
+
|
|
609
|
+
- Pricing data caching to reduce API calls
|
|
610
|
+
- Lazy loading of AWS SDK to improve startup time
|
|
611
|
+
- Parallel pricing queries for multiple resources
|
|
612
|
+
- Efficient template parsing with streaming for large files
|
|
613
|
+
|
|
614
|
+
### Security Considerations
|
|
615
|
+
|
|
616
|
+
- No AWS credentials stored in code
|
|
617
|
+
- Use AWS SDK default credential chain
|
|
618
|
+
- Validate all user inputs (file paths, regions)
|
|
619
|
+
- Sanitize template content before parsing
|
|
620
|
+
- Rate limiting for AWS API calls
|