@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 CHANGED
@@ -20,8 +20,8 @@ export interface Config {
20
20
  name: string;
21
21
  accountId: string;
22
22
  assumedRoleName: string;
23
- accessKeyId: string;
24
- accessKeySecret: string;
23
+ accessKeyId?: string;
24
+ accessKeySecret?: string;
25
25
  tags?: string[];
26
26
  },
27
27
  ];
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");
@@ -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
- const promise = (async () => {
81
- var _a, _b, _c;
82
- const client = new clientSts.STSClient({
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
- const period = row.TimePeriod.Start.substring(0, 7);
120
- row.Groups.forEach((group) => {
121
- const keyName = `${name}_${group.Keys[0]}`;
122
- if (!acc[keyName]) {
123
- acc[keyName] = {
124
- id: keyName,
125
- name,
126
- service: `${group.Keys[0]} (AWS)`,
127
- category: getCategoryByServiceName(
128
- group.Keys[0],
129
- categoryMappings
130
- ),
131
- provider: "AWS",
132
- reports: {},
133
- ...tagKeyValues
134
- };
135
- }
136
- acc[keyName].reports[period] = parseFloat(
137
- group.Metrics.UnblendedCost.Amount
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.getOptionalString("name");
193
- const subscriptionId = c.getOptionalString("subscriptionId");
194
- const tenantId = c.getOptionalString("tenantId");
195
- const clientId = c.getOptionalString("clientId");
196
- 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");
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,
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electrolux-oss/plugin-infrawallet-backend",
3
- "version": "0.1.0",
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 function (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 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-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 function (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 function (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 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
- '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 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-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 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
  ]);