@electrolux-oss/plugin-infrawallet-backend 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.d.ts +2 -2
- package/dist/index.cjs.js +75 -55
- package/dist/index.cjs.js.map +1 -1
- package/package.json +1 -1
- package/seeds/init.js +68 -43
package/config.d.ts
CHANGED
package/dist/index.cjs.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var backendCommon = require('@backstage/backend-common');
|
|
6
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
6
7
|
var express = require('express');
|
|
7
8
|
var Router = require('express-promise-router');
|
|
8
9
|
var clientCostExplorer = require('@aws-sdk/client-cost-explorer');
|
|
@@ -11,7 +12,6 @@ var lodash = require('lodash');
|
|
|
11
12
|
var moment = require('moment');
|
|
12
13
|
var armCostmanagement = require('@azure/arm-costmanagement');
|
|
13
14
|
var identity = require('@azure/identity');
|
|
14
|
-
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
15
15
|
|
|
16
16
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
17
17
|
|
|
@@ -65,9 +65,9 @@ class AwsClient {
|
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
for (const c of conf) {
|
|
68
|
-
const name = c.
|
|
69
|
-
const accountId = c.
|
|
70
|
-
const assumedRoleName = c.
|
|
68
|
+
const name = c.getString("name");
|
|
69
|
+
const accountId = c.getString("accountId");
|
|
70
|
+
const assumedRoleName = c.getString("assumedRoleName");
|
|
71
71
|
const accessKeyId = c.getOptionalString("accessKeyId");
|
|
72
72
|
const accessKeySecret = c.getOptionalString("accessKeySecret");
|
|
73
73
|
const tags = c.getOptionalStringArray("tags");
|
|
@@ -77,15 +77,23 @@ class AwsClient {
|
|
|
77
77
|
tagKeyValues[k.trim()] = v.trim();
|
|
78
78
|
});
|
|
79
79
|
const categoryMappings = await getCategoryMappings(this.database, "aws");
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
let stsParams = {};
|
|
81
|
+
if (accessKeyId && accessKeySecret) {
|
|
82
|
+
stsParams = {
|
|
83
83
|
region: "us-east-1",
|
|
84
84
|
credentials: {
|
|
85
85
|
accessKeyId,
|
|
86
86
|
secretAccessKey: accessKeySecret
|
|
87
87
|
}
|
|
88
|
-
}
|
|
88
|
+
};
|
|
89
|
+
} else {
|
|
90
|
+
stsParams = {
|
|
91
|
+
region: "us-east-1"
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const promise = (async () => {
|
|
95
|
+
var _a, _b, _c;
|
|
96
|
+
const client = new clientSts.STSClient(stsParams);
|
|
89
97
|
const commandInput = {
|
|
90
98
|
// AssumeRoleRequest
|
|
91
99
|
RoleArn: `arn:aws:iam::${accountId}:role/${assumedRoleName}`,
|
|
@@ -116,27 +124,36 @@ class AwsClient {
|
|
|
116
124
|
const transformedData = lodash.reduce(
|
|
117
125
|
costAndusageResponse.ResultsByTime,
|
|
118
126
|
(acc, row) => {
|
|
119
|
-
|
|
120
|
-
row.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
127
|
+
var _a2;
|
|
128
|
+
const rowTime = (_a2 = row.TimePeriod) == null ? void 0 : _a2.Start;
|
|
129
|
+
const period = rowTime ? rowTime.substring(0, 7) : "unknown";
|
|
130
|
+
if (row.Groups) {
|
|
131
|
+
row.Groups.forEach((group) => {
|
|
132
|
+
var _a3;
|
|
133
|
+
const groupKeys = group.Keys ? group.Keys[0] : "";
|
|
134
|
+
const keyName = `${name}_${groupKeys}`;
|
|
135
|
+
if (!acc[keyName]) {
|
|
136
|
+
acc[keyName] = {
|
|
137
|
+
id: keyName,
|
|
138
|
+
name,
|
|
139
|
+
service: `${groupKeys} (AWS)`,
|
|
140
|
+
category: getCategoryByServiceName(
|
|
141
|
+
groupKeys,
|
|
142
|
+
categoryMappings
|
|
143
|
+
),
|
|
144
|
+
provider: "AWS",
|
|
145
|
+
reports: {},
|
|
146
|
+
...tagKeyValues
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const groupMetrics = group.Metrics;
|
|
150
|
+
if (groupMetrics !== void 0) {
|
|
151
|
+
acc[keyName].reports[period] = parseFloat(
|
|
152
|
+
(_a3 = groupMetrics.UnblendedCost.Amount) != null ? _a3 : "0.0"
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
140
157
|
return acc;
|
|
141
158
|
},
|
|
142
159
|
{}
|
|
@@ -189,11 +206,11 @@ class AzureClient {
|
|
|
189
206
|
const results = [];
|
|
190
207
|
const groupPairs = [{ type: "Dimension", name: "ServiceName" }];
|
|
191
208
|
for (const c of conf) {
|
|
192
|
-
const name = c.
|
|
193
|
-
const subscriptionId = c.
|
|
194
|
-
const tenantId = c.
|
|
195
|
-
const clientId = c.
|
|
196
|
-
const clientSecret = c.
|
|
209
|
+
const name = c.getString("name");
|
|
210
|
+
const subscriptionId = c.getString("subscriptionId");
|
|
211
|
+
const tenantId = c.getString("tenantId");
|
|
212
|
+
const clientId = c.getString("clientId");
|
|
213
|
+
const clientSecret = c.getString("clientSecret");
|
|
197
214
|
const credential = new identity.ClientSecretCredential(
|
|
198
215
|
tenantId,
|
|
199
216
|
clientId,
|
|
@@ -261,8 +278,32 @@ class AzureClient {
|
|
|
261
278
|
}
|
|
262
279
|
}
|
|
263
280
|
|
|
281
|
+
async function setUpDatabase(database) {
|
|
282
|
+
var _a;
|
|
283
|
+
const client = await database.getClient();
|
|
284
|
+
const migrationsDir = backendPluginApi.resolvePackagePath(
|
|
285
|
+
"@electrolux-oss/plugin-infrawallet-backend",
|
|
286
|
+
"migrations"
|
|
287
|
+
);
|
|
288
|
+
if (!((_a = database.migrations) == null ? void 0 : _a.skip)) {
|
|
289
|
+
await client.migrate.latest({
|
|
290
|
+
directory: migrationsDir
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
const category_mappings_count = await client("category_mappings").count(
|
|
294
|
+
"id as c"
|
|
295
|
+
);
|
|
296
|
+
if (category_mappings_count[0].c === 0 || category_mappings_count[0].c === "0") {
|
|
297
|
+
const seedsDir = backendPluginApi.resolvePackagePath(
|
|
298
|
+
"@electrolux-oss/plugin-infrawallet-backend",
|
|
299
|
+
"seeds"
|
|
300
|
+
);
|
|
301
|
+
await client.seed.run({ directory: seedsDir });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
264
304
|
async function createRouter(options) {
|
|
265
305
|
const { logger, config, cache, database } = options;
|
|
306
|
+
await setUpDatabase(database);
|
|
266
307
|
const router = Router__default.default();
|
|
267
308
|
router.use(express__default.default.json());
|
|
268
309
|
const azureClient = AzureClient.create(config, database);
|
|
@@ -333,27 +374,6 @@ const infraWalletPlugin = backendPluginApi.createBackendPlugin({
|
|
|
333
374
|
database: backendPluginApi.coreServices.database
|
|
334
375
|
},
|
|
335
376
|
async init({ httpRouter, logger, config, cache, database }) {
|
|
336
|
-
var _a;
|
|
337
|
-
const client = await database.getClient();
|
|
338
|
-
const migrationsDir = backendPluginApi.resolvePackagePath(
|
|
339
|
-
"@electrolux-oss/plugin-infrawallet-backend",
|
|
340
|
-
"migrations"
|
|
341
|
-
);
|
|
342
|
-
if (!((_a = database.migrations) == null ? void 0 : _a.skip)) {
|
|
343
|
-
await client.migrate.latest({
|
|
344
|
-
directory: migrationsDir
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
const category_mappings_count = await client("category_mappings").count(
|
|
348
|
-
"id as c"
|
|
349
|
-
);
|
|
350
|
-
if (category_mappings_count[0].c === 0 || category_mappings_count[0].c === "0") {
|
|
351
|
-
const seedsDir = backendPluginApi.resolvePackagePath(
|
|
352
|
-
"@electrolux-oss/plugin-infrawallet-backend",
|
|
353
|
-
"seeds"
|
|
354
|
-
);
|
|
355
|
-
await client.seed.run({ directory: seedsDir });
|
|
356
|
-
}
|
|
357
377
|
httpRouter.use(
|
|
358
378
|
await createRouter({
|
|
359
379
|
logger,
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/service/functions.ts","../src/service/AwsClient.ts","../src/service/AzureClient.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["import { DatabaseService } from '@backstage/backend-plugin-api';\nimport { CategoryMapping } from './types';\n\nexport async function getCategoryMappings(\n database: DatabaseService,\n provider: string,\n): Promise<{ [category: string]: string[] }> {\n const result: { [category: string]: string[] } = {};\n const client = await database.getClient();\n const mappings = await client\n .where({ provider: provider })\n .select()\n .from<CategoryMapping>('category_mappings');\n mappings.forEach(mapping => {\n if (typeof mapping.cloud_service_names === 'string') {\n // just in case if the database such as sqlite does not support JSON column\n result[mapping.category] = JSON.parse(mapping.cloud_service_names);\n } else {\n result[mapping.category] = mapping.cloud_service_names;\n }\n });\n return result;\n}\n\nexport function getCategoryByServiceName(\n serviceName: string,\n categoryMappings: { [category: string]: string[] },\n): string {\n for (const key of Object.keys(categoryMappings)) {\n const serviceNames = categoryMappings[key];\n if (serviceNames && serviceNames.includes(serviceName)) {\n return key;\n }\n }\n\n return 'Uncategorized';\n}\n","import {\n CostExplorerClient,\n GetCostAndUsageCommand,\n Granularity,\n} from '@aws-sdk/client-cost-explorer';\nimport { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts';\nimport { DatabaseService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { CostQuery, InfraWalletApi, Report } from './InfraWalletApi';\nimport { getCategoryMappings, getCategoryByServiceName } from './functions';\n\nexport class AwsClient implements InfraWalletApi {\n static create(config: Config, database: DatabaseService) {\n return new AwsClient(config, database);\n }\n\n constructor(\n private readonly config: Config,\n private readonly database: DatabaseService,\n ) {}\n\n async fetchCostsFromCloud(query: CostQuery): Promise<Report[]> {\n const conf = this.config.getOptionalConfigArray(\n 'backend.infraWallet.integrations.aws',\n );\n if (!conf) {\n return [];\n }\n\n const promises = [];\n const results = [];\n const groupPairs = [];\n query.groups.split(',').forEach(group => {\n if (group.includes(':')) {\n const [type, name] = group.split(':');\n groupPairs.push({ type, name });\n }\n });\n\n for (const c of conf) {\n const name = c.getOptionalString('name');\n const accountId = c.getOptionalString('accountId');\n const assumedRoleName = c.getOptionalString('assumedRoleName');\n const accessKeyId = c.getOptionalString('accessKeyId');\n const accessKeySecret = c.getOptionalString('accessKeySecret');\n const tags = c.getOptionalStringArray('tags');\n const tagKeyValues: { [key: string]: string } = {};\n tags?.forEach(tag => {\n const [k, v] = tag.split(':');\n tagKeyValues[k.trim()] = v.trim();\n });\n const categoryMappings = await getCategoryMappings(this.database, 'aws');\n\n const promise = (async () => {\n const client = new STSClient({\n region: 'us-east-1',\n credentials: {\n accessKeyId: accessKeyId as string,\n secretAccessKey: accessKeySecret as string,\n },\n });\n const commandInput = {\n // AssumeRoleRequest\n RoleArn: `arn:aws:iam::${accountId}:role/${assumedRoleName}`,\n RoleSessionName: 'AssumeRoleSession1',\n };\n const assumeRoleCommand = new AssumeRoleCommand(commandInput);\n const assumeRoleResponse = await client.send(assumeRoleCommand);\n // init aws cost explorer client\n const awsCeClient = new CostExplorerClient({\n region: 'us-east-1',\n credentials: {\n accessKeyId: assumeRoleResponse.Credentials?.AccessKeyId as string,\n secretAccessKey: assumeRoleResponse.Credentials\n ?.SecretAccessKey as string,\n sessionToken: assumeRoleResponse.Credentials\n ?.SessionToken as string,\n },\n });\n\n // query this aws account's cost and usage using @aws-sdk/client-cost-explorer\n const input = {\n TimePeriod: {\n Start: moment(parseInt(query.startTime, 10)).format('YYYY-MM-DD'),\n End: moment(parseInt(query.endTime, 10)).format('YYYY-MM-DD'),\n },\n Granularity: query.granularity.toUpperCase() as Granularity,\n Filter: { Dimensions: { Key: 'RECORD_TYPE', Values: ['Usage'] } },\n GroupBy: [{ Type: 'DIMENSION', Key: 'SERVICE' }],\n Metrics: ['UnblendedCost'],\n };\n const getCostCommand = new GetCostAndUsageCommand(input);\n const costAndusageResponse = await awsCeClient.send(getCostCommand);\n\n const transformedData = reduce(\n costAndusageResponse.ResultsByTime,\n (acc, row) => {\n const period = row.TimePeriod.Start.substring(0, 7);\n row.Groups.forEach(group => {\n const keyName = `${name}_${group.Keys[0]}`;\n\n if (!acc[keyName]) {\n acc[keyName] = {\n id: keyName,\n name: name,\n service: `${group.Keys[0]} (AWS)`,\n category: getCategoryByServiceName(\n group.Keys[0],\n categoryMappings,\n ),\n provider: 'AWS',\n reports: {},\n ...tagKeyValues,\n };\n }\n\n acc[keyName].reports[period] = parseFloat(\n group.Metrics.UnblendedCost.Amount,\n );\n });\n return acc;\n },\n {},\n );\n\n Object.values(transformedData).map((value: any) => {\n results.push(value);\n });\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return results;\n }\n}\n","import { CostManagementClient } from '@azure/arm-costmanagement';\nimport { ClientSecretCredential } from '@azure/identity';\nimport { DatabaseService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { CostQuery, InfraWalletApi, Report } from './InfraWalletApi';\nimport { getCategoryMappings, getCategoryByServiceName } from './functions';\n\nexport class AzureClient implements InfraWalletApi {\n static create(config: Config, database: DatabaseService) {\n return new AzureClient(config, database);\n }\n\n constructor(\n private readonly config: Config,\n private readonly database: DatabaseService,\n ) {}\n\n async queryAzureCostExplorer(\n azureClient: any,\n subscription: string,\n granularity: string,\n groups: { type: string; name: string }[],\n startDate: moment.Moment,\n endDate: moment.Moment,\n ) {\n const scope = `/subscriptions/${subscription}`;\n\n const query = {\n type: 'ActualCost',\n dataset: {\n granularity: granularity,\n aggregation: { totalCostUSD: { name: 'CostUSD', function: 'Sum' } },\n grouping: groups,\n },\n timeframe: 'Custom',\n timePeriod: {\n from: startDate.toISOString(),\n to: endDate.toISOString(),\n },\n };\n\n const result = await azureClient.query.usage(scope, query);\n return result;\n }\n\n async fetchCostsFromCloud(query: CostQuery): Promise<Report[]> {\n const conf = this.config.getOptionalConfigArray(\n 'backend.infraWallet.integrations.azure',\n );\n if (!conf) {\n return [];\n }\n\n const promises = [];\n const results = [];\n\n const groupPairs = [{ type: 'Dimension', name: 'ServiceName' }];\n for (const c of conf) {\n const name = c.getOptionalString('name');\n const subscriptionId = c.getOptionalString('subscriptionId');\n const tenantId = c.getOptionalString('tenantId');\n const clientId = c.getOptionalString('clientId');\n const clientSecret = c.getOptionalString('clientSecret');\n const credential = new ClientSecretCredential(\n tenantId as string,\n clientId as string,\n clientSecret as string,\n );\n const client = new CostManagementClient(credential);\n const tags = c.getOptionalStringArray('tags');\n const tagKeyValues: { [key: string]: string } = {};\n tags?.forEach(tag => {\n const [k, v] = tag.split(':');\n tagKeyValues[k.trim()] = v.trim();\n });\n const categoryMappings = await getCategoryMappings(\n this.database,\n 'azure',\n );\n\n const promise = (async () => {\n try {\n const costResponse = await this.queryAzureCostExplorer(\n client,\n subscriptionId as string,\n query.granularity,\n groupPairs,\n moment(parseInt(query.startTime, 10)),\n moment(parseInt(query.endTime, 10)),\n );\n\n const transformedData = reduce(\n costResponse.rows,\n (acc, row) => {\n let keyName = name;\n for (let i = 0; i < groupPairs.length; i++) {\n keyName += `->${row[i + 2]}`;\n }\n\n if (!acc[keyName]) {\n acc[keyName] = {\n id: keyName,\n name: name,\n service: `${row[2]} (Azure)`,\n category: getCategoryByServiceName(row[2], categoryMappings),\n provider: 'Azure',\n reports: {},\n ...tagKeyValues,\n };\n }\n\n if (\n !moment(row[1]).isBefore(moment(parseInt(query.startTime, 10)))\n ) {\n acc[keyName].reports[row[1].substring(0, 7)] = parseFloat(\n row[0],\n );\n }\n return acc;\n },\n {},\n );\n\n Object.values(transformedData).map((value: any) => {\n results.push(value);\n });\n } catch (e) {\n throw new Error(e.message);\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return results;\n }\n}\n","import { errorHandler } from '@backstage/backend-common';\nimport {\n CacheService,\n DatabaseService,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { JsonArray } from '@backstage/types';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { AwsClient } from './AwsClient';\nimport { AzureClient } from './AzureClient';\nimport { InfraWalletApi } from './InfraWalletApi';\n\nexport interface RouterOptions {\n logger: LoggerService;\n config: Config;\n cache: CacheService;\n database: DatabaseService;\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, cache, database } = options;\n\n const router = Router();\n router.use(express.json());\n\n const azureClient = AzureClient.create(config, database);\n const awsClient = AwsClient.create(config, database);\n const cloudClients: InfraWalletApi[] = [azureClient, awsClient];\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n router.get('/reports', async (request, response) => {\n const filters = request.query.filters as string;\n const groups = request.query.groups as string;\n const granularity = request.query.granularity as string;\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const promises = [];\n const results = [];\n\n cloudClients.forEach(async client => {\n const fetchCloudCosts = (async () => {\n const cacheKey = [\n client.constructor.name,\n filters,\n groups,\n granularity,\n startTime,\n endTime,\n ].join('_');\n const cachedCosts = (await cache.get(cacheKey)) as JsonArray;\n if (cachedCosts) {\n logger.debug(`${client.constructor.name} costs from cache`);\n cachedCosts.forEach(cost => {\n results.push(cost);\n });\n } else {\n const costs = await client.fetchCostsFromCloud({\n filters: filters,\n groups: groups,\n granularity: granularity,\n startTime: startTime,\n endTime: endTime,\n });\n await cache.set(cacheKey, costs, {\n ttl: 60 * 60 * 2 * 1000,\n }); // cache for 2 hours\n costs.forEach(cost => {\n results.push(cost);\n });\n }\n })();\n promises.push(fetchCloudCosts);\n });\n\n await Promise.all(promises);\n\n response.json({ data: results, status: 'ok' });\n });\n\n router.use(errorHandler());\n return router;\n}\n","import { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * infraWalletPlugin backend plugin\n *\n * @public\n */\nexport const infraWalletPlugin = createBackendPlugin({\n pluginId: 'infrawallet',\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n cache: coreServices.cache,\n database: coreServices.database,\n },\n async init({ httpRouter, logger, config, cache, database }) {\n // check database migrations\n const client = await database.getClient();\n const migrationsDir = resolvePackagePath(\n '@electrolux-oss/plugin-infrawallet-backend',\n 'migrations',\n );\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n // if there are no category mappings, seed the database\n const category_mappings_count = await client('category_mappings').count(\n 'id as c',\n );\n if (\n category_mappings_count[0].c === 0 ||\n category_mappings_count[0].c === '0'\n ) {\n const seedsDir = resolvePackagePath(\n '@electrolux-oss/plugin-infrawallet-backend',\n 'seeds',\n );\n await client.seed.run({ directory: seedsDir });\n }\n\n httpRouter.use(\n await createRouter({\n logger,\n config,\n cache,\n database,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["STSClient","AssumeRoleCommand","CostExplorerClient","moment","GetCostAndUsageCommand","reduce","ClientSecretCredential","CostManagementClient","Router","express","errorHandler","createBackendPlugin","coreServices","resolvePackagePath"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/service/functions.ts","../src/service/AwsClient.ts","../src/service/AzureClient.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["import { DatabaseService } from '@backstage/backend-plugin-api';\nimport { CategoryMapping } from './types';\n\nexport async function getCategoryMappings(\n database: DatabaseService,\n provider: string,\n): Promise<{ [category: string]: string[] }> {\n const result: { [category: string]: string[] } = {};\n const client = await database.getClient();\n const mappings = await client\n .where({ provider: provider })\n .select()\n .from<CategoryMapping>('category_mappings');\n mappings.forEach(mapping => {\n if (typeof mapping.cloud_service_names === 'string') {\n // just in case if the database such as sqlite does not support JSON column\n result[mapping.category] = JSON.parse(mapping.cloud_service_names);\n } else {\n result[mapping.category] = mapping.cloud_service_names;\n }\n });\n return result;\n}\n\nexport function getCategoryByServiceName(\n serviceName: string,\n categoryMappings: { [category: string]: string[] },\n): string {\n for (const key of Object.keys(categoryMappings)) {\n const serviceNames = categoryMappings[key];\n if (serviceNames && serviceNames.includes(serviceName)) {\n return key;\n }\n }\n\n return 'Uncategorized';\n}\n","import {\n CostExplorerClient,\n GetCostAndUsageCommand,\n GetCostAndUsageCommandInput,\n Granularity,\n} from '@aws-sdk/client-cost-explorer';\nimport { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts';\nimport { DatabaseService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { CostQuery, Report } from './types';\nimport { getCategoryMappings, getCategoryByServiceName } from './functions';\n\nexport class AwsClient implements InfraWalletApi {\n static create(config: Config, database: DatabaseService) {\n return new AwsClient(config, database);\n }\n\n constructor(\n private readonly config: Config,\n private readonly database: DatabaseService,\n ) {}\n\n async fetchCostsFromCloud(query: CostQuery): Promise<Report[]> {\n const conf = this.config.getOptionalConfigArray(\n 'backend.infraWallet.integrations.aws',\n );\n if (!conf) {\n return [];\n }\n\n const promises = [];\n const results: Report[] = [];\n const groupPairs = [];\n query.groups.split(',').forEach(group => {\n if (group.includes(':')) {\n const [type, name] = group.split(':');\n groupPairs.push({ type, name });\n }\n });\n\n for (const c of conf) {\n const name = c.getString('name');\n const accountId = c.getString('accountId');\n const assumedRoleName = c.getString('assumedRoleName');\n const accessKeyId = c.getOptionalString('accessKeyId');\n const accessKeySecret = c.getOptionalString('accessKeySecret');\n const tags = c.getOptionalStringArray('tags');\n const tagKeyValues: { [key: string]: string } = {};\n tags?.forEach(tag => {\n const [k, v] = tag.split(':');\n tagKeyValues[k.trim()] = v.trim();\n });\n const categoryMappings = await getCategoryMappings(this.database, 'aws');\n\n let stsParams = {};\n if (accessKeyId && accessKeySecret) {\n stsParams = {\n region: 'us-east-1',\n credentials: {\n accessKeyId: accessKeyId as string,\n secretAccessKey: accessKeySecret as string,\n },\n };\n } else {\n stsParams = {\n region: 'us-east-1',\n };\n }\n const promise = (async () => {\n const client = new STSClient(stsParams);\n const commandInput = {\n // AssumeRoleRequest\n RoleArn: `arn:aws:iam::${accountId}:role/${assumedRoleName}`,\n RoleSessionName: 'AssumeRoleSession1',\n };\n const assumeRoleCommand = new AssumeRoleCommand(commandInput);\n const assumeRoleResponse = await client.send(assumeRoleCommand);\n // init aws cost explorer client\n const awsCeClient = new CostExplorerClient({\n region: 'us-east-1',\n credentials: {\n accessKeyId: assumeRoleResponse.Credentials?.AccessKeyId as string,\n secretAccessKey: assumeRoleResponse.Credentials\n ?.SecretAccessKey as string,\n sessionToken: assumeRoleResponse.Credentials\n ?.SessionToken as string,\n },\n });\n\n // query this aws account's cost and usage using @aws-sdk/client-cost-explorer\n const input: GetCostAndUsageCommandInput = {\n TimePeriod: {\n Start: moment(parseInt(query.startTime, 10)).format('YYYY-MM-DD'),\n End: moment(parseInt(query.endTime, 10)).format('YYYY-MM-DD'),\n },\n Granularity: query.granularity.toUpperCase() as Granularity,\n Filter: { Dimensions: { Key: 'RECORD_TYPE', Values: ['Usage'] } },\n GroupBy: [{ Type: 'DIMENSION', Key: 'SERVICE' }],\n Metrics: ['UnblendedCost'],\n };\n \n const getCostCommand = new GetCostAndUsageCommand(input);\n const costAndusageResponse = await awsCeClient.send(getCostCommand);\n\n const transformedData = reduce(\n costAndusageResponse.ResultsByTime,\n (acc: { [key: string]: Report }, row) => {\n const rowTime = row.TimePeriod?.Start;\n const period = rowTime ? rowTime.substring(0, 7): 'unknown';\n if (row.Groups) {\n row.Groups.forEach(group => {\n const groupKeys = group.Keys ? group.Keys[0] : '';\n const keyName = `${name}_${groupKeys}`;\n \n if (!acc[keyName]) {\n acc[keyName] = {\n id: keyName,\n name: name,\n service: `${groupKeys} (AWS)`,\n category: getCategoryByServiceName(\n groupKeys,\n categoryMappings,\n ),\n provider: 'AWS',\n reports: {},\n ...tagKeyValues,\n };\n }\n\n const groupMetrics = group.Metrics;\n \n if (groupMetrics !== undefined) {\n acc[keyName].reports[period] = parseFloat(\n groupMetrics.UnblendedCost.Amount ?? '0.0',\n );\n }\n });\n }\n\n return acc;\n },\n {},\n );\n\n Object.values(transformedData).map((value: any) => {\n results.push(value);\n });\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return results;\n }\n}\n","import { CostManagementClient } from '@azure/arm-costmanagement';\nimport { ClientSecretCredential } from '@azure/identity';\nimport { DatabaseService } from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { reduce } from 'lodash';\nimport moment from 'moment';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { CostQuery, Report } from './types';\nimport { getCategoryMappings, getCategoryByServiceName } from './functions';\n\nexport class AzureClient implements InfraWalletApi {\n static create(config: Config, database: DatabaseService) {\n return new AzureClient(config, database);\n }\n\n constructor(\n private readonly config: Config,\n private readonly database: DatabaseService,\n ) {}\n\n async queryAzureCostExplorer(\n azureClient: any,\n subscription: string,\n granularity: string,\n groups: { type: string; name: string }[],\n startDate: moment.Moment,\n endDate: moment.Moment,\n ) {\n const scope = `/subscriptions/${subscription}`;\n\n const query = {\n type: 'ActualCost',\n dataset: {\n granularity: granularity,\n aggregation: { totalCostUSD: { name: 'CostUSD', function: 'Sum' } },\n grouping: groups,\n },\n timeframe: 'Custom',\n timePeriod: {\n from: startDate.toISOString(),\n to: endDate.toISOString(),\n },\n };\n\n const result = await azureClient.query.usage(scope, query);\n return result;\n }\n\n async fetchCostsFromCloud(query: CostQuery): Promise<Report[]> {\n const conf = this.config.getOptionalConfigArray(\n 'backend.infraWallet.integrations.azure',\n );\n if (!conf) {\n return [];\n }\n\n const promises = [];\n const results: Report[] = [];\n\n const groupPairs = [{ type: 'Dimension', name: 'ServiceName' }];\n for (const c of conf) {\n const name = c.getString('name');\n const subscriptionId = c.getString('subscriptionId');\n const tenantId = c.getString('tenantId');\n const clientId = c.getString('clientId');\n const clientSecret = c.getString('clientSecret');\n const credential = new ClientSecretCredential(\n tenantId as string,\n clientId as string,\n clientSecret as string,\n );\n const client = new CostManagementClient(credential);\n const tags = c.getOptionalStringArray('tags');\n const tagKeyValues: { [key: string]: string } = {};\n tags?.forEach(tag => {\n const [k, v] = tag.split(':');\n tagKeyValues[k.trim()] = v.trim();\n });\n const categoryMappings = await getCategoryMappings(\n this.database,\n 'azure',\n );\n\n const promise = (async () => {\n try {\n const costResponse = await this.queryAzureCostExplorer(\n client,\n subscriptionId as string,\n query.granularity,\n groupPairs,\n moment(parseInt(query.startTime, 10)),\n moment(parseInt(query.endTime, 10)),\n );\n\n const transformedData = reduce(\n costResponse.rows,\n (acc: { [key: string]: Report }, row) => {\n let keyName = name;\n for (let i = 0; i < groupPairs.length; i++) {\n keyName += `->${row[i + 2]}`;\n }\n\n if (!acc[keyName]) {\n acc[keyName] = {\n id: keyName,\n name: name,\n service: `${row[2]} (Azure)`,\n category: getCategoryByServiceName(row[2], categoryMappings),\n provider: 'Azure',\n reports: {},\n ...tagKeyValues,\n };\n }\n\n if (\n !moment(row[1]).isBefore(moment(parseInt(query.startTime, 10)))\n ) {\n acc[keyName].reports[row[1].substring(0, 7)] = parseFloat(\n row[0],\n );\n }\n return acc;\n },\n {},\n );\n\n Object.values(transformedData).map((value: Report) => {\n results.push(value);\n });\n } catch (e) {\n throw new Error(e.message);\n }\n })();\n promises.push(promise);\n }\n await Promise.all(promises);\n return results;\n }\n}\n","import { errorHandler } from '@backstage/backend-common';\nimport {\n CacheService,\n DatabaseService,\n LoggerService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { AwsClient } from './AwsClient';\nimport { AzureClient } from './AzureClient';\nimport { InfraWalletApi } from './InfraWalletApi';\nimport { Report } from './types';\n\nexport interface RouterOptions {\n logger: LoggerService;\n config: Config;\n cache: CacheService;\n database: DatabaseService;\n}\n\nasync function setUpDatabase(database: DatabaseService) {\n // check database migrations\n const client = await database.getClient();\n const migrationsDir = resolvePackagePath(\n '@electrolux-oss/plugin-infrawallet-backend',\n 'migrations',\n );\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n // if there are no category mappings, seed the database\n const category_mappings_count = await client('category_mappings').count(\n 'id as c',\n );\n if (\n category_mappings_count[0].c === 0 ||\n category_mappings_count[0].c === '0'\n ) {\n const seedsDir = resolvePackagePath(\n '@electrolux-oss/plugin-infrawallet-backend',\n 'seeds',\n );\n await client.seed.run({ directory: seedsDir });\n }\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, cache, database } = options;\n // do database migrations here to support the legacy backend system\n await setUpDatabase(database);\n\n const router = Router();\n router.use(express.json());\n\n const azureClient = AzureClient.create(config, database);\n const awsClient = AwsClient.create(config, database);\n const cloudClients: InfraWalletApi[] = [azureClient, awsClient];\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n router.get('/reports', async (request, response) => {\n const filters = request.query.filters as string;\n const groups = request.query.groups as string;\n const granularity = request.query.granularity as string;\n const startTime = request.query.startTime as string;\n const endTime = request.query.endTime as string;\n const promises: Promise<void>[] = [];\n const results: Report[] = [];\n\n cloudClients.forEach(async client => {\n const fetchCloudCosts = (async () => {\n const cacheKey = [\n client.constructor.name,\n filters,\n groups,\n granularity,\n startTime,\n endTime,\n ].join('_');\n const cachedCosts = (await cache.get(cacheKey)) as Report[] | undefined;\n if (cachedCosts) {\n logger.debug(`${client.constructor.name} costs from cache`);\n cachedCosts.forEach(cost => {\n results.push(cost);\n });\n } else {\n const costs = await client.fetchCostsFromCloud({\n filters: filters,\n groups: groups,\n granularity: granularity,\n startTime: startTime,\n endTime: endTime,\n });\n await cache.set(cacheKey, costs, {\n ttl: 60 * 60 * 2 * 1000,\n }); // cache for 2 hours\n costs.forEach(cost => {\n results.push(cost);\n });\n }\n })();\n promises.push(fetchCloudCosts);\n });\n\n await Promise.all(promises);\n\n response.json({ data: results, status: 'ok' });\n });\n\n router.use(errorHandler());\n return router;\n}\n","import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * infraWalletPlugin backend plugin\n *\n * @public\n */\nexport const infraWalletPlugin = createBackendPlugin({\n pluginId: 'infrawallet',\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n cache: coreServices.cache,\n database: coreServices.database,\n },\n async init({ httpRouter, logger, config, cache, database }) {\n httpRouter.use(\n await createRouter({\n logger,\n config,\n cache,\n database,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["STSClient","AssumeRoleCommand","CostExplorerClient","moment","GetCostAndUsageCommand","reduce","_a","ClientSecretCredential","CostManagementClient","resolvePackagePath","Router","express","errorHandler","createBackendPlugin","coreServices"],"mappings":"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"}
|
package/package.json
CHANGED
package/seeds/init.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
exports.seed = async
|
|
1
|
+
exports.seed = async knex => {
|
|
2
2
|
await knex('category_mappings').insert([
|
|
3
3
|
{
|
|
4
4
|
provider: 'azure',
|
|
5
5
|
category: 'Analytics',
|
|
6
6
|
// make it compatible with sqlite
|
|
7
|
-
cloud_service_names: JSON.stringify([
|
|
8
|
-
'Azure Monitor',
|
|
9
|
-
'Log Analytics',
|
|
10
|
-
'Network Watcher',
|
|
11
|
-
]),
|
|
7
|
+
cloud_service_names: JSON.stringify(['Event Hubs', 'Log Analytics']),
|
|
12
8
|
},
|
|
13
9
|
{
|
|
14
10
|
provider: 'azure',
|
|
15
|
-
category: 'Application
|
|
11
|
+
category: 'Application Integration',
|
|
16
12
|
cloud_service_names: JSON.stringify(['Logic Apps']),
|
|
17
13
|
},
|
|
18
14
|
{
|
|
@@ -21,9 +17,15 @@ exports.seed = async function (knex) {
|
|
|
21
17
|
cloud_service_names: JSON.stringify([
|
|
22
18
|
'Virtual Machines',
|
|
23
19
|
'Azure App Service',
|
|
24
|
-
'Azure Data Factory v2',
|
|
25
20
|
'Functions',
|
|
21
|
+
]),
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
provider: 'azure',
|
|
25
|
+
category: 'Containers',
|
|
26
|
+
cloud_service_names: JSON.stringify([
|
|
26
27
|
'Azure Container Apps',
|
|
28
|
+
'Container Registry',
|
|
27
29
|
]),
|
|
28
30
|
},
|
|
29
31
|
{
|
|
@@ -31,6 +33,7 @@ exports.seed = async function (knex) {
|
|
|
31
33
|
category: 'Database',
|
|
32
34
|
cloud_service_names: JSON.stringify([
|
|
33
35
|
'Azure Cosmos DB',
|
|
36
|
+
'Azure Data Factory v2',
|
|
34
37
|
'Azure Database for MySQL',
|
|
35
38
|
'Redis Cache',
|
|
36
39
|
'SQL Database',
|
|
@@ -38,7 +41,7 @@ exports.seed = async function (knex) {
|
|
|
38
41
|
},
|
|
39
42
|
{
|
|
40
43
|
provider: 'azure',
|
|
41
|
-
category: 'Developer
|
|
44
|
+
category: 'Developer Tools',
|
|
42
45
|
cloud_service_names: JSON.stringify([
|
|
43
46
|
'Azure DevOps',
|
|
44
47
|
'Notification Hubs',
|
|
@@ -47,42 +50,48 @@ exports.seed = async function (knex) {
|
|
|
47
50
|
},
|
|
48
51
|
{
|
|
49
52
|
provider: 'azure',
|
|
50
|
-
category: '
|
|
51
|
-
cloud_service_names: JSON.stringify([
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
category: 'DevOps',
|
|
54
|
+
cloud_service_names: JSON.stringify(['Azure Monitor']),
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
provider: 'azure',
|
|
58
|
+
category: 'Internet of Things',
|
|
59
|
+
cloud_service_names: JSON.stringify(['Event Grid', 'IoT Hub']),
|
|
56
60
|
},
|
|
57
61
|
{
|
|
58
62
|
provider: 'azure',
|
|
59
|
-
category: '
|
|
63
|
+
category: 'Artificial Intelligence',
|
|
60
64
|
cloud_service_names: JSON.stringify([
|
|
61
65
|
'Azure Cognitive Search',
|
|
62
66
|
'Azure Databricks',
|
|
63
67
|
'Cognitive Services',
|
|
64
68
|
]),
|
|
65
69
|
},
|
|
70
|
+
{
|
|
71
|
+
provider: 'azure',
|
|
72
|
+
category: 'Management & Governance',
|
|
73
|
+
cloud_service_names: JSON.stringify(['Network Watcher']),
|
|
74
|
+
},
|
|
66
75
|
{
|
|
67
76
|
provider: 'azure',
|
|
68
77
|
category: 'Networking',
|
|
69
78
|
cloud_service_names: JSON.stringify([
|
|
79
|
+
'Azure DNS',
|
|
70
80
|
'Azure Front Door Service',
|
|
71
81
|
'Bandwidth',
|
|
72
82
|
'Content Delivery Network',
|
|
73
83
|
'Load Balancer',
|
|
74
84
|
'NAT Gateway',
|
|
85
|
+
'Network Traversal',
|
|
75
86
|
'Service Bus',
|
|
76
87
|
'Traffic Manager',
|
|
77
88
|
'Virtual Network',
|
|
78
|
-
'Network Traversal',
|
|
79
|
-
'Azure DNS',
|
|
80
89
|
'VPN Gateway',
|
|
81
90
|
]),
|
|
82
91
|
},
|
|
83
92
|
{
|
|
84
93
|
provider: 'azure',
|
|
85
|
-
category: 'Security
|
|
94
|
+
category: 'Security, Identity, & Compliance',
|
|
86
95
|
cloud_service_names: JSON.stringify([
|
|
87
96
|
'Azure Firewall',
|
|
88
97
|
'Key Vault',
|
|
@@ -92,29 +101,30 @@ exports.seed = async function (knex) {
|
|
|
92
101
|
{
|
|
93
102
|
provider: 'azure',
|
|
94
103
|
category: 'Storage',
|
|
95
|
-
cloud_service_names: JSON.stringify(['
|
|
104
|
+
cloud_service_names: JSON.stringify(['Storage']),
|
|
96
105
|
},
|
|
97
106
|
{
|
|
98
107
|
provider: 'aws',
|
|
99
108
|
category: 'Analytics',
|
|
100
109
|
cloud_service_names: JSON.stringify([
|
|
101
|
-
'
|
|
102
|
-
'
|
|
103
|
-
'
|
|
110
|
+
'Amazon Kinesis',
|
|
111
|
+
'Amazon Managed Streaming for Apache Kafka',
|
|
112
|
+
'Amazon QuickSight',
|
|
113
|
+
'AWS Glue',
|
|
104
114
|
]),
|
|
105
115
|
},
|
|
106
116
|
{
|
|
107
117
|
provider: 'aws',
|
|
108
|
-
category: 'Application
|
|
118
|
+
category: 'Application Integration',
|
|
109
119
|
cloud_service_names: JSON.stringify([
|
|
110
|
-
'AWS Config',
|
|
111
120
|
'Amazon API Gateway',
|
|
112
|
-
'
|
|
121
|
+
'Amazon Simple Notification Service',
|
|
122
|
+
'Amazon Simple Queue Service',
|
|
113
123
|
]),
|
|
114
124
|
},
|
|
115
125
|
{
|
|
116
126
|
provider: 'aws',
|
|
117
|
-
category: 'Cloud
|
|
127
|
+
category: 'Cloud Financial Management',
|
|
118
128
|
cloud_service_names: JSON.stringify(['AWS Cost Explorer']),
|
|
119
129
|
},
|
|
120
130
|
{
|
|
@@ -123,9 +133,15 @@ exports.seed = async function (knex) {
|
|
|
123
133
|
cloud_service_names: JSON.stringify([
|
|
124
134
|
'EC2 - Other',
|
|
125
135
|
'Amazon Elastic Compute Cloud - Compute',
|
|
126
|
-
'Amazon Elastic Container Service for Kubernetes',
|
|
127
136
|
'AWS Lambda',
|
|
128
|
-
|
|
137
|
+
]),
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
provider: 'aws',
|
|
141
|
+
category: 'Containers',
|
|
142
|
+
cloud_service_names: JSON.stringify([
|
|
143
|
+
'Amazon Elastic Container Service for Kubernetes',
|
|
144
|
+
'Amazon Elastic Container Registry (ECR)',
|
|
129
145
|
]),
|
|
130
146
|
},
|
|
131
147
|
{
|
|
@@ -134,45 +150,55 @@ exports.seed = async function (knex) {
|
|
|
134
150
|
cloud_service_names: JSON.stringify([
|
|
135
151
|
'Amazon DynamoDB',
|
|
136
152
|
'Amazon ElastiCache',
|
|
137
|
-
'Amazon Kinesis',
|
|
138
153
|
'Amazon Relational Database Service',
|
|
154
|
+
'Amazon Timestream',
|
|
139
155
|
'DynamoDB Accelerator (DAX)',
|
|
140
156
|
]),
|
|
141
157
|
},
|
|
142
158
|
{
|
|
143
159
|
provider: 'aws',
|
|
144
|
-
category: 'Developer
|
|
160
|
+
category: 'Developer Tools',
|
|
161
|
+
cloud_service_names: JSON.stringify(['AWS CloudShell', 'AWS X-Ray']),
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
provider: 'aws',
|
|
165
|
+
category: 'Internet of Things',
|
|
166
|
+
cloud_service_names: JSON.stringify(['AWS IoT']),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
provider: 'aws',
|
|
170
|
+
category: 'Management & Governance',
|
|
145
171
|
cloud_service_names: JSON.stringify([
|
|
146
|
-
'
|
|
147
|
-
'
|
|
148
|
-
'AWS
|
|
149
|
-
'AWS
|
|
172
|
+
'AmazonCloudWatch',
|
|
173
|
+
'AWS CloudTrail',
|
|
174
|
+
'AWS Config',
|
|
175
|
+
'AWS Service Catalog',
|
|
150
176
|
]),
|
|
151
177
|
},
|
|
152
178
|
{
|
|
153
179
|
provider: 'aws',
|
|
154
|
-
category: '
|
|
155
|
-
cloud_service_names: JSON.stringify([
|
|
180
|
+
category: 'Migration',
|
|
181
|
+
cloud_service_names: JSON.stringify([
|
|
182
|
+
'AWS Migration Hub Refactor Spaces',
|
|
183
|
+
]),
|
|
156
184
|
},
|
|
157
185
|
{
|
|
158
186
|
provider: 'aws',
|
|
159
187
|
category: 'Networking',
|
|
160
188
|
cloud_service_names: JSON.stringify([
|
|
161
189
|
'Amazon Elastic Load Balancing',
|
|
162
|
-
'Amazon Managed Streaming for Apache Kafka',
|
|
163
190
|
'Amazon Route 53',
|
|
164
|
-
'Amazon Timestream',
|
|
165
191
|
'Amazon Virtual Private Cloud',
|
|
166
192
|
]),
|
|
167
193
|
},
|
|
168
194
|
{
|
|
169
195
|
provider: 'aws',
|
|
170
|
-
category: 'Security
|
|
196
|
+
category: 'Security, Identity, & Compliance',
|
|
171
197
|
cloud_service_names: JSON.stringify([
|
|
198
|
+
'Amazon GuardDuty',
|
|
172
199
|
'AWS Key Management Service',
|
|
173
200
|
'AWS Secrets Manager',
|
|
174
201
|
'AWS Security Hub',
|
|
175
|
-
'Amazon GuardDuty',
|
|
176
202
|
'AWS WAF',
|
|
177
203
|
]),
|
|
178
204
|
},
|
|
@@ -180,9 +206,8 @@ exports.seed = async function (knex) {
|
|
|
180
206
|
provider: 'aws',
|
|
181
207
|
category: 'Storage',
|
|
182
208
|
cloud_service_names: JSON.stringify([
|
|
183
|
-
'Amazon Simple Storage Service',
|
|
184
|
-
'Amazon EC2 Container Registry (ECR)',
|
|
185
209
|
'Amazon Glacier',
|
|
210
|
+
'Amazon Simple Storage Service',
|
|
186
211
|
]),
|
|
187
212
|
},
|
|
188
213
|
]);
|