UNPKG

@cloud-carbon-footprint/gcp

Version:

The core logic to get cloud usage data and estimate energy and carbon emissions from Google Cloud Platform.

181 lines (167 loc) 5.31 kB
/* * © 2021 Thoughtworks, Inc. */ import { v3 } from '@google-cloud/monitoring' import { ClientOptions } from 'google-gax' import { BigQuery } from '@google-cloud/bigquery' import { ProjectsClient } from '@google-cloud/resource-manager' import { RecommenderClient } from '@google-cloud/recommender' import { InstancesClient, DisksClient, AddressesClient, ImagesClient, MachineTypesClient, } from '@google-cloud/compute' import { GoogleAuth } from 'google-auth-library' import { ICloudService, Region, ComputeEstimator, StorageEstimator, NetworkingEstimator, MemoryEstimator, UnknownEstimator, CloudProviderAccount, EmbodiedEmissionsEstimator, } from '@cloud-carbon-footprint/core' import { configLoader, EstimationResult, RecommendationResult, GoogleAuthClient, LookupTableInput, LookupTableOutput, GroupBy, } from '@cloud-carbon-footprint/common' import ServiceWrapper from '../lib/ServiceWrapper' import { BillingExportTable, ComputeEngine, Recommendations } from '../lib' import { GCP_CLOUD_CONSTANTS, getGCPEmissionsFactors } from '../domain' export default class GCPAccount extends CloudProviderAccount { constructor( public id: string, public name: string, private regions: string[], ) { super() } async getDataForRegions( startDate: Date, endDate: Date, grouping: GroupBy, ): Promise<EstimationResult[]> { const estimationResults = await Promise.all( this.regions.map(async (regionId) => { return await this.getDataForRegion( regionId, startDate, endDate, grouping, ) }), ) return estimationResults.flat() } async getDataForRegion( regionId: string, startDate: Date, endDate: Date, grouping: GroupBy, ): Promise<EstimationResult[]> { const gcpServices = this.getServices() const gcpConstants = { minWatts: GCP_CLOUD_CONSTANTS.MIN_WATTS_MEDIAN, maxWatts: GCP_CLOUD_CONSTANTS.MAX_WATTS_MEDIAN, powerUsageEffectiveness: GCP_CLOUD_CONSTANTS.getPUE(), } const region = new Region( regionId, gcpServices, getGCPEmissionsFactors(), gcpConstants, ) return await this.getRegionData('GCP', region, startDate, endDate, grouping) } async getDataFromBillingExportTable( startDate: Date, endDate: Date, grouping: GroupBy, ): Promise<EstimationResult[]> { const billingExportTableService = new BillingExportTable( new ComputeEstimator(), new StorageEstimator(GCP_CLOUD_CONSTANTS.SSDCOEFFICIENT), new StorageEstimator(GCP_CLOUD_CONSTANTS.HDDCOEFFICIENT), new NetworkingEstimator(GCP_CLOUD_CONSTANTS.NETWORKING_COEFFICIENT), new MemoryEstimator(GCP_CLOUD_CONSTANTS.MEMORY_COEFFICIENT), new UnknownEstimator(GCP_CLOUD_CONSTANTS.ESTIMATE_UNKNOWN_USAGE_BY), new EmbodiedEmissionsEstimator( GCP_CLOUD_CONSTANTS.SERVER_EXPECTED_LIFESPAN, ), new BigQuery({ projectId: this.id }), ) return await billingExportTableService.getEstimates( startDate, endDate, grouping, ) } static async getBillingExportDataFromInputData( inputData: LookupTableInput[], ): Promise<LookupTableOutput[]> { const billingExportTableService = new BillingExportTable( new ComputeEstimator(), new StorageEstimator(GCP_CLOUD_CONSTANTS.SSDCOEFFICIENT), new StorageEstimator(GCP_CLOUD_CONSTANTS.HDDCOEFFICIENT), new NetworkingEstimator(GCP_CLOUD_CONSTANTS.NETWORKING_COEFFICIENT), new MemoryEstimator(GCP_CLOUD_CONSTANTS.MEMORY_COEFFICIENT), new UnknownEstimator(GCP_CLOUD_CONSTANTS.ESTIMATE_UNKNOWN_USAGE_BY), new EmbodiedEmissionsEstimator( GCP_CLOUD_CONSTANTS.SERVER_EXPECTED_LIFESPAN, ), ) return await billingExportTableService.getEstimatesFromInputData(inputData) } getServices(): ICloudService[] { return configLoader().GCP.CURRENT_SERVICES.map(({ key }) => { return this.getService(key) }) } async getDataForRecommendations(): Promise<RecommendationResult[]> { const auth = new GoogleAuth({ scopes: ['https://www.googleapis.com/auth/cloud-platform'], }) const googleAuthClient: GoogleAuthClient = await auth.getClient() const serviceWrapper = new ServiceWrapper( new ProjectsClient(), googleAuthClient, new InstancesClient(), new DisksClient(), new AddressesClient(), new ImagesClient(), new MachineTypesClient(), new RecommenderClient(), ) const recommendations = new Recommendations( new ComputeEstimator(), new StorageEstimator(GCP_CLOUD_CONSTANTS.HDDCOEFFICIENT), new StorageEstimator(GCP_CLOUD_CONSTANTS.SSDCOEFFICIENT), serviceWrapper, ) return await recommendations.getRecommendations() } private getService(key: string): ICloudService { if (this.services[key] === undefined) throw new Error('Unsupported service: ' + key) const options: ClientOptions = { projectId: this.id, } return this.services[key](options) } private services: { [id: string]: (options: ClientOptions) => ICloudService } = { computeEngine: (options) => { return new ComputeEngine(new v3.MetricServiceClient(options)) }, } }