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,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EC2Calculator = void 0;
|
|
4
|
+
class EC2Calculator {
|
|
5
|
+
supports(resourceType) {
|
|
6
|
+
return resourceType === 'AWS::EC2::Instance';
|
|
7
|
+
}
|
|
8
|
+
async calculateCost(resource, region, pricingClient) {
|
|
9
|
+
const instanceType = resource.properties.InstanceType;
|
|
10
|
+
if (!instanceType) {
|
|
11
|
+
return {
|
|
12
|
+
amount: 0,
|
|
13
|
+
currency: 'USD',
|
|
14
|
+
confidence: 'unknown',
|
|
15
|
+
assumptions: ['Instance type not specified'],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const hourlyRate = await pricingClient.getPrice({
|
|
20
|
+
serviceCode: 'AmazonEC2',
|
|
21
|
+
region: this.normalizeRegion(region),
|
|
22
|
+
filters: [
|
|
23
|
+
{ field: 'instanceType', value: instanceType },
|
|
24
|
+
{ field: 'operatingSystem', value: 'Linux' },
|
|
25
|
+
{ field: 'tenancy', value: 'Shared' },
|
|
26
|
+
{ field: 'preInstalledSw', value: 'NA' },
|
|
27
|
+
{ field: 'capacitystatus', value: 'Used' },
|
|
28
|
+
],
|
|
29
|
+
});
|
|
30
|
+
if (hourlyRate === null) {
|
|
31
|
+
return {
|
|
32
|
+
amount: 0,
|
|
33
|
+
currency: 'USD',
|
|
34
|
+
confidence: 'unknown',
|
|
35
|
+
assumptions: [`Pricing data not available for instance type ${instanceType} in region ${region}`],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const monthlyHours = 730;
|
|
39
|
+
const monthlyCost = hourlyRate * monthlyHours;
|
|
40
|
+
return {
|
|
41
|
+
amount: monthlyCost,
|
|
42
|
+
currency: 'USD',
|
|
43
|
+
confidence: 'high',
|
|
44
|
+
assumptions: [
|
|
45
|
+
`Assumes ${monthlyHours} hours per month (24/7 operation)`,
|
|
46
|
+
'Assumes Linux OS, shared tenancy, on-demand pricing',
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return {
|
|
52
|
+
amount: 0,
|
|
53
|
+
currency: 'USD',
|
|
54
|
+
confidence: 'unknown',
|
|
55
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
normalizeRegion(region) {
|
|
60
|
+
const regionMap = {
|
|
61
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
62
|
+
'us-east-2': 'US East (Ohio)',
|
|
63
|
+
'us-west-1': 'US West (N. California)',
|
|
64
|
+
'us-west-2': 'US West (Oregon)',
|
|
65
|
+
'eu-west-1': 'EU (Ireland)',
|
|
66
|
+
'eu-west-2': 'EU (London)',
|
|
67
|
+
'eu-west-3': 'EU (Paris)',
|
|
68
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
69
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
70
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
71
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
72
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
73
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
74
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
75
|
+
};
|
|
76
|
+
return regionMap[region] || region;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.EC2Calculator = EC2Calculator;
|
|
80
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRUMyQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcmljaW5nL2NhbGN1bGF0b3JzL0VDMkNhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSxhQUFhO0lBQ3hCLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLFlBQVksS0FBSyxvQkFBb0IsQ0FBQztJQUMvQyxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sWUFBWSxHQUFHLFFBQVEsQ0FBQyxVQUFVLENBQUMsWUFBc0IsQ0FBQztRQUVoRSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDbEIsT0FBTztnQkFDTCxNQUFNLEVBQUUsQ0FBQztnQkFDVCxRQUFRLEVBQUUsS0FBSztnQkFDZixVQUFVLEVBQUUsU0FBUztnQkFDckIsV0FBVyxFQUFFLENBQUMsNkJBQTZCLENBQUM7YUFDN0MsQ0FBQztRQUNKLENBQUM7UUFFRCxJQUFJLENBQUM7WUFDSCxNQUFNLFVBQVUsR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQzlDLFdBQVcsRUFBRSxXQUFXO2dCQUN4QixNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUM7Z0JBQ3BDLE9BQU8sRUFBRTtvQkFDUCxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRTtvQkFDOUMsRUFBRSxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRTtvQkFDNUMsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7b0JBQ3JDLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUU7b0JBQ3hDLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUU7aUJBQzNDO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsSUFBSSxVQUFVLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3hCLE9BQU87b0JBQ0wsTUFBTSxFQUFFLENBQUM7b0JBQ1QsUUFBUSxFQUFFLEtBQUs7b0JBQ2YsVUFBVSxFQUFFLFNBQVM7b0JBQ3JCLFdBQVcsRUFBRSxDQUFDLGdEQUFnRCxZQUFZLGNBQWMsTUFBTSxFQUFFLENBQUM7aUJBQ2xHLENBQUM7WUFDSixDQUFDO1lBRUQsTUFBTSxZQUFZLEdBQUcsR0FBRyxDQUFDO1lBQ3pCLE1BQU0sV0FBVyxHQUFHLFVBQVUsR0FBRyxZQUFZLENBQUM7WUFFOUMsT0FBTztnQkFDTCxNQUFNLEVBQUUsV0FBVztnQkFDbkIsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsVUFBVSxFQUFFLE1BQU07Z0JBQ2xCLFdBQVcsRUFBRTtvQkFDWCxXQUFXLFlBQVksbUNBQW1DO29CQUMxRCxxREFBcUQ7aUJBQ3REO2FBQ0YsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTztnQkFDTCxNQUFNLEVBQUUsQ0FBQztnQkFDVCxRQUFRLEVBQUUsS0FBSztnQkFDZixVQUFVLEVBQUUsU0FBUztnQkFDckIsV0FBVyxFQUFFLENBQUMsNEJBQTRCLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2FBQ3BHLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFjO1FBQ3BDLE1BQU0sU0FBUyxHQUEyQjtZQUN4QyxXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLFdBQVcsRUFBRSxnQkFBZ0I7WUFDN0IsV0FBVyxFQUFFLHlCQUF5QjtZQUN0QyxXQUFXLEVBQUUsa0JBQWtCO1lBQy9CLFdBQVcsRUFBRSxjQUFjO1lBQzNCLFdBQVcsRUFBRSxhQUFhO1lBQzFCLFdBQVcsRUFBRSxZQUFZO1lBQ3pCLGNBQWMsRUFBRSxnQkFBZ0I7WUFDaEMsWUFBWSxFQUFFLGdCQUFnQjtZQUM5QixZQUFZLEVBQUUsdUJBQXVCO1lBQ3JDLGdCQUFnQixFQUFFLDBCQUEwQjtZQUM1QyxnQkFBZ0IsRUFBRSx1QkFBdUI7WUFDekMsZ0JBQWdCLEVBQUUsc0JBQXNCO1lBQ3hDLGdCQUFnQixFQUFFLHNCQUFzQjtTQUN6QyxDQUFDO1FBRUYsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQXJGRCxzQ0FxRkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXNvdXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbmV4cG9ydCBjbGFzcyBFQzJDYWxjdWxhdG9yIGltcGxlbWVudHMgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciB7XG4gIHN1cHBvcnRzKHJlc291cmNlVHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6RUMyOjpJbnN0YW5jZSc7XG4gIH1cblxuICBhc3luYyBjYWxjdWxhdGVDb3N0KFxuICAgIHJlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgY29uc3QgaW5zdGFuY2VUeXBlID0gcmVzb3VyY2UucHJvcGVydGllcy5JbnN0YW5jZVR5cGUgYXMgc3RyaW5nO1xuXG4gICAgaWYgKCFpbnN0YW5jZVR5cGUpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbJ0luc3RhbmNlIHR5cGUgbm90IHNwZWNpZmllZCddLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgaG91cmx5UmF0ZSA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgICBzZXJ2aWNlQ29kZTogJ0FtYXpvbkVDMicsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdpbnN0YW5jZVR5cGUnLCB2YWx1ZTogaW5zdGFuY2VUeXBlIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ29wZXJhdGluZ1N5c3RlbScsIHZhbHVlOiAnTGludXgnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ3RlbmFuY3knLCB2YWx1ZTogJ1NoYXJlZCcgfSxcbiAgICAgICAgICB7IGZpZWxkOiAncHJlSW5zdGFsbGVkU3cnLCB2YWx1ZTogJ05BJyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICdjYXBhY2l0eXN0YXR1cycsIHZhbHVlOiAnVXNlZCcgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaG91cmx5UmF0ZSA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICAgIGFzc3VtcHRpb25zOiBbYFByaWNpbmcgZGF0YSBub3QgYXZhaWxhYmxlIGZvciBpbnN0YW5jZSB0eXBlICR7aW5zdGFuY2VUeXBlfSBpbiByZWdpb24gJHtyZWdpb259YF0sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1vbnRobHlIb3VycyA9IDczMDtcbiAgICAgIGNvbnN0IG1vbnRobHlDb3N0ID0gaG91cmx5UmF0ZSAqIG1vbnRobHlIb3VycztcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnaGlnaCcsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgICAgYEFzc3VtZXMgJHttb250aGx5SG91cnN9IGhvdXJzIHBlciBtb250aCAoMjQvNyBvcGVyYXRpb24pYCxcbiAgICAgICAgICAnQXNzdW1lcyBMaW51eCBPUywgc2hhcmVkIHRlbmFuY3ksIG9uLWRlbWFuZCBwcmljaW5nJyxcbiAgICAgICAgXSxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbYEZhaWxlZCB0byBmZXRjaCBwcmljaW5nOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBub3JtYWxpemVSZWdpb24ocmVnaW9uOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHJlZ2lvbk1hcDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgICd1cy1lYXN0LTEnOiAnVVMgRWFzdCAoTi4gVmlyZ2luaWEpJyxcbiAgICAgICd1cy1lYXN0LTInOiAnVVMgRWFzdCAoT2hpbyknLFxuICAgICAgJ3VzLXdlc3QtMSc6ICdVUyBXZXN0IChOLiBDYWxpZm9ybmlhKScsXG4gICAgICAndXMtd2VzdC0yJzogJ1VTIFdlc3QgKE9yZWdvbiknLFxuICAgICAgJ2V1LXdlc3QtMSc6ICdFVSAoSXJlbGFuZCknLFxuICAgICAgJ2V1LXdlc3QtMic6ICdFVSAoTG9uZG9uKScsXG4gICAgICAnZXUtd2VzdC0zJzogJ0VVIChQYXJpcyknLFxuICAgICAgJ2V1LWNlbnRyYWwtMSc6ICdFVSAoRnJhbmtmdXJ0KScsXG4gICAgICAnZXUtbm9ydGgtMSc6ICdFVSAoU3RvY2tob2xtKScsXG4gICAgICAnYXAtc291dGgtMSc6ICdBc2lhIFBhY2lmaWMgKE11bWJhaSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0xJzogJ0FzaWEgUGFjaWZpYyAoU2luZ2Fwb3JlKScsXG4gICAgICAnYXAtc291dGhlYXN0LTInOiAnQXNpYSBQYWNpZmljIChTeWRuZXkpJyxcbiAgICAgICdhcC1ub3J0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFRva3lvKScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTInOiAnQXNpYSBQYWNpZmljIChTZW91bCknLFxuICAgIH07XG5cbiAgICByZXR1cm4gcmVnaW9uTWFwW3JlZ2lvbl0gfHwgcmVnaW9uO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class ECSCalculator implements ResourceCostCalculator {
|
|
4
|
+
supports(resourceType: string): boolean;
|
|
5
|
+
calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
6
|
+
private calculateFargateCost;
|
|
7
|
+
private calculateEC2Cost;
|
|
8
|
+
private normalizeRegion;
|
|
9
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ECSCalculator = void 0;
|
|
4
|
+
class ECSCalculator {
|
|
5
|
+
supports(resourceType) {
|
|
6
|
+
return resourceType === 'AWS::ECS::Service';
|
|
7
|
+
}
|
|
8
|
+
async calculateCost(resource, region, pricingClient) {
|
|
9
|
+
const desiredCount = resource.properties.DesiredCount || 1;
|
|
10
|
+
const launchType = resource.properties.LaunchType || 'FARGATE';
|
|
11
|
+
if (launchType === 'FARGATE') {
|
|
12
|
+
return this.calculateFargateCost(resource, desiredCount, region, pricingClient);
|
|
13
|
+
}
|
|
14
|
+
else if (launchType === 'EC2') {
|
|
15
|
+
return this.calculateEC2Cost(desiredCount);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
return {
|
|
19
|
+
amount: 0,
|
|
20
|
+
currency: 'USD',
|
|
21
|
+
confidence: 'unknown',
|
|
22
|
+
assumptions: [`Unsupported launch type: ${launchType}`],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async calculateFargateCost(_resource, desiredCount, region, pricingClient) {
|
|
27
|
+
try {
|
|
28
|
+
// Default assumptions for Fargate task
|
|
29
|
+
const assumedVCpu = 0.25; // 0.25 vCPU
|
|
30
|
+
const assumedMemoryGB = 0.5; // 0.5 GB
|
|
31
|
+
const vCpuCostPerHour = await pricingClient.getPrice({
|
|
32
|
+
serviceCode: 'AmazonECS',
|
|
33
|
+
region: this.normalizeRegion(region),
|
|
34
|
+
filters: [
|
|
35
|
+
{ field: 'productFamily', value: 'Compute' },
|
|
36
|
+
{ field: 'usagetype', value: `${region}-Fargate-vCPU-Hours:perCPU` },
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
const memoryCostPerHour = await pricingClient.getPrice({
|
|
40
|
+
serviceCode: 'AmazonECS',
|
|
41
|
+
region: this.normalizeRegion(region),
|
|
42
|
+
filters: [
|
|
43
|
+
{ field: 'productFamily', value: 'Compute' },
|
|
44
|
+
{ field: 'usagetype', value: `${region}-Fargate-GB-Hours:perGB` },
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
if (vCpuCostPerHour === null || memoryCostPerHour === null) {
|
|
48
|
+
return {
|
|
49
|
+
amount: 0,
|
|
50
|
+
currency: 'USD',
|
|
51
|
+
confidence: 'unknown',
|
|
52
|
+
assumptions: ['Pricing data not available for ECS Fargate'],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const hoursPerMonth = 730;
|
|
56
|
+
const vCpuCost = assumedVCpu * vCpuCostPerHour * hoursPerMonth * desiredCount;
|
|
57
|
+
const memoryCost = assumedMemoryGB * memoryCostPerHour * hoursPerMonth * desiredCount;
|
|
58
|
+
const monthlyCost = vCpuCost + memoryCost;
|
|
59
|
+
return {
|
|
60
|
+
amount: monthlyCost,
|
|
61
|
+
currency: 'USD',
|
|
62
|
+
confidence: 'medium',
|
|
63
|
+
assumptions: [
|
|
64
|
+
`${desiredCount} task(s) running`,
|
|
65
|
+
`Assumes ${assumedVCpu} vCPU per task`,
|
|
66
|
+
`Assumes ${assumedMemoryGB} GB memory per task`,
|
|
67
|
+
`Assumes ${hoursPerMonth} hours per month (24/7 operation)`,
|
|
68
|
+
'Fargate launch type',
|
|
69
|
+
'Does not include data transfer or storage costs',
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return {
|
|
75
|
+
amount: 0,
|
|
76
|
+
currency: 'USD',
|
|
77
|
+
confidence: 'unknown',
|
|
78
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
calculateEC2Cost(desiredCount) {
|
|
83
|
+
return {
|
|
84
|
+
amount: 0,
|
|
85
|
+
currency: 'USD',
|
|
86
|
+
confidence: 'low',
|
|
87
|
+
assumptions: [
|
|
88
|
+
`${desiredCount} task(s) running on EC2 launch type`,
|
|
89
|
+
'EC2 launch type costs depend on underlying EC2 instances',
|
|
90
|
+
'Refer to EC2 instance costs for actual pricing',
|
|
91
|
+
'Does not include ECS task-specific costs (minimal for EC2 launch type)',
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
normalizeRegion(region) {
|
|
96
|
+
const regionMap = {
|
|
97
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
98
|
+
'us-east-2': 'US East (Ohio)',
|
|
99
|
+
'us-west-1': 'US West (N. California)',
|
|
100
|
+
'us-west-2': 'US West (Oregon)',
|
|
101
|
+
'eu-west-1': 'EU (Ireland)',
|
|
102
|
+
'eu-west-2': 'EU (London)',
|
|
103
|
+
'eu-west-3': 'EU (Paris)',
|
|
104
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
105
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
106
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
107
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
108
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
109
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
110
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
111
|
+
};
|
|
112
|
+
return regionMap[region] || region;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.ECSCalculator = ECSCalculator;
|
|
116
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRUNTQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcmljaW5nL2NhbGN1bGF0b3JzL0VDU0NhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSxhQUFhO0lBQ3hCLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLFlBQVksS0FBSyxtQkFBbUIsQ0FBQztJQUM5QyxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sWUFBWSxHQUFJLFFBQVEsQ0FBQyxVQUFVLENBQUMsWUFBdUIsSUFBSSxDQUFDLENBQUM7UUFDdkUsTUFBTSxVQUFVLEdBQUksUUFBUSxDQUFDLFVBQVUsQ0FBQyxVQUFxQixJQUFJLFNBQVMsQ0FBQztRQUUzRSxJQUFJLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM3QixPQUFPLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxhQUFhLENBQUMsQ0FBQztRQUNsRixDQUFDO2FBQU0sSUFBSSxVQUFVLEtBQUssS0FBSyxFQUFFLENBQUM7WUFDaEMsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDN0MsQ0FBQzthQUFNLENBQUM7WUFDTixPQUFPO2dCQUNMLE1BQU0sRUFBRSxDQUFDO2dCQUNULFFBQVEsRUFBRSxLQUFLO2dCQUNmLFVBQVUsRUFBRSxTQUFTO2dCQUNyQixXQUFXLEVBQUUsQ0FBQyw0QkFBNEIsVUFBVSxFQUFFLENBQUM7YUFDeEQsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRU8sS0FBSyxDQUFDLG9CQUFvQixDQUNoQyxTQUF5QixFQUN6QixZQUFvQixFQUNwQixNQUFjLEVBQ2QsYUFBNEI7UUFFNUIsSUFBSSxDQUFDO1lBQ0gsdUNBQXVDO1lBQ3ZDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxDQUFDLFlBQVk7WUFDdEMsTUFBTSxlQUFlLEdBQUcsR0FBRyxDQUFDLENBQUMsU0FBUztZQUV0QyxNQUFNLGVBQWUsR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQ25ELFdBQVcsRUFBRSxXQUFXO2dCQUN4QixNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUM7Z0JBQ3BDLE9BQU8sRUFBRTtvQkFDUCxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRTtvQkFDNUMsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0sNEJBQTRCLEVBQUU7aUJBQ3JFO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQ3JELFdBQVcsRUFBRSxXQUFXO2dCQUN4QixNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUM7Z0JBQ3BDLE9BQU8sRUFBRTtvQkFDUCxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRTtvQkFDNUMsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxHQUFHLE1BQU0seUJBQXlCLEVBQUU7aUJBQ2xFO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsSUFBSSxlQUFlLEtBQUssSUFBSSxJQUFJLGlCQUFpQixLQUFLLElBQUksRUFBRSxDQUFDO2dCQUMzRCxPQUFPO29CQUNMLE1BQU0sRUFBRSxDQUFDO29CQUNULFFBQVEsRUFBRSxLQUFLO29CQUNmLFVBQVUsRUFBRSxTQUFTO29CQUNyQixXQUFXLEVBQUUsQ0FBQyw0Q0FBNEMsQ0FBQztpQkFDNUQsQ0FBQztZQUNKLENBQUM7WUFFRCxNQUFNLGFBQWEsR0FBRyxHQUFHLENBQUM7WUFDMUIsTUFBTSxRQUFRLEdBQUcsV0FBVyxHQUFHLGVBQWUsR0FBRyxhQUFhLEdBQUcsWUFBWSxDQUFDO1lBQzlFLE1BQU0sVUFBVSxHQUFHLGVBQWUsR0FBRyxpQkFBaUIsR0FBRyxhQUFhLEdBQUcsWUFBWSxDQUFDO1lBQ3RGLE1BQU0sV0FBVyxHQUFHLFFBQVEsR0FBRyxVQUFVLENBQUM7WUFFMUMsT0FBTztnQkFDTCxNQUFNLEVBQUUsV0FBVztnQkFDbkIsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsVUFBVSxFQUFFLFFBQVE7Z0JBQ3BCLFdBQVcsRUFBRTtvQkFDWCxHQUFHLFlBQVksa0JBQWtCO29CQUNqQyxXQUFXLFdBQVcsZ0JBQWdCO29CQUN0QyxXQUFXLGVBQWUscUJBQXFCO29CQUMvQyxXQUFXLGFBQWEsbUNBQW1DO29CQUMzRCxxQkFBcUI7b0JBQ3JCLGlEQUFpRDtpQkFDbEQ7YUFDRixDQUFDO1FBQ0osQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixPQUFPO2dCQUNMLE1BQU0sRUFBRSxDQUFDO2dCQUNULFFBQVEsRUFBRSxLQUFLO2dCQUNmLFVBQVUsRUFBRSxTQUFTO2dCQUNyQixXQUFXLEVBQUUsQ0FBQyw0QkFBNEIsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7YUFDcEcsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRU8sZ0JBQWdCLENBQUMsWUFBb0I7UUFDM0MsT0FBTztZQUNMLE1BQU0sRUFBRSxDQUFDO1lBQ1QsUUFBUSxFQUFFLEtBQUs7WUFDZixVQUFVLEVBQUUsS0FBSztZQUNqQixXQUFXLEVBQUU7Z0JBQ1gsR0FBRyxZQUFZLHFDQUFxQztnQkFDcEQsMERBQTBEO2dCQUMxRCxnREFBZ0Q7Z0JBQ2hELHdFQUF3RTthQUN6RTtTQUNGLENBQUM7SUFDSixDQUFDO0lBRU8sZUFBZSxDQUFDLE1BQWM7UUFDcEMsTUFBTSxTQUFTLEdBQTJCO1lBQ3hDLFdBQVcsRUFBRSx1QkFBdUI7WUFDcEMsV0FBVyxFQUFFLGdCQUFnQjtZQUM3QixXQUFXLEVBQUUseUJBQXlCO1lBQ3RDLFdBQVcsRUFBRSxrQkFBa0I7WUFDL0IsV0FBVyxFQUFFLGNBQWM7WUFDM0IsV0FBVyxFQUFFLGFBQWE7WUFDMUIsV0FBVyxFQUFFLFlBQVk7WUFDekIsY0FBYyxFQUFFLGdCQUFnQjtZQUNoQyxZQUFZLEVBQUUsZ0JBQWdCO1lBQzlCLFlBQVksRUFBRSx1QkFBdUI7WUFDckMsZ0JBQWdCLEVBQUUsMEJBQTBCO1lBQzVDLGdCQUFnQixFQUFFLHVCQUF1QjtZQUN6QyxnQkFBZ0IsRUFBRSxzQkFBc0I7WUFDeEMsZ0JBQWdCLEVBQUUsc0JBQXNCO1NBQ3pDLENBQUM7UUFFRixPQUFPLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxNQUFNLENBQUM7SUFDckMsQ0FBQztDQUNGO0FBL0hELHNDQStIQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGNsYXNzIEVDU0NhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gcmVzb3VyY2VUeXBlID09PSAnQVdTOjpFQ1M6OlNlcnZpY2UnO1xuICB9XG5cbiAgYXN5bmMgY2FsY3VsYXRlQ29zdChcbiAgICByZXNvdXJjZTogUmVzb3VyY2VXaXRoSWQsXG4gICAgcmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpY2luZ0NsaWVudDogUHJpY2luZ0NsaWVudCxcbiAgKTogUHJvbWlzZTxNb250aGx5Q29zdD4ge1xuICAgIGNvbnN0IGRlc2lyZWRDb3VudCA9IChyZXNvdXJjZS5wcm9wZXJ0aWVzLkRlc2lyZWRDb3VudCBhcyBudW1iZXIpIHx8IDE7XG4gICAgY29uc3QgbGF1bmNoVHlwZSA9IChyZXNvdXJjZS5wcm9wZXJ0aWVzLkxhdW5jaFR5cGUgYXMgc3RyaW5nKSB8fCAnRkFSR0FURSc7XG5cbiAgICBpZiAobGF1bmNoVHlwZSA9PT0gJ0ZBUkdBVEUnKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWxjdWxhdGVGYXJnYXRlQ29zdChyZXNvdXJjZSwgZGVzaXJlZENvdW50LCByZWdpb24sIHByaWNpbmdDbGllbnQpO1xuICAgIH0gZWxzZSBpZiAobGF1bmNoVHlwZSA9PT0gJ0VDMicpIHtcbiAgICAgIHJldHVybiB0aGlzLmNhbGN1bGF0ZUVDMkNvc3QoZGVzaXJlZENvdW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgVW5zdXBwb3J0ZWQgbGF1bmNoIHR5cGU6ICR7bGF1bmNoVHlwZX1gXSxcbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBjYWxjdWxhdGVGYXJnYXRlQ29zdChcbiAgICBfcmVzb3VyY2U6IFJlc291cmNlV2l0aElkLFxuICAgIGRlc2lyZWRDb3VudDogbnVtYmVyLFxuICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgIHByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICB0cnkge1xuICAgICAgLy8gRGVmYXVsdCBhc3N1bXB0aW9ucyBmb3IgRmFyZ2F0ZSB0YXNrXG4gICAgICBjb25zdCBhc3N1bWVkVkNwdSA9IDAuMjU7IC8vIDAuMjUgdkNQVVxuICAgICAgY29uc3QgYXNzdW1lZE1lbW9yeUdCID0gMC41OyAvLyAwLjUgR0JcblxuICAgICAgY29uc3QgdkNwdUNvc3RQZXJIb3VyID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uRUNTJyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbXG4gICAgICAgICAgeyBmaWVsZDogJ3Byb2R1Y3RGYW1pbHknLCB2YWx1ZTogJ0NvbXB1dGUnIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ3VzYWdldHlwZScsIHZhbHVlOiBgJHtyZWdpb259LUZhcmdhdGUtdkNQVS1Ib3VyczpwZXJDUFVgIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgbWVtb3J5Q29zdFBlckhvdXIgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25FQ1MnLFxuICAgICAgICByZWdpb246IHRoaXMubm9ybWFsaXplUmVnaW9uKHJlZ2lvbiksXG4gICAgICAgIGZpbHRlcnM6IFtcbiAgICAgICAgICB7IGZpZWxkOiAncHJvZHVjdEZhbWlseScsIHZhbHVlOiAnQ29tcHV0ZScgfSxcbiAgICAgICAgICB7IGZpZWxkOiAndXNhZ2V0eXBlJywgdmFsdWU6IGAke3JlZ2lvbn0tRmFyZ2F0ZS1HQi1Ib3VyczpwZXJHQmAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAodkNwdUNvc3RQZXJIb3VyID09PSBudWxsIHx8IG1lbW9yeUNvc3RQZXJIb3VyID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgICAgYXNzdW1wdGlvbnM6IFsnUHJpY2luZyBkYXRhIG5vdCBhdmFpbGFibGUgZm9yIEVDUyBGYXJnYXRlJ10sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGhvdXJzUGVyTW9udGggPSA3MzA7XG4gICAgICBjb25zdCB2Q3B1Q29zdCA9IGFzc3VtZWRWQ3B1ICogdkNwdUNvc3RQZXJIb3VyICogaG91cnNQZXJNb250aCAqIGRlc2lyZWRDb3VudDtcbiAgICAgIGNvbnN0IG1lbW9yeUNvc3QgPSBhc3N1bWVkTWVtb3J5R0IgKiBtZW1vcnlDb3N0UGVySG91ciAqIGhvdXJzUGVyTW9udGggKiBkZXNpcmVkQ291bnQ7XG4gICAgICBjb25zdCBtb250aGx5Q29zdCA9IHZDcHVDb3N0ICsgbWVtb3J5Q29zdDtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICBgJHtkZXNpcmVkQ291bnR9IHRhc2socykgcnVubmluZ2AsXG4gICAgICAgICAgYEFzc3VtZXMgJHthc3N1bWVkVkNwdX0gdkNQVSBwZXIgdGFza2AsXG4gICAgICAgICAgYEFzc3VtZXMgJHthc3N1bWVkTWVtb3J5R0J9IEdCIG1lbW9yeSBwZXIgdGFza2AsXG4gICAgICAgICAgYEFzc3VtZXMgJHtob3Vyc1Blck1vbnRofSBob3VycyBwZXIgbW9udGggKDI0Lzcgb3BlcmF0aW9uKWAsXG4gICAgICAgICAgJ0ZhcmdhdGUgbGF1bmNoIHR5cGUnLFxuICAgICAgICAgICdEb2VzIG5vdCBpbmNsdWRlIGRhdGEgdHJhbnNmZXIgb3Igc3RvcmFnZSBjb3N0cycsXG4gICAgICAgIF0sXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICBhc3N1bXB0aW9uczogW2BGYWlsZWQgdG8gZmV0Y2ggcHJpY2luZzogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YF0sXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgY2FsY3VsYXRlRUMyQ29zdChkZXNpcmVkQ291bnQ6IG51bWJlcik6IE1vbnRobHlDb3N0IHtcbiAgICByZXR1cm4ge1xuICAgICAgYW1vdW50OiAwLFxuICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgY29uZmlkZW5jZTogJ2xvdycsXG4gICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICBgJHtkZXNpcmVkQ291bnR9IHRhc2socykgcnVubmluZyBvbiBFQzIgbGF1bmNoIHR5cGVgLFxuICAgICAgICAnRUMyIGxhdW5jaCB0eXBlIGNvc3RzIGRlcGVuZCBvbiB1bmRlcmx5aW5nIEVDMiBpbnN0YW5jZXMnLFxuICAgICAgICAnUmVmZXIgdG8gRUMyIGluc3RhbmNlIGNvc3RzIGZvciBhY3R1YWwgcHJpY2luZycsXG4gICAgICAgICdEb2VzIG5vdCBpbmNsdWRlIEVDUyB0YXNrLXNwZWNpZmljIGNvc3RzIChtaW5pbWFsIGZvciBFQzIgbGF1bmNoIHR5cGUpJyxcbiAgICAgIF0sXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplUmVnaW9uKHJlZ2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCByZWdpb25NYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAndXMtZWFzdC0xJzogJ1VTIEVhc3QgKE4uIFZpcmdpbmlhKScsXG4gICAgICAndXMtZWFzdC0yJzogJ1VTIEVhc3QgKE9oaW8pJyxcbiAgICAgICd1cy13ZXN0LTEnOiAnVVMgV2VzdCAoTi4gQ2FsaWZvcm5pYSknLFxuICAgICAgJ3VzLXdlc3QtMic6ICdVUyBXZXN0IChPcmVnb24pJyxcbiAgICAgICdldS13ZXN0LTEnOiAnRVUgKElyZWxhbmQpJyxcbiAgICAgICdldS13ZXN0LTInOiAnRVUgKExvbmRvbiknLFxuICAgICAgJ2V1LXdlc3QtMyc6ICdFVSAoUGFyaXMpJyxcbiAgICAgICdldS1jZW50cmFsLTEnOiAnRVUgKEZyYW5rZnVydCknLFxuICAgICAgJ2V1LW5vcnRoLTEnOiAnRVUgKFN0b2NraG9sbSknLFxuICAgICAgJ2FwLXNvdXRoLTEnOiAnQXNpYSBQYWNpZmljIChNdW1iYWkpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFNpbmdhcG9yZSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU3lkbmV5KScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChUb2t5byknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU2VvdWwpJyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlZ2lvbk1hcFtyZWdpb25dIHx8IHJlZ2lvbjtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class ElastiCacheCalculator implements ResourceCostCalculator {
|
|
4
|
+
supports(resourceType: string): boolean;
|
|
5
|
+
calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
6
|
+
private normalizeEngine;
|
|
7
|
+
private normalizeRegion;
|
|
8
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ElastiCacheCalculator = void 0;
|
|
4
|
+
class ElastiCacheCalculator {
|
|
5
|
+
supports(resourceType) {
|
|
6
|
+
return resourceType === 'AWS::ElastiCache::CacheCluster';
|
|
7
|
+
}
|
|
8
|
+
async calculateCost(resource, region, pricingClient) {
|
|
9
|
+
const cacheNodeType = resource.properties.CacheNodeType;
|
|
10
|
+
const engine = resource.properties.Engine;
|
|
11
|
+
const numCacheNodes = resource.properties.NumCacheNodes || 1;
|
|
12
|
+
const azMode = resource.properties.AZMode;
|
|
13
|
+
if (!cacheNodeType || !engine) {
|
|
14
|
+
return {
|
|
15
|
+
amount: 0,
|
|
16
|
+
currency: 'USD',
|
|
17
|
+
confidence: 'unknown',
|
|
18
|
+
assumptions: ['Cache node type or engine not specified'],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
// Query AWS Pricing API for node hourly rates
|
|
23
|
+
const hourlyRate = await pricingClient.getPrice({
|
|
24
|
+
serviceCode: 'AmazonElastiCache',
|
|
25
|
+
region: this.normalizeRegion(region),
|
|
26
|
+
filters: [
|
|
27
|
+
{ field: 'instanceType', value: cacheNodeType },
|
|
28
|
+
{ field: 'cacheEngine', value: this.normalizeEngine(engine) },
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
if (hourlyRate === null) {
|
|
32
|
+
return {
|
|
33
|
+
amount: 0,
|
|
34
|
+
currency: 'USD',
|
|
35
|
+
confidence: 'unknown',
|
|
36
|
+
assumptions: [
|
|
37
|
+
`Pricing data not available for node type ${cacheNodeType} with engine ${engine} in region ${region}`,
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const monthlyHours = 730;
|
|
42
|
+
const perNodeCost = hourlyRate * monthlyHours;
|
|
43
|
+
let totalCost = perNodeCost * numCacheNodes;
|
|
44
|
+
const assumptions = [
|
|
45
|
+
`Assumes ${monthlyHours} hours per month (24/7 operation)`,
|
|
46
|
+
`Node type: ${cacheNodeType}`,
|
|
47
|
+
`Engine: ${engine}`,
|
|
48
|
+
`Number of cache nodes: ${numCacheNodes}`,
|
|
49
|
+
`Per-node monthly cost: $${perNodeCost.toFixed(2)}`,
|
|
50
|
+
];
|
|
51
|
+
// Account for multi-AZ replica costs when configured
|
|
52
|
+
if (azMode === 'cross-az') {
|
|
53
|
+
// Multi-AZ adds replica nodes (typically doubles the cost)
|
|
54
|
+
totalCost *= 2;
|
|
55
|
+
assumptions.push('Multi-AZ deployment with replica nodes (cost doubled)');
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
assumptions.push('Single-AZ deployment');
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
amount: totalCost,
|
|
62
|
+
currency: 'USD',
|
|
63
|
+
confidence: 'high',
|
|
64
|
+
assumptions,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
return {
|
|
69
|
+
amount: 0,
|
|
70
|
+
currency: 'USD',
|
|
71
|
+
confidence: 'unknown',
|
|
72
|
+
assumptions: [
|
|
73
|
+
`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`,
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
normalizeEngine(engine) {
|
|
79
|
+
const engineMap = {
|
|
80
|
+
redis: 'Redis',
|
|
81
|
+
memcached: 'Memcached',
|
|
82
|
+
};
|
|
83
|
+
return engineMap[engine.toLowerCase()] || engine;
|
|
84
|
+
}
|
|
85
|
+
normalizeRegion(region) {
|
|
86
|
+
const regionMap = {
|
|
87
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
88
|
+
'us-east-2': 'US East (Ohio)',
|
|
89
|
+
'us-west-1': 'US West (N. California)',
|
|
90
|
+
'us-west-2': 'US West (Oregon)',
|
|
91
|
+
'eu-west-1': 'EU (Ireland)',
|
|
92
|
+
'eu-west-2': 'EU (London)',
|
|
93
|
+
'eu-west-3': 'EU (Paris)',
|
|
94
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
95
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
96
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
97
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
98
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
99
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
100
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
101
|
+
};
|
|
102
|
+
return regionMap[region] || region;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.ElastiCacheCalculator = ElastiCacheCalculator;
|
|
106
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRWxhc3RpQ2FjaGVDYWxjdWxhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ByaWNpbmcvY2FsY3VsYXRvcnMvRWxhc3RpQ2FjaGVDYWxjdWxhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUdBLE1BQWEscUJBQXFCO0lBQ2hDLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLFlBQVksS0FBSyxnQ0FBZ0MsQ0FBQztJQUMzRCxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQyxVQUFVLENBQUMsYUFBdUIsQ0FBQztRQUNsRSxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLE1BQWdCLENBQUM7UUFDcEQsTUFBTSxhQUFhLEdBQUksUUFBUSxDQUFDLFVBQVUsQ0FBQyxhQUF3QixJQUFJLENBQUMsQ0FBQztRQUN6RSxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLE1BQWdCLENBQUM7UUFFcEQsSUFBSSxDQUFDLGFBQWEsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzlCLE9BQU87Z0JBQ0wsTUFBTSxFQUFFLENBQUM7Z0JBQ1QsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsVUFBVSxFQUFFLFNBQVM7Z0JBQ3JCLFdBQVcsRUFBRSxDQUFDLHlDQUF5QyxDQUFDO2FBQ3pELENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsOENBQThDO1lBQzlDLE1BQU0sVUFBVSxHQUFHLE1BQU0sYUFBYSxDQUFDLFFBQVEsQ0FBQztnQkFDOUMsV0FBVyxFQUFFLG1CQUFtQjtnQkFDaEMsTUFBTSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDO2dCQUNwQyxPQUFPLEVBQUU7b0JBQ1AsRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxhQUFhLEVB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dXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbmV4cG9ydCBjbGFzcyBFbGFzdGlDYWNoZUNhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gcmVzb3VyY2VUeXBlID09PSAnQVdTOjpFbGFzdGlDYWNoZTo6Q2FjaGVDbHVzdGVyJztcbiAgfVxuXG4gIGFzeW5jIGNhbGN1bGF0ZUNvc3QoXG4gICAgcmVzb3VyY2U6IFJlc291cmNlV2l0aElkLFxuICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgIHByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICBjb25zdCBjYWNoZU5vZGVUeXBlID0gcmVzb3VyY2UucHJvcGVydGllcy5DYWNoZU5vZGVUeXBlIGFzIHN0cmluZztcbiAgICBjb25zdCBlbmdpbmUgPSByZXNvdXJjZS5wcm9wZXJ0aWVzLkVuZ2luZSBhcyBzdHJpbmc7XG4gICAgY29uc3QgbnVtQ2FjaGVOb2RlcyA9IChyZXNvdXJjZS5wcm9wZXJ0aWVzLk51bUNhY2hlTm9kZXMgYXMgbnVtYmVyKSB8fCAxO1xuICAgIGNvbnN0IGF6TW9kZSA9IHJlc291cmNlLnByb3BlcnRpZXMuQVpNb2RlIGFzIHN0cmluZztcblxuICAgIGlmICghY2FjaGVOb2RlVHlwZSB8fCAhZW5naW5lKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICBhc3N1bXB0aW9uczogWydDYWNoZSBub2RlIHR5cGUgb3IgZW5naW5lIG5vdCBzcGVjaWZpZWQnXSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFF1ZXJ5IEFXUyBQcmljaW5nIEFQSSBmb3Igbm9kZSBob3VybHkgcmF0ZXNcbiAgICAgIGNvbnN0IGhvdXJseVJhdGUgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25FbGFzdGlDYWNoZScsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdpbnN0YW5jZVR5cGUnLCB2YWx1ZTogY2FjaGVOb2RlVHlwZSB9LFxuICAgICAgICAgIHsgZmllbGQ6ICdjYWNoZUVuZ2luZScsIHZhbHVlOiB0aGlzLm5vcm1hbGl6ZUVuZ2luZShlbmdpbmUpIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcblxuICAgICAgaWYgKGhvdXJseVJhdGUgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICAgICAgYFByaWNpbmcgZGF0YSBub3QgYXZhaWxhYmxlIGZvciBub2RlIHR5cGUgJHtjYWNoZU5vZGVUeXBlfSB3aXRoIGVuZ2luZSAke2VuZ2luZX0gaW4gcmVnaW9uICR7cmVnaW9ufWAsXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbW9udGhseUhvdXJzID0gNzMwO1xuICAgICAgY29uc3QgcGVyTm9kZUNvc3QgPSBob3VybHlSYXRlICogbW9udGhseUhvdXJzO1xuICAgICAgbGV0IHRvdGFsQ29zdCA9IHBlck5vZGVDb3N0ICogbnVtQ2FjaGVOb2RlcztcblxuICAgICAgY29uc3QgYXNzdW1wdGlvbnMgPSBbXG4gICAgICAgIGBBc3N1bWVzICR7bW9udGhseUhvdXJzfSBob3VycyBwZXIgbW9udGggKDI0Lzcgb3BlcmF0aW9uKWAsXG4gICAgICAgIGBOb2RlIHR5cGU6ICR7Y2FjaGVOb2RlVHlwZX1gLFxuICAgICAgICBgRW5naW5lOiAke2VuZ2luZX1gLFxuICAgICAgICBgTnVtYmVyIG9mIGNhY2hlIG5vZGVzOiAke251bUNhY2hlTm9kZXN9YCxcbiAgICAgICAgYFBlci1ub2RlIG1vbnRobHkgY29zdDogJCR7cGVyTm9kZUNvc3QudG9GaXhlZCgyKX1gLFxuICAgICAgXTtcblxuICAgICAgLy8gQWNjb3VudCBmb3IgbXVsdGktQVogcmVwbGljYSBjb3N0cyB3aGVuIGNvbmZpZ3VyZWRcbiAgICAgIGlmIChhek1vZGUgPT09ICdjcm9zcy1heicpIHtcbiAgICAgICAgLy8gTXVsdGktQVogYWRkcyByZXBsaWNhIG5vZGVzICh0eXBpY2FsbHkgZG91YmxlcyB0aGUgY29zdClcbiAgICAgICAgdG90YWxDb3N0ICo9IDI7XG4gICAgICAgIGFzc3VtcHRpb25zLnB1c2goJ011bHRpLUFaIGRlcGxveW1lbnQgd2l0aCByZXBsaWNhIG5vZGVzIChjb3N0IGRvdWJsZWQpJyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhc3N1bXB0aW9ucy5wdXNoKCdTaW5nbGUtQVogZGVwbG95bWVudCcpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IHRvdGFsQ29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnaGlnaCcsXG4gICAgICAgIGFzc3VtcHRpb25zLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICBgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWAsXG4gICAgICAgIF0sXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplRW5naW5lKGVuZ2luZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBlbmdpbmVNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICByZWRpczogJ1JlZGlzJyxcbiAgICAgIG1lbWNhY2hlZDogJ01lbWNhY2hlZCcsXG4gICAgfTtcblxuICAgIHJldHVybiBlbmdpbmVNYXBbZW5naW5lLnRvTG93ZXJDYXNlKCldIHx8IGVuZ2luZTtcbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplUmVnaW9uKHJlZ2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCByZWdpb25NYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAndXMtZWFzdC0xJzogJ1VTIEVhc3QgKE4uIFZpcmdpbmlhKScsXG4gICAgICAndXMtZWFzdC0yJzogJ1VTIEVhc3QgKE9oaW8pJyxcbiAgICAgICd1cy13ZXN0LTEnOiAnVVMgV2VzdCAoTi4gQ2FsaWZvcm5pYSknLFxuICAgICAgJ3VzLXdlc3QtMic6ICdVUyBXZXN0IChPcmVnb24pJyxcbiAgICAgICdldS13ZXN0LTEnOiAnRVUgKElyZWxhbmQpJyxcbiAgICAgICdldS13ZXN0LTInOiAnRVUgKExvbmRvbiknLFxuICAgICAgJ2V1LXdlc3QtMyc6ICdFVSAoUGFyaXMpJyxcbiAgICAgICdldS1jZW50cmFsLTEnOiAnRVUgKEZyYW5rZnVydCknLFxuICAgICAgJ2V1LW5vcnRoLTEnOiAnRVUgKFN0b2NraG9sbSknLFxuICAgICAgJ2FwLXNvdXRoLTEnOiAnQXNpYSBQYWNpZmljIChNdW1iYWkpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFNpbmdhcG9yZSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU3lkbmV5KScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChUb2t5byknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU2VvdWwpJyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlZ2lvbk1hcFtyZWdpb25dIHx8IHJlZ2lvbjtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class LambdaCalculator implements ResourceCostCalculator {
|
|
4
|
+
private readonly customInvocationsPerMonth?;
|
|
5
|
+
private readonly customAverageDurationMs?;
|
|
6
|
+
private readonly DEFAULT_INVOCATIONS;
|
|
7
|
+
private readonly DEFAULT_DURATION_MS;
|
|
8
|
+
private readonly DEFAULT_MEMORY_MB;
|
|
9
|
+
constructor(customInvocationsPerMonth?: number | undefined, customAverageDurationMs?: number | undefined);
|
|
10
|
+
supports(resourceType: string): boolean;
|
|
11
|
+
calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
12
|
+
private normalizeRegion;
|
|
13
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LambdaCalculator = void 0;
|
|
4
|
+
class LambdaCalculator {
|
|
5
|
+
customInvocationsPerMonth;
|
|
6
|
+
customAverageDurationMs;
|
|
7
|
+
DEFAULT_INVOCATIONS = 1000000;
|
|
8
|
+
DEFAULT_DURATION_MS = 1000;
|
|
9
|
+
DEFAULT_MEMORY_MB = 128;
|
|
10
|
+
constructor(customInvocationsPerMonth, customAverageDurationMs) {
|
|
11
|
+
this.customInvocationsPerMonth = customInvocationsPerMonth;
|
|
12
|
+
this.customAverageDurationMs = customAverageDurationMs;
|
|
13
|
+
}
|
|
14
|
+
supports(resourceType) {
|
|
15
|
+
return resourceType === 'AWS::Lambda::Function';
|
|
16
|
+
}
|
|
17
|
+
async calculateCost(resource, region, pricingClient) {
|
|
18
|
+
const memorySize = resource.properties.MemorySize || this.DEFAULT_MEMORY_MB;
|
|
19
|
+
const invocations = this.customInvocationsPerMonth ?? this.DEFAULT_INVOCATIONS;
|
|
20
|
+
const durationMs = this.customAverageDurationMs ?? this.DEFAULT_DURATION_MS;
|
|
21
|
+
try {
|
|
22
|
+
const requestPrice = await pricingClient.getPrice({
|
|
23
|
+
serviceCode: 'AWSLambda',
|
|
24
|
+
region: this.normalizeRegion(region),
|
|
25
|
+
filters: [
|
|
26
|
+
{ field: 'group', value: 'AWS-Lambda-Requests' },
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
const computePrice = await pricingClient.getPrice({
|
|
30
|
+
serviceCode: 'AWSLambda',
|
|
31
|
+
region: this.normalizeRegion(region),
|
|
32
|
+
filters: [
|
|
33
|
+
{ field: 'group', value: 'AWS-Lambda-Duration' },
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
const assumptions = [
|
|
37
|
+
`Assumes ${invocations.toLocaleString()} invocations per month`,
|
|
38
|
+
`Assumes ${durationMs}ms average execution time`,
|
|
39
|
+
`Assumes ${memorySize}MB memory allocation`,
|
|
40
|
+
];
|
|
41
|
+
if (this.customInvocationsPerMonth !== undefined) {
|
|
42
|
+
assumptions.push('Using custom invocation count assumption from configuration');
|
|
43
|
+
}
|
|
44
|
+
if (this.customAverageDurationMs !== undefined) {
|
|
45
|
+
assumptions.push('Using custom duration assumption from configuration');
|
|
46
|
+
}
|
|
47
|
+
if (requestPrice === null || computePrice === null) {
|
|
48
|
+
return {
|
|
49
|
+
amount: 0,
|
|
50
|
+
currency: 'USD',
|
|
51
|
+
confidence: 'unknown',
|
|
52
|
+
assumptions: [
|
|
53
|
+
`Pricing data not available for Lambda in region ${region}`,
|
|
54
|
+
...assumptions,
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const requestCost = (invocations / 1000000) * requestPrice;
|
|
59
|
+
const gbSeconds = (memorySize / 1024) * (durationMs / 1000) * invocations;
|
|
60
|
+
const computeCost = gbSeconds * computePrice;
|
|
61
|
+
const totalCost = requestCost + computeCost;
|
|
62
|
+
return {
|
|
63
|
+
amount: totalCost,
|
|
64
|
+
currency: 'USD',
|
|
65
|
+
confidence: 'medium',
|
|
66
|
+
assumptions,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
const assumptions = [
|
|
71
|
+
`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`,
|
|
72
|
+
`Would assume ${invocations.toLocaleString()} invocations per month`,
|
|
73
|
+
`Would assume ${durationMs}ms average execution time`,
|
|
74
|
+
`Would assume ${memorySize}MB memory allocation`,
|
|
75
|
+
];
|
|
76
|
+
if (this.customInvocationsPerMonth !== undefined) {
|
|
77
|
+
assumptions.push('Using custom invocation count assumption from configuration');
|
|
78
|
+
}
|
|
79
|
+
if (this.customAverageDurationMs !== undefined) {
|
|
80
|
+
assumptions.push('Using custom duration assumption from configuration');
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
amount: 0,
|
|
84
|
+
currency: 'USD',
|
|
85
|
+
confidence: 'unknown',
|
|
86
|
+
assumptions,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
normalizeRegion(region) {
|
|
91
|
+
const regionMap = {
|
|
92
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
93
|
+
'us-east-2': 'US East (Ohio)',
|
|
94
|
+
'us-west-1': 'US West (N. California)',
|
|
95
|
+
'us-west-2': 'US West (Oregon)',
|
|
96
|
+
'eu-west-1': 'EU (Ireland)',
|
|
97
|
+
'eu-west-2': 'EU (London)',
|
|
98
|
+
'eu-west-3': 'EU (Paris)',
|
|
99
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
100
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
101
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
102
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
103
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
104
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
105
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
106
|
+
};
|
|
107
|
+
return regionMap[region] || region;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.LambdaCalculator = LambdaCalculator;
|
|
111
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTGFtYmRhQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcmljaW5nL2NhbGN1bGF0b3JzL0xhbWJkYUNhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSxnQkFBZ0I7SUFNUjtJQUNBO0lBTkYsbUJBQW1CLEdBQUcsT0FBTyxDQUFDO0lBQzlCLG1CQUFtQixHQUFHLElBQUksQ0FBQztJQUMzQixpQkFBaUIsR0FBRyxHQUFHLENBQUM7SUFFekMsWUFDbUIseUJBQWtDLEVBQ2xDLHVCQUFnQztRQURoQyw4QkFBeUIsR0FBekIseUJBQXlCLENBQVM7UUFDbEMsNEJBQXVCLEdBQXZCLHVCQUF1QixDQUFTO0lBQ2hELENBQUM7SUFFSixRQUFRLENBQUMsWUFBb0I7UUFDM0IsT0FBTyxZQUFZLEtBQUssdUJBQXVCLENBQUM7SUFDbEQsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQ2pCLFFBQXdCLEVBQ3hCLE1BQWMsRUFDZCxhQUE0QjtRQUU1QixNQUFNLFVBQVUsR0FBSSxRQUFRLENBQUMsVUFBVSxDQUFDLFVBQXFCLElBQUksSUFBSSxDQUFDLGlCQUFpQixDQUFDO1FBQ3hGLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyx5QkFBeUIsSUFBSSxJQUFJLENBQUMsbUJBQW1CLENBQUM7UUFDL0UsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixJQUFJLElBQUksQ0FBQyxtQkFBbUIsQ0FBQztRQUU1RSxJQUFJLENBQUM7WUFDSCxNQUFNLFlBQVksR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQ2hELFdBQVcsRUFBRSxXQUFXO2dCQUN4QixNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUM7Z0JBQ3BDLE9BQU8sRUFBRTtvQkFDUCxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLHFCQUFxQixFQUFFO2lCQUNqRDthQUNG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V0FBVyxFQUFFLGNBQWM7WUFDM0IsV0FBVyxFQUFFLGFBQWE7WUFDMUIsV0FBVyxFQUFFLFlBQVk7WUFDekIsY0FBYyxFQUFFLGdCQUFnQjtZQUNoQyxZQUFZLEVBQUUsZ0JBQWdCO1lBQzlCLFlBQVksRUFBRSx1QkFBdUI7WUFDckMsZ0JBQWdCLEVBQUUsMEJBQTBCO1lBQzVDLGdCQUFnQixFQUFFLHVCQUF1QjtZQUN6QyxnQkFBZ0IsRUFBRSxzQkFBc0I7WUFDeEMsZ0JBQWdCLEVBQUUsc0JBQXNCO1NBQ3pDLENBQUM7UUFFRixPQUFPLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxNQUFNLENBQUM7SUFDckMsQ0FBQztDQUNGO0FBMUhELDRDQTBIQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGNsYXNzIExhbWJkYUNhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX0lOVk9DQVRJT05TID0gMTAwMDAwMDtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX0RVUkFUSU9OX01TID0gMTAwMDtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX01FTU9SWV9NQiA9IDEyODtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IGN1c3RvbUludm9jYXRpb25zUGVyTW9udGg/OiBudW1iZXIsXG4gICAgcHJpdmF0ZSByZWFkb25seSBjdXN0b21BdmVyYWdlRHVyYXRpb25Ncz86IG51bWJlcixcbiAgKSB7fVxuXG4gIHN1cHBvcnRzKHJlc291cmNlVHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbic7XG4gIH1cblxuICBhc3luYyBjYWxjdWxhdGVDb3N0KFxuICAgIHJlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgY29uc3QgbWVtb3J5U2l6ZSA9IChyZXNvdXJjZS5wcm9wZXJ0aWVzLk1lbW9yeVNpemUgYXMgbnVtYmVyKSB8fCB0aGlzLkRFRkFVTFRfTUVNT1JZX01CO1xuICAgIGNvbnN0IGludm9jYXRpb25zID0gdGhpcy5jdXN0b21JbnZvY2F0aW9uc1Blck1vbnRoID8/IHRoaXMuREVGQVVMVF9JTlZPQ0FUSU9OUztcbiAgICBjb25zdCBkdXJhdGlvbk1zID0gdGhpcy5jdXN0b21BdmVyYWdlRHVyYXRpb25NcyA/PyB0aGlzLkRFRkFVTFRfRFVSQVRJT05fTVM7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVxdWVzdFByaWNlID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQVdTTGFtYmRhJyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbXG4gICAgICAgICAgeyBmaWVsZDogJ2dyb3VwJywgdmFsdWU6ICdBV1MtTGFtYmRhLVJlcXVlc3RzJyB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IGNvbXB1dGVQcmljZSA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgICBzZXJ2aWNlQ29kZTogJ0FXU0xhbWJkYScsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdncm91cCcsIHZhbHVlOiAnQVdTLUxhbWJkYS1EdXJhdGlvbicgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBhc3N1bXB0aW9ucyA9IFtcbiAgICAgICAgYEFzc3VtZXMgJHtpbnZvY2F0aW9ucy50b0xvY2FsZVN0cmluZygpfSBpbnZvY2F0aW9ucyBwZXIgbW9udGhgLFxuICAgICAgICBgQXNzdW1lcyAke2R1cmF0aW9uTXN9bXMgYXZlcmFnZSBleGVjdXRpb24gdGltZWAsXG4gICAgICAgIGBBc3N1bWVzICR7bWVtb3J5U2l6ZX1NQiBtZW1vcnkgYWxsb2NhdGlvbmAsXG4gICAgICBdO1xuXG4gICAgICBpZiAodGhpcy5jdXN0b21JbnZvY2F0aW9uc1Blck1vbnRoICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYXNzdW1wdGlvbnMucHVzaCgnVXNpbmcgY3VzdG9tIGludm9jYXRpb24gY291bnQgYXNzdW1wdGlvbiBmcm9tIGNvbmZpZ3VyYXRpb24nKTtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLmN1c3RvbUF2ZXJhZ2VEdXJhdGlvbk1zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYXNzdW1wdGlvbnMucHVzaCgnVXNpbmcgY3VzdG9tIGR1cmF0aW9uIGFzc3VtcHRpb24gZnJvbSBjb25maWd1cmF0aW9uJyk7XG4gICAgICB9XG5cbiAgICAgIGlmIChyZXF1ZXN0UHJpY2UgPT09IG51bGwgfHwgY29tcHV0ZVByaWNlID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgICBjb25maWRlbmNlOiAndW5rbm93bicsXG4gICAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICAgIGBQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgTGFtYmRhIGluIHJlZ2lvbiAke3JlZ2lvbn1gLFxuICAgICAgICAgICAgLi4uYXNzdW1wdGlvbnMsXG4gICAgICAgICAgXSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVxdWVzdENvc3QgPSAoaW52b2NhdGlvbnMgLyAxMDAwMDAwKSAqIHJlcXVlc3RQcmljZTtcblxuICAgICAgY29uc3QgZ2JTZWNvbmRzID0gKG1lbW9yeVNpemUgLyAxMDI0KSAqIChkdXJhdGlvbk1zIC8gMTAwMCkgKiBpbnZvY2F0aW9ucztcbiAgICAgIGNvbnN0IGNvbXB1dGVDb3N0ID0gZ2JTZWNvbmRzICogY29tcHV0ZVByaWNlO1xuXG4gICAgICBjb25zdCB0b3RhbENvc3QgPSByZXF1ZXN0Q29zdCArIGNvbXB1dGVDb3N0O1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IHRvdGFsQ29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgICAgYXNzdW1wdGlvbnMsXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCBhc3N1bXB0aW9ucyA9IFtcbiAgICAgICAgYEZhaWxlZCB0byBmZXRjaCBwcmljaW5nOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gLFxuICAgICAgICBgV291bGQgYXNzdW1lICR7aW52b2NhdGlvbnMudG9Mb2NhbGVTdHJpbmcoKX0gaW52b2NhdGlvbnMgcGVyIG1vbnRoYCxcbiAgICAgICAgYFdvdWxkIGFzc3VtZSAke2R1cmF0aW9uTXN9bXMgYXZlcmFnZSBleGVjdXRpb24gdGltZWAsXG4gICAgICAgIGBXb3VsZCBhc3N1bWUgJHttZW1vcnlTaXplfU1CIG1lbW9yeSBhbGxvY2F0aW9uYCxcbiAgICAgIF07XG5cbiAgICAgIGlmICh0aGlzLmN1c3RvbUludm9jYXRpb25zUGVyTW9udGggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBhc3N1bXB0aW9ucy5wdXNoKCdVc2luZyBjdXN0b20gaW52b2NhdGlvbiBjb3VudCBhc3N1bXB0aW9uIGZyb20gY29uZmlndXJhdGlvbicpO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuY3VzdG9tQXZlcmFnZUR1cmF0aW9uTXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBhc3N1bXB0aW9ucy5wdXNoKCdVc2luZyBjdXN0b20gZHVyYXRpb24gYXNzdW1wdGlvbiBmcm9tIGNvbmZpZ3VyYXRpb24nKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnMsXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplUmVnaW9uKHJlZ2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCByZWdpb25NYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAndXMtZWFzdC0xJzogJ1VTIEVhc3QgKE4uIFZpcmdpbmlhKScsXG4gICAgICAndXMtZWFzdC0yJzogJ1VTIEVhc3QgKE9oaW8pJyxcbiAgICAgICd1cy13ZXN0LTEnOiAnVVMgV2VzdCAoTi4gQ2FsaWZvcm5pYSknLFxuICAgICAgJ3VzLXdlc3QtMic6ICdVUyBXZXN0IChPcmVnb24pJyxcbiAgICAgICdldS13ZXN0LTEnOiAnRVUgKElyZWxhbmQpJyxcbiAgICAgICdldS13ZXN0LTInOiAnRVUgKExvbmRvbiknLFxuICAgICAgJ2V1LXdlc3QtMyc6ICdFVSAoUGFyaXMpJyxcbiAgICAgICdldS1jZW50cmFsLTEnOiAnRVUgKEZyYW5rZnVydCknLFxuICAgICAgJ2V1LW5vcnRoLTEnOiAnRVUgKFN0b2NraG9sbSknLFxuICAgICAgJ2FwLXNvdXRoLTEnOiAnQXNpYSBQYWNpZmljIChNdW1iYWkpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFNpbmdhcG9yZSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU3lkbmV5KScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChUb2t5byknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU2VvdWwpJyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlZ2lvbk1hcFtyZWdpb25dIHx8IHJlZ2lvbjtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class NLBCalculator implements ResourceCostCalculator {
|
|
4
|
+
private customNewConnectionsPerSecond?;
|
|
5
|
+
private customActiveConnectionsPerMinute?;
|
|
6
|
+
private customProcessedBytesGB?;
|
|
7
|
+
private readonly DEFAULT_NEW_CONNECTIONS_PER_SECOND;
|
|
8
|
+
private readonly DEFAULT_ACTIVE_CONNECTIONS_PER_MINUTE;
|
|
9
|
+
private readonly DEFAULT_PROCESSED_BYTES_GB;
|
|
10
|
+
private readonly HOURS_PER_MONTH;
|
|
11
|
+
constructor(customNewConnectionsPerSecond?: number | undefined, customActiveConnectionsPerMinute?: number | undefined, customProcessedBytesGB?: number | undefined);
|
|
12
|
+
supports(resourceType: string): boolean;
|
|
13
|
+
calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
14
|
+
private normalizeRegion;
|
|
15
|
+
private getRegionPrefix;
|
|
16
|
+
}
|