@cloud-carbon-footprint/gcp
Version:
The core logic to get cloud usage data and estimate energy and carbon emissions from Google Cloud Platform.
161 lines • 6.81 kB
JavaScript
"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 {
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.noResultsOnPageMessage = 'NO_RESULTS_ON_PAGE';
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