UNPKG

@csermet/multiprovider

Version:

cloud-graph provider plugin for AWS used to fetch AWS cloud data.

266 lines (265 loc) 10.6 kB
"use strict"; 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')); });