UNPKG

@cloud-carbon-footprint/aws

Version:

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

107 lines (96 loc) 3.46 kB
/* * © 2021 Thoughtworks, Inc. */ import moment from 'moment' import { CostExplorer } from 'aws-sdk' import { StorageUsage, FootprintEstimate, StorageEstimator, CloudConstants, CloudConstantsEmissionsFactors, } from '@cloud-carbon-footprint/core' import { AWS_CLOUD_CONSTANTS } from '../domain' import { ServiceWrapper } from './ServiceWrapper' export class VolumeUsage implements StorageUsage { readonly terabyteHours: number readonly timestamp: Date readonly diskType: DiskType } export interface MutableFootprintEstimate { timestamp: Date co2e: number kilowattHours: number } export enum DiskType { SSD = 'SSD', HDD = 'HDD', UNKNOWN = 'UNKNOWN', } export async function getUsageFromCostExplorer( params: CostExplorer.GetCostAndUsageRequest, diskTypeCallBack: (awsGroupKey: string) => DiskType, serviceWrapper: ServiceWrapper, ): Promise<VolumeUsage[]> { const responses: CostExplorer.GetCostAndUsageResponse[] = await serviceWrapper.getCostAndUsageResponses(params) return responses .map((response) => { return response.ResultsByTime.map((result) => { const timestampString = result.TimePeriod.Start return result.Groups.map((group) => { const gbMonth = Number.parseFloat(group.Metrics.UsageQuantity.Amount) const terabyteHours = estimateTerabyteHours(gbMonth, timestampString) const diskType = diskTypeCallBack(group.Keys[0]) // Should be improved return { terabyteHours: terabyteHours, timestamp: new Date(timestampString), diskType: diskType, } }) }) }) .flat() .flat() .filter((storageUsage: StorageUsage) => storageUsage.terabyteHours) } function estimateTerabyteHours(sizeGbMonth: number, timestamp: string) { // This function converts an AWS EBS Gigabyte-Month pricing metric into a TerabyteHours value that is needed for Storage Estimation. // We do this by converting Gigabytes into Terabytes, then multiplying this by the number of hours in a month. // Source: https://aws.amazon.com/premiumsupport/knowledge-center/ebs-volume-charges/ return (sizeGbMonth / 1000) * moment(timestamp).daysInMonth() * 24 } export function getEstimatesFromCostExplorer( region: string, volumeUsages: VolumeUsage[], emissionsFactors: CloudConstantsEmissionsFactors, constants: CloudConstants, ): FootprintEstimate[] { const ssdEstimator = new StorageEstimator(AWS_CLOUD_CONSTANTS.SSDCOEFFICIENT) const hddEstimator = new StorageEstimator(AWS_CLOUD_CONSTANTS.HDDCOEFFICIENT) const ssdUsage = volumeUsages.filter( ({ diskType: diskType }) => DiskType.SSD === diskType, ) const hddUsage = volumeUsages.filter( ({ diskType: diskType }) => DiskType.HDD === diskType, ) const footprintEstimates = [ ...ssdEstimator.estimate(ssdUsage, region, emissionsFactors, constants), ...hddEstimator.estimate(hddUsage, region, emissionsFactors, constants), ] return Object.values( footprintEstimates.reduce( (acc: { [key: string]: MutableFootprintEstimate }, estimate) => { if (!acc[estimate.timestamp.toISOString()]) { acc[estimate.timestamp.toISOString()] = estimate return acc } acc[estimate.timestamp.toISOString()].co2e += estimate.co2e acc[estimate.timestamp.toISOString()].kilowattHours += estimate.kilowattHours return acc }, {}, ), ) }