@pagerduty/backstage-plugin-backend 0.12.0 → 0.13.0
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/CHANGELOG.md +19 -0
- package/dist/index.d.ts +3 -2
- package/dist/plugin.cjs.js +12 -4
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +46 -93
- package/dist/service/router.cjs.js.map +1 -1
- package/dist/services/autoMatchJobs.cjs.js +53 -0
- package/dist/services/autoMatchJobs.cjs.js.map +1 -0
- package/dist/services/autoMatchRunner.cjs.js +72 -0
- package/dist/services/autoMatchRunner.cjs.js.map +1 -0
- package/dist/services/dataLoader.cjs.js +11 -4
- package/dist/services/dataLoader.cjs.js.map +1 -1
- package/package.json +3 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @pagerduty/backstage-plugin-backend
|
|
2
2
|
|
|
3
|
+
## 0.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9941800: Refactor the service mappings screen and add an auto-matching functionality to mass map PagerDuty service to Backstage entities
|
|
8
|
+
- e1f99a7: Remove deprecated @backstage/backend-common library. This is a potential breaking change for users who are still on the old backend system:
|
|
9
|
+
|
|
10
|
+
- `createPagerDutyServiceAction(...)` now requires its `config` prop.
|
|
11
|
+
- `createRouter(...)` now requires its `auth` prop.
|
|
12
|
+
|
|
13
|
+
Note that none of this is breaking for users of the new backend system.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- ef0af04: Moved to a process/polling based loading of the automatic mapping matches
|
|
18
|
+
- Updated dependencies [9941800]
|
|
19
|
+
- Updated dependencies [ef0af04]
|
|
20
|
+
- @pagerduty/backstage-plugin-common@0.4.0
|
|
21
|
+
|
|
3
22
|
## 0.12.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
-
import { LoggerService, RootConfigService, DiscoveryService, AuthService } from '@backstage/backend-plugin-api';
|
|
2
|
+
import { LoggerService, RootConfigService, DiscoveryService, AuthService, CacheService } from '@backstage/backend-plugin-api';
|
|
3
3
|
import { PagerDutyEntityMapping, PagerDutySetting, PagerDutyService, PagerDutyEntityMappingsResponse } from '@pagerduty/backstage-plugin-common';
|
|
4
4
|
import * as express from 'express';
|
|
5
5
|
import { CatalogApi, GetEntitiesResponse } from '@backstage/catalog-client';
|
|
@@ -29,8 +29,9 @@ interface RouterOptions {
|
|
|
29
29
|
config: RootConfigService;
|
|
30
30
|
store: PagerDutyBackendStore;
|
|
31
31
|
discovery: DiscoveryService;
|
|
32
|
-
auth
|
|
32
|
+
auth: AuthService;
|
|
33
33
|
catalogApi?: CatalogApi;
|
|
34
|
+
cache: CacheService;
|
|
34
35
|
}
|
|
35
36
|
type Annotations = {
|
|
36
37
|
'pagerduty.com/integration-key': string;
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -31,9 +31,18 @@ const pagerDutyPlugin = backendPluginApi.createBackendPlugin({
|
|
|
31
31
|
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
32
32
|
database: backendPluginApi.coreServices.database,
|
|
33
33
|
discovery: backendPluginApi.coreServices.discovery,
|
|
34
|
-
auth: backendPluginApi.coreServices.auth
|
|
34
|
+
auth: backendPluginApi.coreServices.auth,
|
|
35
|
+
cache: backendPluginApi.coreServices.cache
|
|
35
36
|
},
|
|
36
|
-
async init({
|
|
37
|
+
async init({
|
|
38
|
+
config,
|
|
39
|
+
logger,
|
|
40
|
+
httpRouter,
|
|
41
|
+
database,
|
|
42
|
+
discovery,
|
|
43
|
+
auth,
|
|
44
|
+
cache
|
|
45
|
+
}) {
|
|
37
46
|
const pagerDutyBackendStore = await PagerDutyBackendDatabase.PagerDutyBackendDatabase.create(await database.getClient(), {
|
|
38
47
|
skipMigrations: false
|
|
39
48
|
});
|
|
@@ -42,8 +51,7 @@ const pagerDutyPlugin = backendPluginApi.createBackendPlugin({
|
|
|
42
51
|
config,
|
|
43
52
|
logger,
|
|
44
53
|
store: pagerDutyBackendStore,
|
|
45
|
-
|
|
46
|
-
auth,
|
|
54
|
+
cache,
|
|
47
55
|
catalogApi: new catalogClient.CatalogClient({
|
|
48
56
|
discoveryApi: discovery,
|
|
49
57
|
fetchApi: new CatalogFetchApi(logger, auth)
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n AuthService,\n LoggerService,\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\nimport { PagerDutyBackendDatabase, PagerDutyBackendStore } from './db';\nimport { CatalogClient } from '@backstage/catalog-client';\n\nclass CatalogFetchApi {\n constructor(\n private readonly logger: LoggerService,\n private readonly auth: AuthService,\n ) { }\n\n async fetch(\n input: unknown,\n init: RequestInit | undefined,\n ): Promise<Response> {\n const request = new Request(input as RequestInfo | URL, init);\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: await this.auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n request.headers.set('Authorization', `Bearer ${token}`);\n this.logger.debug(`Added token to outgoing request to ${request.url}`);\n return fetch(request);\n }\n}\n\n/** @public */\nexport const pagerDutyPlugin = createBackendPlugin({\n pluginId: 'pagerduty',\n register(env) {\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n httpRouter: coreServices.httpRouter,\n database: coreServices.database,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n },\n async init({
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n AuthService,\n LoggerService,\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\nimport { PagerDutyBackendDatabase, PagerDutyBackendStore } from './db';\nimport { CatalogClient } from '@backstage/catalog-client';\n\nclass CatalogFetchApi {\n constructor(\n private readonly logger: LoggerService,\n private readonly auth: AuthService,\n ) { }\n\n async fetch(\n input: unknown,\n init: RequestInit | undefined,\n ): Promise<Response> {\n const request = new Request(input as RequestInfo | URL, init);\n const { token } = await this.auth.getPluginRequestToken({\n onBehalfOf: await this.auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n\n request.headers.set('Authorization', `Bearer ${token}`);\n this.logger.debug(`Added token to outgoing request to ${request.url}`);\n return fetch(request);\n }\n}\n\n/** @public */\nexport const pagerDutyPlugin = createBackendPlugin({\n pluginId: 'pagerduty',\n register(env) {\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n httpRouter: coreServices.httpRouter,\n database: coreServices.database,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n cache: coreServices.cache,\n },\n async init({\n config,\n logger,\n httpRouter,\n database,\n discovery,\n auth,\n cache,\n }) {\n const pagerDutyBackendStore: PagerDutyBackendStore =\n await PagerDutyBackendDatabase.create(await database.getClient(), {\n skipMigrations: false,\n });\n\n httpRouter.use(\n await createRouter({\n config,\n logger,\n store: pagerDutyBackendStore,\n discovery,\n auth,\n cache,\n catalogApi: new CatalogClient({\n discoveryApi: discovery,\n fetchApi: new CatalogFetchApi(logger, auth),\n }),\n }),\n );\n // The default Backstage behaviour is to require authentication on routes.\n // https://backstage.io/docs/backend-system/core-services/http-router/#using-the-service\n // Setting enableUnauthenticatedAccess to true will allow unauthenticated access to the PagerDuty plugin routes.\n const enableUnauthenticatedAccess: boolean = config.getOptionalBoolean('pagerDuty.enableUnauthenticatedAccess') ?? false;\n if (enableUnauthenticatedAccess === true) {\n httpRouter.addAuthPolicy({\n path: '/',\n allow: 'unauthenticated',\n });\n }\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","PagerDutyBackendDatabase","createRouter","CatalogClient"],"mappings":";;;;;;;AAUA,MAAM,eAAA,CAAgB;AAAA,EACpB,WAAA,CACmB,QACA,IAAA,EACjB;AAFiB,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,EACf;AAAA,EAEJ,MAAM,KAAA,CACJ,KAAA,EACA,IAAA,EACmB;AACnB,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,KAAA,EAA4B,IAAI,CAAA;AAC5D,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,IAAA,CAAK,KAAK,qBAAA,CAAsB;AAAA,MACtD,UAAA,EAAY,MAAM,IAAA,CAAK,IAAA,CAAK,wBAAA,EAAyB;AAAA,MACrD,cAAA,EAAgB;AAAA,KACjB,CAAA;AAED,IAAA,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,eAAA,EAAiB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAE,CAAA;AACtD,IAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,mCAAA,EAAsC,OAAA,CAAQ,GAAG,CAAA,CAAE,CAAA;AACrE,IAAA,OAAO,MAAM,OAAO,CAAA;AAAA,EACtB;AACF;AAGO,MAAM,kBAAkBA,oCAAA,CAAoB;AAAA,EACjD,QAAA,EAAU,WAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,QAAQC,6BAAA,CAAa,MAAA;AAAA,QACrB,QAAQA,6BAAA,CAAa,UAAA;AAAA,QACrB,YAAYA,6BAAA,CAAa,UAAA;AAAA,QACzB,UAAUA,6BAAA,CAAa,QAAA;AAAA,QACvB,WAAWA,6BAAA,CAAa,SAAA;AAAA,QACxB,MAAMA,6BAAA,CAAa,IAAA;AAAA,QACnB,OAAOA,6BAAA,CAAa;AAAA,OACtB;AAAA,MACA,MAAM,IAAA,CAAK;AAAA,QACT,MAAA;AAAA,QACA,MAAA;AAAA,QACA,UAAA;AAAA,QACA,QAAA;AAAA,QACA,SAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA,OACF,EAAG;AACD,QAAA,MAAM,wBACJ,MAAMC,iDAAA,CAAyB,OAAO,MAAM,QAAA,CAAS,WAAU,EAAG;AAAA,UAChE,cAAA,EAAgB;AAAA,SACjB,CAAA;AAEH,QAAA,UAAA,CAAW,GAAA;AAAA,UACT,MAAMC,mBAAA,CAAa;AAAA,YACjB,MAAA;AAAA,YACA,MAAA;AAAA,YACA,KAAA,EAAO,qBAAA;AAAA,YAGP,KAAA;AAAA,YACA,UAAA,EAAY,IAAIC,2BAAA,CAAc;AAAA,cAC5B,YAAA,EAAc,SAAA;AAAA,cACd,QAAA,EAAU,IAAI,eAAA,CAAgB,MAAA,EAAQ,IAAI;AAAA,aAC3C;AAAA,WACF;AAAA,SACH;AAIA,QAAA,MAAM,2BAAA,GAAuC,MAAA,CAAO,kBAAA,CAAmB,uCAAuC,CAAA,IAAK,KAAA;AACnH,QAAA,IAAI,gCAAgC,IAAA,EAAM;AACxC,UAAA,UAAA,CAAW,aAAA,CAAc;AAAA,YACvB,IAAA,EAAM,GAAA;AAAA,YACN,KAAA,EAAO;AAAA,WACR,CAAA;AAAA,QACH;AAAA,MACF;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var backendCommon = require('@backstage/backend-common');
|
|
4
3
|
var pagerduty = require('../apis/pagerduty.cjs.js');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
4
|
+
var autoMatchRunner = require('../services/autoMatchRunner.cjs.js');
|
|
5
|
+
var autoMatchJobs = require('../services/autoMatchJobs.cjs.js');
|
|
7
6
|
var backstagePluginCommon = require('@pagerduty/backstage-plugin-common');
|
|
8
7
|
var auth = require('../auth/auth.cjs.js');
|
|
9
8
|
var express = require('express');
|
|
10
9
|
var Router = require('express-promise-router');
|
|
11
10
|
var mappingsController = require('../controllers/mappings-controller.cjs.js');
|
|
12
11
|
var catalogEntity = require('../utils/catalog-entity.cjs.js');
|
|
12
|
+
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
13
13
|
|
|
14
14
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
15
15
|
|
|
@@ -152,18 +152,19 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
152
152
|
return result;
|
|
153
153
|
}
|
|
154
154
|
async function createRouter(options) {
|
|
155
|
-
const { logger, config, store, catalogApi } = options;
|
|
156
|
-
let { auth: auth$1 } = options;
|
|
157
|
-
if (!auth$1) {
|
|
158
|
-
auth$1 = backendCommon.createLegacyAuthAdapters(options).auth;
|
|
159
|
-
}
|
|
155
|
+
const { logger, config, store, catalogApi, cache } = options;
|
|
160
156
|
if (!catalogApi) {
|
|
161
157
|
throw new Error("Catalog API is required to start the PagerDuty plugin backend");
|
|
162
158
|
}
|
|
159
|
+
if (!cache) {
|
|
160
|
+
throw new Error("Cache service is required to start the PagerDuty plugin backend");
|
|
161
|
+
}
|
|
163
162
|
await auth.loadAuthConfig(config, logger);
|
|
164
163
|
pagerduty.loadPagerDutyEndpointsFromConfig(config, logger);
|
|
165
164
|
const router = Router__default.default();
|
|
166
165
|
router.use(express__namespace.json());
|
|
166
|
+
const runAutoMatch = autoMatchRunner.createAutoMatchRunner(catalogApi);
|
|
167
|
+
const autoMatchJobs$1 = new autoMatchJobs.AutoMatchJobRegistry(cache, runAutoMatch);
|
|
167
168
|
router.delete(
|
|
168
169
|
"/dependencies/service/:serviceId",
|
|
169
170
|
async (request, response) => {
|
|
@@ -624,93 +625,45 @@ async function createRouter(options) {
|
|
|
624
625
|
}
|
|
625
626
|
}
|
|
626
627
|
);
|
|
627
|
-
router.post("/mapping/entity/auto-match", async (request, response) => {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
response.status(400).json({
|
|
633
|
-
error: "Invalid threshold. Must be a number between 0 and 100."
|
|
634
|
-
});
|
|
635
|
-
return;
|
|
636
|
-
}
|
|
637
|
-
const bestOnly = request.body.bestOnly ?? false;
|
|
638
|
-
const loadStartTime = Date.now();
|
|
639
|
-
const { pdServices, bsComponents } = await dataLoader.loadBothSources({
|
|
640
|
-
catalogApi
|
|
628
|
+
router.post("/mapping/entity/auto-match/start", async (request, response) => {
|
|
629
|
+
const threshold = request.body.threshold ?? 100;
|
|
630
|
+
if (typeof threshold !== "number" || threshold < 0 || threshold > 100) {
|
|
631
|
+
response.status(400).json({
|
|
632
|
+
error: "Invalid threshold. Must be a number between 0 and 100."
|
|
641
633
|
});
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
};
|
|
665
|
-
response.json({
|
|
666
|
-
matches: matches.map((m) => ({
|
|
667
|
-
pagerDutyService: {
|
|
668
|
-
serviceId: m.pagerDutyService.sourceId,
|
|
669
|
-
name: m.pagerDutyService.rawName,
|
|
670
|
-
team: m.pagerDutyService.teamName,
|
|
671
|
-
account: m.pagerDutyService.account
|
|
672
|
-
},
|
|
673
|
-
backstageComponent: {
|
|
674
|
-
entityRef: m.backstageComponent.sourceId,
|
|
675
|
-
name: m.backstageComponent.rawName,
|
|
676
|
-
owner: m.backstageComponent.teamName
|
|
677
|
-
},
|
|
678
|
-
score: m.score,
|
|
679
|
-
confidence: getConfidenceLevel(m.score),
|
|
680
|
-
scoreBreakdown: m.scoreBreakdown
|
|
681
|
-
})),
|
|
682
|
-
statistics: {
|
|
683
|
-
totalPagerDutyServices: filteredPdServices.length,
|
|
684
|
-
totalBackstageComponents: bsComponents.length,
|
|
685
|
-
totalPossibleComparisons: totalComparisons,
|
|
686
|
-
matchesFound: matches.length,
|
|
687
|
-
exactMatches,
|
|
688
|
-
highConfidenceMatches: highConfidence,
|
|
689
|
-
mediumConfidenceMatches: mediumConfidence,
|
|
690
|
-
threshold,
|
|
691
|
-
loadTimeMs: loadTime,
|
|
692
|
-
matchTimeMs: matchTime,
|
|
693
|
-
totalTimeMs: loadTime + matchTime
|
|
694
|
-
}
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
const bestOnly = request.body.bestOnly ?? false;
|
|
637
|
+
const team = request.body.team;
|
|
638
|
+
const account = request.body.account;
|
|
639
|
+
const job = await autoMatchJobs$1.start({
|
|
640
|
+
threshold,
|
|
641
|
+
bestOnly,
|
|
642
|
+
team,
|
|
643
|
+
account
|
|
644
|
+
});
|
|
645
|
+
response.status(202).json({
|
|
646
|
+
jobId: job.id,
|
|
647
|
+
status: job.status
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
router.get("/mapping/entity/auto-match/:jobId", async (request, response) => {
|
|
651
|
+
const jobId = request.params.jobId;
|
|
652
|
+
const job = await autoMatchJobs$1.get(jobId);
|
|
653
|
+
if (!job) {
|
|
654
|
+
response.status(404).json({
|
|
655
|
+
error: `Auto-match job ${jobId} not found.`
|
|
695
656
|
});
|
|
696
|
-
|
|
697
|
-
logger.error(`Auto-match failed: ${error}`);
|
|
698
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
699
|
-
response.status(error.status).json({
|
|
700
|
-
errors: [`${error.message}`]
|
|
701
|
-
});
|
|
702
|
-
} else if (error instanceof dataLoader.ServiceLoadError) {
|
|
703
|
-
response.status(503).json({
|
|
704
|
-
error: "Service temporarily unavailable",
|
|
705
|
-
message: error.message
|
|
706
|
-
});
|
|
707
|
-
} else {
|
|
708
|
-
response.status(500).json({
|
|
709
|
-
error: "Auto-match failed",
|
|
710
|
-
message: error instanceof Error ? error.message : String(error)
|
|
711
|
-
});
|
|
712
|
-
}
|
|
657
|
+
return;
|
|
713
658
|
}
|
|
659
|
+
response.json({
|
|
660
|
+
jobId: job.id,
|
|
661
|
+
status: job.status,
|
|
662
|
+
createdAt: job.createdAt,
|
|
663
|
+
completedAt: job.completedAt,
|
|
664
|
+
result: job.result,
|
|
665
|
+
error: job.error
|
|
666
|
+
});
|
|
714
667
|
});
|
|
715
668
|
router.get("/escalation_policies", async (_, response) => {
|
|
716
669
|
try {
|
|
@@ -970,7 +923,7 @@ async function createRouter(options) {
|
|
|
970
923
|
router.get("/health", async (_, response) => {
|
|
971
924
|
response.status(200).json({ status: "ok" });
|
|
972
925
|
});
|
|
973
|
-
router.use(
|
|
926
|
+
router.use(rootHttpRouter.MiddlewareFactory.create({ config, logger }).error());
|
|
974
927
|
return router;
|
|
975
928
|
}
|
|
976
929
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["import {\n AuthService,\n DiscoveryService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport {\n createLegacyAuthAdapters,\n errorHandler,\n} from '@backstage/backend-common';\nimport {\n getAllEscalationPolicies,\n getChangeEvents,\n getIncidents,\n getOncallUsers,\n getServiceById,\n getServiceByIntegrationKey,\n getServiceStandards,\n getServiceMetrics,\n getAllServices,\n getAllTeams,\n getFilteredServices,\n loadPagerDutyEndpointsFromConfig,\n createServiceIntegration,\n getServiceRelationshipsById,\n addServiceRelationsToService,\n removeServiceRelationsFromService,\n} from '../apis/pagerduty';\nimport { loadBothSources, ServiceLoadError } from '../services/dataLoader';\nimport {\n findMatches,\n filterToBestMatchPerService,\n type MatchingConfig,\n} from '../services/matchingEngine';\nimport {\n HttpError,\n PagerDutyChangeEventsResponse,\n PagerDutyIncidentsResponse,\n PagerDutyOnCallUsersResponse,\n PagerDutyServiceResponse,\n PagerDutyServiceStandardsResponse,\n PagerDutyServiceMetricsResponse,\n PagerDutyServicesResponse,\n PagerDutyEntityMapping,\n PagerDutyEntityMappingsResponse,\n PagerDutyService,\n PagerDutyServiceDependency,\n PagerDutySetting,\n} from '@pagerduty/backstage-plugin-common';\nimport { loadAuthConfig } from '../auth/auth';\nimport {\n PagerDutyBackendStore,\n RawDbEntityResultRow,\n} from '../db/PagerDutyBackendDatabase';\nimport * as express from 'express';\nimport Router from 'express-promise-router';\nimport type { CatalogApi, GetEntitiesResponse } from '@backstage/catalog-client';\n\nimport * as MappingsController from '../controllers/mappings-controller';\nimport * as CatalogEntityUtils from '../utils/catalog-entity';\n\nexport interface RouterOptions {\n logger: LoggerService;\n config: RootConfigService;\n store: PagerDutyBackendStore;\n discovery: DiscoveryService;\n auth?: AuthService;\n catalogApi?: CatalogApi;\n}\n\nexport type Annotations = {\n 'pagerduty.com/integration-key': string;\n 'pagerduty.com/service-id': string;\n 'pagerduty.com/account': string;\n};\n\nexport async function buildEntityMappingsResponse(\n entityMappings: RawDbEntityResultRow[],\n componentEntitiesDict: Record<\n string,\n {\n ref: string;\n name: string;\n }\n >,\n componentEntities: GetEntitiesResponse,\n pagerDutyServices: PagerDutyService[],\n): Promise<PagerDutyEntityMappingsResponse> {\n const result: PagerDutyEntityMappingsResponse = {\n mappings: [],\n };\n\n pagerDutyServices.forEach(service => {\n // Check for service mapping annotation in any entity config file and get the entity ref\n const entityRef = componentEntitiesDict[service.id]?.ref;\n const entityName = componentEntitiesDict[service.id]?.name;\n\n // Check if the service is mapped to an entity in the database\n const entityMapping = entityMappings.find(\n mapping => mapping.serviceId === service.id,\n );\n\n if (entityMapping) {\n if (entityRef === undefined) {\n if (\n entityMapping.entityRef === '' ||\n entityMapping.entityRef === undefined\n ) {\n result.mappings.push({\n entityRef: '',\n entityName: '',\n integrationKey: entityMapping.integrationKey,\n serviceId: entityMapping.serviceId,\n status: 'NotMapped',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n } else {\n const entityRefName =\n componentEntities.items.find(\n entity =>\n `${entity.kind}:${entity.metadata.namespace}/${entity.metadata.name}`.toLowerCase() ===\n entityMapping.entityRef,\n )?.metadata.name ?? '';\n\n result.mappings.push({\n entityRef: entityMapping.entityRef,\n entityName: entityRefName,\n serviceId: entityMapping.serviceId,\n integrationKey: entityMapping.integrationKey,\n status: 'OutOfSync',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n }\n } else if (entityRef !== entityMapping.entityRef) {\n const entityRefName =\n componentEntities.items.find(\n entity =>\n `${entity.kind}:${entity.metadata.namespace}/${entity.metadata.name}`.toLowerCase() ===\n entityMapping.entityRef,\n )?.metadata.name ?? '';\n\n result.mappings.push({\n entityRef:\n entityMapping.entityRef !== '' ? entityMapping.entityRef : '',\n entityName: entityMapping.entityRef !== '' ? entityRefName : '',\n serviceId: entityMapping.serviceId,\n integrationKey: entityMapping.integrationKey,\n status: 'OutOfSync',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n } else if (entityRef === entityMapping.entityRef) {\n result.mappings.push({\n entityRef:\n entityMapping.entityRef !== '' ? entityMapping.entityRef : '',\n entityName: entityMapping.entityRef !== '' ? entityName : '',\n serviceId: entityMapping.serviceId,\n integrationKey: entityMapping.integrationKey,\n status: 'InSync',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n }\n } else {\n const backstageVendorId = 'PRO19CT';\n const backstageIntegrationKey =\n service.integrations?.find(\n integration => integration.vendor?.id === backstageVendorId,\n )?.integration_key ?? '';\n\n if (entityRef !== undefined) {\n result.mappings.push({\n entityRef: entityRef,\n entityName: entityName,\n serviceId: service.id,\n integrationKey: backstageIntegrationKey,\n status: 'InSync',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n } else {\n result.mappings.push({\n entityRef: '',\n entityName: '',\n serviceId: service.id,\n integrationKey: backstageIntegrationKey,\n status: 'NotMapped',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n }\n }\n });\n\n const sortedResult = result.mappings.sort((a, b) => {\n if (a.serviceName! < b.serviceName!) {\n return -1;\n } else if (a.serviceName! > b.serviceName!) {\n return 1;\n }\n return 0;\n });\n\n result.mappings = sortedResult;\n\n return result;\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, store, catalogApi } = options;\n let { auth } = options;\n\n if (!auth) {\n auth = createLegacyAuthAdapters(options).auth;\n }\n\n if (!catalogApi) {\n throw new Error('Catalog API is required to start the PagerDuty plugin backend');\n }\n\n // Get authentication Config\n await loadAuthConfig(config, logger);\n\n // Get optional PagerDuty custom endpoints from config\n loadPagerDutyEndpointsFromConfig(config, logger);\n\n // Create the router\n const router = Router();\n router.use(express.json());\n\n // DELETE /dependencies/service/:serviceId\n router.delete(\n '/dependencies/service/:serviceId',\n async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n if (serviceId === '') {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' must be provided as part of the path\",\n );\n return;\n }\n\n const dependencies: string[] =\n Object.keys(request.body).length === 0 ? [] : request.body;\n if (!dependencies || dependencies.length === 0) {\n response\n .status(400)\n .json(\n \"Bad Request: 'dependencies' must be provided as part of the request body\",\n );\n return;\n }\n\n const serviceRelations: PagerDutyServiceDependency[] = [];\n\n dependencies.forEach(async dependency => {\n serviceRelations.push({\n supporting_service: {\n id: dependency,\n type: 'service',\n },\n dependent_service: {\n id: serviceId,\n type: 'service',\n },\n });\n });\n\n await removeServiceRelationsFromService(serviceRelations, account);\n\n response.sendStatus(200);\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // POST /dependencies/service/:serviceId\n router.post('/dependencies/service/:serviceId', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n if (serviceId === '') {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' must be provided as part of the path\",\n );\n return;\n }\n\n const dependencies: string[] =\n Object.keys(request.body).length === 0 ? [] : request.body;\n if (!dependencies || dependencies.length === 0) {\n response\n .status(400)\n .json(\n \"Bad Request: 'dependencies' must be provided as part of the request body\",\n );\n return;\n }\n\n const serviceRelations: PagerDutyServiceDependency[] = [];\n\n dependencies.forEach(async dependency => {\n serviceRelations.push({\n supporting_service: {\n id: dependency,\n type: 'service',\n },\n dependent_service: {\n id: serviceId,\n type: 'service',\n },\n });\n });\n\n await addServiceRelationsToService(serviceRelations, account);\n\n response.sendStatus(200);\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n router.get('/dependencies/service/:serviceId', async (request, response) => {\n try {\n const serviceId = request.params.serviceId;\n const account = (request.query.account as string) || '';\n\n if (serviceId) {\n const serviceRelationships: PagerDutyServiceDependency[] =\n await getServiceRelationshipsById(serviceId, account);\n\n if (serviceRelationships) {\n response.json({\n relationships: serviceRelationships,\n });\n }\n } else {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' must be provided as part of the path\",\n );\n }\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /catalog/entity/:entityRef\n router.get(\n '/catalog/entity/:type/:namespace/:name',\n async (request, response) => {\n const type = request.params.type;\n const namespace = request.params.namespace;\n const name = request.params.name;\n\n try {\n if (type && namespace && name) {\n const entityRef = `${type}:${namespace}/${name}`.toLowerCase();\n const foundEntity = await catalogApi?.getEntityByRef(entityRef);\n\n if (foundEntity) {\n response.json(\n foundEntity.metadata.annotations?.['pagerduty.com/service-id'],\n );\n } else {\n response.status(404);\n }\n } else {\n response\n .status(400)\n .json(\n \"Bad Request: ':entityRef' must be provided as part of the path\",\n );\n }\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // POST /settings\n router.post('/settings', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const settings: PagerDutySetting[] = request.body;\n\n // For each setting, update or insert the value in the database\n await Promise.all(\n settings.map(async setting => {\n if (setting.id === undefined || setting.value === undefined) {\n response\n .status(400)\n .json(\"Bad Request: 'id' and 'value' are required\");\n return;\n }\n\n if (!isValidSetting(setting.value)) {\n response\n .status(400)\n .json(\n \"Bad Request: 'value' is invalid. Valid options are 'backstage', 'pagerduty', 'both' or 'disabled'\",\n );\n return;\n }\n\n await store.updateSetting(setting);\n }),\n );\n\n response.sendStatus(200);\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /settings/:settingId\n router.get('/settings/:settingId', async (request, response) => {\n try {\n // Get param from the request\n const settingId = request.params.settingId;\n\n // Find setting by id\n const setting = await store.findSetting(settingId);\n\n if (!setting) {\n response.status(404).json({});\n return;\n }\n\n response.json(setting);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n function isValidSetting(value: string): boolean {\n if (\n value === 'backstage' ||\n value === 'pagerduty' ||\n value === 'both' ||\n value === 'disabled'\n ) {\n return true;\n }\n\n return false;\n }\n\n // POST /mapping/entity\n router.post('/mapping/entity', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const entity: PagerDutyEntityMapping = request.body;\n\n if (!entity.serviceId) {\n response\n .status(400)\n .json(\n \"Bad Request: 'serviceId' must be provided as part of the request body\",\n );\n return;\n }\n\n // Get all the entity mappings from the database\n const entityMappings = await store.getAllEntityMappings();\n const oldMapping = entityMappings.find(\n mapping => mapping.serviceId === entity.serviceId,\n );\n\n // in case a mapping is defined and no integration exists,\n // we need to create one\n if (\n entity.entityRef !== '' &&\n (entity.integrationKey === '' || entity.integrationKey === undefined)\n ) {\n const backstageVendorId = 'PRO19CT';\n // check for existing integration key on service\n const service = await getServiceById(entity.serviceId, entity.account);\n const backstageIntegration = service.integrations?.find(\n integration => integration.vendor?.id === backstageVendorId,\n );\n\n if (!backstageIntegration) {\n // If an integration does not exist for service,\n // create it in PagerDuty\n const integrationKey = await createServiceIntegration({\n serviceId: entity.serviceId,\n vendorId: backstageVendorId,\n account: entity.account,\n });\n\n entity.integrationKey = integrationKey;\n } else {\n entity.integrationKey = backstageIntegration.integration_key;\n }\n }\n\n const entityMappingId = await store.insertEntityMapping(entity);\n\n // Refresh new and old entity unless they are empty strings\n if (entity.entityRef !== '') {\n // force refresh of new entity\n await catalogApi?.refreshEntity(entity.entityRef);\n }\n\n if (oldMapping && oldMapping.entityRef !== '') {\n // force refresh of old entity\n await catalogApi?.refreshEntity(oldMapping.entityRef);\n }\n\n response.json({\n id: entityMappingId,\n entityRef: entity.entityRef,\n integrationKey: entity.integrationKey,\n serviceId: entity.serviceId,\n status: entity.status,\n account: entity.account,\n });\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n } else {\n logger.error(\n `Unexpected error occurred while processing request: ${error}`,\n );\n response.status(500).json({\n errors: [error instanceof Error ? error.message : String(error)],\n });\n }\n }\n });\n\n // POST /mapping/entities/bulk\n router.post('/mapping/entities/bulk', async (request, response) => {\n try {\n const { mappings } = request.body;\n\n if (!Array.isArray(mappings)) {\n response.status(400).json({\n error: \"Bad Request: 'mappings' must be an array\",\n });\n return;\n }\n\n const existingMappings = await store.getAllEntityMappings();\n const existingServiceIds = new Set(\n existingMappings.map(m => m.serviceId),\n );\n\n const newMappings: PagerDutyEntityMapping[] = [];\n const skipped: PagerDutyEntityMapping[] = [];\n const errors = [];\n\n for (const entity of mappings) {\n if (!entity.serviceId) {\n errors.push({\n entityRef: entity.entityRef,\n error: 'Missing serviceId',\n });\n continue;\n }\n\n if (existingServiceIds.has(entity.serviceId)) {\n skipped.push(entity);\n continue;\n }\n\n if (\n entity.entityRef !== '' &&\n (entity.integrationKey === '' || entity.integrationKey === undefined)\n ) {\n try {\n const backstageVendorId = 'PRO19CT';\n const service = await getServiceById(\n entity.serviceId,\n entity.account,\n );\n const backstageIntegration = service.integrations?.find(\n integration => integration.vendor?.id === backstageVendorId,\n );\n\n if (!backstageIntegration) {\n const integrationKey = await createServiceIntegration({\n serviceId: entity.serviceId,\n vendorId: backstageVendorId,\n account: entity.account,\n });\n\n entity.integrationKey = integrationKey;\n } else {\n entity.integrationKey = backstageIntegration.integration_key;\n }\n } catch (error) {\n errors.push({\n entityRef: entity.entityRef,\n serviceId: entity.serviceId,\n error:\n error instanceof Error\n ? `Failed to create integration: ${error.message}`\n : 'Failed to create integration',\n });\n continue;\n }\n }\n\n newMappings.push(entity);\n }\n\n let insertedIds: string[] = [];\n if (newMappings.length > 0) {\n try {\n insertedIds = await store.bulkInsertEntityMappings(newMappings);\n\n await Promise.all(\n newMappings.map(async entity => {\n if (entity.entityRef !== '') {\n await catalogApi?.refreshEntity(entity.entityRef);\n }\n }),\n );\n } catch (error) {\n logger.error(`Bulk insert failed: ${error}`);\n response.status(500).json({\n errors: ['Bulk insert failed'],\n });\n return;\n }\n }\n\n const results = newMappings.map((entity, index) => ({\n id: insertedIds[index],\n entityRef: entity.entityRef,\n integrationKey: entity.integrationKey,\n serviceId: entity.serviceId,\n status: entity.status,\n account: entity.account,\n }));\n\n response.json({\n success: results,\n skipped: skipped.map(entity => ({\n entityRef: entity.entityRef,\n serviceId: entity.serviceId,\n reason: 'Mapping already exists for this service ID',\n })),\n errors: errors,\n total: mappings.length,\n successCount: results.length,\n skippedCount: skipped.length,\n errorCount: errors.length,\n });\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing bulk mappings: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n } else {\n logger.error(`Unexpected error: ${error}`);\n response.status(500).json({\n errors: ['Internal server error'],\n });\n }\n }\n });\n\n // DEPRECATED: GET /mapping/entity\n router.get('/mapping/entity', async (_, response) => {\n try {\n // Get all the entity mappings from the database\n const entityMappings = await store.getAllEntityMappings();\n\n // Get all the entities from the catalog\n const componentEntities = await catalogApi!.getEntities({\n filter: {\n kind: 'Component',\n },\n });\n\n // Build reference dictionary of componentEntities with serviceId as the key and entity reference and name pair as the value\n const componentEntitiesDict: Record<\n string,\n { ref: string; name: string }\n > = await CatalogEntityUtils.createComponentEntitiesReferenceDict(componentEntities);\n\n // Get all services from PagerDuty\n const pagerDutyServices = await getAllServices();\n\n // Build the response object\n const result: PagerDutyEntityMappingsResponse =\n await buildEntityMappingsResponse(\n entityMappings,\n componentEntitiesDict,\n componentEntities,\n pagerDutyServices,\n );\n\n response.json(result);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n router.post('/mapping/entities', MappingsController.getMappingEntities(store, catalogApi));\n\n // GET /mapping/entity\n router.get(\n '/mapping/entity/:type/:namespace/:name',\n async (request, response) => {\n try {\n // Get the type, namespace and entity name from the request parameters\n const entityType: string = request.params.type || '';\n const entityNamespace: string = request.params.namespace || '';\n const entityName: string = request.params.name || '';\n\n if (entityType === '' || entityNamespace === '' || entityName === '') {\n response.status(400).json('Required params not specified.');\n return;\n }\n\n const entityRef =\n `${entityType}:${entityNamespace}/${entityName}`.toLowerCase();\n\n // Get all the entity mappings from the database\n const entityMapping = await store.findEntityMappingByEntityRef(\n entityRef,\n );\n\n if (!entityMapping) {\n response\n .status(404)\n .json(`Mapping for entityRef ${entityRef} not found.`);\n return;\n }\n\n response.json({\n mapping: entityMapping,\n });\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // GET /mapping/entity/service/:serviceId\n router.get(\n '/mapping/entity/service/:serviceId',\n async (request, response) => {\n try {\n // Get the type, namespace and entity name from the request parameters\n const serviceId: string = request.params.serviceId ?? '';\n\n if (serviceId === '') {\n response.status(400).json('Required params not specified.');\n return;\n }\n\n // Get all the entity mappings from the database\n const entityMapping = await store.findEntityMappingByServiceId(\n serviceId,\n );\n\n if (!entityMapping) {\n response\n .status(404)\n .json(`Mapping for serviceId ${serviceId} not found.`);\n return;\n }\n\n response.json({\n mapping: entityMapping,\n });\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // POST /mapping/entity/auto-match\n router.post('/mapping/entity/auto-match', async (request, response) => {\n try {\n // Default 100% threshold ensures only exact matches, customers can adjust if needed\n const threshold: number = request.body.threshold ?? 100;\n const account: string | undefined = request.body.account;\n\n if (typeof threshold !== 'number' || threshold < 0 || threshold > 100) {\n response.status(400).json({\n error: 'Invalid threshold. Must be a number between 0 and 100.',\n });\n return;\n }\n\n const bestOnly: boolean = request.body.bestOnly ?? false;\n\n const loadStartTime = Date.now();\n const { pdServices, bsComponents } = await loadBothSources({\n catalogApi: catalogApi!,\n });\n\n const filteredPdServices = account\n ? pdServices.filter(service => service.account === account)\n : pdServices;\n\n const loadTime = Date.now() - loadStartTime;\n\n const matchStartTime = Date.now();\n const matchingConfig: MatchingConfig = { threshold };\n let matches = findMatches(filteredPdServices, bsComponents, matchingConfig);\n\n if (bestOnly) {\n matches = filterToBestMatchPerService(matches);\n }\n\n const matchTime = Date.now() - matchStartTime;\n\n const totalComparisons = filteredPdServices.length * bsComponents.length;\n const exactMatches = matches.filter(m => m.score === 100).length;\n const highConfidence = matches.filter(\n m => m.score >= 90 && m.score < 100,\n ).length;\n const mediumConfidence = matches.filter(\n m => m.score >= 80 && m.score < 90,\n ).length;\n\n const getConfidenceLevel = (\n score: number,\n ): 'exact' | 'high' | 'medium' | 'low' => {\n if (score === 100) return 'exact';\n if (score >= 90) return 'high';\n if (score >= 80) return 'medium';\n return 'low';\n };\n\n response.json({\n matches: matches.map(m => ({\n pagerDutyService: {\n serviceId: m.pagerDutyService.sourceId,\n name: m.pagerDutyService.rawName,\n team: m.pagerDutyService.teamName,\n account: m.pagerDutyService.account,\n },\n backstageComponent: {\n entityRef: m.backstageComponent.sourceId,\n name: m.backstageComponent.rawName,\n owner: m.backstageComponent.teamName,\n },\n score: m.score,\n confidence: getConfidenceLevel(m.score),\n scoreBreakdown: m.scoreBreakdown,\n })),\n statistics: {\n totalPagerDutyServices: filteredPdServices.length,\n totalBackstageComponents: bsComponents.length,\n totalPossibleComparisons: totalComparisons,\n matchesFound: matches.length,\n exactMatches,\n highConfidenceMatches: highConfidence,\n mediumConfidenceMatches: mediumConfidence,\n threshold,\n loadTimeMs: loadTime,\n matchTimeMs: matchTime,\n totalTimeMs: loadTime + matchTime,\n },\n });\n } catch (error) {\n logger.error(`Auto-match failed: ${error}`);\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n } else if (error instanceof ServiceLoadError) {\n response.status(503).json({\n error: 'Service temporarily unavailable',\n message: error.message,\n });\n } else {\n response.status(500).json({\n error: 'Auto-match failed',\n message: error instanceof Error ? error.message : String(error),\n });\n }\n }\n });\n\n // GET /escalation_policies\n router.get('/escalation_policies', async (_, response) => {\n try {\n let escalationPolicyList = await getAllEscalationPolicies();\n\n // sort the escalation policies by account and name\n escalationPolicyList = escalationPolicyList.sort((a, b) => {\n if (a.account === b.account) {\n return a.name.localeCompare(b.name);\n }\n return a.account!.localeCompare(b.account!);\n });\n\n const escalationPolicyDropDownOptions = escalationPolicyList.map(\n policy => {\n let policyLabel = policy.name;\n if (policy.account && policy.account !== 'default') {\n policyLabel = `(${policy.account}) ${policy.name}`;\n }\n\n return {\n label: policyLabel,\n value: policy.id,\n };\n },\n );\n\n response.json(escalationPolicyDropDownOptions);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /oncall\n router.get('/oncall-users', async (request, response) => {\n try {\n // Get the escalation policy ID from the request parameters with parameter name \"escalation_policy_ids[]\"\n const escalationPolicyId: string =\n (request.query.escalation_policy_ids as string) || '';\n const account = (request.query.account as string) || '';\n\n if (escalationPolicyId === '') {\n response\n .status(400)\n .json(\"Bad Request: 'escalation_policy_ids[]' is required\");\n return;\n }\n\n const oncallUsers = await getOncallUsers(escalationPolicyId, account);\n const onCallUsersResponse: PagerDutyOnCallUsersResponse = {\n users: oncallUsers,\n };\n\n response.json(onCallUsersResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /services/:serviceId\n router.get('/services/:serviceId', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n if (serviceId === '') {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' must be provided as part of the path or 'integration_key' as a query parameter\",\n );\n return;\n }\n\n const service = await getServiceById(serviceId, account);\n const serviceResponse: PagerDutyServiceResponse = {\n service: service,\n };\n\n response.json(serviceResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /teams?account=:account\n router.get('/teams', async (request, response) => {\n try {\n const account = request.query.account as string | undefined;\n const teams = await getAllTeams(account);\n response.json(teams);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n\n // GET /services - Unified endpoint for all service queries\n // Query params:\n // - integration_key: fetch service by integration key\n // - team_id, query, limit, account: fetch filtered services\n // - no params: fetch all services\n router.get('/services', async (request, response) => {\n try {\n const integrationKey = request.query.integration_key as string | undefined;\n const teamId = request.query.team_id as string | undefined;\n const query = request.query.query as string | undefined;\n const limit = request.query.limit\n ? parseInt(request.query.limit as string, 10)\n : undefined;\n const account = request.query.account as string | undefined;\n\n // Case 1: Fetch by integration key\n if (integrationKey) {\n const service = await getServiceByIntegrationKey(\n integrationKey,\n account || '',\n );\n const serviceResponse: PagerDutyServiceResponse = {\n service: service,\n };\n response.json(serviceResponse);\n return;\n }\n\n // Case 2: Fetch filtered services (if team_id, query, or limit provided)\n if (teamId || query || limit) {\n const teamIdsArray: string[] | undefined = teamId ? [teamId] : undefined;\n const services = await getFilteredServices(\n teamIdsArray,\n query,\n limit || 100,\n account,\n );\n response.json(services);\n return;\n }\n\n // Case 3: Fetch all services (default)\n const services = await getAllServices();\n const servicesResponse: PagerDutyServicesResponse = {\n services: services,\n };\n response.json(servicesResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n } else {\n logger.error(\n `Unexpected error occurred while processing request: ${error}`,\n );\n response.status(500).json({\n errors: [error instanceof Error ? error.message : String(error)],\n });\n }\n }\n });\n\n // POST /services/:serviceId/integration/:vendorId\n router.post(\n '/services/:serviceId/integration/:vendorId',\n async (request, response) => {\n try {\n const serviceId: string = request.params.serviceId || '';\n const vendorId: string = request.params.vendorId || '';\n const account = (request.query.account as string) || '';\n\n if (serviceId === '' || vendorId === '') {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' and ':vendorId' must be provided as part of the path\",\n );\n return;\n }\n\n const integrationKey = await createServiceIntegration({\n serviceId,\n vendorId,\n account,\n });\n\n response.json(integrationKey);\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // GET /services/:serviceId/change-events\n router.get(\n '/services/:serviceId/change-events',\n async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n const changeEvents = await getChangeEvents(serviceId, account);\n const changeEventsResponse: PagerDutyChangeEventsResponse = {\n change_events: changeEvents,\n };\n\n response.json(changeEventsResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // GET /services/:serviceId/incidents\n router.get('/services/:serviceId/incidents', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n const incidents = await getIncidents(serviceId, account);\n const incidentsResponse: PagerDutyIncidentsResponse = {\n incidents,\n };\n\n response.json(incidentsResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /services/:serviceId/standards\n router.get('/services/:serviceId/standards', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n const serviceStandards = await getServiceStandards(serviceId, account);\n const serviceStandardsResponse: PagerDutyServiceStandardsResponse = {\n standards: serviceStandards,\n };\n\n response.json(serviceStandardsResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /services/:serviceId/metrics\n router.get('/services/:serviceId/metrics', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n const metrics = await getServiceMetrics(serviceId, account);\n\n const metricsResponse: PagerDutyServiceMetricsResponse = {\n metrics: metrics,\n };\n\n response.json(metricsResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /accounts\n router.get('/accounts', async (_, response) => {\n try {\n const accountsConfig = config.getOptional('pagerDuty.accounts') as\n | Array<{\n id: string;\n isDefault?: boolean;\n }>\n | undefined;\n\n if (accountsConfig && accountsConfig.length > 0) {\n const accounts = accountsConfig.map(account => ({\n id: account.id,\n isDefault: account.isDefault || false,\n }));\n response.status(200).json({ accounts });\n } else {\n response.status(200).json({ accounts: [] });\n }\n } catch (error) {\n logger.error(`Failed to get accounts: ${error}`);\n response.status(500).json({ error: 'Failed to get accounts' });\n }\n });\n\n // GET /health\n router.get('/health', async (_, response) => {\n response.status(200).json({ status: 'ok' });\n });\n\n // Add error handler\n router.use(errorHandler());\n\n // Return the router\n return router;\n}\n"],"names":["auth","createLegacyAuthAdapters","loadAuthConfig","loadPagerDutyEndpointsFromConfig","Router","express","removeServiceRelationsFromService","HttpError","addServiceRelationsToService","getServiceRelationshipsById","getServiceById","createServiceIntegration","CatalogEntityUtils.createComponentEntitiesReferenceDict","getAllServices","MappingsController.getMappingEntities","loadBothSources","findMatches","filterToBestMatchPerService","ServiceLoadError","getAllEscalationPolicies","getOncallUsers","getAllTeams","getServiceByIntegrationKey","services","getFilteredServices","getChangeEvents","getIncidents","getServiceStandards","getServiceMetrics","errorHandler"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.ts"],"sourcesContent":["import {\n AuthService,\n CacheService,\n DiscoveryService,\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport {\n getAllEscalationPolicies,\n getChangeEvents,\n getIncidents,\n getOncallUsers,\n getServiceById,\n getServiceByIntegrationKey,\n getServiceStandards,\n getServiceMetrics,\n getAllServices,\n getAllTeams,\n getFilteredServices,\n loadPagerDutyEndpointsFromConfig,\n createServiceIntegration,\n getServiceRelationshipsById,\n addServiceRelationsToService,\n removeServiceRelationsFromService,\n} from '../apis/pagerduty';\nimport { createAutoMatchRunner } from '../services/autoMatchRunner';\nimport { AutoMatchJobRegistry } from '../services/autoMatchJobs';\nimport {\n HttpError,\n PagerDutyChangeEventsResponse,\n PagerDutyIncidentsResponse,\n PagerDutyOnCallUsersResponse,\n PagerDutyServiceResponse,\n PagerDutyServiceStandardsResponse,\n PagerDutyServiceMetricsResponse,\n PagerDutyServicesResponse,\n PagerDutyEntityMapping,\n PagerDutyEntityMappingsResponse,\n PagerDutyService,\n PagerDutyServiceDependency,\n PagerDutySetting,\n} from '@pagerduty/backstage-plugin-common';\nimport { loadAuthConfig } from '../auth/auth';\nimport {\n PagerDutyBackendStore,\n RawDbEntityResultRow,\n} from '../db/PagerDutyBackendDatabase';\nimport * as express from 'express';\nimport Router from 'express-promise-router';\nimport type { CatalogApi, GetEntitiesResponse } from '@backstage/catalog-client';\n\nimport * as MappingsController from '../controllers/mappings-controller';\nimport * as CatalogEntityUtils from '../utils/catalog-entity';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\n\nexport interface RouterOptions {\n logger: LoggerService;\n config: RootConfigService;\n store: PagerDutyBackendStore;\n discovery: DiscoveryService;\n auth: AuthService;\n catalogApi?: CatalogApi;\n cache: CacheService;\n}\n\nexport type Annotations = {\n 'pagerduty.com/integration-key': string;\n 'pagerduty.com/service-id': string;\n 'pagerduty.com/account': string;\n};\n\nexport async function buildEntityMappingsResponse(\n entityMappings: RawDbEntityResultRow[],\n componentEntitiesDict: Record<\n string,\n {\n ref: string;\n name: string;\n }\n >,\n componentEntities: GetEntitiesResponse,\n pagerDutyServices: PagerDutyService[],\n): Promise<PagerDutyEntityMappingsResponse> {\n const result: PagerDutyEntityMappingsResponse = {\n mappings: [],\n };\n\n pagerDutyServices.forEach(service => {\n // Check for service mapping annotation in any entity config file and get the entity ref\n const entityRef = componentEntitiesDict[service.id]?.ref;\n const entityName = componentEntitiesDict[service.id]?.name;\n\n // Check if the service is mapped to an entity in the database\n const entityMapping = entityMappings.find(\n mapping => mapping.serviceId === service.id,\n );\n\n if (entityMapping) {\n if (entityRef === undefined) {\n if (\n entityMapping.entityRef === '' ||\n entityMapping.entityRef === undefined\n ) {\n result.mappings.push({\n entityRef: '',\n entityName: '',\n integrationKey: entityMapping.integrationKey,\n serviceId: entityMapping.serviceId,\n status: 'NotMapped',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n } else {\n const entityRefName =\n componentEntities.items.find(\n entity =>\n `${entity.kind}:${entity.metadata.namespace}/${entity.metadata.name}`.toLowerCase() ===\n entityMapping.entityRef,\n )?.metadata.name ?? '';\n\n result.mappings.push({\n entityRef: entityMapping.entityRef,\n entityName: entityRefName,\n serviceId: entityMapping.serviceId,\n integrationKey: entityMapping.integrationKey,\n status: 'OutOfSync',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n }\n } else if (entityRef !== entityMapping.entityRef) {\n const entityRefName =\n componentEntities.items.find(\n entity =>\n `${entity.kind}:${entity.metadata.namespace}/${entity.metadata.name}`.toLowerCase() ===\n entityMapping.entityRef,\n )?.metadata.name ?? '';\n\n result.mappings.push({\n entityRef:\n entityMapping.entityRef !== '' ? entityMapping.entityRef : '',\n entityName: entityMapping.entityRef !== '' ? entityRefName : '',\n serviceId: entityMapping.serviceId,\n integrationKey: entityMapping.integrationKey,\n status: 'OutOfSync',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n } else if (entityRef === entityMapping.entityRef) {\n result.mappings.push({\n entityRef:\n entityMapping.entityRef !== '' ? entityMapping.entityRef : '',\n entityName: entityMapping.entityRef !== '' ? entityName : '',\n serviceId: entityMapping.serviceId,\n integrationKey: entityMapping.integrationKey,\n status: 'InSync',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n }\n } else {\n const backstageVendorId = 'PRO19CT';\n const backstageIntegrationKey =\n service.integrations?.find(\n integration => integration.vendor?.id === backstageVendorId,\n )?.integration_key ?? '';\n\n if (entityRef !== undefined) {\n result.mappings.push({\n entityRef: entityRef,\n entityName: entityName,\n serviceId: service.id,\n integrationKey: backstageIntegrationKey,\n status: 'InSync',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n } else {\n result.mappings.push({\n entityRef: '',\n entityName: '',\n serviceId: service.id,\n integrationKey: backstageIntegrationKey,\n status: 'NotMapped',\n serviceName: service.name,\n team: service.teams?.[0]?.name ?? '',\n escalationPolicy:\n service.escalation_policy !== undefined\n ? service.escalation_policy.name\n : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n }\n }\n });\n\n const sortedResult = result.mappings.sort((a, b) => {\n if (a.serviceName! < b.serviceName!) {\n return -1;\n } else if (a.serviceName! > b.serviceName!) {\n return 1;\n }\n return 0;\n });\n\n result.mappings = sortedResult;\n\n return result;\n}\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, store, catalogApi, cache } = options;\n\n if (!catalogApi) {\n throw new Error('Catalog API is required to start the PagerDuty plugin backend');\n }\n\n if (!cache) {\n throw new Error('Cache service is required to start the PagerDuty plugin backend');\n }\n\n // Get authentication Config\n await loadAuthConfig(config, logger);\n\n // Get optional PagerDuty custom endpoints from config\n loadPagerDutyEndpointsFromConfig(config, logger);\n\n // Create the router\n const router = Router();\n router.use(express.json());\n\n const runAutoMatch = createAutoMatchRunner(catalogApi);\n const autoMatchJobs = new AutoMatchJobRegistry(cache, runAutoMatch);\n\n // DELETE /dependencies/service/:serviceId\n router.delete(\n '/dependencies/service/:serviceId',\n async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n if (serviceId === '') {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' must be provided as part of the path\",\n );\n return;\n }\n\n const dependencies: string[] =\n Object.keys(request.body).length === 0 ? [] : request.body;\n if (!dependencies || dependencies.length === 0) {\n response\n .status(400)\n .json(\n \"Bad Request: 'dependencies' must be provided as part of the request body\",\n );\n return;\n }\n\n const serviceRelations: PagerDutyServiceDependency[] = [];\n\n dependencies.forEach(async dependency => {\n serviceRelations.push({\n supporting_service: {\n id: dependency,\n type: 'service',\n },\n dependent_service: {\n id: serviceId,\n type: 'service',\n },\n });\n });\n\n await removeServiceRelationsFromService(serviceRelations, account);\n\n response.sendStatus(200);\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // POST /dependencies/service/:serviceId\n router.post('/dependencies/service/:serviceId', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n if (serviceId === '') {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' must be provided as part of the path\",\n );\n return;\n }\n\n const dependencies: string[] =\n Object.keys(request.body).length === 0 ? [] : request.body;\n if (!dependencies || dependencies.length === 0) {\n response\n .status(400)\n .json(\n \"Bad Request: 'dependencies' must be provided as part of the request body\",\n );\n return;\n }\n\n const serviceRelations: PagerDutyServiceDependency[] = [];\n\n dependencies.forEach(async dependency => {\n serviceRelations.push({\n supporting_service: {\n id: dependency,\n type: 'service',\n },\n dependent_service: {\n id: serviceId,\n type: 'service',\n },\n });\n });\n\n await addServiceRelationsToService(serviceRelations, account);\n\n response.sendStatus(200);\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n router.get('/dependencies/service/:serviceId', async (request, response) => {\n try {\n const serviceId = request.params.serviceId;\n const account = (request.query.account as string) || '';\n\n if (serviceId) {\n const serviceRelationships: PagerDutyServiceDependency[] =\n await getServiceRelationshipsById(serviceId, account);\n\n if (serviceRelationships) {\n response.json({\n relationships: serviceRelationships,\n });\n }\n } else {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' must be provided as part of the path\",\n );\n }\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /catalog/entity/:entityRef\n router.get(\n '/catalog/entity/:type/:namespace/:name',\n async (request, response) => {\n const type = request.params.type;\n const namespace = request.params.namespace;\n const name = request.params.name;\n\n try {\n if (type && namespace && name) {\n const entityRef = `${type}:${namespace}/${name}`.toLowerCase();\n const foundEntity = await catalogApi?.getEntityByRef(entityRef);\n\n if (foundEntity) {\n response.json(\n foundEntity.metadata.annotations?.['pagerduty.com/service-id'],\n );\n } else {\n response.status(404);\n }\n } else {\n response\n .status(400)\n .json(\n \"Bad Request: ':entityRef' must be provided as part of the path\",\n );\n }\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // POST /settings\n router.post('/settings', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const settings: PagerDutySetting[] = request.body;\n\n // For each setting, update or insert the value in the database\n await Promise.all(\n settings.map(async setting => {\n if (setting.id === undefined || setting.value === undefined) {\n response\n .status(400)\n .json(\"Bad Request: 'id' and 'value' are required\");\n return;\n }\n\n if (!isValidSetting(setting.value)) {\n response\n .status(400)\n .json(\n \"Bad Request: 'value' is invalid. Valid options are 'backstage', 'pagerduty', 'both' or 'disabled'\",\n );\n return;\n }\n\n await store.updateSetting(setting);\n }),\n );\n\n response.sendStatus(200);\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /settings/:settingId\n router.get('/settings/:settingId', async (request, response) => {\n try {\n // Get param from the request\n const settingId = request.params.settingId;\n\n // Find setting by id\n const setting = await store.findSetting(settingId);\n\n if (!setting) {\n response.status(404).json({});\n return;\n }\n\n response.json(setting);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n function isValidSetting(value: string): boolean {\n if (\n value === 'backstage' ||\n value === 'pagerduty' ||\n value === 'both' ||\n value === 'disabled'\n ) {\n return true;\n }\n\n return false;\n }\n\n // POST /mapping/entity\n router.post('/mapping/entity', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const entity: PagerDutyEntityMapping = request.body;\n\n if (!entity.serviceId) {\n response\n .status(400)\n .json(\n \"Bad Request: 'serviceId' must be provided as part of the request body\",\n );\n return;\n }\n\n // Get all the entity mappings from the database\n const entityMappings = await store.getAllEntityMappings();\n const oldMapping = entityMappings.find(\n mapping => mapping.serviceId === entity.serviceId,\n );\n\n // in case a mapping is defined and no integration exists,\n // we need to create one\n if (\n entity.entityRef !== '' &&\n (entity.integrationKey === '' || entity.integrationKey === undefined)\n ) {\n const backstageVendorId = 'PRO19CT';\n // check for existing integration key on service\n const service = await getServiceById(entity.serviceId, entity.account);\n const backstageIntegration = service.integrations?.find(\n integration => integration.vendor?.id === backstageVendorId,\n );\n\n if (!backstageIntegration) {\n // If an integration does not exist for service,\n // create it in PagerDuty\n const integrationKey = await createServiceIntegration({\n serviceId: entity.serviceId,\n vendorId: backstageVendorId,\n account: entity.account,\n });\n\n entity.integrationKey = integrationKey;\n } else {\n entity.integrationKey = backstageIntegration.integration_key;\n }\n }\n\n const entityMappingId = await store.insertEntityMapping(entity);\n\n // Refresh new and old entity unless they are empty strings\n if (entity.entityRef !== '') {\n // force refresh of new entity\n await catalogApi?.refreshEntity(entity.entityRef);\n }\n\n if (oldMapping && oldMapping.entityRef !== '') {\n // force refresh of old entity\n await catalogApi?.refreshEntity(oldMapping.entityRef);\n }\n\n response.json({\n id: entityMappingId,\n entityRef: entity.entityRef,\n integrationKey: entity.integrationKey,\n serviceId: entity.serviceId,\n status: entity.status,\n account: entity.account,\n });\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n } else {\n logger.error(\n `Unexpected error occurred while processing request: ${error}`,\n );\n response.status(500).json({\n errors: [error instanceof Error ? error.message : String(error)],\n });\n }\n }\n });\n\n // POST /mapping/entities/bulk\n router.post('/mapping/entities/bulk', async (request, response) => {\n try {\n const { mappings } = request.body;\n\n if (!Array.isArray(mappings)) {\n response.status(400).json({\n error: \"Bad Request: 'mappings' must be an array\",\n });\n return;\n }\n\n const existingMappings = await store.getAllEntityMappings();\n const existingServiceIds = new Set(\n existingMappings.map(m => m.serviceId),\n );\n\n const newMappings: PagerDutyEntityMapping[] = [];\n const skipped: PagerDutyEntityMapping[] = [];\n const errors = [];\n\n for (const entity of mappings) {\n if (!entity.serviceId) {\n errors.push({\n entityRef: entity.entityRef,\n error: 'Missing serviceId',\n });\n continue;\n }\n\n if (existingServiceIds.has(entity.serviceId)) {\n skipped.push(entity);\n continue;\n }\n\n if (\n entity.entityRef !== '' &&\n (entity.integrationKey === '' || entity.integrationKey === undefined)\n ) {\n try {\n const backstageVendorId = 'PRO19CT';\n const service = await getServiceById(\n entity.serviceId,\n entity.account,\n );\n const backstageIntegration = service.integrations?.find(\n integration => integration.vendor?.id === backstageVendorId,\n );\n\n if (!backstageIntegration) {\n const integrationKey = await createServiceIntegration({\n serviceId: entity.serviceId,\n vendorId: backstageVendorId,\n account: entity.account,\n });\n\n entity.integrationKey = integrationKey;\n } else {\n entity.integrationKey = backstageIntegration.integration_key;\n }\n } catch (error) {\n errors.push({\n entityRef: entity.entityRef,\n serviceId: entity.serviceId,\n error:\n error instanceof Error\n ? `Failed to create integration: ${error.message}`\n : 'Failed to create integration',\n });\n continue;\n }\n }\n\n newMappings.push(entity);\n }\n\n let insertedIds: string[] = [];\n if (newMappings.length > 0) {\n try {\n insertedIds = await store.bulkInsertEntityMappings(newMappings);\n\n await Promise.all(\n newMappings.map(async entity => {\n if (entity.entityRef !== '') {\n await catalogApi?.refreshEntity(entity.entityRef);\n }\n }),\n );\n } catch (error) {\n logger.error(`Bulk insert failed: ${error}`);\n response.status(500).json({\n errors: ['Bulk insert failed'],\n });\n return;\n }\n }\n\n const results = newMappings.map((entity, index) => ({\n id: insertedIds[index],\n entityRef: entity.entityRef,\n integrationKey: entity.integrationKey,\n serviceId: entity.serviceId,\n status: entity.status,\n account: entity.account,\n }));\n\n response.json({\n success: results,\n skipped: skipped.map(entity => ({\n entityRef: entity.entityRef,\n serviceId: entity.serviceId,\n reason: 'Mapping already exists for this service ID',\n })),\n errors: errors,\n total: mappings.length,\n successCount: results.length,\n skippedCount: skipped.length,\n errorCount: errors.length,\n });\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing bulk mappings: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n } else {\n logger.error(`Unexpected error: ${error}`);\n response.status(500).json({\n errors: ['Internal server error'],\n });\n }\n }\n });\n\n // DEPRECATED: GET /mapping/entity\n router.get('/mapping/entity', async (_, response) => {\n try {\n // Get all the entity mappings from the database\n const entityMappings = await store.getAllEntityMappings();\n\n // Get all the entities from the catalog\n const componentEntities = await catalogApi!.getEntities({\n filter: {\n kind: 'Component',\n },\n });\n\n // Build reference dictionary of componentEntities with serviceId as the key and entity reference and name pair as the value\n const componentEntitiesDict: Record<\n string,\n { ref: string; name: string }\n > = await CatalogEntityUtils.createComponentEntitiesReferenceDict(componentEntities);\n\n // Get all services from PagerDuty\n const pagerDutyServices = await getAllServices();\n\n // Build the response object\n const result: PagerDutyEntityMappingsResponse =\n await buildEntityMappingsResponse(\n entityMappings,\n componentEntitiesDict,\n componentEntities,\n pagerDutyServices,\n );\n\n response.json(result);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n router.post('/mapping/entities', MappingsController.getMappingEntities(store, catalogApi));\n\n // GET /mapping/entity\n router.get(\n '/mapping/entity/:type/:namespace/:name',\n async (request, response) => {\n try {\n // Get the type, namespace and entity name from the request parameters\n const entityType: string = request.params.type || '';\n const entityNamespace: string = request.params.namespace || '';\n const entityName: string = request.params.name || '';\n\n if (entityType === '' || entityNamespace === '' || entityName === '') {\n response.status(400).json('Required params not specified.');\n return;\n }\n\n const entityRef =\n `${entityType}:${entityNamespace}/${entityName}`.toLowerCase();\n\n // Get all the entity mappings from the database\n const entityMapping = await store.findEntityMappingByEntityRef(\n entityRef,\n );\n\n if (!entityMapping) {\n response\n .status(404)\n .json(`Mapping for entityRef ${entityRef} not found.`);\n return;\n }\n\n response.json({\n mapping: entityMapping,\n });\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // GET /mapping/entity/service/:serviceId\n router.get(\n '/mapping/entity/service/:serviceId',\n async (request, response) => {\n try {\n // Get the type, namespace and entity name from the request parameters\n const serviceId: string = request.params.serviceId ?? '';\n\n if (serviceId === '') {\n response.status(400).json('Required params not specified.');\n return;\n }\n\n // Get all the entity mappings from the database\n const entityMapping = await store.findEntityMappingByServiceId(\n serviceId,\n );\n\n if (!entityMapping) {\n response\n .status(404)\n .json(`Mapping for serviceId ${serviceId} not found.`);\n return;\n }\n\n response.json({\n mapping: entityMapping,\n });\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // POST /mapping/entity/auto-match/start\n router.post('/mapping/entity/auto-match/start', async (request, response) => {\n const threshold: number = request.body.threshold ?? 100;\n\n if (typeof threshold !== 'number' || threshold < 0 || threshold > 100) {\n response.status(400).json({\n error: 'Invalid threshold. Must be a number between 0 and 100.',\n });\n return;\n }\n\n const bestOnly: boolean = request.body.bestOnly ?? false;\n const team: string | undefined = request.body.team;\n const account: string | undefined = request.body.account;\n\n const job = await autoMatchJobs.start({\n threshold,\n bestOnly,\n team,\n account,\n });\n\n response.status(202).json({\n jobId: job.id,\n status: job.status,\n });\n });\n\n // GET /mapping/entity/auto-match/:jobId\n router.get('/mapping/entity/auto-match/:jobId', async (request, response) => {\n const jobId = request.params.jobId;\n const job = await autoMatchJobs.get(jobId);\n\n if (!job) {\n response.status(404).json({\n error: `Auto-match job ${jobId} not found.`,\n });\n return;\n }\n\n response.json({\n jobId: job.id,\n status: job.status,\n createdAt: job.createdAt,\n completedAt: job.completedAt,\n result: job.result,\n error: job.error,\n });\n });\n\n // GET /escalation_policies\n router.get('/escalation_policies', async (_, response) => {\n try {\n let escalationPolicyList = await getAllEscalationPolicies();\n\n // sort the escalation policies by account and name\n escalationPolicyList = escalationPolicyList.sort((a, b) => {\n if (a.account === b.account) {\n return a.name.localeCompare(b.name);\n }\n return a.account!.localeCompare(b.account!);\n });\n\n const escalationPolicyDropDownOptions = escalationPolicyList.map(\n policy => {\n let policyLabel = policy.name;\n if (policy.account && policy.account !== 'default') {\n policyLabel = `(${policy.account}) ${policy.name}`;\n }\n\n return {\n label: policyLabel,\n value: policy.id,\n };\n },\n );\n\n response.json(escalationPolicyDropDownOptions);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /oncall\n router.get('/oncall-users', async (request, response) => {\n try {\n // Get the escalation policy ID from the request parameters with parameter name \"escalation_policy_ids[]\"\n const escalationPolicyId: string =\n (request.query.escalation_policy_ids as string) || '';\n const account = (request.query.account as string) || '';\n\n if (escalationPolicyId === '') {\n response\n .status(400)\n .json(\"Bad Request: 'escalation_policy_ids[]' is required\");\n return;\n }\n\n const oncallUsers = await getOncallUsers(escalationPolicyId, account);\n const onCallUsersResponse: PagerDutyOnCallUsersResponse = {\n users: oncallUsers,\n };\n\n response.json(onCallUsersResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /services/:serviceId\n router.get('/services/:serviceId', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n if (serviceId === '') {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' must be provided as part of the path or 'integration_key' as a query parameter\",\n );\n return;\n }\n\n const service = await getServiceById(serviceId, account);\n const serviceResponse: PagerDutyServiceResponse = {\n service: service,\n };\n\n response.json(serviceResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /teams?account=:account\n router.get('/teams', async (request, response) => {\n try {\n const account = request.query.account as string | undefined;\n const teams = await getAllTeams(account);\n response.json(teams);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n\n // GET /services - Unified endpoint for all service queries\n // Query params:\n // - integration_key: fetch service by integration key\n // - team_id, query, limit, account: fetch filtered services\n // - no params: fetch all services\n router.get('/services', async (request, response) => {\n try {\n const integrationKey = request.query.integration_key as string | undefined;\n const teamId = request.query.team_id as string | undefined;\n const query = request.query.query as string | undefined;\n const limit = request.query.limit\n ? parseInt(request.query.limit as string, 10)\n : undefined;\n const account = request.query.account as string | undefined;\n\n // Case 1: Fetch by integration key\n if (integrationKey) {\n const service = await getServiceByIntegrationKey(\n integrationKey,\n account || '',\n );\n const serviceResponse: PagerDutyServiceResponse = {\n service: service,\n };\n response.json(serviceResponse);\n return;\n }\n\n // Case 2: Fetch filtered services (if team_id, query, or limit provided)\n if (teamId || query || limit) {\n const teamIdsArray: string[] | undefined = teamId ? [teamId] : undefined;\n const services = await getFilteredServices(\n teamIdsArray,\n query,\n limit || 100,\n account,\n );\n response.json(services);\n return;\n }\n\n // Case 3: Fetch all services (default)\n const services = await getAllServices();\n const servicesResponse: PagerDutyServicesResponse = {\n services: services,\n };\n response.json(servicesResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n } else {\n logger.error(\n `Unexpected error occurred while processing request: ${error}`,\n );\n response.status(500).json({\n errors: [error instanceof Error ? error.message : String(error)],\n });\n }\n }\n });\n\n // POST /services/:serviceId/integration/:vendorId\n router.post(\n '/services/:serviceId/integration/:vendorId',\n async (request, response) => {\n try {\n const serviceId: string = request.params.serviceId || '';\n const vendorId: string = request.params.vendorId || '';\n const account = (request.query.account as string) || '';\n\n if (serviceId === '' || vendorId === '') {\n response\n .status(400)\n .json(\n \"Bad Request: ':serviceId' and ':vendorId' must be provided as part of the path\",\n );\n return;\n }\n\n const integrationKey = await createServiceIntegration({\n serviceId,\n vendorId,\n account,\n });\n\n response.json(integrationKey);\n } catch (error) {\n if (error instanceof HttpError) {\n logger.error(\n `Error occurred while processing request: ${error.message}`,\n );\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // GET /services/:serviceId/change-events\n router.get(\n '/services/:serviceId/change-events',\n async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n const changeEvents = await getChangeEvents(serviceId, account);\n const changeEventsResponse: PagerDutyChangeEventsResponse = {\n change_events: changeEvents,\n };\n\n response.json(changeEventsResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n },\n );\n\n // GET /services/:serviceId/incidents\n router.get('/services/:serviceId/incidents', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n const incidents = await getIncidents(serviceId, account);\n const incidentsResponse: PagerDutyIncidentsResponse = {\n incidents,\n };\n\n response.json(incidentsResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /services/:serviceId/standards\n router.get('/services/:serviceId/standards', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n const serviceStandards = await getServiceStandards(serviceId, account);\n const serviceStandardsResponse: PagerDutyServiceStandardsResponse = {\n standards: serviceStandards,\n };\n\n response.json(serviceStandardsResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /services/:serviceId/metrics\n router.get('/services/:serviceId/metrics', async (request, response) => {\n try {\n // Get the serviceId from the request parameters\n const serviceId: string = request.params.serviceId || '';\n const account = (request.query.account as string) || '';\n\n const metrics = await getServiceMetrics(serviceId, account);\n\n const metricsResponse: PagerDutyServiceMetricsResponse = {\n metrics: metrics,\n };\n\n response.json(metricsResponse);\n } catch (error) {\n if (error instanceof HttpError) {\n response.status(error.status).json({\n errors: [`${error.message}`],\n });\n }\n }\n });\n\n // GET /accounts\n router.get('/accounts', async (_, response) => {\n try {\n const accountsConfig = config.getOptional('pagerDuty.accounts') as\n | Array<{\n id: string;\n isDefault?: boolean;\n }>\n | undefined;\n\n if (accountsConfig && accountsConfig.length > 0) {\n const accounts = accountsConfig.map(account => ({\n id: account.id,\n isDefault: account.isDefault || false,\n }));\n response.status(200).json({ accounts });\n } else {\n response.status(200).json({ accounts: [] });\n }\n } catch (error) {\n logger.error(`Failed to get accounts: ${error}`);\n response.status(500).json({ error: 'Failed to get accounts' });\n }\n });\n\n // GET /health\n router.get('/health', async (_, response) => {\n response.status(200).json({ status: 'ok' });\n });\n\n // Add error handler\n router.use(MiddlewareFactory.create({ config, logger }).error());\n\n // Return the router\n return router;\n}\n"],"names":["loadAuthConfig","loadPagerDutyEndpointsFromConfig","Router","express","createAutoMatchRunner","autoMatchJobs","AutoMatchJobRegistry","removeServiceRelationsFromService","HttpError","addServiceRelationsToService","getServiceRelationshipsById","getServiceById","createServiceIntegration","CatalogEntityUtils.createComponentEntitiesReferenceDict","getAllServices","MappingsController.getMappingEntities","getAllEscalationPolicies","getOncallUsers","getAllTeams","getServiceByIntegrationKey","services","getFilteredServices","getChangeEvents","getIncidents","getServiceStandards","getServiceMetrics","MiddlewareFactory"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var uuid = require('uuid');
|
|
4
|
+
|
|
5
|
+
const JOB_TTL_MS = 30 * 60 * 1e3;
|
|
6
|
+
const KEY_PREFIX = "auto-match-job:";
|
|
7
|
+
const key = (id) => `${KEY_PREFIX}${id}`;
|
|
8
|
+
class AutoMatchJobRegistry {
|
|
9
|
+
constructor(cache, runner, ttlMs = JOB_TTL_MS) {
|
|
10
|
+
this.cache = cache;
|
|
11
|
+
this.runner = runner;
|
|
12
|
+
this.ttlMs = ttlMs;
|
|
13
|
+
}
|
|
14
|
+
async start(params) {
|
|
15
|
+
const job = {
|
|
16
|
+
id: uuid.v4(),
|
|
17
|
+
status: "pending",
|
|
18
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
19
|
+
};
|
|
20
|
+
await this.write(job);
|
|
21
|
+
void this.execute(job, params);
|
|
22
|
+
return job;
|
|
23
|
+
}
|
|
24
|
+
async get(jobId) {
|
|
25
|
+
return await this.cache.get(key(jobId));
|
|
26
|
+
}
|
|
27
|
+
async write(job) {
|
|
28
|
+
await this.cache.set(key(job.id), job, { ttl: this.ttlMs });
|
|
29
|
+
}
|
|
30
|
+
async execute(job, params) {
|
|
31
|
+
const running = { ...job, status: "running" };
|
|
32
|
+
await this.write(running);
|
|
33
|
+
try {
|
|
34
|
+
const result = await this.runner(params);
|
|
35
|
+
await this.write({
|
|
36
|
+
...running,
|
|
37
|
+
status: "completed",
|
|
38
|
+
result,
|
|
39
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
40
|
+
});
|
|
41
|
+
} catch (error) {
|
|
42
|
+
await this.write({
|
|
43
|
+
...running,
|
|
44
|
+
status: "failed",
|
|
45
|
+
error: error instanceof Error ? error.message : String(error),
|
|
46
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
exports.AutoMatchJobRegistry = AutoMatchJobRegistry;
|
|
53
|
+
//# sourceMappingURL=autoMatchJobs.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autoMatchJobs.cjs.js","sources":["../../src/services/autoMatchJobs.ts"],"sourcesContent":["import { v4 as uuid } from 'uuid';\nimport { CacheService } from '@backstage/backend-plugin-api';\nimport {\n AutoMatchEntityMappingsResponse,\n AutoMatchJobStatus,\n} from '@pagerduty/backstage-plugin-common';\n\nexport interface AutoMatchJob {\n id: string;\n status: AutoMatchJobStatus;\n createdAt: string;\n completedAt?: string;\n result?: AutoMatchEntityMappingsResponse;\n error?: string;\n}\n\nexport interface AutoMatchJobParams {\n threshold: number;\n bestOnly: boolean;\n team?: string;\n account?: string;\n}\n\nexport type AutoMatchJobRunner = (\n params: AutoMatchJobParams,\n) => Promise<AutoMatchEntityMappingsResponse>;\n\nconst JOB_TTL_MS = 30 * 60 * 1000;\nconst KEY_PREFIX = 'auto-match-job:';\n\nconst key = (id: string) => `${KEY_PREFIX}${id}`;\n\nexport class AutoMatchJobRegistry {\n constructor(\n private readonly cache: CacheService,\n private readonly runner: AutoMatchJobRunner,\n private readonly ttlMs: number = JOB_TTL_MS,\n ) {}\n\n async start(params: AutoMatchJobParams): Promise<AutoMatchJob> {\n const job: AutoMatchJob = {\n id: uuid(),\n status: 'pending',\n createdAt: new Date().toISOString(),\n };\n await this.write(job);\n\n // Kick off execution without awaiting.\n void this.execute(job, params);\n\n return job;\n }\n\n async get(jobId: string): Promise<AutoMatchJob | undefined> {\n return (await this.cache.get(key(jobId))) as AutoMatchJob | undefined;\n }\n\n private async write(job: AutoMatchJob): Promise<void> {\n await this.cache.set(key(job.id), job as unknown as Parameters<CacheService['set']>[1], { ttl: this.ttlMs });\n }\n\n private async execute(\n job: AutoMatchJob,\n params: AutoMatchJobParams,\n ): Promise<void> {\n const running: AutoMatchJob = { ...job, status: 'running' };\n await this.write(running);\n\n try {\n const result = await this.runner(params);\n await this.write({\n ...running,\n status: 'completed',\n result,\n completedAt: new Date().toISOString(),\n });\n } catch (error) {\n await this.write({\n ...running,\n status: 'failed',\n error: error instanceof Error ? error.message : String(error),\n completedAt: new Date().toISOString(),\n });\n }\n }\n}\n"],"names":["uuid"],"mappings":";;;;AA2BA,MAAM,UAAA,GAAa,KAAK,EAAA,GAAK,GAAA;AAC7B,MAAM,UAAA,GAAa,iBAAA;AAEnB,MAAM,MAAM,CAAC,EAAA,KAAe,CAAA,EAAG,UAAU,GAAG,EAAE,CAAA,CAAA;AAEvC,MAAM,oBAAA,CAAqB;AAAA,EAChC,WAAA,CACmB,KAAA,EACA,MAAA,EACA,KAAA,GAAgB,UAAA,EACjC;AAHiB,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAAA,EAChB;AAAA,EAEH,MAAM,MAAM,MAAA,EAAmD;AAC7D,IAAA,MAAM,GAAA,GAAoB;AAAA,MACxB,IAAIA,OAAA,EAAK;AAAA,MACT,MAAA,EAAQ,SAAA;AAAA,MACR,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,KACpC;AACA,IAAA,MAAM,IAAA,CAAK,MAAM,GAAG,CAAA;AAGpB,IAAA,KAAK,IAAA,CAAK,OAAA,CAAQ,GAAA,EAAK,MAAM,CAAA;AAE7B,IAAA,OAAO,GAAA;AAAA,EACT;AAAA,EAEA,MAAM,IAAI,KAAA,EAAkD;AAC1D,IAAA,OAAQ,MAAM,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACzC;AAAA,EAEA,MAAc,MAAM,GAAA,EAAkC;AACpD,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,GAAA,CAAI,GAAA,CAAI,EAAE,CAAA,EAAG,GAAA,EAAsD,EAAE,GAAA,EAAK,IAAA,CAAK,KAAA,EAAO,CAAA;AAAA,EAC7G;AAAA,EAEA,MAAc,OAAA,CACZ,GAAA,EACA,MAAA,EACe;AACf,IAAA,MAAM,OAAA,GAAwB,EAAE,GAAG,GAAA,EAAK,QAAQ,SAAA,EAAU;AAC1D,IAAA,MAAM,IAAA,CAAK,MAAM,OAAO,CAAA;AAExB,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA;AACvC,MAAA,MAAM,KAAK,KAAA,CAAM;AAAA,QACf,GAAG,OAAA;AAAA,QACH,MAAA,EAAQ,WAAA;AAAA,QACR,MAAA;AAAA,QACA,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACrC,CAAA;AAAA,IACH,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,KAAK,KAAA,CAAM;AAAA,QACf,GAAG,OAAA;AAAA,QACH,MAAA,EAAQ,QAAA;AAAA,QACR,OAAO,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAAA,QAC5D,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACrC,CAAA;AAAA,IACH;AAAA,EACF;AACF;;;;"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var dataLoader = require('./dataLoader.cjs.js');
|
|
4
|
+
var matchingEngine = require('./matchingEngine.cjs.js');
|
|
5
|
+
|
|
6
|
+
const getConfidenceLevel = (score) => {
|
|
7
|
+
if (score === 100) return "exact";
|
|
8
|
+
if (score >= 90) return "high";
|
|
9
|
+
if (score >= 80) return "medium";
|
|
10
|
+
return "low";
|
|
11
|
+
};
|
|
12
|
+
function createAutoMatchRunner(catalogApi) {
|
|
13
|
+
return async function runAutoMatch(params) {
|
|
14
|
+
const { threshold, bestOnly, team, account } = params;
|
|
15
|
+
const loadStartTime = Date.now();
|
|
16
|
+
const { pdServices, bsComponents } = await dataLoader.loadBothSources({
|
|
17
|
+
catalogApi,
|
|
18
|
+
teamFilter: team
|
|
19
|
+
});
|
|
20
|
+
const filteredPdServices = account ? pdServices.filter((service) => service.account === account) : pdServices;
|
|
21
|
+
const loadTime = Date.now() - loadStartTime;
|
|
22
|
+
const matchStartTime = Date.now();
|
|
23
|
+
const matchingConfig = { threshold };
|
|
24
|
+
let matches = matchingEngine.findMatches(filteredPdServices, bsComponents, matchingConfig);
|
|
25
|
+
if (bestOnly) {
|
|
26
|
+
matches = matchingEngine.filterToBestMatchPerService(matches);
|
|
27
|
+
}
|
|
28
|
+
const matchTime = Date.now() - matchStartTime;
|
|
29
|
+
const totalComparisons = filteredPdServices.length * bsComponents.length;
|
|
30
|
+
const exactMatches = matches.filter((m) => m.score === 100).length;
|
|
31
|
+
const highConfidence = matches.filter(
|
|
32
|
+
(m) => m.score >= 90 && m.score < 100
|
|
33
|
+
).length;
|
|
34
|
+
const mediumConfidence = matches.filter(
|
|
35
|
+
(m) => m.score >= 80 && m.score < 90
|
|
36
|
+
).length;
|
|
37
|
+
return {
|
|
38
|
+
matches: matches.map((m) => ({
|
|
39
|
+
pagerDutyService: {
|
|
40
|
+
serviceId: m.pagerDutyService.sourceId,
|
|
41
|
+
name: m.pagerDutyService.rawName,
|
|
42
|
+
team: m.pagerDutyService.teamName,
|
|
43
|
+
account: m.pagerDutyService.account
|
|
44
|
+
},
|
|
45
|
+
backstageComponent: {
|
|
46
|
+
entityRef: m.backstageComponent.sourceId,
|
|
47
|
+
name: m.backstageComponent.rawName,
|
|
48
|
+
owner: m.backstageComponent.teamName
|
|
49
|
+
},
|
|
50
|
+
score: m.score,
|
|
51
|
+
confidence: getConfidenceLevel(m.score),
|
|
52
|
+
scoreBreakdown: m.scoreBreakdown
|
|
53
|
+
})),
|
|
54
|
+
statistics: {
|
|
55
|
+
totalPagerDutyServices: filteredPdServices.length,
|
|
56
|
+
totalBackstageComponents: bsComponents.length,
|
|
57
|
+
totalPossibleComparisons: totalComparisons,
|
|
58
|
+
matchesFound: matches.length,
|
|
59
|
+
exactMatches,
|
|
60
|
+
highConfidenceMatches: highConfidence,
|
|
61
|
+
mediumConfidenceMatches: mediumConfidence,
|
|
62
|
+
threshold,
|
|
63
|
+
loadTimeMs: loadTime,
|
|
64
|
+
matchTimeMs: matchTime,
|
|
65
|
+
totalTimeMs: loadTime + matchTime
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exports.createAutoMatchRunner = createAutoMatchRunner;
|
|
72
|
+
//# sourceMappingURL=autoMatchRunner.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autoMatchRunner.cjs.js","sources":["../../src/services/autoMatchRunner.ts"],"sourcesContent":["import type { CatalogApi } from '@backstage/catalog-client';\nimport { AutoMatchEntityMappingsResponse } from '@pagerduty/backstage-plugin-common';\nimport { loadBothSources } from './dataLoader';\nimport {\n findMatches,\n filterToBestMatchPerService,\n type MatchingConfig,\n} from './matchingEngine';\nimport type { AutoMatchJobParams } from './autoMatchJobs';\n\nconst getConfidenceLevel = (\n score: number,\n): 'exact' | 'high' | 'medium' | 'low' => {\n if (score === 100) return 'exact';\n if (score >= 90) return 'high';\n if (score >= 80) return 'medium';\n return 'low';\n};\n\nexport function createAutoMatchRunner(catalogApi: CatalogApi) {\n return async function runAutoMatch(\n params: AutoMatchJobParams,\n ): Promise<AutoMatchEntityMappingsResponse> {\n const { threshold, bestOnly, team, account } = params;\n\n const loadStartTime = Date.now();\n const { pdServices, bsComponents } = await loadBothSources({\n catalogApi,\n teamFilter: team,\n });\n\n const filteredPdServices = account\n ? pdServices.filter(service => service.account === account)\n : pdServices;\n\n const loadTime = Date.now() - loadStartTime;\n\n const matchStartTime = Date.now();\n const matchingConfig: MatchingConfig = { threshold };\n let matches = findMatches(filteredPdServices, bsComponents, matchingConfig);\n\n if (bestOnly) {\n matches = filterToBestMatchPerService(matches);\n }\n\n const matchTime = Date.now() - matchStartTime;\n\n const totalComparisons = filteredPdServices.length * bsComponents.length;\n const exactMatches = matches.filter(m => m.score === 100).length;\n const highConfidence = matches.filter(\n m => m.score >= 90 && m.score < 100,\n ).length;\n const mediumConfidence = matches.filter(\n m => m.score >= 80 && m.score < 90,\n ).length;\n\n return {\n matches: matches.map(m => ({\n pagerDutyService: {\n serviceId: m.pagerDutyService.sourceId,\n name: m.pagerDutyService.rawName,\n team: m.pagerDutyService.teamName,\n account: m.pagerDutyService.account,\n },\n backstageComponent: {\n entityRef: m.backstageComponent.sourceId,\n name: m.backstageComponent.rawName,\n owner: m.backstageComponent.teamName,\n },\n score: m.score,\n confidence: getConfidenceLevel(m.score),\n scoreBreakdown: m.scoreBreakdown,\n })),\n statistics: {\n totalPagerDutyServices: filteredPdServices.length,\n totalBackstageComponents: bsComponents.length,\n totalPossibleComparisons: totalComparisons,\n matchesFound: matches.length,\n exactMatches,\n highConfidenceMatches: highConfidence,\n mediumConfidenceMatches: mediumConfidence,\n threshold,\n loadTimeMs: loadTime,\n matchTimeMs: matchTime,\n totalTimeMs: loadTime + matchTime,\n },\n };\n };\n}\n"],"names":["loadBothSources","findMatches","filterToBestMatchPerService"],"mappings":"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"}
|
|
@@ -29,13 +29,20 @@ async function loadPagerDutyServices() {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
async function loadBackstageComponents({
|
|
32
|
-
catalogApi
|
|
32
|
+
catalogApi,
|
|
33
|
+
teamFilter
|
|
33
34
|
}) {
|
|
34
35
|
try {
|
|
36
|
+
const filter = {
|
|
37
|
+
kind: "Component"
|
|
38
|
+
};
|
|
39
|
+
if (teamFilter) {
|
|
40
|
+
const bare = teamFilter.replace(/^group:[^/]+\//i, "");
|
|
41
|
+
const full = teamFilter.includes(":") ? teamFilter : `group:default/${teamFilter}`;
|
|
42
|
+
filter["spec.owner"] = bare === full ? [bare] : [bare, full];
|
|
43
|
+
}
|
|
35
44
|
const response = await catalogApi.getEntities({
|
|
36
|
-
filter
|
|
37
|
-
kind: "Component"
|
|
38
|
-
}
|
|
45
|
+
filter
|
|
39
46
|
});
|
|
40
47
|
const normalizedComponents = response.items.map(
|
|
41
48
|
(entity) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataLoader.cjs.js","sources":["../../src/services/dataLoader.ts"],"sourcesContent":["import { getAllServices } from '../apis/pagerduty';\nimport {\n normalizePagerDutyService,\n normalizeBackstageComponent,\n type NormalizedService,\n} from '../utils/normalization';\nimport type { CatalogApi } from '@backstage/catalog-client';\nimport type { PagerDutyService } from '@pagerduty/backstage-plugin-common';\nimport type { Entity } from '@backstage/catalog-model';\n\nexport class ServiceLoadError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ServiceLoadError';\n }\n}\n\nexport interface DataLoaderContext {\n catalogApi: CatalogApi;\n}\n\nexport interface LoadedSources {\n pdServices: NormalizedService[];\n bsComponents: NormalizedService[];\n}\n\nexport async function loadPagerDutyServices(): Promise<NormalizedService[]> {\n try {\n const services: PagerDutyService[] = await getAllServices();\n\n const normalizedServices: NormalizedService[] = services.map(service => {\n const teamName = service.teams?.[0]?.summary ?? '';\n\n return normalizePagerDutyService(\n service.name,\n teamName,\n service.id,\n service.account,\n );\n });\n\n return normalizedServices;\n } catch (error) {\n throw new ServiceLoadError(\n `Failed to load PagerDuty services: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n}\n\nexport async function loadBackstageComponents({\n catalogApi,\n}: DataLoaderContext): Promise<NormalizedService[]> {\n try {\n
|
|
1
|
+
{"version":3,"file":"dataLoader.cjs.js","sources":["../../src/services/dataLoader.ts"],"sourcesContent":["import { getAllServices } from '../apis/pagerduty';\nimport {\n normalizePagerDutyService,\n normalizeBackstageComponent,\n type NormalizedService,\n} from '../utils/normalization';\nimport type { CatalogApi } from '@backstage/catalog-client';\nimport type { PagerDutyService } from '@pagerduty/backstage-plugin-common';\nimport type { Entity } from '@backstage/catalog-model';\n\nexport class ServiceLoadError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ServiceLoadError';\n }\n}\n\nexport interface DataLoaderContext {\n catalogApi: CatalogApi;\n teamFilter?: string;\n}\n\nexport interface LoadedSources {\n pdServices: NormalizedService[];\n bsComponents: NormalizedService[];\n}\n\nexport async function loadPagerDutyServices(): Promise<NormalizedService[]> {\n try {\n const services: PagerDutyService[] = await getAllServices();\n\n const normalizedServices: NormalizedService[] = services.map(service => {\n const teamName = service.teams?.[0]?.summary ?? '';\n\n return normalizePagerDutyService(\n service.name,\n teamName,\n service.id,\n service.account,\n );\n });\n\n return normalizedServices;\n } catch (error) {\n throw new ServiceLoadError(\n `Failed to load PagerDuty services: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n}\n\nexport async function loadBackstageComponents({\n catalogApi,\n teamFilter,\n}: DataLoaderContext): Promise<NormalizedService[]> {\n try {\n const filter: Record<string, string | string[]> = {\n kind: 'Component',\n };\n\n if (teamFilter) {\n // Catalog may normalize owners to full entity refs (e.g. \"group:default/foo\")\n // or store them as plain names (\"foo\"). Accept both forms.\n const bare = teamFilter.replace(/^group:[^/]+\\//i, '');\n const full = teamFilter.includes(':') ? teamFilter : `group:default/${teamFilter}`;\n filter['spec.owner'] = bare === full ? [bare] : [bare, full];\n }\n\n const response = await catalogApi.getEntities({\n filter,\n });\n\n const normalizedComponents: NormalizedService[] = response.items.map(\n (entity: Entity) => {\n const entityRef =\n `${entity.kind}:${entity.metadata.namespace}/${entity.metadata.name}`.toLowerCase();\n\n const owner =\n typeof entity.spec?.owner === 'string' ? entity.spec.owner : '';\n\n return normalizeBackstageComponent(\n entity.metadata.name,\n owner,\n entityRef,\n );\n },\n );\n\n return normalizedComponents;\n } catch (error) {\n throw new ServiceLoadError(\n `Failed to load Backstage components: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n}\n\nexport async function loadBothSources(\n context: DataLoaderContext,\n): Promise<LoadedSources> {\n const [pdServices, bsComponents] = await Promise.all([\n loadPagerDutyServices(),\n loadBackstageComponents(context),\n ]);\n\n return {\n pdServices,\n bsComponents,\n };\n}\n"],"names":["getAllServices","normalizePagerDutyService","normalizeBackstageComponent"],"mappings":";;;;;AAUO,MAAM,yBAAyB,KAAA,CAAM;AAAA,EAC1C,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AACF;AAYA,eAAsB,qBAAA,GAAsD;AAC1E,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAA+B,MAAMA,wBAAA,EAAe;AAE1D,IAAA,MAAM,kBAAA,GAA0C,QAAA,CAAS,GAAA,CAAI,CAAA,OAAA,KAAW;AACtE,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,KAAA,GAAQ,CAAC,GAAG,OAAA,IAAW,EAAA;AAEhD,MAAA,OAAOC,uCAAA;AAAA,QACL,OAAA,CAAQ,IAAA;AAAA,QACR,QAAA;AAAA,QACA,OAAA,CAAQ,EAAA;AAAA,QACR,OAAA,CAAQ;AAAA,OACV;AAAA,IACF,CAAC,CAAA;AAED,IAAA,OAAO,kBAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,gBAAA;AAAA,MACR,sCACE,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CACvD,CAAA;AAAA,KACF;AAAA,EACF;AACF;AAEA,eAAsB,uBAAA,CAAwB;AAAA,EAC5C,UAAA;AAAA,EACA;AACF,CAAA,EAAoD;AAClD,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAA4C;AAAA,MAChD,IAAA,EAAM;AAAA,KACR;AAEA,IAAA,IAAI,UAAA,EAAY;AAGd,MAAA,MAAM,IAAA,GAAO,UAAA,CAAW,OAAA,CAAQ,iBAAA,EAAmB,EAAE,CAAA;AACrD,MAAA,MAAM,OAAO,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,GAAI,UAAA,GAAa,iBAAiB,UAAU,CAAA,CAAA;AAChF,MAAA,MAAA,CAAO,YAAY,IAAI,IAAA,KAAS,IAAA,GAAO,CAAC,IAAI,CAAA,GAAI,CAAC,IAAA,EAAM,IAAI,CAAA;AAAA,IAC7D;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,UAAA,CAAW,WAAA,CAAY;AAAA,MAC5C;AAAA,KACD,CAAA;AAED,IAAA,MAAM,oBAAA,GAA4C,SAAS,KAAA,CAAM,GAAA;AAAA,MAC/D,CAAC,MAAA,KAAmB;AAClB,QAAA,MAAM,SAAA,GACJ,CAAA,EAAG,MAAA,CAAO,IAAI,CAAA,CAAA,EAAI,MAAA,CAAO,QAAA,CAAS,SAAS,CAAA,CAAA,EAAI,MAAA,CAAO,QAAA,CAAS,IAAI,GAAG,WAAA,EAAY;AAEpF,QAAA,MAAM,KAAA,GACJ,OAAO,MAAA,CAAO,IAAA,EAAM,UAAU,QAAA,GAAW,MAAA,CAAO,KAAK,KAAA,GAAQ,EAAA;AAE/D,QAAA,OAAOC,yCAAA;AAAA,UACL,OAAO,QAAA,CAAS,IAAA;AAAA,UAChB,KAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAEA,IAAA,OAAO,oBAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,gBAAA;AAAA,MACR,wCACE,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CACvD,CAAA;AAAA,KACF;AAAA,EACF;AACF;AAEA,eAAsB,gBACpB,OAAA,EACwB;AACxB,EAAA,MAAM,CAAC,UAAA,EAAY,YAAY,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,IACnD,qBAAA,EAAsB;AAAA,IACtB,wBAAwB,OAAO;AAAA,GAChC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA;AAAA,GACF;AACF;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagerduty/backstage-plugin-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"main": "dist/index.cjs.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"postpack": "backstage-cli package postpack"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@backstage/backend-
|
|
40
|
+
"@backstage/backend-defaults": "^0.15.1",
|
|
41
41
|
"@backstage/backend-plugin-api": "^1.6.2",
|
|
42
42
|
"@backstage/catalog-client": "^1.12.1",
|
|
43
|
-
"@pagerduty/backstage-plugin-common": "~0.
|
|
43
|
+
"@pagerduty/backstage-plugin-common": "~0.4.0",
|
|
44
44
|
"@skyra/jaro-winkler": "^1.1.1",
|
|
45
45
|
"@types/express": "^4.17.6",
|
|
46
46
|
"express": "^4.20.0",
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"uuid": "^9.0.1"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@backstage/backend-defaults": "^0.15.1",
|
|
55
54
|
"@backstage/backend-test-utils": "^1.10.4",
|
|
56
55
|
"@backstage/cli": "^0.35.3",
|
|
57
56
|
"jest-mock": "^30.0.2",
|