@electrolux-oss/plugin-infrawallet-backend 0.1.1 → 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/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.getOptionalString("name");
69
- const accountId = c.getOptionalString("accountId");
70
- const assumedRoleName = c.getOptionalString("assumedRoleName");
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");
@@ -124,27 +124,36 @@ class AwsClient {
124
124
  const transformedData = lodash.reduce(
125
125
  costAndusageResponse.ResultsByTime,
126
126
  (acc, row) => {
127
- const period = row.TimePeriod.Start.substring(0, 7);
128
- row.Groups.forEach((group) => {
129
- const keyName = `${name}_${group.Keys[0]}`;
130
- if (!acc[keyName]) {
131
- acc[keyName] = {
132
- id: keyName,
133
- name,
134
- service: `${group.Keys[0]} (AWS)`,
135
- category: getCategoryByServiceName(
136
- group.Keys[0],
137
- categoryMappings
138
- ),
139
- provider: "AWS",
140
- reports: {},
141
- ...tagKeyValues
142
- };
143
- }
144
- acc[keyName].reports[period] = parseFloat(
145
- group.Metrics.UnblendedCost.Amount
146
- );
147
- });
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
+ }
148
157
  return acc;
149
158
  },
150
159
  {}
@@ -197,11 +206,11 @@ class AzureClient {
197
206
  const results = [];
198
207
  const groupPairs = [{ type: "Dimension", name: "ServiceName" }];
199
208
  for (const c of conf) {
200
- const name = c.getOptionalString("name");
201
- const subscriptionId = c.getOptionalString("subscriptionId");
202
- const tenantId = c.getOptionalString("tenantId");
203
- const clientId = c.getOptionalString("clientId");
204
- const clientSecret = c.getOptionalString("clientSecret");
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");
205
214
  const credential = new identity.ClientSecretCredential(
206
215
  tenantId,
207
216
  clientId,
@@ -269,8 +278,32 @@ class AzureClient {
269
278
  }
270
279
  }
271
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
+ }
272
304
  async function createRouter(options) {
273
305
  const { logger, config, cache, database } = options;
306
+ await setUpDatabase(database);
274
307
  const router = Router__default.default();
275
308
  router.use(express__default.default.json());
276
309
  const azureClient = AzureClient.create(config, database);
@@ -341,27 +374,6 @@ const infraWalletPlugin = backendPluginApi.createBackendPlugin({
341
374
  database: backendPluginApi.coreServices.database
342
375
  },
343
376
  async init({ httpRouter, logger, config, cache, database }) {
344
- var _a;
345
- const client = await database.getClient();
346
- const migrationsDir = backendPluginApi.resolvePackagePath(
347
- "@electrolux-oss/plugin-infrawallet-backend",
348
- "migrations"
349
- );
350
- if (!((_a = database.migrations) == null ? void 0 : _a.skip)) {
351
- await client.migrate.latest({
352
- directory: migrationsDir
353
- });
354
- }
355
- const category_mappings_count = await client("category_mappings").count(
356
- "id as c"
357
- );
358
- if (category_mappings_count[0].c === 0 || category_mappings_count[0].c === "0") {
359
- const seedsDir = backendPluginApi.resolvePackagePath(
360
- "@electrolux-oss/plugin-infrawallet-backend",
361
- "seeds"
362
- );
363
- await client.seed.run({ directory: seedsDir });
364
- }
365
377
  httpRouter.use(
366
378
  await createRouter({
367
379
  logger,
@@ -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 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 = {\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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electrolux-oss/plugin-infrawallet-backend",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "backstage": {
5
5
  "role": "backend-plugin"
6
6
  },
package/seeds/init.js CHANGED
@@ -1,18 +1,14 @@
1
- exports.seed = async (knex) => {
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-Integration',
11
+ category: 'Application Integration',
16
12
  cloud_service_names: JSON.stringify(['Logic Apps']),
17
13
  },
18
14
  {
@@ -21,9 +17,15 @@ exports.seed = async (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 (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 (knex) => {
38
41
  },
39
42
  {
40
43
  provider: 'azure',
41
- category: 'Developer-Tools',
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 (knex) => {
47
50
  },
48
51
  {
49
52
  provider: 'azure',
50
- category: 'Internet-of-Things',
51
- cloud_service_names: JSON.stringify([
52
- 'Event Grid',
53
- 'Event Hubs',
54
- 'IoT Hub',
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: 'Machine-Learning',
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-Identity-Compliance',
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 (knex) => {
92
101
  {
93
102
  provider: 'azure',
94
103
  category: 'Storage',
95
- cloud_service_names: JSON.stringify(['Container Registry', 'Storage']),
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
- 'AWS CloudTrail',
102
- 'AWS X-Ray',
103
- 'AmazonCloudWatch',
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-Integration',
118
+ category: 'Application Integration',
109
119
  cloud_service_names: JSON.stringify([
110
- 'AWS Config',
111
120
  'Amazon API Gateway',
112
- 'AWS Service Catalog',
121
+ 'Amazon Simple Notification Service',
122
+ 'Amazon Simple Queue Service',
113
123
  ]),
114
124
  },
115
125
  {
116
126
  provider: 'aws',
117
- category: 'Cloud-Financial-Management',
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 (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
- 'AWS Glue',
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 (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-Tools',
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
- 'Amazon Simple Notification Service',
147
- 'Amazon Simple Queue Service',
148
- 'AWS Migration Hub Refactor Spaces',
149
- 'AWS CloudShell',
172
+ 'AmazonCloudWatch',
173
+ 'AWS CloudTrail',
174
+ 'AWS Config',
175
+ 'AWS Service Catalog',
150
176
  ]),
151
177
  },
152
178
  {
153
179
  provider: 'aws',
154
- category: 'Internet-of-Things',
155
- cloud_service_names: JSON.stringify(['AWS IoT']),
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-Identity-Compliance',
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 (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
  ]);