UNPKG

@cloud-carbon-footprint/aws

Version:

The core logic to get cloud usage data and estimate energy and carbon emissions from Amazon Web Services.

143 lines 9.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const moment_1 = __importDefault(require("moment")); const common_1 = require("@cloud-carbon-footprint/common"); const ComputeOptimizer_1 = require("./ComputeOptimizer"); const AWSComputeEstimatesBuilder_1 = __importDefault(require("../AWSComputeEstimatesBuilder")); const AWSStorageEstimatesBuilder_1 = __importDefault(require("../AWSStorageEstimatesBuilder")); const AWSMemoryEstimatesBuilder_1 = __importDefault(require("../AWSMemoryEstimatesBuilder")); const CostAndUsageTypes_1 = require("../CostAndUsageTypes"); const domain_1 = require("../../domain"); const AWSRegions_1 = require("../AWSRegions"); class ComputeOptimizerRecommendations { constructor(computeEstimator, memoryEstimator, ssdStorageEstimator, hddStorageEstimator, serviceWrapper) { this.computeEstimator = computeEstimator; this.memoryEstimator = memoryEstimator; this.ssdStorageEstimator = ssdStorageEstimator; this.hddStorageEstimator = hddStorageEstimator; this.serviceWrapper = serviceWrapper; this.recommendationsLogger = new common_1.Logger('AWSRecommendations'); } async getRecommendations(centralComputeOptimizerBucket) { const params = { Bucket: centralComputeOptimizerBucket, }; try { const bucketObjectsList = await this.serviceWrapper.listBucketObjects(params); const recommendationsResult = []; const includedRecommendationTypes = ['OVER_PROVISIONED', 'NOTOPTIMIZED']; for (const recommendationsData of bucketObjectsList.Contents) { const recommendationDate = new Date(recommendationsData.Key.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}/g)[0].toString()); const isFromPreviousDay = moment_1.default.utc(recommendationDate) >= moment_1.default.utc().subtract(1, 'days'); const isIncludedService = !recommendationsData.Key.includes('asg'); const service = recommendationsData.Key.split('/')[1]; if (isFromPreviousDay && isIncludedService) { const params = { Bucket: bucketObjectsList.Name, Key: recommendationsData.Key, }; const parsedRecommendations = await this.serviceWrapper.getComputeOptimizerRecommendationsResponse(params); for (let i = 0; i < parsedRecommendations.length; i++) { const recommendation = parsedRecommendations[i]; const recommendationType = recommendation.finding; if (includedRecommendationTypes.includes(recommendationType.toUpperCase())) { const computeOptimizerRecommendationServices = { ec2: [ ComputeOptimizer_1.EC2CurrentComputeOptimizerRecommendation, ComputeOptimizer_1.EC2TargetComputeOptimizerRecommendation, ], ebs: [ ComputeOptimizer_1.EBSCurrentComputeOptimizerRecommendation, ComputeOptimizer_1.EBSTargetComputeOptimizerRecommendation, ], lambda: [ ComputeOptimizer_1.LambdaCurrentComputeOptimizerRecommendation, ComputeOptimizer_1.LambdaTargetComputeOptimizerRecommendation, ], }; const currentComputeOptimizerRecommendation = new computeOptimizerRecommendationServices[service][0](recommendation); const targetComputeOptimizerRecommendation = new computeOptimizerRecommendationServices[service][1](recommendation); if (targetComputeOptimizerRecommendation.costSavings) { let kilowattHourSavings = 0; let co2eSavings = 0; if (service === 'ebs') { const currentStorageFootprint = this.getStorageFootprintEstimate(currentComputeOptimizerRecommendation); const targetStorageFootprint = this.getStorageFootprintEstimate(targetComputeOptimizerRecommendation); kilowattHourSavings = currentStorageFootprint.kilowattHours - targetStorageFootprint.kilowattHours; co2eSavings = currentStorageFootprint.co2e - targetStorageFootprint.co2e; } else { const [currentComputeFootprint, currentMemoryFootprint] = await this.getComputeAndMemoryFootprintEstimates(currentComputeOptimizerRecommendation, this.recommendationsLogger); const [targetComputeFootprint, targetMemoryFootprint] = await this.getComputeAndMemoryFootprintEstimates(targetComputeOptimizerRecommendation, this.recommendationsLogger); kilowattHourSavings = currentComputeFootprint.kilowattHours - targetComputeFootprint.kilowattHours; co2eSavings = currentComputeFootprint.co2e - targetComputeFootprint.co2e; if (currentMemoryFootprint.co2e || targetMemoryFootprint.co2e) { kilowattHourSavings += currentMemoryFootprint.kilowattHours - targetMemoryFootprint.kilowattHours; co2eSavings += currentMemoryFootprint.co2e - targetMemoryFootprint.co2e; } } recommendationsResult.push({ cloudProvider: 'AWS', accountId: currentComputeOptimizerRecommendation.accountId, accountName: currentComputeOptimizerRecommendation.accountId, instanceName: currentComputeOptimizerRecommendation?.instanceName, region: currentComputeOptimizerRecommendation.region, recommendationType: currentComputeOptimizerRecommendation.type, resourceId: currentComputeOptimizerRecommendation.resourceId, recommendationDetail: this.getRecommendationDetail(service, currentComputeOptimizerRecommendation, targetComputeOptimizerRecommendation), costSavings: parseFloat(targetComputeOptimizerRecommendation.costSavings) || 0, co2eSavings, kilowattHourSavings, }); } } } } } return recommendationsResult; } catch (e) { throw new Error(`Failed to grab AWS Compute Optimizer recommendations. Reason: ${e.message}`); } } getRecommendationDetail(service, currentRecommendation, targetRecommendation) { const modifyType = { ec2: 'instance type', ebs: 'volume type', lambda: 'configuration memory size', }; return `Save cost by changing ${modifyType[service]} from ${currentRecommendation.description} to ${targetRecommendation.description}.`; } async getComputeAndMemoryFootprintEstimates(computeOptimizerRecommendation, logger) { const dateTime = new Date().toISOString(); const emissionsFactors = await (0, common_1.getEmissionsFactors)(computeOptimizerRecommendation.region, dateTime, domain_1.AWS_EMISSIONS_FACTORS_METRIC_TON_PER_KWH, AWSRegions_1.AWS_MAPPED_REGIONS_TO_ELECTRICITY_MAPS_ZONES, logger); const computeFootprint = new AWSComputeEstimatesBuilder_1.default(computeOptimizerRecommendation, this.computeEstimator, emissionsFactors).computeFootprint; const memoryFootprint = new AWSMemoryEstimatesBuilder_1.default(computeOptimizerRecommendation, this.memoryEstimator, emissionsFactors).memoryFootprint; return [computeFootprint, memoryFootprint]; } getStorageFootprintEstimate(computeOptimizerRecommendation) { let storageEstimator = this.hddStorageEstimator; if (this.volumeTypeIsSSD(computeOptimizerRecommendation.volumeType)) { storageEstimator = this.ssdStorageEstimator; } return new AWSStorageEstimatesBuilder_1.default(computeOptimizerRecommendation, storageEstimator).storageFootprint; } volumeTypeIsSSD(volumeType) { return CostAndUsageTypes_1.SSD_USAGE_TYPES.some((type) => type.includes(volumeType)); } } exports.default = ComputeOptimizerRecommendations; //# sourceMappingURL=ComputeOptimizerRecommendations.js.map