@csermet/multiprovider
Version:
cloud-graph provider plugin for AWS used to fetch AWS cloud data.
266 lines (265 loc) • 10.6 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const sdk_1 = __importDefault(require("@cloudgraph/sdk"));
const dynamodb_1 = __importDefault(require("aws-sdk/clients/dynamodb"));
const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
const groupBy_1 = __importDefault(require("lodash/groupBy"));
const logger_1 = __importDefault(require("../../properties/logger"));
const format_1 = require("../../utils/format");
const errorLog_1 = __importDefault(require("../../utils/errorLog"));
const utils_1 = require("../../utils");
const lt = { ...logger_1.default };
const { logger } = sdk_1.default;
const serviceName = 'DynamoDB';
const errorLog = new errorLog_1.default(serviceName);
const endpoint = utils_1.initTestEndpoint(serviceName);
const checkIfEnabled = (status) => status && !['DISABLED', 'DISABLING'].includes(status);
const ttlInfoFormatter = (ttlInfo) => {
const { TimeToLiveStatus } = ttlInfo;
return checkIfEnabled(TimeToLiveStatus);
};
const backupInfoFormatter = (backupInfo) => {
const { PointInTimeRecoveryDescription: { PointInTimeRecoveryStatus }, } = backupInfo;
return checkIfEnabled(PointInTimeRecoveryStatus);
};
/**
* DynamoDB
*/
const listTableNamesForRegion = async ({ dynamoDb, resolveRegion, }) => new Promise(resolve => {
const tableList = [];
const listTableNameOpts = {};
const listTables = (exclusiveStartTableName) => {
if (exclusiveStartTableName) {
listTableNameOpts.ExclusiveStartTableName = exclusiveStartTableName;
}
dynamoDb.listTables(listTableNameOpts, (err, listTablesOutput) => {
if (err) {
errorLog.generateAwsErrorLog({
functionName: 'dynamodb:listTables',
err,
});
}
/**
* No DynamoDB data for this region
*/
if (isEmpty_1.default(listTablesOutput)) {
return resolveRegion();
}
const { TableNames, LastEvaluatedTableName: lastEvaluatedTable } = listTablesOutput;
/**
* No DynamoDB Tables for this region
*/
if (isEmpty_1.default(TableNames)) {
return resolveRegion();
}
tableList.push(...TableNames);
if (lastEvaluatedTable) {
listTables(lastEvaluatedTable);
}
resolve(tableList);
});
};
listTables();
});
const getTableDescription = async (dynamoDb, tableName) => new Promise(resolve => {
dynamoDb.describeTable({ TableName: tableName }, (err, tableInfoOutput) => {
if (err || !tableInfoOutput) {
errorLog.generateAwsErrorLog({
functionName: 'dynamodb:describeTable',
err,
});
}
if (!isEmpty_1.default(tableInfoOutput)) {
resolve(tableInfoOutput.Table);
}
resolve({});
});
});
const getTableTags = async (dynamoDb, resourceArn) => new Promise(resolveTags => {
const tags = [];
const listAllTagsOpts = {
ResourceArn: resourceArn,
};
const listAllTags = (token) => {
if (token) {
listAllTagsOpts.NextToken = token;
}
try {
dynamoDb.listTagsOfResource(listAllTagsOpts, (err, data) => {
const { Tags = [], NextToken: nextToken } = data || {};
if (err) {
errorLog.generateAwsErrorLog({
functionName: 'dynamodb:listTagsOfResource',
err,
});
}
tags.push(...Tags);
if (nextToken) {
logger.debug(lt.foundAnotherThousand);
listAllTags(nextToken);
}
else {
resolveTags(format_1.convertAwsTagsToTagMap(tags));
}
});
}
catch (error) {
resolveTags({});
}
};
listAllTags();
});
const getTableTTLDescription = async (dynamoDb, tableName) => new Promise(resolve => {
dynamoDb.describeTimeToLive({
TableName: tableName,
}, (err, data) => {
if (err) {
errorLog.generateAwsErrorLog({
functionName: 'dynamodb:describeTimeToLive',
err,
});
}
if (!isEmpty_1.default(data)) {
resolve(data.TimeToLiveDescription);
}
resolve({});
});
});
const getTableBackupsDescription = async (dynamoDb, tableName) => new Promise(resolve => {
dynamoDb.describeContinuousBackups({
TableName: tableName,
}, (err, data) => {
if (err) {
errorLog.generateAwsErrorLog({
functionName: 'dynamodb:describeContinuousBackups',
err,
});
}
if (!isEmpty_1.default(data)) {
resolve(data.ContinuousBackupsDescription);
}
resolve({ ContinuousBackupsStatus: 'DISABLED' });
});
});
const getTableReplicaAutoScaling = async (dynamoDb, tableName) => new Promise(resolve => {
dynamoDb.describeTableReplicaAutoScaling({
TableName: tableName,
}, (err, data) => {
if (err) {
errorLog.generateAwsErrorLog({
functionName: 'dynamodb:describeTableReplicaAutoScaling',
err,
});
}
if (!isEmpty_1.default(data)) {
resolve(data.TableAutoScalingDescription);
}
resolve({});
});
});
exports.default = async ({ regions, config, }) => new Promise(async (resolve) => {
const tableNames = [];
const tableData = [];
const regionPromises = [];
const tablePromises = [];
const tagsPromises = [];
const ttlInfoPromises = [];
const backupInfoPromises = [];
const tableReplicaAutoScalingPromises = [];
// First we get all table name for all regions
regions.split(',').map(region => {
// We instatiate a client per region
const dynamoDb = new dynamodb_1.default({ ...config, region, endpoint });
const regionPromise = new Promise(async (resolveRegion) => {
// Then we try to fetch all table names per region
// region gets resolved if there's any data found for this region
const regionTableNameList = await listTableNamesForRegion({
dynamoDb,
resolveRegion,
});
// If data exists in this region we begin populating the tableNames array of objects
tableNames.push(...regionTableNameList.map(name => ({ name, region })));
resolveRegion();
});
regionPromises.push(regionPromise);
});
await Promise.all(regionPromises);
logger.debug(lt.fetchedDynamoDbTableNames(tableNames.length));
// In each of the following we set simultaneous clients for each of the tables,
// to fetch all data at once, if possible
// Then we get the full table description for each name
tableNames.map(({ name: tableName, region }) => {
const dynamoDb = new dynamodb_1.default({ ...config, region, endpoint });
const tablePromise = new Promise(async (resolveTable) => {
const tableDescription = await getTableDescription(dynamoDb, tableName);
tableData.push({
region,
...tableDescription,
});
resolveTable();
});
tablePromises.push(tablePromise);
});
logger.debug(lt.gettingTableDetails);
await Promise.all(tablePromises);
// Afterwards we get all tags for each table
tableData.map(({ TableArn: tableArn, region }, idx) => {
const dynamoDb = new dynamodb_1.default({ ...config, region, endpoint });
const tagsPromise = new Promise(async (resolveTags) => {
tableData[idx].Tags = (await getTableTags(dynamoDb, tableArn)) || {};
resolveTags();
});
tagsPromises.push(tagsPromise);
});
logger.debug(lt.gettingTableTags);
await Promise.all(tagsPromises);
// Then we get the ttl description for each table
tableData.map(({ TableName, region }, idx) => {
const dynamoDb = new dynamodb_1.default({ ...config, region, endpoint });
const ttlInfoPromise = new Promise(async (resolveTtlInfo) => {
const ttlInfo = await getTableTTLDescription(dynamoDb, TableName);
tableData[idx].ttlEnabled = ttlInfoFormatter(ttlInfo);
resolveTtlInfo();
});
ttlInfoPromises.push(ttlInfoPromise);
});
logger.debug(lt.gettingTableTtlInfo);
await Promise.all(ttlInfoPromises);
// Get the backup information for each table
tableData.map(({ TableName, region }, idx) => {
const dynamoDb = new dynamodb_1.default({ ...config, region, endpoint });
const backupInfoPromise = new Promise(async (resolveBackupInfo) => {
const backupInfo = await getTableBackupsDescription(dynamoDb, TableName);
tableData[idx].pointInTimeRecoveryEnabled =
backupInfoFormatter(backupInfo);
resolveBackupInfo();
});
backupInfoPromises.push(backupInfoPromise);
});
logger.debug(lt.gettingTableBackupInfo);
await Promise.all(backupInfoPromises);
// Finally we get the auto scaling settings for each table
tableData.map(({ TableName: tableName, region }, idx) => {
const dynamoDb = new dynamodb_1.default({ ...config, region, endpoint });
const tableReplicaAutoScalingPromise = new Promise(async (resolveTableReplicaAutoScaling) => {
const globalSettings = await getTableReplicaAutoScaling(dynamoDb, tableName);
tableData[idx].Replicas = tableData[idx].Replicas?.map(({ RegionName: regionName, ...rest }) => {
const autoScaling = globalSettings?.Replicas?.find(r => r.RegionName === regionName) || {};
return {
AutoScaling: autoScaling,
RegionName: regionName,
...rest,
};
});
resolveTableReplicaAutoScaling();
});
tableReplicaAutoScalingPromises.push(tableReplicaAutoScalingPromise);
});
logger.debug(lt.gettingTableBackupInfo);
await Promise.all(tableReplicaAutoScalingPromises);
errorLog.reset();
resolve(groupBy_1.default(tableData, 'region'));
});