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,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NLBCalculator = void 0;
|
|
4
|
+
class NLBCalculator {
|
|
5
|
+
customNewConnectionsPerSecond;
|
|
6
|
+
customActiveConnectionsPerMinute;
|
|
7
|
+
customProcessedBytesGB;
|
|
8
|
+
DEFAULT_NEW_CONNECTIONS_PER_SECOND = 25;
|
|
9
|
+
DEFAULT_ACTIVE_CONNECTIONS_PER_MINUTE = 3000;
|
|
10
|
+
DEFAULT_PROCESSED_BYTES_GB = 100;
|
|
11
|
+
HOURS_PER_MONTH = 730;
|
|
12
|
+
constructor(customNewConnectionsPerSecond, customActiveConnectionsPerMinute, customProcessedBytesGB) {
|
|
13
|
+
this.customNewConnectionsPerSecond = customNewConnectionsPerSecond;
|
|
14
|
+
this.customActiveConnectionsPerMinute = customActiveConnectionsPerMinute;
|
|
15
|
+
this.customProcessedBytesGB = customProcessedBytesGB;
|
|
16
|
+
}
|
|
17
|
+
supports(resourceType) {
|
|
18
|
+
return resourceType === 'AWS::ElasticLoadBalancingV2::LoadBalancer';
|
|
19
|
+
}
|
|
20
|
+
async calculateCost(resource, region, pricingClient) {
|
|
21
|
+
// Check if this is a Network Load Balancer
|
|
22
|
+
const loadBalancerType = resource.properties?.Type;
|
|
23
|
+
if (loadBalancerType && loadBalancerType !== 'network') {
|
|
24
|
+
return {
|
|
25
|
+
amount: 0,
|
|
26
|
+
currency: 'USD',
|
|
27
|
+
confidence: 'unknown',
|
|
28
|
+
assumptions: ['This calculator only supports Network Load Balancers'],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
// Get hourly rate
|
|
33
|
+
const hourlyRate = await pricingClient.getPrice({
|
|
34
|
+
serviceCode: 'AWSELB',
|
|
35
|
+
region: this.normalizeRegion(region),
|
|
36
|
+
filters: [
|
|
37
|
+
{ field: 'productFamily', value: 'Load Balancer-Network' },
|
|
38
|
+
{ field: 'usagetype', value: `${this.getRegionPrefix(region)}LoadBalancerUsage` },
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
// Get NLCU rate
|
|
42
|
+
const nlcuRate = await pricingClient.getPrice({
|
|
43
|
+
serviceCode: 'AWSELB',
|
|
44
|
+
region: this.normalizeRegion(region),
|
|
45
|
+
filters: [
|
|
46
|
+
{ field: 'productFamily', value: 'Load Balancer-Network' },
|
|
47
|
+
{ field: 'usagetype', value: `${this.getRegionPrefix(region)}LCUUsage` },
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
if (hourlyRate === null || nlcuRate === null) {
|
|
51
|
+
return {
|
|
52
|
+
amount: 0,
|
|
53
|
+
currency: 'USD',
|
|
54
|
+
confidence: 'unknown',
|
|
55
|
+
assumptions: [
|
|
56
|
+
`Pricing data not available for Network Load Balancer in region ${region}`,
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const newConnectionsPerSecond = this.customNewConnectionsPerSecond || this.DEFAULT_NEW_CONNECTIONS_PER_SECOND;
|
|
61
|
+
const activeConnectionsPerMinute = this.customActiveConnectionsPerMinute || this.DEFAULT_ACTIVE_CONNECTIONS_PER_MINUTE;
|
|
62
|
+
const processedBytesGB = this.customProcessedBytesGB || this.DEFAULT_PROCESSED_BYTES_GB;
|
|
63
|
+
// Calculate NLCU consumption
|
|
64
|
+
// 1 NLCU provides: 800 new connections/sec, 100,000 active connections/min, 1 GB processed/hour
|
|
65
|
+
const nlcuFromNewConnections = newConnectionsPerSecond / 800;
|
|
66
|
+
const nlcuFromActiveConnections = activeConnectionsPerMinute / 100000;
|
|
67
|
+
const gbPerHour = processedBytesGB / this.HOURS_PER_MONTH;
|
|
68
|
+
const nlcuFromProcessedBytes = gbPerHour;
|
|
69
|
+
// Use the highest NLCU consumption
|
|
70
|
+
const nlcuPerHour = Math.max(nlcuFromNewConnections, nlcuFromActiveConnections, nlcuFromProcessedBytes);
|
|
71
|
+
const hourlyCost = hourlyRate * this.HOURS_PER_MONTH;
|
|
72
|
+
const nlcuCost = nlcuRate * nlcuPerHour * this.HOURS_PER_MONTH;
|
|
73
|
+
const totalCost = hourlyCost + nlcuCost;
|
|
74
|
+
return {
|
|
75
|
+
amount: totalCost,
|
|
76
|
+
currency: 'USD',
|
|
77
|
+
confidence: 'medium',
|
|
78
|
+
assumptions: [
|
|
79
|
+
`Hourly rate: $${hourlyRate.toFixed(4)}/hour × ${this.HOURS_PER_MONTH} hours = $${hourlyCost.toFixed(2)}/month`,
|
|
80
|
+
`NLCU consumption: ${nlcuPerHour.toFixed(2)} NLCU/hour based on:`,
|
|
81
|
+
` - New connections: ${newConnectionsPerSecond}/sec → ${nlcuFromNewConnections.toFixed(2)} NLCU`,
|
|
82
|
+
` - Active connections: ${activeConnectionsPerMinute}/min → ${nlcuFromActiveConnections.toFixed(2)} NLCU`,
|
|
83
|
+
` - Processed data: ${processedBytesGB} GB/month → ${nlcuFromProcessedBytes.toFixed(2)} NLCU`,
|
|
84
|
+
`NLCU cost: $${nlcuRate.toFixed(4)}/NLCU/hour × ${nlcuPerHour.toFixed(2)} NLCU × ${this.HOURS_PER_MONTH} hours = $${nlcuCost.toFixed(2)}/month`,
|
|
85
|
+
`Total: $${totalCost.toFixed(2)}/month`,
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
return {
|
|
91
|
+
amount: 0,
|
|
92
|
+
currency: 'USD',
|
|
93
|
+
confidence: 'unknown',
|
|
94
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
normalizeRegion(region) {
|
|
99
|
+
const regionMap = {
|
|
100
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
101
|
+
'us-east-2': 'US East (Ohio)',
|
|
102
|
+
'us-west-1': 'US West (N. California)',
|
|
103
|
+
'us-west-2': 'US West (Oregon)',
|
|
104
|
+
'eu-west-1': 'EU (Ireland)',
|
|
105
|
+
'eu-west-2': 'EU (London)',
|
|
106
|
+
'eu-west-3': 'EU (Paris)',
|
|
107
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
108
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
109
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
110
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
111
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
112
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
113
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
114
|
+
};
|
|
115
|
+
return regionMap[region] || region;
|
|
116
|
+
}
|
|
117
|
+
getRegionPrefix(region) {
|
|
118
|
+
const prefixMap = {
|
|
119
|
+
'us-east-1': 'USE1',
|
|
120
|
+
'us-east-2': 'USE2',
|
|
121
|
+
'us-west-1': 'USW1',
|
|
122
|
+
'us-west-2': 'USW2',
|
|
123
|
+
'eu-west-1': 'EUW1',
|
|
124
|
+
'eu-west-2': 'EUW2',
|
|
125
|
+
'eu-west-3': 'EUW3',
|
|
126
|
+
'eu-central-1': 'EUC1',
|
|
127
|
+
'eu-north-1': 'EUN1',
|
|
128
|
+
'ap-south-1': 'APS1',
|
|
129
|
+
'ap-southeast-1': 'APS2',
|
|
130
|
+
'ap-southeast-2': 'APS3',
|
|
131
|
+
'ap-northeast-1': 'APN1',
|
|
132
|
+
'ap-northeast-2': 'APN2',
|
|
133
|
+
};
|
|
134
|
+
return prefixMap[region] || '';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.NLBCalculator = NLBCalculator;
|
|
138
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTkxCQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcmljaW5nL2NhbGN1bGF0b3JzL05MQkNhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSxhQUFhO0lBT2Q7SUFDQTtJQUNBO0lBUk8sa0NBQWtDLEdBQUcsRUFBRSxDQUFDO0lBQ3hDLHFDQUFxQyxHQUFHLElBQUksQ0FBQztJQUM3QywwQkFBMEIsR0FBRyxHQUFHLENBQUM7SUFDakMsZUFBZSxHQUFHLEdBQUcsQ0FBQztJQUV2QyxZQUNVLDZCQUFzQyxFQUN0QyxnQ0FBeUMsRUFDekMsc0JBQStCO1FBRi9CLGtDQUE2QixHQUE3Qiw2QkFBNkIsQ0FBUztRQUN0QyxxQ0FBZ0MsR0FBaEMsZ0NBQWdDLENBQVM7UUFDekMsMkJBQXNCLEdBQXRCLHNCQUFzQixDQUFTO0lBQ3RDLENBQUM7SUFFSixRQUFRLENBQUMsWUFBb0I7UUFDM0IsT0FBTyxZQUFZLEtBQUssMkNBQTJDLENBQUM7SUFDdEUsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQ2pCLFFBQXdCLEVBQ3hCLE1BQWMsRUFDZCxhQUE0QjtRQUU1QiwyQ0FBMkM7UUFDM0MsTUFBTSxnQkFBZ0IsR0FBRyxRQUFRLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQztRQUNuRCxJQUFJLGdCQUFnQixJQUFJLGdCQUFnQixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3ZELE9BQU87Z0JBQ0wsTUFBTSxFQUFFLENBQUM7Z0JBQ1QsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsVUFBVSxFQUFFLFNBQVM7Z0JBQ3JCLFdBQVcsRUFBRSxDQUFDLHNEQUFzRCxDQUFDO2FBQ3RFLENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsa0JBQWtCO1lBQ2xCLE1BQU0sVUFBVSxHQUFHLE1BQU0sYUFBYSxDQUFDLFFBQVEsQ0FBQztnQkFDOUMsV0FBVyxFQUFFLFFBQVE7Z0JBQ3JCLE1B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ckMsQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFjO1FBQ3BDLE1BQU0sU0FBUyxHQUEyQjtZQUN4QyxXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixjQUFjLEVBQUUsTUFBTTtZQUN0QixZQUFZLEVBQUUsTUFBTTtZQUNwQixZQUFZLEVBQUUsTUFBTTtZQUNwQixnQkFBZ0IsRUFBRSxNQUFNO1lBQ3hCLGdCQUFnQixFQUFFLE1BQU07WUFDeEIsZ0JBQWdCLEVBQUUsTUFBTTtZQUN4QixnQkFBZ0IsRUFBRSxNQUFNO1NBQ3pCLENBQUM7UUFFRixPQUFPLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDakMsQ0FBQztDQUNGO0FBMUpELHNDQTBKQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGNsYXNzIE5MQkNhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX05FV19DT05ORUNUSU9OU19QRVJfU0VDT05EID0gMjU7XG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9BQ1RJVkVfQ09OTkVDVElPTlNfUEVSX01JTlVURSA9IDMwMDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9QUk9DRVNTRURfQllURVNfR0IgPSAxMDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgSE9VUlNfUEVSX01PTlRIID0gNzMwO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgY3VzdG9tTmV3Q29ubmVjdGlvbnNQZXJTZWNvbmQ/OiBudW1iZXIsXG4gICAgcHJpdmF0ZSBjdXN0b21BY3RpdmVDb25uZWN0aW9uc1Blck1pbnV0ZT86IG51bWJlcixcbiAgICBwcml2YXRlIGN1c3RvbVByb2Nlc3NlZEJ5dGVzR0I/OiBudW1iZXIsXG4gICkge31cblxuICBzdXBwb3J0cyhyZXNvdXJjZVR5cGU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiByZXNvdXJjZVR5cGUgPT09ICdBV1M6OkVsYXN0aWNMb2FkQmFsYW5jaW5nVjI6OkxvYWRCYWxhbmNlcic7XG4gIH1cblxuICBhc3luYyBjYWxjdWxhdGVDb3N0KFxuICAgIHJlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgLy8gQ2hlY2sgaWYgdGhpcyBpcyBhIE5ldHdvcmsgTG9hZCBCYWxhbmNlclxuICAgIGNvbnN0IGxvYWRCYWxhbmNlclR5cGUgPSByZXNvdXJjZS5wcm9wZXJ0aWVzPy5UeXBlO1xuICAgIGlmIChsb2FkQmFsYW5jZXJUeXBlICYmIGxvYWRCYWxhbmNlclR5cGUgIT09ICduZXR3b3JrJykge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFsnVGhpcyBjYWxjdWxhdG9yIG9ubHkgc3VwcG9ydHMgTmV0d29yayBMb2FkIEJhbGFuY2VycyddLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgLy8gR2V0IGhvdXJseSByYXRlXG4gICAgICBjb25zdCBob3VybHlSYXRlID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQVdTRUxCJyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbXG4gICAgICAgICAgeyBmaWVsZDogJ3Byb2R1Y3RGYW1pbHknLCB2YWx1ZTogJ0xvYWQgQmFsYW5jZXItTmV0d29yaycgfSxcbiAgICAgICAgICB7IGZpZWxkOiAndXNhZ2V0eXBlJywgdmFsdWU6IGAke3RoaXMuZ2V0UmVnaW9uUHJlZml4KHJlZ2lvbil9TG9hZEJhbGFuY2VyVXNhZ2VgIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcblxuICAgICAgLy8gR2V0IE5MQ1UgcmF0ZVxuICAgICAgY29uc3QgbmxjdVJhdGUgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBV1NFTEInLFxuICAgICAgICByZWdpb246IHRoaXMubm9ybWFsaXplUmVnaW9uKHJlZ2lvbiksXG4gICAgICAgIGZpbHRlcnM6IFtcbiAgICAgICAgICB7IGZpZWxkOiAncHJvZHVjdEZhbWlseScsIHZhbHVlOiAnTG9hZCBCYWxhbmNlci1OZXR3b3JrJyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICd1c2FnZXR5cGUnLCB2YWx1ZTogYCR7dGhpcy5nZXRSZWdpb25QcmVmaXgocmVnaW9uKX1MQ1VVc2FnZWAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBpZiAoaG91cmx5UmF0ZSA9PT0gbnVsbCB8fCBubGN1UmF0ZSA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFtb3VudDogMCxcbiAgICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgICAgICBgUHJpY2luZyBkYXRhIG5vdCBhdmFpbGFibGUgZm9yIE5ldHdvcmsgTG9hZCBCYWxhbmNlciBpbiByZWdpb24gJHtyZWdpb259YCxcbiAgICAgICAgICBdLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBuZXdDb25uZWN0aW9uc1BlclNlY29uZCA9XG4gICAgICAgIHRoaXMuY3VzdG9tTmV3Q29ubmVjdGlvbnNQZXJTZWNvbmQgfHwgdGhpcy5ERUZBVUxUX05FV19DT05ORUNUSU9OU19QRVJfU0VDT05EO1xuICAgICAgY29uc3QgYWN0aXZlQ29ubmVjdGlvbnNQZXJNaW51dGUgPVxuICAgICAgICB0aGlzLmN1c3RvbUFjdGl2ZUNvbm5lY3Rpb25zUGVyTWludXRlIHx8IHRoaXMuREVGQVVMVF9BQ1RJVkVfQ09OTkVDVElPTlNfUEVSX01JTlVURTtcbiAgICAgIGNvbnN0IHByb2Nlc3NlZEJ5dGVzR0IgPVxuICAgICAgICB0aGlzLmN1c3RvbVByb2Nlc3NlZEJ5dGVzR0IgfHwgdGhpcy5ERUZBVUxUX1BST0NFU1NFRF9CWVRFU19HQjtcblxuICAgICAgLy8gQ2FsY3VsYXRlIE5MQ1UgY29uc3VtcHRpb25cbiAgICAgIC8vIDEgTkxDVSBwcm92aWRlczogODAwIG5ldyBjb25uZWN0aW9ucy9zZWMsIDEwMCwwMDAgYWN0aXZlIGNvbm5lY3Rpb25zL21pbiwgMSBHQiBwcm9jZXNzZWQvaG91clxuICAgICAgY29uc3QgbmxjdUZyb21OZXdDb25uZWN0aW9ucyA9IG5ld0Nvbm5lY3Rpb25zUGVyU2Vjb25kIC8gODAwO1xuICAgICAgY29uc3QgbmxjdUZyb21BY3RpdmVDb25uZWN0aW9ucyA9IGFjdGl2ZUNvbm5lY3Rpb25zUGVyTWludXRlIC8gMTAwMDAwO1xuICAgICAgY29uc3QgZ2JQZXJIb3VyID0gcHJvY2Vzc2VkQnl0ZXNHQiAvIHRoaXMuSE9VUlNfUEVSX01PTlRIO1xuICAgICAgY29uc3QgbmxjdUZyb21Qcm9jZXNzZWRCeXRlcyA9IGdiUGVySG91cjtcblxuICAgICAgLy8gVXNlIHRoZSBoaWdoZXN0IE5MQ1UgY29uc3VtcHRpb25cbiAgICAgIGNvbnN0IG5sY3VQZXJIb3VyID0gTWF0aC5tYXgoXG4gICAgICAgIG5sY3VGcm9tTmV3Q29ubmVjdGlvbnMsXG4gICAgICAgIG5sY3VGcm9tQWN0aXZlQ29ubmVjdGlvbnMsXG4gICAgICAgIG5sY3VGcm9tUHJvY2Vzc2VkQnl0ZXMsXG4gICAgICApO1xuXG4gICAgICBjb25zdCBob3VybHlDb3N0ID0gaG91cmx5UmF0ZSAqIHRoaXMuSE9VUlNfUEVSX01PTlRIO1xuICAgICAgY29uc3QgbmxjdUNvc3QgPSBubGN1UmF0ZSAqIG5sY3VQZXJIb3VyICogdGhpcy5IT1VSU19QRVJfTU9OVEg7XG4gICAgICBjb25zdCB0b3RhbENvc3QgPSBob3VybHlDb3N0ICsgbmxjdUNvc3Q7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFtb3VudDogdG90YWxDb3N0LFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICdtZWRpdW0nLFxuICAgICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICAgIGBIb3VybHkgcmF0ZTogJCR7aG91cmx5UmF0ZS50b0ZpeGVkKDQpfS9ob3VyIMOXICR7dGhpcy5IT1VSU19QRVJfTU9OVEh9IGhvdXJzID0gJCR7aG91cmx5Q29zdC50b0ZpeGVkKDIpfS9tb250aGAsXG4gICAgICAgICAgYE5MQ1UgY29uc3VtcHRpb246ICR7bmxjdVBlckhvdXIudG9GaXhlZCgyKX0gTkxDVS9ob3VyIGJhc2VkIG9uOmAsXG4gICAgICAgICAgYCAgLSBOZXcgY29ubmVjdGlvbnM6ICR7bmV3Q29ubmVjdGlvbnNQZXJTZWNvbmR9L3NlYyDihpIgJHtubGN1RnJvbU5ld0Nvbm5lY3Rpb25zLnRvRml4ZWQoMil9IE5MQ1VgLFxuICAgICAgICAgIGAgIC0gQWN0aXZlIGNvbm5lY3Rpb25zOiAke2FjdGl2ZUNvbm5lY3Rpb25zUGVyTWludXRlfS9taW4g4oaSICR7bmxjdUZyb21BY3RpdmVDb25uZWN0aW9ucy50b0ZpeGVkKDIpfSBOTENVYCxcbiAgICAgICAgICBgICAtIFByb2Nlc3NlZCBkYXRhOiAke3Byb2Nlc3NlZEJ5dGVzR0J9IEdCL21vbnRoIOKGkiAke25sY3VGcm9tUHJvY2Vzc2VkQnl0ZXMudG9GaXhlZCgyKX0gTkxDVWAsXG4gICAgICAgICAgYE5MQ1UgY29zdDogJCR7bmxjdVJhdGUudG9GaXhlZCg0KX0vTkxDVS9ob3VyIMOXICR7bmxjdVBlckhvdXIudG9GaXhlZCgyKX0gTkxDVSDDlyAke3RoaXMuSE9VUlNfUEVSX01PTlRIfSBob3VycyA9ICQke25sY3VDb3N0LnRvRml4ZWQoMil9L21vbnRoYCxcbiAgICAgICAgICBgVG90YWw6ICQke3RvdGFsQ29zdC50b0ZpeGVkKDIpfS9tb250aGAsXG4gICAgICAgIF0sXG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICBhc3N1bXB0aW9uczogW2BGYWlsZWQgdG8gZmV0Y2ggcHJpY2luZzogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YF0sXG4gICAgICB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbm9ybWFsaXplUmVnaW9uKHJlZ2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCByZWdpb25NYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAndXMtZWFzdC0xJzogJ1VTIEVhc3QgKE4uIFZpcmdpbmlhKScsXG4gICAgICAndXMtZWFzdC0yJzogJ1VTIEVhc3QgKE9oaW8pJyxcbiAgICAgICd1cy13ZXN0LTEnOiAnVVMgV2VzdCAoTi4gQ2FsaWZvcm5pYSknLFxuICAgICAgJ3VzLXdlc3QtMic6ICdVUyBXZXN0IChPcmVnb24pJyxcbiAgICAgICdldS13ZXN0LTEnOiAnRVUgKElyZWxhbmQpJyxcbiAgICAgICdldS13ZXN0LTInOiAnRVUgKExvbmRvbiknLFxuICAgICAgJ2V1LXdlc3QtMyc6ICdFVSAoUGFyaXMpJyxcbiAgICAgICdldS1jZW50cmFsLTEnOiAnRVUgKEZyYW5rZnVydCknLFxuICAgICAgJ2V1LW5vcnRoLTEnOiAnRVUgKFN0b2NraG9sbSknLFxuICAgICAgJ2FwLXNvdXRoLTEnOiAnQXNpYSBQYWNpZmljIChNdW1iYWkpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMSc6ICdBc2lhIFBhY2lmaWMgKFNpbmdhcG9yZSknLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU3lkbmV5KScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChUb2t5byknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0yJzogJ0FzaWEgUGFjaWZpYyAoU2VvdWwpJyxcbiAgICB9O1xuXG4gICAgcmV0dXJuIHJlZ2lvbk1hcFtyZWdpb25dIHx8IHJlZ2lvbjtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0UmVnaW9uUHJlZml4KHJlZ2lvbjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBwcmVmaXhNYXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAndXMtZWFzdC0xJzogJ1VTRTEnLFxuICAgICAgJ3VzLWVhc3QtMic6ICdVU0UyJyxcbiAgICAgICd1cy13ZXN0LTEnOiAnVVNXMScsXG4gICAgICAndXMtd2VzdC0yJzogJ1VTVzInLFxuICAgICAgJ2V1LXdlc3QtMSc6ICdFVVcxJyxcbiAgICAgICdldS13ZXN0LTInOiAnRVVXMicsXG4gICAgICAnZXUtd2VzdC0zJzogJ0VVVzMnLFxuICAgICAgJ2V1LWNlbnRyYWwtMSc6ICdFVUMxJyxcbiAgICAgICdldS1ub3J0aC0xJzogJ0VVTjEnLFxuICAgICAgJ2FwLXNvdXRoLTEnOiAnQVBTMScsXG4gICAgICAnYXAtc291dGhlYXN0LTEnOiAnQVBTMicsXG4gICAgICAnYXAtc291dGhlYXN0LTInOiAnQVBTMycsXG4gICAgICAnYXAtbm9ydGhlYXN0LTEnOiAnQVBOMScsXG4gICAgICAnYXAtbm9ydGhlYXN0LTInOiAnQVBOMicsXG4gICAgfTtcblxuICAgIHJldHVybiBwcmVmaXhNYXBbcmVnaW9uXSB8fCAnJztcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class NatGatewayCalculator implements ResourceCostCalculator {
|
|
4
|
+
private customDataProcessedGB?;
|
|
5
|
+
private readonly DEFAULT_DATA_PROCESSED_GB;
|
|
6
|
+
private readonly HOURS_PER_MONTH;
|
|
7
|
+
constructor(customDataProcessedGB?: number | undefined);
|
|
8
|
+
supports(resourceType: string): boolean;
|
|
9
|
+
calculateCost(_resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
10
|
+
private normalizeRegion;
|
|
11
|
+
private getRegionPrefix;
|
|
12
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NatGatewayCalculator = void 0;
|
|
4
|
+
class NatGatewayCalculator {
|
|
5
|
+
customDataProcessedGB;
|
|
6
|
+
DEFAULT_DATA_PROCESSED_GB = 100;
|
|
7
|
+
HOURS_PER_MONTH = 730;
|
|
8
|
+
constructor(customDataProcessedGB) {
|
|
9
|
+
this.customDataProcessedGB = customDataProcessedGB;
|
|
10
|
+
}
|
|
11
|
+
supports(resourceType) {
|
|
12
|
+
return resourceType === 'AWS::EC2::NatGateway';
|
|
13
|
+
}
|
|
14
|
+
async calculateCost(_resource, region, pricingClient) {
|
|
15
|
+
try {
|
|
16
|
+
// Get hourly rate
|
|
17
|
+
const hourlyRate = await pricingClient.getPrice({
|
|
18
|
+
serviceCode: 'AmazonEC2',
|
|
19
|
+
region: this.normalizeRegion(region),
|
|
20
|
+
filters: [
|
|
21
|
+
{ field: 'productFamily', value: 'NAT Gateway' },
|
|
22
|
+
{ field: 'usagetype', value: `${this.getRegionPrefix(region)}NatGateway-Hours` },
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
// Get data processing rate
|
|
26
|
+
const dataProcessingRate = await pricingClient.getPrice({
|
|
27
|
+
serviceCode: 'AmazonEC2',
|
|
28
|
+
region: this.normalizeRegion(region),
|
|
29
|
+
filters: [
|
|
30
|
+
{ field: 'productFamily', value: 'NAT Gateway' },
|
|
31
|
+
{ field: 'usagetype', value: `${this.getRegionPrefix(region)}NatGateway-Bytes` },
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
if (hourlyRate === null || dataProcessingRate === null) {
|
|
35
|
+
const dataProcessedGB = this.customDataProcessedGB || this.DEFAULT_DATA_PROCESSED_GB;
|
|
36
|
+
const assumptions = [
|
|
37
|
+
`Pricing data not available for NAT Gateway in region ${region}`,
|
|
38
|
+
`Would assume ${dataProcessedGB} GB of data processing per month`,
|
|
39
|
+
`Would assume ${this.HOURS_PER_MONTH} hours per month`,
|
|
40
|
+
];
|
|
41
|
+
if (this.customDataProcessedGB !== undefined) {
|
|
42
|
+
assumptions.push('Using custom data processing assumption from configuration');
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
amount: 0,
|
|
46
|
+
currency: 'USD',
|
|
47
|
+
confidence: 'unknown',
|
|
48
|
+
assumptions,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const dataProcessedGB = this.customDataProcessedGB || this.DEFAULT_DATA_PROCESSED_GB;
|
|
52
|
+
const hourlyCost = hourlyRate * this.HOURS_PER_MONTH;
|
|
53
|
+
const dataProcessingCost = dataProcessingRate * dataProcessedGB;
|
|
54
|
+
const totalCost = hourlyCost + dataProcessingCost;
|
|
55
|
+
return {
|
|
56
|
+
amount: totalCost,
|
|
57
|
+
currency: 'USD',
|
|
58
|
+
confidence: 'medium',
|
|
59
|
+
assumptions: [
|
|
60
|
+
`Hourly rate: $${hourlyRate.toFixed(4)}/hour × ${this.HOURS_PER_MONTH} hours = $${hourlyCost.toFixed(2)}/month`,
|
|
61
|
+
`Data processing: $${dataProcessingRate.toFixed(4)}/GB × ${dataProcessedGB} GB = $${dataProcessingCost.toFixed(2)}/month`,
|
|
62
|
+
`Total: $${totalCost.toFixed(2)}/month`,
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return {
|
|
68
|
+
amount: 0,
|
|
69
|
+
currency: 'USD',
|
|
70
|
+
confidence: 'unknown',
|
|
71
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
normalizeRegion(region) {
|
|
76
|
+
const regionMap = {
|
|
77
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
78
|
+
'us-east-2': 'US East (Ohio)',
|
|
79
|
+
'us-west-1': 'US West (N. California)',
|
|
80
|
+
'us-west-2': 'US West (Oregon)',
|
|
81
|
+
'eu-west-1': 'EU (Ireland)',
|
|
82
|
+
'eu-west-2': 'EU (London)',
|
|
83
|
+
'eu-west-3': 'EU (Paris)',
|
|
84
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
85
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
86
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
87
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
88
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
89
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
90
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
91
|
+
};
|
|
92
|
+
return regionMap[region] || region;
|
|
93
|
+
}
|
|
94
|
+
getRegionPrefix(region) {
|
|
95
|
+
// AWS uses region prefixes in usage types (e.g., USE1 for us-east-1)
|
|
96
|
+
const prefixMap = {
|
|
97
|
+
'us-east-1': 'USE1',
|
|
98
|
+
'us-east-2': 'USE2',
|
|
99
|
+
'us-west-1': 'USW1',
|
|
100
|
+
'us-west-2': 'USW2',
|
|
101
|
+
'eu-west-1': 'EUW1',
|
|
102
|
+
'eu-west-2': 'EUW2',
|
|
103
|
+
'eu-west-3': 'EUW3',
|
|
104
|
+
'eu-central-1': 'EUC1',
|
|
105
|
+
'eu-north-1': 'EUN1',
|
|
106
|
+
'ap-south-1': 'APS1',
|
|
107
|
+
'ap-southeast-1': 'APS2',
|
|
108
|
+
'ap-southeast-2': 'APS3',
|
|
109
|
+
'ap-northeast-1': 'APN1',
|
|
110
|
+
'ap-northeast-2': 'APN2',
|
|
111
|
+
};
|
|
112
|
+
return prefixMap[region] || '';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.NatGatewayCalculator = NatGatewayCalculator;
|
|
116
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTmF0R2F0ZXdheUNhbGN1bGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJpY2luZy9jYWxjdWxhdG9ycy9OYXRHYXRld2F5Q2FsY3VsYXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSxNQUFhLG9CQUFvQjtJQUlYO0lBSEgseUJBQXlCLEdBQUcsR0FBRyxDQUFDO0lBQ2hDLGVBQWUsR0FBRyxHQUFHLENBQUM7SUFFdkMsWUFBb0IscUJBQThCO1FBQTlCLDBCQUFxQixHQUFyQixxQkFBcUIsQ0FBUztJQUFHLENBQUM7SUFFdEQsUUFBUSxDQUFDLFlBQW9CO1FBQzNCLE9BQU8sWUFBWSxLQUFLLHNCQUFzQixDQUFDO0lBQ2pELENBQUM7SUFFRCxLQUFLLENBQUMsYUFBYSxDQUNqQixTQUF5QixFQUN6QixNQUFjLEVBQ2QsYUFBNEI7UUFFNUIsSUFBSSxDQUFDO1lBQ0gsa0JBQWtCO1lBQ2xCLE1BQU0sVUFBVSxHQUFHLE1BQU0sYUFBYSxDQUFDLFFBQVEsQ0FBQztnQkFDOUMsV0FBVyxFQUFFLFdBQVc7Z0JBQ3hCLE1BQU0sRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQztnQkFDcEMsT0FBTyxFQUFFO29CQUNQLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFO29CQUNoRCxFQUFFLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsa0JBQWtCLEVBQUU7aUJBQ2pGO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsMkJBQTJCO1lBQzNCLE1BQU0sa0JBQWtCLEdBQUcsTUFBTSxhQUFhLENBQUMsUUFBUSxDQUFDO2dCQUN0RCxXQUFXLEVBQUUsV0FBVztnQkFDeEIsTUFBTSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDO2dCQUNwQyxPQUFPLEVBQUU7b0JBQ1AsRUFBRSxLQUFLLEVB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QU8sU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLE1BQU0sQ0FBQztJQUNyQyxDQUFDO0lBRU8sZUFBZSxDQUFDLE1BQWM7UUFDcEMscUVBQXFFO1FBQ3JFLE1BQU0sU0FBUyxHQUEyQjtZQUN4QyxXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixXQUFXLEVBQUUsTUFBTTtZQUNuQixjQUFjLEVBQUUsTUFBTTtZQUN0QixZQUFZLEVBQUUsTUFBTTtZQUNwQixZQUFZLEVBQUUsTUFBTTtZQUNwQixnQkFBZ0IsRUFBRSxNQUFNO1lBQ3hCLGdCQUFnQixFQUFFLE1BQU07WUFDeEIsZ0JBQWdCLEVBQUUsTUFBTTtZQUN4QixnQkFBZ0IsRUFBRSxNQUFNO1NBQ3pCLENBQUM7UUFFRixPQUFPLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDakMsQ0FBQztDQUNGO0FBM0hELG9EQTJIQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlc291cmNlV2l0aElkIH0gZnJvbSAnLi4vLi4vZGlmZi90eXBlcyc7XG5pbXBvcnQgeyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yLCBNb250aGx5Q29zdCwgUHJpY2luZ0NsaWVudCB9IGZyb20gJy4uL3R5cGVzJztcblxuZXhwb3J0IGNsYXNzIE5hdEdhdGV3YXlDYWxjdWxhdG9yIGltcGxlbWVudHMgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9EQVRBX1BST0NFU1NFRF9HQiA9IDEwMDtcbiAgcHJpdmF0ZSByZWFkb25seSBIT1VSU19QRVJfTU9OVEggPSA3MzA7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBjdXN0b21EYXRhUHJvY2Vzc2VkR0I/OiBudW1iZXIpIHt9XG5cbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gcmVzb3VyY2VUeXBlID09PSAnQVdTOjpFQzI6Ok5hdEdhdGV3YXknO1xuICB9XG5cbiAgYXN5bmMgY2FsY3VsYXRlQ29zdChcbiAgICBfcmVzb3VyY2U6IFJlc291cmNlV2l0aElkLFxuICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgIHByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICB0cnkge1xuICAgICAgLy8gR2V0IGhvdXJseSByYXRlXG4gICAgICBjb25zdCBob3VybHlSYXRlID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uRUMyJyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbXG4gICAgICAgICAgeyBmaWVsZDogJ3Byb2R1Y3RGYW1pbHknLCB2YWx1ZTogJ05BVCBHYXRld2F5JyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICd1c2FnZXR5cGUnLCB2YWx1ZTogYCR7dGhpcy5nZXRSZWdpb25QcmVmaXgocmVnaW9uKX1OYXRHYXRld2F5LUhvdXJzYCB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIEdldCBkYXRhIHByb2Nlc3NpbmcgcmF0ZVxuICAgICAgY29uc3QgZGF0YVByb2Nlc3NpbmdSYXRlID0gYXdhaXQgcHJpY2luZ0NsaWVudC5nZXRQcmljZSh7XG4gICAgICAgIHNlcnZpY2VDb2RlOiAnQW1hem9uRUMyJyxcbiAgICAgICAgcmVnaW9uOiB0aGlzLm5vcm1hbGl6ZVJlZ2lvbihyZWdpb24pLFxuICAgICAgICBmaWx0ZXJzOiBbXG4gICAgICAgICAgeyBmaWVsZDogJ3Byb2R1Y3RGYW1pbHknLCB2YWx1ZTogJ05BVCBHYXRld2F5JyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICd1c2FnZXR5cGUnLCB2YWx1ZTogYCR7dGhpcy5nZXRSZWdpb25QcmVmaXgocmVnaW9uKX1OYXRHYXRld2F5LUJ5dGVzYCB9LFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGlmIChob3VybHlSYXRlID09PSBudWxsIHx8IGRhdGFQcm9jZXNzaW5nUmF0ZSA9PT0gbnVsbCkge1xuICAgICAgICBjb25zdCBkYXRhUHJvY2Vzc2VkR0IgPSB0aGlzLmN1c3RvbURhdGFQcm9jZXNzZWRHQiB8fCB0aGlzLkRFRkFVTFRfREFUQV9QUk9DRVNTRURfR0I7XG4gICAgICAgIGNvbnN0IGFzc3VtcHRpb25zID0gW1xuICAgICAgICAgIGBQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgTkFUIEdhdGV3YXkgaW4gcmVnaW9uICR7cmVnaW9ufWAsXG4gICAgICAgICAgYFdvdWxkIGFzc3VtZSAke2RhdGFQcm9jZXNzZWRHQn0gR0Igb2YgZGF0YSBwcm9jZXNzaW5nIHBlciBtb250aGAsXG4gICAgICAgICAgYFdvdWxkIGFzc3VtZSAke3RoaXMuSE9VUlNfUEVSX01PTlRIfSBob3VycyBwZXIgbW9udGhgLFxuICAgICAgICBdO1xuXG4gICAgICAgIGlmICh0aGlzLmN1c3RvbURhdGFQcm9jZXNzZWRHQiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgYXNzdW1wdGlvbnMucHVzaCgnVXNpbmcgY3VzdG9tIGRhdGEgcHJvY2Vzc2luZyBhc3N1bXB0aW9uIGZyb20gY29uZmlndXJhdGlvbicpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9ucyxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YVByb2Nlc3NlZEdCID0gdGhpcy5jdXN0b21EYXRhUHJvY2Vzc2VkR0IgfHwgdGhpcy5ERUZBVUxUX0RBVEFfUFJPQ0VTU0VEX0dCO1xuICAgICAgY29uc3QgaG91cmx5Q29zdCA9IGhvdXJseVJhdGUgKiB0aGlzLkhPVVJTX1BFUl9NT05USDtcbiAgICAgIGNvbnN0IGRhdGFQcm9jZXNzaW5nQ29zdCA9IGRhdGFQcm9jZXNzaW5nUmF0ZSAqIGRhdGFQcm9jZXNzZWRHQjtcbiAgICAgIGNvbnN0IHRvdGFsQ29zdCA9IGhvdXJseUNvc3QgKyBkYXRhUHJvY2Vzc2luZ0Nvc3Q7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFtb3VudDogdG90YWxDb3N0LFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICdtZWRpdW0nLFxuICAgICAgICBhc3N1bXB0aW9uczogW1xuICAgICAgICAgIGBIb3VybHkgcmF0ZTogJCR7aG91cmx5UmF0ZS50b0ZpeGVkKDQpfS9ob3VyIMOXICR7dGhpcy5IT1VSU19QRVJfTU9OVEh9IGhvdXJzID0gJCR7aG91cmx5Q29zdC50b0ZpeGVkKDIpfS9tb250aGAsXG4gICAgICAgICAgYERhdGEgcHJvY2Vzc2luZzogJCR7ZGF0YVByb2Nlc3NpbmdSYXRlLnRvRml4ZWQoNCl9L0dCIMOXICR7ZGF0YVByb2Nlc3NlZEdCfSBHQiA9ICQke2RhdGFQcm9jZXNzaW5nQ29zdC50b0ZpeGVkKDIpfS9tb250aGAsXG4gICAgICAgICAgYFRvdGFsOiAkJHt0b3RhbENvc3QudG9GaXhlZCgyKX0vbW9udGhgLFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG5vcm1hbGl6ZVJlZ2lvbihyZWdpb246IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcmVnaW9uTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgJ3VzLWVhc3QtMSc6ICdVUyBFYXN0IChOLiBWaXJnaW5pYSknLFxuICAgICAgJ3VzLWVhc3QtMic6ICdVUyBFYXN0IChPaGlvKScsXG4gICAgICAndXMtd2VzdC0xJzogJ1VTIFdlc3QgKE4uIENhbGlmb3JuaWEpJyxcbiAgICAgICd1cy13ZXN0LTInOiAnVVMgV2VzdCAoT3JlZ29uKScsXG4gICAgICAnZXUtd2VzdC0xJzogJ0VVIChJcmVsYW5kKScsXG4gICAgICAnZXUtd2VzdC0yJzogJ0VVIChMb25kb24pJyxcbiAgICAgICdldS13ZXN0LTMnOiAnRVUgKFBhcmlzKScsXG4gICAgICAnZXUtY2VudHJhbC0xJzogJ0VVIChGcmFua2Z1cnQpJyxcbiAgICAgICdldS1ub3J0aC0xJzogJ0VVIChTdG9ja2hvbG0pJyxcbiAgICAgICdhcC1zb3V0aC0xJzogJ0FzaWEgUGFjaWZpYyAoTXVtYmFpKScsXG4gICAgICAnYXAtc291dGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChTaW5nYXBvcmUpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMic6ICdBc2lhIFBhY2lmaWMgKFN5ZG5leSknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0xJzogJ0FzaWEgUGFjaWZpYyAoVG9reW8pJyxcbiAgICAgICdhcC1ub3J0aGVhc3QtMic6ICdBc2lhIFBhY2lmaWMgKFNlb3VsKScsXG4gICAgfTtcblxuICAgIHJldHVybiByZWdpb25NYXBbcmVnaW9uXSB8fCByZWdpb247XG4gIH1cblxuICBwcml2YXRlIGdldFJlZ2lvblByZWZpeChyZWdpb246IHN0cmluZyk6IHN0cmluZyB7XG4gICAgLy8gQVdTIHVzZXMgcmVnaW9uIHByZWZpeGVzIGluIHVzYWdlIHR5cGVzIChlLmcuLCBVU0UxIGZvciB1cy1lYXN0LTEpXG4gICAgY29uc3QgcHJlZml4TWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgJ3VzLWVhc3QtMSc6ICdVU0UxJyxcbiAgICAgICd1cy1lYXN0LTInOiAnVVNFMicsXG4gICAgICAndXMtd2VzdC0xJzogJ1VTVzEnLFxuICAgICAgJ3VzLXdlc3QtMic6ICdVU1cyJyxcbiAgICAgICdldS13ZXN0LTEnOiAnRVVXMScsXG4gICAgICAnZXUtd2VzdC0yJzogJ0VVVzInLFxuICAgICAgJ2V1LXdlc3QtMyc6ICdFVVczJyxcbiAgICAgICdldS1jZW50cmFsLTEnOiAnRVVDMScsXG4gICAgICAnZXUtbm9ydGgtMSc6ICdFVU4xJyxcbiAgICAgICdhcC1zb3V0aC0xJzogJ0FQUzEnLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0xJzogJ0FQUzInLFxuICAgICAgJ2FwLXNvdXRoZWFzdC0yJzogJ0FQUzMnLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0xJzogJ0FQTjEnLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0yJzogJ0FQTjInLFxuICAgIH07XG5cbiAgICByZXR1cm4gcHJlZml4TWFwW3JlZ2lvbl0gfHwgJyc7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class RDSCalculator implements ResourceCostCalculator {
|
|
4
|
+
private readonly DEFAULT_STORAGE_GB;
|
|
5
|
+
supports(resourceType: string): boolean;
|
|
6
|
+
calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
7
|
+
private normalizeEngine;
|
|
8
|
+
private normalizeRegion;
|
|
9
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RDSCalculator = void 0;
|
|
4
|
+
class RDSCalculator {
|
|
5
|
+
DEFAULT_STORAGE_GB = 100;
|
|
6
|
+
supports(resourceType) {
|
|
7
|
+
return resourceType === 'AWS::RDS::DBInstance';
|
|
8
|
+
}
|
|
9
|
+
async calculateCost(resource, region, pricingClient) {
|
|
10
|
+
const instanceClass = resource.properties.DBInstanceClass;
|
|
11
|
+
const engine = resource.properties.Engine;
|
|
12
|
+
if (!instanceClass || !engine) {
|
|
13
|
+
return {
|
|
14
|
+
amount: 0,
|
|
15
|
+
currency: 'USD',
|
|
16
|
+
confidence: 'unknown',
|
|
17
|
+
assumptions: ['DB instance class or engine not specified'],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const hourlyRate = await pricingClient.getPrice({
|
|
22
|
+
serviceCode: 'AmazonRDS',
|
|
23
|
+
region: this.normalizeRegion(region),
|
|
24
|
+
filters: [
|
|
25
|
+
{ field: 'instanceType', value: instanceClass },
|
|
26
|
+
{ field: 'databaseEngine', value: this.normalizeEngine(engine) },
|
|
27
|
+
{ field: 'deploymentOption', value: 'Single-AZ' },
|
|
28
|
+
],
|
|
29
|
+
});
|
|
30
|
+
const storagePrice = await pricingClient.getPrice({
|
|
31
|
+
serviceCode: 'AmazonRDS',
|
|
32
|
+
region: this.normalizeRegion(region),
|
|
33
|
+
filters: [
|
|
34
|
+
{ field: 'volumeType', value: 'General Purpose' },
|
|
35
|
+
{ field: 'databaseEngine', value: this.normalizeEngine(engine) },
|
|
36
|
+
],
|
|
37
|
+
});
|
|
38
|
+
if (hourlyRate === null) {
|
|
39
|
+
return {
|
|
40
|
+
amount: 0,
|
|
41
|
+
currency: 'USD',
|
|
42
|
+
confidence: 'unknown',
|
|
43
|
+
assumptions: [`Pricing data not available for instance class ${instanceClass} in region ${region}`],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const monthlyHours = 730;
|
|
47
|
+
const instanceCost = hourlyRate * monthlyHours;
|
|
48
|
+
const storageCost = (storagePrice || 0) * this.DEFAULT_STORAGE_GB;
|
|
49
|
+
const totalCost = instanceCost + storageCost;
|
|
50
|
+
return {
|
|
51
|
+
amount: totalCost,
|
|
52
|
+
currency: 'USD',
|
|
53
|
+
confidence: 'high',
|
|
54
|
+
assumptions: [
|
|
55
|
+
`Assumes ${monthlyHours} hours per month (24/7 operation)`,
|
|
56
|
+
`Assumes ${this.DEFAULT_STORAGE_GB} GB of General Purpose (gp2) storage`,
|
|
57
|
+
'Assumes Single-AZ deployment',
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
amount: 0,
|
|
64
|
+
currency: 'USD',
|
|
65
|
+
confidence: 'unknown',
|
|
66
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
normalizeEngine(engine) {
|
|
71
|
+
const engineMap = {
|
|
72
|
+
'mysql': 'MySQL',
|
|
73
|
+
'postgres': 'PostgreSQL',
|
|
74
|
+
'mariadb': 'MariaDB',
|
|
75
|
+
'oracle-se2': 'Oracle',
|
|
76
|
+
'sqlserver-ex': 'SQL Server',
|
|
77
|
+
'aurora-mysql': 'Aurora MySQL',
|
|
78
|
+
'aurora-postgresql': 'Aurora PostgreSQL',
|
|
79
|
+
};
|
|
80
|
+
return engineMap[engine.toLowerCase()] || engine;
|
|
81
|
+
}
|
|
82
|
+
normalizeRegion(region) {
|
|
83
|
+
const regionMap = {
|
|
84
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
85
|
+
'us-east-2': 'US East (Ohio)',
|
|
86
|
+
'us-west-1': 'US West (N. California)',
|
|
87
|
+
'us-west-2': 'US West (Oregon)',
|
|
88
|
+
'eu-west-1': 'EU (Ireland)',
|
|
89
|
+
'eu-west-2': 'EU (London)',
|
|
90
|
+
'eu-west-3': 'EU (Paris)',
|
|
91
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
92
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
93
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
94
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
95
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
96
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
97
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
98
|
+
};
|
|
99
|
+
return regionMap[region] || region;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.RDSCalculator = RDSCalculator;
|
|
103
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUkRTQ2FsY3VsYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wcmljaW5nL2NhbGN1bGF0b3JzL1JEU0NhbGN1bGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsTUFBYSxhQUFhO0lBQ1Asa0JBQWtCLEdBQUcsR0FBRyxDQUFDO0lBRTFDLFFBQVEsQ0FBQyxZQUFvQjtRQUMzQixPQUFPLFlBQVksS0FBSyxzQkFBc0IsQ0FBQztJQUNqRCxDQUFDO0lBRUQsS0FBSyxDQUFDLGFBQWEsQ0FDakIsUUFBd0IsRUFDeEIsTUFBYyxFQUNkLGFBQTRCO1FBRTVCLE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQyxVQUFVLENBQUMsZUFBeUIsQ0FBQztRQUNwRSxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsVUFBVSxDQUFDLE1BQWdCLENBQUM7UUFFcEQsSUFBSSxDQUFDLGFBQWEsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzlCLE9BQU87Z0JBQ0wsTUFBTSxFQUFFLENBQUM7Z0JBQ1QsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsVUFBVSxFQUFFLFNBQVM7Z0JBQ3JCLFdBQVcsRUFBRSxDQUFDLDJDQUEyQyxDQUFDO2FBQzNELENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxDQUFDO1lBQ0gsTUFBTSxVQUFVLEdBQUcsTUFBTSxhQUFhLENBQUMsUUFBUSxDQUFDO2dCQUM5QyxXQUFXLEVBQUUsV0FBVztnQkFDeEIsTUFBTSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDO2dCQUNwQyxPQUFPLEVBQUU7b0JBQ1AsRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUU7b0JBQy9DLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxFQUFFO29CQUNoRSxFQUFFLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxLQUFL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LENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQWhIRCxzQ0FnSEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXNvdXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbmV4cG9ydCBjbGFzcyBSRFNDYWxjdWxhdG9yIGltcGxlbWVudHMgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgREVGQVVMVF9TVE9SQUdFX0dCID0gMTAwO1xuXG4gIHN1cHBvcnRzKHJlc291cmNlVHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHJlc291cmNlVHlwZSA9PT0gJ0FXUzo6UkRTOjpEQkluc3RhbmNlJztcbiAgfVxuXG4gIGFzeW5jIGNhbGN1bGF0ZUNvc3QoXG4gICAgcmVzb3VyY2U6IFJlc291cmNlV2l0aElkLFxuICAgIHJlZ2lvbjogc3RyaW5nLFxuICAgIHByaWNpbmdDbGllbnQ6IFByaWNpbmdDbGllbnQsXG4gICk6IFByb21pc2U8TW9udGhseUNvc3Q+IHtcbiAgICBjb25zdCBpbnN0YW5jZUNsYXNzID0gcmVzb3VyY2UucHJvcGVydGllcy5EQkluc3RhbmNlQ2xhc3MgYXMgc3RyaW5nO1xuICAgIGNvbnN0IGVuZ2luZSA9IHJlc291cmNlLnByb3BlcnRpZXMuRW5naW5lIGFzIHN0cmluZztcblxuICAgIGlmICghaW5zdGFuY2VDbGFzcyB8fCAhZW5naW5lKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgIGN1cnJlbmN5OiAnVVNEJyxcbiAgICAgICAgY29uZmlkZW5jZTogJ3Vua25vd24nLFxuICAgICAgICBhc3N1bXB0aW9uczogWydEQiBpbnN0YW5jZSBjbGFzcyBvciBlbmdpbmUgbm90IHNwZWNpZmllZCddLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgaG91cmx5UmF0ZSA9IGF3YWl0IHByaWNpbmdDbGllbnQuZ2V0UHJpY2Uoe1xuICAgICAgICBzZXJ2aWNlQ29kZTogJ0FtYXpvblJEUycsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdpbnN0YW5jZVR5cGUnLCB2YWx1ZTogaW5zdGFuY2VDbGFzcyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICdkYXRhYmFzZUVuZ2luZScsIHZhbHVlOiB0aGlzLm5vcm1hbGl6ZUVuZ2luZShlbmdpbmUpIH0sXG4gICAgICAgICAgeyBmaWVsZDogJ2RlcGxveW1lbnRPcHRpb24nLCB2YWx1ZTogJ1NpbmdsZS1BWicgfSxcbiAgICAgICAgXSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBzdG9yYWdlUHJpY2UgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25SRFMnLFxuICAgICAgICByZWdpb246IHRoaXMubm9ybWFsaXplUmVnaW9uKHJlZ2lvbiksXG4gICAgICAgIGZpbHRlcnM6IFtcbiAgICAgICAgICB7IGZpZWxkOiAndm9sdW1lVHlwZScsIHZhbHVlOiAnR2VuZXJhbCBQdXJwb3NlJyB9LFxuICAgICAgICAgIHsgZmllbGQ6ICdkYXRhYmFzZUVuZ2luZScsIHZhbHVlOiB0aGlzLm5vcm1hbGl6ZUVuZ2luZShlbmdpbmUpIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcblxuICAgICAgaWYgKGhvdXJseVJhdGUgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9uczogW2BQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgaW5zdGFuY2UgY2xhc3MgJHtpbnN0YW5jZUNsYXNzfSBpbiByZWdpb24gJHtyZWdpb259YF0sXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1vbnRobHlIb3VycyA9IDczMDtcbiAgICAgIGNvbnN0IGluc3RhbmNlQ29zdCA9IGhvdXJseVJhdGUgKiBtb250aGx5SG91cnM7XG4gICAgICBjb25zdCBzdG9yYWdlQ29zdCA9IChzdG9yYWdlUHJpY2UgfHwgMCkgKiB0aGlzLkRFRkFVTFRfU1RPUkFHRV9HQjtcbiAgICAgIGNvbnN0IHRvdGFsQ29zdCA9IGluc3RhbmNlQ29zdCArIHN0b3JhZ2VDb3N0O1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhbW91bnQ6IHRvdGFsQ29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnaGlnaCcsXG4gICAgICAgIGFzc3VtcHRpb25zOiBbXG4gICAgICAgICAgYEFzc3VtZXMgJHttb250aGx5SG91cnN9IGhvdXJzIHBlciBtb250aCAoMjQvNyBvcGVyYXRpb24pYCxcbiAgICAgICAgICBgQXNzdW1lcyAke3RoaXMuREVGQVVMVF9TVE9SQUdFX0dCfSBHQiBvZiBHZW5lcmFsIFB1cnBvc2UgKGdwMikgc3RvcmFnZWAsXG4gICAgICAgICAgJ0Fzc3VtZXMgU2luZ2xlLUFaIGRlcGxveW1lbnQnLFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG5vcm1hbGl6ZUVuZ2luZShlbmdpbmU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgZW5naW5lTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgJ215c3FsJzogJ015U1FMJyxcbiAgICAgICdwb3N0Z3Jlcyc6ICdQb3N0Z3JlU1FMJyxcbiAgICAgICdtYXJpYWRiJzogJ01hcmlhREInLFxuICAgICAgJ29yYWNsZS1zZTInOiAnT3JhY2xlJyxcbiAgICAgICdzcWxzZXJ2ZXItZXgnOiAnU1FMIFNlcnZlcicsXG4gICAgICAnYXVyb3JhLW15c3FsJzogJ0F1cm9yYSBNeVNRTCcsXG4gICAgICAnYXVyb3JhLXBvc3RncmVzcWwnOiAnQXVyb3JhIFBvc3RncmVTUUwnLFxuICAgIH07XG5cbiAgICByZXR1cm4gZW5naW5lTWFwW2VuZ2luZS50b0xvd2VyQ2FzZSgpXSB8fCBlbmdpbmU7XG4gIH1cblxuICBwcml2YXRlIG5vcm1hbGl6ZVJlZ2lvbihyZWdpb246IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcmVnaW9uTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgJ3VzLWVhc3QtMSc6ICdVUyBFYXN0IChOLiBWaXJnaW5pYSknLFxuICAgICAgJ3VzLWVhc3QtMic6ICdVUyBFYXN0IChPaGlvKScsXG4gICAgICAndXMtd2VzdC0xJzogJ1VTIFdlc3QgKE4uIENhbGlmb3JuaWEpJyxcbiAgICAgICd1cy13ZXN0LTInOiAnVVMgV2VzdCAoT3JlZ29uKScsXG4gICAgICAnZXUtd2VzdC0xJzogJ0VVIChJcmVsYW5kKScsXG4gICAgICAnZXUtd2VzdC0yJzogJ0VVIChMb25kb24pJyxcbiAgICAgICdldS13ZXN0LTMnOiAnRVUgKFBhcmlzKScsXG4gICAgICAnZXUtY2VudHJhbC0xJzogJ0VVIChGcmFua2Z1cnQpJyxcbiAgICAgICdldS1ub3J0aC0xJzogJ0VVIChTdG9ja2hvbG0pJyxcbiAgICAgICdhcC1zb3V0aC0xJzogJ0FzaWEgUGFjaWZpYyAoTXVtYmFpKScsXG4gICAgICAnYXAtc291dGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChTaW5nYXBvcmUpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMic6ICdBc2lhIFBhY2lmaWMgKFN5ZG5leSknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0xJzogJ0FzaWEgUGFjaWZpYyAoVG9reW8pJyxcbiAgICAgICdhcC1ub3J0aGVhc3QtMic6ICdBc2lhIFBhY2lmaWMgKFNlb3VsKScsXG4gICAgfTtcblxuICAgIHJldHVybiByZWdpb25NYXBbcmVnaW9uXSB8fCByZWdpb247XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class S3Calculator implements ResourceCostCalculator {
|
|
4
|
+
private readonly DEFAULT_STORAGE_GB;
|
|
5
|
+
supports(resourceType: string): boolean;
|
|
6
|
+
calculateCost(_resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
7
|
+
private normalizeRegion;
|
|
8
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.S3Calculator = void 0;
|
|
4
|
+
class S3Calculator {
|
|
5
|
+
DEFAULT_STORAGE_GB = 100;
|
|
6
|
+
supports(resourceType) {
|
|
7
|
+
return resourceType === 'AWS::S3::Bucket';
|
|
8
|
+
}
|
|
9
|
+
async calculateCost(_resource, region, pricingClient) {
|
|
10
|
+
try {
|
|
11
|
+
const pricePerGB = await pricingClient.getPrice({
|
|
12
|
+
serviceCode: 'AmazonS3',
|
|
13
|
+
region: this.normalizeRegion(region),
|
|
14
|
+
filters: [
|
|
15
|
+
{ field: 'storageClass', value: 'General Purpose' },
|
|
16
|
+
{ field: 'volumeType', value: 'Standard' },
|
|
17
|
+
],
|
|
18
|
+
});
|
|
19
|
+
if (pricePerGB === null) {
|
|
20
|
+
return {
|
|
21
|
+
amount: 0,
|
|
22
|
+
currency: 'USD',
|
|
23
|
+
confidence: 'unknown',
|
|
24
|
+
assumptions: [`Pricing data not available for S3 in region ${region}`],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const monthlyCost = pricePerGB * this.DEFAULT_STORAGE_GB;
|
|
28
|
+
return {
|
|
29
|
+
amount: monthlyCost,
|
|
30
|
+
currency: 'USD',
|
|
31
|
+
confidence: 'medium',
|
|
32
|
+
assumptions: [
|
|
33
|
+
`Assumes ${this.DEFAULT_STORAGE_GB} GB of standard storage`,
|
|
34
|
+
'Does not include request costs or data transfer',
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return {
|
|
40
|
+
amount: 0,
|
|
41
|
+
currency: 'USD',
|
|
42
|
+
confidence: 'unknown',
|
|
43
|
+
assumptions: [`Failed to fetch pricing: ${error instanceof Error ? error.message : String(error)}`],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
normalizeRegion(region) {
|
|
48
|
+
const regionMap = {
|
|
49
|
+
'us-east-1': 'US East (N. Virginia)',
|
|
50
|
+
'us-east-2': 'US East (Ohio)',
|
|
51
|
+
'us-west-1': 'US West (N. California)',
|
|
52
|
+
'us-west-2': 'US West (Oregon)',
|
|
53
|
+
'eu-west-1': 'EU (Ireland)',
|
|
54
|
+
'eu-west-2': 'EU (London)',
|
|
55
|
+
'eu-west-3': 'EU (Paris)',
|
|
56
|
+
'eu-central-1': 'EU (Frankfurt)',
|
|
57
|
+
'eu-north-1': 'EU (Stockholm)',
|
|
58
|
+
'ap-south-1': 'Asia Pacific (Mumbai)',
|
|
59
|
+
'ap-southeast-1': 'Asia Pacific (Singapore)',
|
|
60
|
+
'ap-southeast-2': 'Asia Pacific (Sydney)',
|
|
61
|
+
'ap-northeast-1': 'Asia Pacific (Tokyo)',
|
|
62
|
+
'ap-northeast-2': 'Asia Pacific (Seoul)',
|
|
63
|
+
};
|
|
64
|
+
return regionMap[region] || region;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.S3Calculator = S3Calculator;
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUzNDYWxjdWxhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3ByaWNpbmcvY2FsY3VsYXRvcnMvUzNDYWxjdWxhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUdBLE1BQWEsWUFBWTtJQUNOLGtCQUFrQixHQUFHLEdBQUcsQ0FBQztJQUUxQyxRQUFRLENBQUMsWUFBb0I7UUFDM0IsT0FBTyxZQUFZLEtBQUssaUJBQWlCLENBQUM7SUFDNUMsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQ2pCLFNBQXlCLEVBQ3pCLE1BQWMsRUFDZCxhQUE0QjtRQUU1QixJQUFJLENBQUM7WUFDSCxNQUFNLFVBQVUsR0FBRyxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQzlDLFdBQVcsRUFBRSxVQUFVO2dCQUN2QixNQUFNLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUM7Z0JBQ3BDLE9BQU8sRUFBRTtvQkFDUCxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsS0FBSyxFQUFFLGlCQUFpQixFQUFFO29CQUNuRCxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLFVBQVUsRUFBRTtpQkFDM0M7YUFDRixDQUFDLENBQUM7WUFFSCxJQUFJLFVBQVUsS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDeEIsT0FBTztvQkFDTCxNQUFNLEVBQUUsQ0FBQztvQkFDVCxRQUFRLEVBQUUsS0FBSztvQkFDZixVQUFVLEVBQUUsU0FBUztvQkFDckIsV0FBVyxFQUFFLENBQUMsK0NBQStDLE1BQU0sRUFBRSxDQUFDO2lCQUN2RSxDQUFDO1lBQ0osQ0FBQztZQUVELE1BQU0sV0FBVyxHQUFHLFVBQVUsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUM7WUFFekQsT0FBTztnQkFDTCxNQUFNLEVBQUUsV0FBVztnQkFDbkIsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsVUFBVSxFQUFFLFFBQVE7Z0JBQ3BCLFdBQVcsRUFBRTtvQkFDWCxXQUFXLElBQUksQ0FBQyxrQkFBa0IseUJBQXlCO29CQUMzRCxpREFBaUQ7aUJBQ2xEO2FBQ0YsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsT0FBTztnQkFDTCxNQUFNLEVBQUUsQ0FBQztnQkFDVCxRQUFRLEVBQUUsS0FBSztnQkFDZixVQUFVLEVBQUUsU0FBUztnQkFDckIsV0FBVyxFQUFFLENBQUMsNEJBQTRCLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO2FBQ3BHLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVPLGVBQWUsQ0FBQyxNQUFjO1FBQ3BDLE1BQU0sU0FBUyxHQUEyQjtZQUN4QyxXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLFdBQVcsRUFBRSxnQkFBZ0I7WUFDN0IsV0FBVyxFQUFFLHlCQUF5QjtZQUN0QyxXQUFXLEVBQUUsa0JBQWtCO1lBQy9CLFdBQVcsRUFBRSxjQUFjO1lBQzNCLFdBQVcsRUFBRSxhQUFhO1lBQzFCLFdBQVcsRUFBRSxZQUFZO1lBQ3pCLGNBQWMsRUFBRSxnQkFBZ0I7WUFDaEMsWUFBWSxFQUFFLGdCQUFnQjtZQUM5QixZQUFZLEVBQUUsdUJBQXVCO1lBQ3JDLGdCQUFnQixFQUFFLDBCQUEwQjtZQUM1QyxnQkFBZ0IsRUFBRSx1QkFBdUI7WUFDekMsZ0JBQWdCLEVBQUUsc0JBQXNCO1lBQ3hDLGdCQUFnQixFQUFFLHNCQUFzQjtTQUN6QyxDQUFDO1FBRUYsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDO0lBQ3JDLENBQUM7Q0FDRjtBQXhFRCxvQ0F3RUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBSZXNvdXJjZVdpdGhJZCB9IGZyb20gJy4uLy4uL2RpZmYvdHlwZXMnO1xuaW1wb3J0IHsgUmVzb3VyY2VDb3N0Q2FsY3VsYXRvciwgTW9udGhseUNvc3QsIFByaWNpbmdDbGllbnQgfSBmcm9tICcuLi90eXBlcyc7XG5cbmV4cG9ydCBjbGFzcyBTM0NhbGN1bGF0b3IgaW1wbGVtZW50cyBSZXNvdXJjZUNvc3RDYWxjdWxhdG9yIHtcbiAgcHJpdmF0ZSByZWFkb25seSBERUZBVUxUX1NUT1JBR0VfR0IgPSAxMDA7XG5cbiAgc3VwcG9ydHMocmVzb3VyY2VUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gcmVzb3VyY2VUeXBlID09PSAnQVdTOjpTMzo6QnVja2V0JztcbiAgfVxuXG4gIGFzeW5jIGNhbGN1bGF0ZUNvc3QoXG4gICAgX3Jlc291cmNlOiBSZXNvdXJjZVdpdGhJZCxcbiAgICByZWdpb246IHN0cmluZyxcbiAgICBwcmljaW5nQ2xpZW50OiBQcmljaW5nQ2xpZW50LFxuICApOiBQcm9taXNlPE1vbnRobHlDb3N0PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHByaWNlUGVyR0IgPSBhd2FpdCBwcmljaW5nQ2xpZW50LmdldFByaWNlKHtcbiAgICAgICAgc2VydmljZUNvZGU6ICdBbWF6b25TMycsXG4gICAgICAgIHJlZ2lvbjogdGhpcy5ub3JtYWxpemVSZWdpb24ocmVnaW9uKSxcbiAgICAgICAgZmlsdGVyczogW1xuICAgICAgICAgIHsgZmllbGQ6ICdzdG9yYWdlQ2xhc3MnLCB2YWx1ZTogJ0dlbmVyYWwgUHVycG9zZScgfSxcbiAgICAgICAgICB7IGZpZWxkOiAndm9sdW1lVHlwZScsIHZhbHVlOiAnU3RhbmRhcmQnIH0sXG4gICAgICAgIF0sXG4gICAgICB9KTtcblxuICAgICAgaWYgKHByaWNlUGVyR0IgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbW91bnQ6IDAsXG4gICAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgICBhc3N1bXB0aW9uczogW2BQcmljaW5nIGRhdGEgbm90IGF2YWlsYWJsZSBmb3IgUzMgaW4gcmVnaW9uICR7cmVnaW9ufWBdLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtb250aGx5Q29zdCA9IHByaWNlUGVyR0IgKiB0aGlzLkRFRkFVTFRfU1RPUkFHRV9HQjtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiBtb250aGx5Q29zdCxcbiAgICAgICAgY3VycmVuY3k6ICdVU0QnLFxuICAgICAgICBjb25maWRlbmNlOiAnbWVkaXVtJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtcbiAgICAgICAgICBgQXNzdW1lcyAke3RoaXMuREVGQVVMVF9TVE9SQUdFX0dCfSBHQiBvZiBzdGFuZGFyZCBzdG9yYWdlYCxcbiAgICAgICAgICAnRG9lcyBub3QgaW5jbHVkZSByZXF1ZXN0IGNvc3RzIG9yIGRhdGEgdHJhbnNmZXInLFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYW1vdW50OiAwLFxuICAgICAgICBjdXJyZW5jeTogJ1VTRCcsXG4gICAgICAgIGNvbmZpZGVuY2U6ICd1bmtub3duJyxcbiAgICAgICAgYXNzdW1wdGlvbnM6IFtgRmFpbGVkIHRvIGZldGNoIHByaWNpbmc6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG5vcm1hbGl6ZVJlZ2lvbihyZWdpb246IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcmVnaW9uTWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgJ3VzLWVhc3QtMSc6ICdVUyBFYXN0IChOLiBWaXJnaW5pYSknLFxuICAgICAgJ3VzLWVhc3QtMic6ICdVUyBFYXN0IChPaGlvKScsXG4gICAgICAndXMtd2VzdC0xJzogJ1VTIFdlc3QgKE4uIENhbGlmb3JuaWEpJyxcbiAgICAgICd1cy13ZXN0LTInOiAnVVMgV2VzdCAoT3JlZ29uKScsXG4gICAgICAnZXUtd2VzdC0xJzogJ0VVIChJcmVsYW5kKScsXG4gICAgICAnZXUtd2VzdC0yJzogJ0VVIChMb25kb24pJyxcbiAgICAgICdldS13ZXN0LTMnOiAnRVUgKFBhcmlzKScsXG4gICAgICAnZXUtY2VudHJhbC0xJzogJ0VVIChGcmFua2Z1cnQpJyxcbiAgICAgICdldS1ub3J0aC0xJzogJ0VVIChTdG9ja2hvbG0pJyxcbiAgICAgICdhcC1zb3V0aC0xJzogJ0FzaWEgUGFjaWZpYyAoTXVtYmFpKScsXG4gICAgICAnYXAtc291dGhlYXN0LTEnOiAnQXNpYSBQYWNpZmljIChTaW5nYXBvcmUpJyxcbiAgICAgICdhcC1zb3V0aGVhc3QtMic6ICdBc2lhIFBhY2lmaWMgKFN5ZG5leSknLFxuICAgICAgJ2FwLW5vcnRoZWFzdC0xJzogJ0FzaWEgUGFjaWZpYyAoVG9reW8pJyxcbiAgICAgICdhcC1ub3J0aGVhc3QtMic6ICdBc2lhIFBhY2lmaWMgKFNlb3VsKScsXG4gICAgfTtcblxuICAgIHJldHVybiByZWdpb25NYXBbcmVnaW9uXSB8fCByZWdpb247XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ResourceWithId } from '../../diff/types';
|
|
2
|
+
import { ResourceCostCalculator, MonthlyCost, PricingClient } from '../types';
|
|
3
|
+
export declare class VPCEndpointCalculator implements ResourceCostCalculator {
|
|
4
|
+
private customDataProcessedGB?;
|
|
5
|
+
private readonly DEFAULT_DATA_PROCESSED_GB;
|
|
6
|
+
private readonly HOURS_PER_MONTH;
|
|
7
|
+
constructor(customDataProcessedGB?: number | undefined);
|
|
8
|
+
supports(resourceType: string): boolean;
|
|
9
|
+
calculateCost(resource: ResourceWithId, region: string, pricingClient: PricingClient): Promise<MonthlyCost>;
|
|
10
|
+
private normalizeRegion;
|
|
11
|
+
private getRegionPrefix;
|
|
12
|
+
}
|