UNPKG

@cloud-carbon-footprint/aws

Version:

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

111 lines 6.77 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const common_1 = require("@cloud-carbon-footprint/common"); const AWSComputeEstimatesBuilder_1 = __importDefault(require("../AWSComputeEstimatesBuilder")); const AWSMemoryEstimatesBuilder_1 = __importDefault(require("../AWSMemoryEstimatesBuilder")); const Rightsizing_1 = require("./Rightsizing"); const domain_1 = require("../../domain"); const AWSRegions_1 = require("../AWSRegions"); class RightsizingRecommendations { constructor(computeEstimator, memoryEstimator, serviceWrapper) { this.computeEstimator = computeEstimator; this.memoryEstimator = memoryEstimator; this.serviceWrapper = serviceWrapper; this.rightsizingRecommendationsService = 'AmazonEC2'; this.recommendationsLogger = new common_1.Logger('AWSRecommendations'); } async getRecommendations(recommendationTarget) { const params = { Service: this.rightsizingRecommendationsService, Configuration: { BenefitsConsidered: false, RecommendationTarget: recommendationTarget, }, }; try { const results = await this.serviceWrapper.getRightsizingRecommendationsResponses(params); const rightsizingRecommendations = results.flatMap(({ RightsizingRecommendations }) => RightsizingRecommendations); const recommendationsResult = []; for (let i = 0; i < rightsizingRecommendations.length; i++) { const recommendation = rightsizingRecommendations[i]; const rightsizingCurrentRecommendation = new Rightsizing_1.RightsizingCurrentRecommendation(recommendation); const [currentComputeFootprint, currentMemoryFootprint] = await this.getFootprintEstimates(rightsizingCurrentRecommendation); let kilowattHourSavings = currentComputeFootprint.kilowattHours; let co2eSavings = currentComputeFootprint.co2e; let costSavings = rightsizingCurrentRecommendation.costSavings; let recommendationDetail = this.getRecommendationDetail(rightsizingCurrentRecommendation); if (currentMemoryFootprint.co2e) { kilowattHourSavings += currentMemoryFootprint.kilowattHours; co2eSavings += currentMemoryFootprint.co2e; } if (recommendation.RightsizingType === 'Modify') { this.getTargetInstance(recommendation); const rightsizingTargetRecommendation = new Rightsizing_1.RightsizingTargetRecommendation(recommendation); const [targetComputeFootprint, targetMemoryFootprint] = await this.getFootprintEstimates(rightsizingTargetRecommendation); kilowattHourSavings -= targetComputeFootprint.kilowattHours; co2eSavings -= targetComputeFootprint.co2e; costSavings = rightsizingTargetRecommendation.costSavings; recommendationDetail = this.getRecommendationDetail(rightsizingCurrentRecommendation, rightsizingTargetRecommendation); if (targetMemoryFootprint.co2e) { kilowattHourSavings -= targetMemoryFootprint.kilowattHours; co2eSavings -= targetMemoryFootprint.co2e; } } recommendationsResult.push({ cloudProvider: 'AWS', accountId: rightsizingCurrentRecommendation.accountId, accountName: rightsizingCurrentRecommendation.accountId, region: rightsizingCurrentRecommendation.region, recommendationType: rightsizingCurrentRecommendation.type, recommendationDetail, kilowattHourSavings, resourceId: rightsizingCurrentRecommendation.resourceId, instanceName: rightsizingCurrentRecommendation.instanceName, co2eSavings, costSavings, }); } return recommendationsResult; } catch (e) { throw new Error(`Failed to grab AWS Rightsizing recommendations. Reason: ${e.message}`); } } getRecommendationDetail(rightsizingCurrentRecommendation, rightsizingTargetRecommendation) { const modifyDetail = `Update instance type ${rightsizingCurrentRecommendation.instanceType} to ${rightsizingTargetRecommendation?.instanceType}`; let defaultDetail = `${rightsizingCurrentRecommendation.type} instance: ${rightsizingCurrentRecommendation.instanceName}.`; if (!rightsizingCurrentRecommendation.instanceName) { defaultDetail = `${rightsizingCurrentRecommendation.type} instance with Resource ID: ${rightsizingCurrentRecommendation.resourceId}.`; } const recommendationTypes = { Terminate: defaultDetail, Modify: `${defaultDetail} ${modifyDetail}`, }; return recommendationTypes[rightsizingCurrentRecommendation.type]; } async getFootprintEstimates(rightsizingRecommendation) { const dateTime = new Date().toISOString(); const emissionsFactors = await (0, common_1.getEmissionsFactors)(rightsizingRecommendation.region, dateTime, domain_1.AWS_EMISSIONS_FACTORS_METRIC_TON_PER_KWH, AWSRegions_1.AWS_MAPPED_REGIONS_TO_ELECTRICITY_MAPS_ZONES, this.recommendationsLogger); const computeFootprint = new AWSComputeEstimatesBuilder_1.default(rightsizingRecommendation, this.computeEstimator, emissionsFactors).computeFootprint; const memoryFootprint = new AWSMemoryEstimatesBuilder_1.default(rightsizingRecommendation, this.memoryEstimator, emissionsFactors).memoryFootprint; return [computeFootprint, memoryFootprint]; } getTargetInstance(rightsizingRecommendationData) { let targetInstance = rightsizingRecommendationData.ModifyRecommendationDetail.TargetInstances.pop(); let savings = 0; rightsizingRecommendationData.ModifyRecommendationDetail.TargetInstances.map((instance) => { if (parseFloat(instance.EstimatedMonthlySavings) >= savings) { savings = parseFloat(instance.EstimatedMonthlySavings); targetInstance = instance; } }); rightsizingRecommendationData.ModifyRecommendationDetail.TargetInstances = [ targetInstance, ]; } } exports.default = RightsizingRecommendations; //# sourceMappingURL=RightsizingRecommendations.js.map