UNPKG

@cloud-carbon-footprint/gcp

Version:

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

170 lines 6.99 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const ramda_1 = __importDefault(require("ramda")); const common_1 = require("@cloud-carbon-footprint/common"); const RETRY_AFTER = 10; class ServiceWrapper { projectsClient; authClient; instancesClient; disksClient; addressesClient; imagesClient; machineTypesClient; recommenderClient; serviceWrapperLogger; noResultsOnPageMessage = 'NO_RESULTS_ON_PAGE'; constructor(projectsClient, authClient, instancesClient, disksClient, addressesClient, imagesClient, machineTypesClient, recommenderClient) { this.projectsClient = projectsClient; this.authClient = authClient; this.instancesClient = instancesClient; this.disksClient = disksClient; this.addressesClient = addressesClient; this.imagesClient = imagesClient; this.machineTypesClient = machineTypesClient; this.recommenderClient = recommenderClient; this.serviceWrapperLogger = new common_1.Logger('GCP Service Wrapper'); } async getActiveProjectsAndZones() { const projects = await this.getProjects(); const activeProjects = projects.filter((project) => project.state === 'ACTIVE'); const activeProjectsAndZones = []; const projectChunks = ramda_1.default.splitEvery(150, activeProjects); for (const projectChunk of projectChunks) { const projectZonesForChunk = await Promise.all(projectChunk.map(async (project) => { return await this.getZonesForProject(project); })); activeProjectsAndZones.push(projectZonesForChunk); } return ramda_1.default.flatten(activeProjectsAndZones); } async getProjects() { const [projects] = await this.projectsClient.searchProjects(); return projects; } async getZonesForProject(project) { try { const computeEngineRequest = { project: project.projectId, auth: this.authClient, }; const instancesResult = await this.instancesClient.aggregatedListAsync(computeEngineRequest); const disksResult = await this.disksClient.aggregatedListAsync(computeEngineRequest); const addressesResult = await this.addressesClient.aggregatedListAsync(computeEngineRequest); const instanceZones = await this.extractZones(instancesResult); const diskZones = await this.extractZones(disksResult); const addressesZones = await this.extractZones(addressesResult); return { id: project.projectId, name: project.displayName, zones: ramda_1.default.uniq([ ...instanceZones, ...addressesZones, ...diskZones, 'global', ]), }; } catch (e) { this.serviceWrapperLogger.warn(`Failed to get active zones for project: ${project.projectId}. Error: ${e.message} `); return []; } } async extractZones(results) { const items = []; for await (const [zone, result] of results) { if (result.warning?.code !== this.noResultsOnPageMessage) { const formattedZone = zone.replace('zones/', '').replace('regions/', ''); items.push(formattedZone); } } return items; } async getRecommendationsForRecommenderIds(projectId, zone, recommenderIds) { const recommendationByRecommenderIds = []; for (const recommenderId of recommenderIds) { let inProcess = true; while (inProcess) { try { const [recommendations] = await this.recommenderClient.listRecommendations({ parent: this.recommenderClient.projectLocationRecommenderPath(projectId, zone, recommenderId), }); inProcess = false; recommendationByRecommenderIds.push({ id: recommenderId, zone: zone, recommendations, }); } catch (err) { if (err.details?.includes('Quota exceeded')) { this.serviceWrapperLogger.warn(`GCP Recommendations API quota exceeded. Retrying after ${RETRY_AFTER} seconds.`); await (0, common_1.wait)(RETRY_AFTER * 1000); } else { this.serviceWrapperLogger.warn(`Failed to get recommendations for GCP recommender ID: ${recommenderId}. Error: ${err.message}`); inProcess = false; } } } } return recommendationByRecommenderIds; } async getInstanceDetails(projectId, instanceId, zone) { const computeEngineRequest = { project: projectId, zone: zone, instance: instanceId, auth: this.authClient, }; const [instanceDetails] = await this.instancesClient.get(computeEngineRequest); return instanceDetails; } async getMachineTypeDetails(projectId, machineType, zone) { const machineTypeRequest = { project: projectId, zone: zone, machineType: machineType, auth: this.authClient, }; const [machineTypeDetails] = await this.machineTypesClient.get(machineTypeRequest); return machineTypeDetails; } getStorageTypeFromDiskName(diskName) { return diskName.includes('ssd') ? 'SSD' : 'HDD'; } async getDiskDetails(projectId, diskId, zone) { const diskDetailsRequest = { project: projectId, zone: zone, disk: diskId, auth: this.authClient, }; const [diskDetails] = await this.disksClient.get(diskDetailsRequest); return diskDetails; } async getImageDetails(projectId, imageId) { const imageDetailsRequest = { project: projectId, image: imageId, auth: this.authClient, }; const [imageDetails] = await this.imagesClient.get(imageDetailsRequest); return imageDetails; } async getAddressDetails(projectId, addressId, zone) { const AddressDetailsRequest = { project: projectId, region: zone, address: addressId, auth: this.authClient, }; const [addressDetails] = await this.addressesClient.get(AddressDetailsRequest); return addressDetails; } } exports.default = ServiceWrapper; //# sourceMappingURL=ServiceWrapper.js.map