@pagerduty/backstage-plugin-backend 0.8.1-next.31 → 0.8.1-next.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +31 -482
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -6
- package/package.json +14 -12
- package/migrations/20240722_add_settings_table.js +0 -27
package/dist/index.cjs.js
CHANGED
|
@@ -39,8 +39,7 @@ var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
|
|
|
39
39
|
let authPersistence;
|
|
40
40
|
let isLegacyConfig$1 = false;
|
|
41
41
|
async function getAuthToken(accountId) {
|
|
42
|
-
|
|
43
|
-
if (!(authPersistence == null ? void 0 : authPersistence.accountTokens)) {
|
|
42
|
+
if (!authPersistence?.accountTokens) {
|
|
44
43
|
await loadAuthConfig(authPersistence.config, authPersistence.logger);
|
|
45
44
|
}
|
|
46
45
|
if (isLegacyConfig$1) {
|
|
@@ -53,7 +52,7 @@ async function getAuthToken(accountId) {
|
|
|
53
52
|
return authPersistence.accountTokens[accountId].authToken;
|
|
54
53
|
}
|
|
55
54
|
} else {
|
|
56
|
-
const defaultFallback =
|
|
55
|
+
const defaultFallback = authPersistence.defaultAccount ?? "";
|
|
57
56
|
if (authPersistence.accountTokens[defaultFallback].authToken !== "" && authPersistence.accountTokens[defaultFallback].authToken.includes("Bearer") && authPersistence.accountTokens[defaultFallback].authTokenExpiryDate > Date.now() || authPersistence.accountTokens[defaultFallback].authToken !== "" && authPersistence.accountTokens[defaultFallback].authToken.includes("Token")) {
|
|
58
57
|
return authPersistence.accountTokens[defaultFallback].authToken;
|
|
59
58
|
}
|
|
@@ -62,7 +61,6 @@ async function getAuthToken(accountId) {
|
|
|
62
61
|
return "";
|
|
63
62
|
}
|
|
64
63
|
async function loadAuthConfig(config, logger) {
|
|
65
|
-
var _a;
|
|
66
64
|
try {
|
|
67
65
|
const defaultAccountId = "default";
|
|
68
66
|
authPersistence = {
|
|
@@ -84,7 +82,7 @@ async function loadAuthConfig(config, logger) {
|
|
|
84
82
|
config.getString("pagerDuty.oauth.clientId"),
|
|
85
83
|
config.getString("pagerDuty.oauth.clientSecret"),
|
|
86
84
|
config.getString("pagerDuty.oauth.subDomain"),
|
|
87
|
-
|
|
85
|
+
config.getOptionalString("pagerDuty.oauth.region") ?? "us"
|
|
88
86
|
);
|
|
89
87
|
authPersistence.accountTokens[defaultAccountId] = tokenInfo;
|
|
90
88
|
logger.info("PagerDuty OAuth configuration loaded successfully.");
|
|
@@ -101,12 +99,11 @@ async function loadAuthConfig(config, logger) {
|
|
|
101
99
|
logger.info("New PagerDuty accounts configuration found in config file.");
|
|
102
100
|
isLegacyConfig$1 = false;
|
|
103
101
|
const accounts = config.getOptional("pagerDuty.accounts");
|
|
104
|
-
if (accounts &&
|
|
102
|
+
if (accounts && accounts?.length === 1) {
|
|
105
103
|
logger.info("Only one account found in config file. Setting it as default.");
|
|
106
104
|
authPersistence.defaultAccount = accounts[0].id;
|
|
107
105
|
}
|
|
108
|
-
accounts
|
|
109
|
-
var _a2;
|
|
106
|
+
accounts?.forEach(async (account) => {
|
|
110
107
|
const maskedAccountId = maskString(account.id);
|
|
111
108
|
if (account.isDefault && !authPersistence.defaultAccount) {
|
|
112
109
|
logger.info(`Default account found in config file. Setting it as default.`);
|
|
@@ -123,7 +120,7 @@ async function loadAuthConfig(config, logger) {
|
|
|
123
120
|
account.oauth.clientId,
|
|
124
121
|
account.oauth.clientSecret,
|
|
125
122
|
account.oauth.subDomain,
|
|
126
|
-
|
|
123
|
+
account.oauth.region ?? "us"
|
|
127
124
|
);
|
|
128
125
|
authPersistence.accountTokens[account.id] = tokenInfo;
|
|
129
126
|
logger.info(`PagerDuty OAuth configuration loaded successfully for account ${maskedAccountId}.`);
|
|
@@ -204,17 +201,15 @@ const EndpointConfig = {};
|
|
|
204
201
|
let fallbackEndpointConfig;
|
|
205
202
|
let isLegacyConfig = false;
|
|
206
203
|
function setFallbackEndpointConfig(account) {
|
|
207
|
-
var _a, _b;
|
|
208
204
|
fallbackEndpointConfig = {
|
|
209
|
-
eventsBaseUrl:
|
|
210
|
-
apiBaseUrl:
|
|
205
|
+
eventsBaseUrl: account.eventsBaseUrl ?? "https://events.pagerduty.com/v2",
|
|
206
|
+
apiBaseUrl: account.apiBaseUrl ?? "https://api.pagerduty.com"
|
|
211
207
|
};
|
|
212
208
|
}
|
|
213
209
|
function insertEndpointConfig(account) {
|
|
214
|
-
var _a, _b;
|
|
215
210
|
EndpointConfig[account.id] = {
|
|
216
|
-
eventsBaseUrl:
|
|
217
|
-
apiBaseUrl:
|
|
211
|
+
eventsBaseUrl: account.eventsBaseUrl ?? "https://events.pagerduty.com/v2",
|
|
212
|
+
apiBaseUrl: account.apiBaseUrl ?? "https://api.pagerduty.com"
|
|
218
213
|
};
|
|
219
214
|
}
|
|
220
215
|
function loadPagerDutyEndpointsFromConfig(config, logger) {
|
|
@@ -222,7 +217,7 @@ function loadPagerDutyEndpointsFromConfig(config, logger) {
|
|
|
222
217
|
logger.debug(`New accounts configuration detected. Loading PagerDuty endpoints from config.`);
|
|
223
218
|
isLegacyConfig = false;
|
|
224
219
|
const accounts = config.getOptional("pagerDuty.accounts");
|
|
225
|
-
if (
|
|
220
|
+
if (accounts?.length === 1) {
|
|
226
221
|
logger.debug(`Single account configuration detected. Loading PagerDuty endpoints from config to 'default'.`);
|
|
227
222
|
EndpointConfig.default = {
|
|
228
223
|
eventsBaseUrl: accounts[0].eventsBaseUrl !== void 0 ? accounts[0].eventsBaseUrl : "https://events.pagerduty.com/v2",
|
|
@@ -230,7 +225,7 @@ function loadPagerDutyEndpointsFromConfig(config, logger) {
|
|
|
230
225
|
};
|
|
231
226
|
} else {
|
|
232
227
|
logger.debug(`Multiple account configuration detected. Loading PagerDuty endpoints from config.`);
|
|
233
|
-
accounts
|
|
228
|
+
accounts?.forEach((account) => {
|
|
234
229
|
if (account.isDefault) {
|
|
235
230
|
setFallbackEndpointConfig(account);
|
|
236
231
|
}
|
|
@@ -255,121 +250,7 @@ function getApiBaseUrl(account) {
|
|
|
255
250
|
}
|
|
256
251
|
return fallbackEndpointConfig.apiBaseUrl;
|
|
257
252
|
}
|
|
258
|
-
async function addServiceRelationsToService(serviceRelations, account) {
|
|
259
|
-
let response;
|
|
260
|
-
const options = {
|
|
261
|
-
method: "POST",
|
|
262
|
-
headers: {
|
|
263
|
-
Authorization: await getAuthToken(account),
|
|
264
|
-
"Accept": "application/vnd.pagerduty+json;version=2",
|
|
265
|
-
"Content-Type": "application/json"
|
|
266
|
-
},
|
|
267
|
-
body: JSON.stringify({
|
|
268
|
-
relationships: serviceRelations
|
|
269
|
-
})
|
|
270
|
-
};
|
|
271
|
-
const apiBaseUrl = getApiBaseUrl(account);
|
|
272
|
-
const baseUrl = `${apiBaseUrl}/service_dependencies/associate`;
|
|
273
|
-
console.log(`Adding service relations: ${JSON.stringify({ relationships: serviceRelations })}`);
|
|
274
|
-
try {
|
|
275
|
-
response = await fetch__default.default(`${baseUrl}`, options);
|
|
276
|
-
} catch (error) {
|
|
277
|
-
throw new Error(`Failed to retrieve service dependencies: ${error}`);
|
|
278
|
-
}
|
|
279
|
-
switch (response.status) {
|
|
280
|
-
case 400:
|
|
281
|
-
throw new backstagePluginCommon.HttpError("Failed to add service dependencies. Caller provided invalid arguments. Please review the response for error details. Retrying with the same arguments will not work.", 400);
|
|
282
|
-
case 401:
|
|
283
|
-
throw new backstagePluginCommon.HttpError("Failed to add service dependencies. Caller did not supply credentials or did not provide the correct credentials. If you are using an API key, it may be invalid or your Authorization header may be malformed.", 401);
|
|
284
|
-
case 403:
|
|
285
|
-
throw new backstagePluginCommon.HttpError("Failed to add service dependencies. Caller is not authorized to view the requested resource. While your authentication is valid, the authenticated user or token does not have permission to perform this action.", 403);
|
|
286
|
-
case 404:
|
|
287
|
-
throw new backstagePluginCommon.HttpError("Failed to add service dependencies. The requested resource was not found.", 404);
|
|
288
|
-
}
|
|
289
|
-
let result;
|
|
290
|
-
try {
|
|
291
|
-
result = await response.json();
|
|
292
|
-
return result.relationships;
|
|
293
|
-
} catch (error) {
|
|
294
|
-
throw new backstagePluginCommon.HttpError(`Failed to parse service dependency information: ${error}`, 500);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
async function removeServiceRelationsFromService(serviceRelations, account) {
|
|
298
|
-
let response;
|
|
299
|
-
const options = {
|
|
300
|
-
method: "POST",
|
|
301
|
-
headers: {
|
|
302
|
-
Authorization: await getAuthToken(account),
|
|
303
|
-
"Accept": "application/vnd.pagerduty+json;version=2",
|
|
304
|
-
"Content-Type": "application/json"
|
|
305
|
-
},
|
|
306
|
-
body: JSON.stringify({
|
|
307
|
-
relationships: serviceRelations
|
|
308
|
-
})
|
|
309
|
-
};
|
|
310
|
-
const apiBaseUrl = getApiBaseUrl(account);
|
|
311
|
-
const baseUrl = `${apiBaseUrl}/service_dependencies/disassociate`;
|
|
312
|
-
console.log(`Removing service relations: ${JSON.stringify({ relationships: serviceRelations })}`);
|
|
313
|
-
try {
|
|
314
|
-
response = await fetch__default.default(`${baseUrl}`, options);
|
|
315
|
-
} catch (error) {
|
|
316
|
-
throw new Error(`Failed to retrieve service dependencies: ${error}`);
|
|
317
|
-
}
|
|
318
|
-
switch (response.status) {
|
|
319
|
-
case 400:
|
|
320
|
-
throw new backstagePluginCommon.HttpError("Failed to remove service dependencies. Caller provided invalid arguments. Please review the response for error details. Retrying with the same arguments will not work.", 400);
|
|
321
|
-
case 401:
|
|
322
|
-
throw new backstagePluginCommon.HttpError("Failed to remove service dependencies. Caller did not supply credentials or did not provide the correct credentials. If you are using an API key, it may be invalid or your Authorization header may be malformed.", 401);
|
|
323
|
-
case 403:
|
|
324
|
-
throw new backstagePluginCommon.HttpError("Failed to remove service dependencies. Caller is not authorized to view the requested resource. While your authentication is valid, the authenticated user or token does not have permission to perform this action.", 403);
|
|
325
|
-
case 404:
|
|
326
|
-
throw new backstagePluginCommon.HttpError("Failed to remove service dependencies. The requested resource was not found.", 404);
|
|
327
|
-
}
|
|
328
|
-
let result;
|
|
329
|
-
try {
|
|
330
|
-
result = await response.json();
|
|
331
|
-
return result.relationships;
|
|
332
|
-
} catch (error) {
|
|
333
|
-
throw new backstagePluginCommon.HttpError(`Failed to parse service dependency information: ${error}`, 500);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
async function getServiceRelationshipsById(serviceId, account) {
|
|
337
|
-
let response;
|
|
338
|
-
const options = {
|
|
339
|
-
method: "GET",
|
|
340
|
-
headers: {
|
|
341
|
-
Authorization: await getAuthToken(account),
|
|
342
|
-
"Accept": "application/vnd.pagerduty+json;version=2",
|
|
343
|
-
"Content-Type": "application/json"
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
const apiBaseUrl = getApiBaseUrl(account);
|
|
347
|
-
const baseUrl = `${apiBaseUrl}/service_dependencies/technical_services/${serviceId}`;
|
|
348
|
-
try {
|
|
349
|
-
response = await fetch__default.default(`${baseUrl}`, options);
|
|
350
|
-
} catch (error) {
|
|
351
|
-
throw new Error(`Failed to retrieve service dependencies: ${error}`);
|
|
352
|
-
}
|
|
353
|
-
switch (response.status) {
|
|
354
|
-
case 400:
|
|
355
|
-
throw new backstagePluginCommon.HttpError("Failed to list service dependencies. Caller provided invalid arguments. Please review the response for error details. Retrying with the same arguments will not work.", 400);
|
|
356
|
-
case 401:
|
|
357
|
-
throw new backstagePluginCommon.HttpError("Failed to list service dependencies. Caller did not supply credentials or did not provide the correct credentials. If you are using an API key, it may be invalid or your Authorization header may be malformed.", 401);
|
|
358
|
-
case 403:
|
|
359
|
-
throw new backstagePluginCommon.HttpError("Failed to list service dependencies. Caller is not authorized to view the requested resource. While your authentication is valid, the authenticated user or token does not have permission to perform this action.", 403);
|
|
360
|
-
case 404:
|
|
361
|
-
throw new backstagePluginCommon.HttpError("Failed to list service dependencies. The requested resource was not found.", 404);
|
|
362
|
-
}
|
|
363
|
-
let result;
|
|
364
|
-
try {
|
|
365
|
-
result = await response.json();
|
|
366
|
-
return result.relationships;
|
|
367
|
-
} catch (error) {
|
|
368
|
-
throw new backstagePluginCommon.HttpError(`Failed to parse service dependency information: ${error}`, 500);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
253
|
async function getEscalationPolicies(offset, limit, account) {
|
|
372
|
-
var _a;
|
|
373
254
|
let response;
|
|
374
255
|
const params = `total=true&sort_by=name&offset=${offset}&limit=${limit}`;
|
|
375
256
|
const options = {
|
|
@@ -400,7 +281,7 @@ async function getEscalationPolicies(offset, limit, account) {
|
|
|
400
281
|
let result;
|
|
401
282
|
try {
|
|
402
283
|
result = await response.json();
|
|
403
|
-
return [
|
|
284
|
+
return [result.more ?? false, result.escalation_policies];
|
|
404
285
|
} catch (error) {
|
|
405
286
|
throw new backstagePluginCommon.HttpError(`Failed to parse escalation policy information: ${error}`, 500);
|
|
406
287
|
}
|
|
@@ -766,65 +647,14 @@ async function getServiceMetrics(serviceId, account) {
|
|
|
766
647
|
throw new backstagePluginCommon.HttpError(`Failed to parse service metrics information: ${error}`, 500);
|
|
767
648
|
}
|
|
768
649
|
}
|
|
769
|
-
async function createServiceIntegration({ serviceId, vendorId, account }) {
|
|
770
|
-
var _a;
|
|
771
|
-
let response;
|
|
772
|
-
const apiBaseUrl = getApiBaseUrl(account);
|
|
773
|
-
const baseUrl = `${apiBaseUrl}/services`;
|
|
774
|
-
const token = await getAuthToken(account);
|
|
775
|
-
const options = {
|
|
776
|
-
method: "POST",
|
|
777
|
-
body: JSON.stringify({
|
|
778
|
-
integration: {
|
|
779
|
-
name: "Backstage",
|
|
780
|
-
service: {
|
|
781
|
-
id: serviceId,
|
|
782
|
-
type: "service_reference"
|
|
783
|
-
},
|
|
784
|
-
vendor: {
|
|
785
|
-
id: vendorId,
|
|
786
|
-
type: "vendor_reference"
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
}),
|
|
790
|
-
headers: {
|
|
791
|
-
Authorization: token,
|
|
792
|
-
"Accept": "application/vnd.pagerduty+json;version=2",
|
|
793
|
-
"Content-Type": "application/json"
|
|
794
|
-
}
|
|
795
|
-
};
|
|
796
|
-
try {
|
|
797
|
-
response = await fetch__default.default(`${baseUrl}/${serviceId}/integrations`, options);
|
|
798
|
-
} catch (error) {
|
|
799
|
-
throw new Error(`Failed to create service integration: ${error}`);
|
|
800
|
-
}
|
|
801
|
-
switch (response.status) {
|
|
802
|
-
case 400:
|
|
803
|
-
throw new Error(`Failed to create service integration. Caller provided invalid arguments.`);
|
|
804
|
-
case 401:
|
|
805
|
-
throw new Error(`Failed to create service integration. Caller did not supply credentials or did not provide the correct credentials.`);
|
|
806
|
-
case 403:
|
|
807
|
-
throw new Error(`Failed to create service integration. Caller is not authorized to view the requested resource.`);
|
|
808
|
-
case 429:
|
|
809
|
-
throw new Error(`Failed to create service integration. Rate limit exceeded.`);
|
|
810
|
-
}
|
|
811
|
-
let result;
|
|
812
|
-
try {
|
|
813
|
-
result = await response.json();
|
|
814
|
-
return (_a = result.integration.integration_key) != null ? _a : "";
|
|
815
|
-
} catch (error) {
|
|
816
|
-
throw new Error(`Failed to parse service information: ${error}`);
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
650
|
|
|
820
651
|
async function createComponentEntitiesReferenceDict({ items: componentEntities }) {
|
|
821
652
|
const componentEntitiesDict = {};
|
|
822
653
|
await Promise.all(componentEntities.map(async (entity) => {
|
|
823
|
-
var _a;
|
|
824
654
|
const annotations = JSON.parse(JSON.stringify(entity.metadata.annotations));
|
|
825
655
|
const serviceId = annotations["pagerduty.com/service-id"];
|
|
826
656
|
const integrationKey = annotations["pagerduty.com/integration-key"];
|
|
827
|
-
const account =
|
|
657
|
+
const account = annotations["pagerduty.com/account"] ?? "";
|
|
828
658
|
if (serviceId !== void 0 && serviceId !== "") {
|
|
829
659
|
componentEntitiesDict[serviceId] = {
|
|
830
660
|
ref: `${entity.kind}:${entity.metadata.namespace}/${entity.metadata.name}`.toLowerCase(),
|
|
@@ -847,9 +677,8 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
847
677
|
mappings: []
|
|
848
678
|
};
|
|
849
679
|
pagerDutyServices.forEach((service) => {
|
|
850
|
-
|
|
851
|
-
const
|
|
852
|
-
const entityName = (_b = componentEntitiesDict[service.id]) == null ? void 0 : _b.name;
|
|
680
|
+
const entityRef = componentEntitiesDict[service.id]?.ref;
|
|
681
|
+
const entityName = componentEntitiesDict[service.id]?.name;
|
|
853
682
|
const entityMapping = entityMappings.find((mapping) => mapping.serviceId === service.id);
|
|
854
683
|
if (entityMapping) {
|
|
855
684
|
if (entityRef === void 0) {
|
|
@@ -861,13 +690,13 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
861
690
|
serviceId: entityMapping.serviceId,
|
|
862
691
|
status: "NotMapped",
|
|
863
692
|
serviceName: service.name,
|
|
864
|
-
team:
|
|
693
|
+
team: service.teams?.[0]?.name ?? "",
|
|
865
694
|
escalationPolicy: service.escalation_policy !== void 0 ? service.escalation_policy.name : "",
|
|
866
695
|
serviceUrl: service.html_url,
|
|
867
696
|
account: service.account
|
|
868
697
|
});
|
|
869
698
|
} else {
|
|
870
|
-
const entityRefName =
|
|
699
|
+
const entityRefName = componentEntities.items.find((entity) => `${entity.kind}:${entity.metadata.namespace}/${entity.metadata.name}`.toLowerCase() === entityMapping.entityRef)?.metadata.name ?? "";
|
|
871
700
|
result.mappings.push({
|
|
872
701
|
entityRef: entityMapping.entityRef,
|
|
873
702
|
entityName: entityRefName,
|
|
@@ -875,14 +704,14 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
875
704
|
integrationKey: entityMapping.integrationKey,
|
|
876
705
|
status: "OutOfSync",
|
|
877
706
|
serviceName: service.name,
|
|
878
|
-
team:
|
|
707
|
+
team: service.teams?.[0]?.name ?? "",
|
|
879
708
|
escalationPolicy: service.escalation_policy !== void 0 ? service.escalation_policy.name : "",
|
|
880
709
|
serviceUrl: service.html_url,
|
|
881
710
|
account: service.account
|
|
882
711
|
});
|
|
883
712
|
}
|
|
884
713
|
} else if (entityRef !== entityMapping.entityRef) {
|
|
885
|
-
const entityRefName =
|
|
714
|
+
const entityRefName = componentEntities.items.find((entity) => `${entity.kind}:${entity.metadata.namespace}/${entity.metadata.name}`.toLowerCase() === entityMapping.entityRef)?.metadata.name ?? "";
|
|
886
715
|
result.mappings.push({
|
|
887
716
|
entityRef: entityMapping.entityRef !== "" ? entityMapping.entityRef : "",
|
|
888
717
|
entityName: entityMapping.entityRef !== "" ? entityRefName : "",
|
|
@@ -890,7 +719,7 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
890
719
|
integrationKey: entityMapping.integrationKey,
|
|
891
720
|
status: "OutOfSync",
|
|
892
721
|
serviceName: service.name,
|
|
893
|
-
team:
|
|
722
|
+
team: service.teams?.[0]?.name ?? "",
|
|
894
723
|
escalationPolicy: service.escalation_policy !== void 0 ? service.escalation_policy.name : "",
|
|
895
724
|
serviceUrl: service.html_url,
|
|
896
725
|
account: service.account
|
|
@@ -903,7 +732,7 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
903
732
|
integrationKey: entityMapping.integrationKey,
|
|
904
733
|
status: "InSync",
|
|
905
734
|
serviceName: service.name,
|
|
906
|
-
team:
|
|
735
|
+
team: service.teams?.[0]?.name ?? "",
|
|
907
736
|
escalationPolicy: service.escalation_policy !== void 0 ? service.escalation_policy.name : "",
|
|
908
737
|
serviceUrl: service.html_url,
|
|
909
738
|
account: service.account
|
|
@@ -911,10 +740,7 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
911
740
|
}
|
|
912
741
|
} else {
|
|
913
742
|
const backstageVendorId = "PRO19CT";
|
|
914
|
-
const backstageIntegrationKey =
|
|
915
|
-
var _a2;
|
|
916
|
-
return ((_a2 = integration.vendor) == null ? void 0 : _a2.id) === backstageVendorId;
|
|
917
|
-
})) == null ? void 0 : _t.integration_key) != null ? _u : "";
|
|
743
|
+
const backstageIntegrationKey = service.integrations?.find((integration) => integration.vendor?.id === backstageVendorId)?.integration_key ?? "";
|
|
918
744
|
if (entityRef !== void 0) {
|
|
919
745
|
result.mappings.push({
|
|
920
746
|
entityRef,
|
|
@@ -923,7 +749,7 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
923
749
|
integrationKey: backstageIntegrationKey,
|
|
924
750
|
status: "InSync",
|
|
925
751
|
serviceName: service.name,
|
|
926
|
-
team:
|
|
752
|
+
team: service.teams?.[0]?.name ?? "",
|
|
927
753
|
escalationPolicy: service.escalation_policy !== void 0 ? service.escalation_policy.name : "",
|
|
928
754
|
serviceUrl: service.html_url,
|
|
929
755
|
account: service.account
|
|
@@ -936,7 +762,7 @@ async function buildEntityMappingsResponse(entityMappings, componentEntitiesDict
|
|
|
936
762
|
integrationKey: backstageIntegrationKey,
|
|
937
763
|
status: "NotMapped",
|
|
938
764
|
serviceName: service.name,
|
|
939
|
-
team:
|
|
765
|
+
team: service.teams?.[0]?.name ?? "",
|
|
940
766
|
escalationPolicy: service.escalation_policy !== void 0 ? service.escalation_policy.name : "",
|
|
941
767
|
serviceUrl: service.html_url,
|
|
942
768
|
account: service.account
|
|
@@ -965,196 +791,7 @@ async function createRouter(options) {
|
|
|
965
791
|
loadPagerDutyEndpointsFromConfig(config, logger);
|
|
966
792
|
const router = Router__default.default();
|
|
967
793
|
router.use(express__namespace.json());
|
|
968
|
-
router.delete("/dependencies/service/:serviceId", async (request, response) => {
|
|
969
|
-
try {
|
|
970
|
-
const serviceId = request.params.serviceId || "";
|
|
971
|
-
const account = request.query.account || "";
|
|
972
|
-
if (serviceId === "") {
|
|
973
|
-
logger.info(`Bad Request: ':serviceId' must be provided as part of the path`);
|
|
974
|
-
response.status(400).json("Bad Request: ':serviceId' must be provided as part of the path");
|
|
975
|
-
}
|
|
976
|
-
const dependencies = request.body;
|
|
977
|
-
if (!dependencies || dependencies.length === 0) {
|
|
978
|
-
logger.info(`Bad Request: 'dependencies' must be provided as part of the request body`);
|
|
979
|
-
response.status(400).json("Bad Request: 'dependencies' must be provided as part of the request body");
|
|
980
|
-
}
|
|
981
|
-
logger.info(`Received dependencies to remove from PagerDuty: ${JSON.stringify(dependencies)}`);
|
|
982
|
-
const serviceRelations = [];
|
|
983
|
-
dependencies.forEach(async (dependency) => {
|
|
984
|
-
serviceRelations.push({
|
|
985
|
-
supporting_service: {
|
|
986
|
-
id: dependency,
|
|
987
|
-
type: "service"
|
|
988
|
-
},
|
|
989
|
-
dependent_service: {
|
|
990
|
-
id: serviceId,
|
|
991
|
-
type: "service"
|
|
992
|
-
}
|
|
993
|
-
});
|
|
994
|
-
});
|
|
995
|
-
await removeServiceRelationsFromService(serviceRelations, account);
|
|
996
|
-
response.sendStatus(200);
|
|
997
|
-
} catch (error) {
|
|
998
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
999
|
-
logger.error(`Error occurred while processing request: ${error.message}`);
|
|
1000
|
-
response.status(error.status).json({
|
|
1001
|
-
errors: [
|
|
1002
|
-
`${error.message}`
|
|
1003
|
-
]
|
|
1004
|
-
});
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
});
|
|
1008
|
-
router.post("/dependencies/service/:serviceId", async (request, response) => {
|
|
1009
|
-
try {
|
|
1010
|
-
logger.info(`Received params : ${JSON.stringify(request.params)}`);
|
|
1011
|
-
const serviceId = request.params.serviceId || "";
|
|
1012
|
-
const account = request.query.account || "";
|
|
1013
|
-
if (serviceId === "") {
|
|
1014
|
-
logger.info(`Bad Request: ':serviceId' must be provided as part of the path`);
|
|
1015
|
-
response.status(400).json("Bad Request: ':serviceId' must be provided as part of the path");
|
|
1016
|
-
}
|
|
1017
|
-
const dependencies = request.body;
|
|
1018
|
-
if (!dependencies || dependencies.length === 0) {
|
|
1019
|
-
logger.info(`Bad Request: 'dependencies' must be provided as part of the request body`);
|
|
1020
|
-
response.status(400).json("Bad Request: 'dependencies' must be provided as part of the request body");
|
|
1021
|
-
}
|
|
1022
|
-
logger.info(`Received dependencies to add to PagerDuty: ${JSON.stringify(dependencies)}`);
|
|
1023
|
-
const serviceRelations = [];
|
|
1024
|
-
dependencies.forEach(async (dependency) => {
|
|
1025
|
-
serviceRelations.push({
|
|
1026
|
-
supporting_service: {
|
|
1027
|
-
id: dependency,
|
|
1028
|
-
type: "service"
|
|
1029
|
-
},
|
|
1030
|
-
dependent_service: {
|
|
1031
|
-
id: serviceId,
|
|
1032
|
-
type: "service"
|
|
1033
|
-
}
|
|
1034
|
-
});
|
|
1035
|
-
});
|
|
1036
|
-
await addServiceRelationsToService(serviceRelations, account);
|
|
1037
|
-
response.sendStatus(200);
|
|
1038
|
-
} catch (error) {
|
|
1039
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
1040
|
-
logger.error(`Error occurred while processing request: ${error.message}`);
|
|
1041
|
-
response.status(error.status).json({
|
|
1042
|
-
errors: [
|
|
1043
|
-
`${error.message}`
|
|
1044
|
-
]
|
|
1045
|
-
});
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
});
|
|
1049
|
-
router.get("/dependencies/service/:serviceId", async (request, response) => {
|
|
1050
|
-
try {
|
|
1051
|
-
const serviceId = request.params.serviceId;
|
|
1052
|
-
const account = request.query.account || "";
|
|
1053
|
-
if (serviceId) {
|
|
1054
|
-
const serviceRelationships = await getServiceRelationshipsById(serviceId, account);
|
|
1055
|
-
if (serviceRelationships && serviceRelationships.length > 0) {
|
|
1056
|
-
response.json({
|
|
1057
|
-
relationships: serviceRelationships
|
|
1058
|
-
});
|
|
1059
|
-
}
|
|
1060
|
-
} else {
|
|
1061
|
-
response.status(400).json("Bad Request: ':serviceId' must be provided as part of the path");
|
|
1062
|
-
}
|
|
1063
|
-
response.status(404);
|
|
1064
|
-
} catch (error) {
|
|
1065
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
1066
|
-
response.status(error.status).json({
|
|
1067
|
-
errors: [
|
|
1068
|
-
`${error.message}`
|
|
1069
|
-
]
|
|
1070
|
-
});
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
});
|
|
1074
|
-
router.get("/catalog/entity/:type/:namespace/:name", async (request, response) => {
|
|
1075
|
-
var _a;
|
|
1076
|
-
const type = request.params.type;
|
|
1077
|
-
const namespace = request.params.namespace;
|
|
1078
|
-
const name = request.params.name;
|
|
1079
|
-
try {
|
|
1080
|
-
if (type && namespace && name) {
|
|
1081
|
-
const entityRef = `${type}:${namespace}/${name}`.toLowerCase();
|
|
1082
|
-
const foundEntity = await (catalogApi == null ? void 0 : catalogApi.getEntityByRef(entityRef));
|
|
1083
|
-
if (foundEntity) {
|
|
1084
|
-
response.json((_a = foundEntity.metadata.annotations) == null ? void 0 : _a["pagerduty.com/service-id"]);
|
|
1085
|
-
} else {
|
|
1086
|
-
response.status(404);
|
|
1087
|
-
}
|
|
1088
|
-
} else {
|
|
1089
|
-
response.status(400).json("Bad Request: ':entityRef' must be provided as part of the path");
|
|
1090
|
-
}
|
|
1091
|
-
} catch (error) {
|
|
1092
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
1093
|
-
response.status(error.status).json({
|
|
1094
|
-
errors: [
|
|
1095
|
-
`${error.message}`
|
|
1096
|
-
]
|
|
1097
|
-
});
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
});
|
|
1101
|
-
router.post("/settings", async (request, response) => {
|
|
1102
|
-
try {
|
|
1103
|
-
const settings = request.body;
|
|
1104
|
-
logger.info(`Received settings: ${JSON.stringify(settings)}`);
|
|
1105
|
-
await Promise.all(settings.map(async (setting) => {
|
|
1106
|
-
logger.info(`Processing setting: ${JSON.stringify(setting)}`);
|
|
1107
|
-
if (setting.id === void 0 || setting.value === void 0) {
|
|
1108
|
-
logger.info(`Bad Request: 'id' and 'value' are required`);
|
|
1109
|
-
response.status(400).json("Bad Request: 'id' and 'value' are required");
|
|
1110
|
-
}
|
|
1111
|
-
if (!isValidSetting(setting.value)) {
|
|
1112
|
-
logger.info(`Bad Request: 'value' is invalid`);
|
|
1113
|
-
response.status(400).json("Bad Request: 'value' is invalid. Valid options are 'backstage', 'pagerduty', 'both' or 'disabled'");
|
|
1114
|
-
}
|
|
1115
|
-
logger.info(`Setting value is valid: ${setting.value}`);
|
|
1116
|
-
await store.updateSetting(setting);
|
|
1117
|
-
logger.info(`Setting updated: ${JSON.stringify(setting)}`);
|
|
1118
|
-
}));
|
|
1119
|
-
response.sendStatus(200);
|
|
1120
|
-
} catch (error) {
|
|
1121
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
1122
|
-
logger.error(`Error occurred while processing request: ${error.message}`);
|
|
1123
|
-
response.status(error.status).json({
|
|
1124
|
-
errors: [
|
|
1125
|
-
`${error.message}`
|
|
1126
|
-
]
|
|
1127
|
-
});
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
});
|
|
1131
|
-
router.get("/settings/:settingId", async (request, response) => {
|
|
1132
|
-
try {
|
|
1133
|
-
const settingId = request.params.settingId;
|
|
1134
|
-
const setting = await store.findSetting(settingId);
|
|
1135
|
-
if (!setting) {
|
|
1136
|
-
response.status(404).json(`Setting with id ${settingId} not found.`);
|
|
1137
|
-
return;
|
|
1138
|
-
}
|
|
1139
|
-
response.json(setting);
|
|
1140
|
-
} catch (error) {
|
|
1141
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
1142
|
-
response.status(error.status).json({
|
|
1143
|
-
errors: [
|
|
1144
|
-
`${error.message}`
|
|
1145
|
-
]
|
|
1146
|
-
});
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
});
|
|
1150
|
-
function isValidSetting(value) {
|
|
1151
|
-
if (value === "backstage" || value === "pagerduty" || value === "both" || value === "disabled") {
|
|
1152
|
-
return true;
|
|
1153
|
-
}
|
|
1154
|
-
return false;
|
|
1155
|
-
}
|
|
1156
794
|
router.post("/mapping/entity", async (request, response) => {
|
|
1157
|
-
var _a;
|
|
1158
795
|
try {
|
|
1159
796
|
const entity = request.body;
|
|
1160
797
|
if (!entity.serviceId) {
|
|
@@ -1162,30 +799,12 @@ async function createRouter(options) {
|
|
|
1162
799
|
}
|
|
1163
800
|
const entityMappings = await store.getAllEntityMappings();
|
|
1164
801
|
const oldMapping = entityMappings.find((mapping) => mapping.serviceId === entity.serviceId);
|
|
1165
|
-
if (entity.entityRef !== "" && (entity.integrationKey === "" || entity.integrationKey === void 0)) {
|
|
1166
|
-
const backstageVendorId = "PRO19CT";
|
|
1167
|
-
const service = await getServiceById(entity.serviceId, entity.account);
|
|
1168
|
-
const backstageIntegration = (_a = service.integrations) == null ? void 0 : _a.find((integration) => {
|
|
1169
|
-
var _a2;
|
|
1170
|
-
return ((_a2 = integration.vendor) == null ? void 0 : _a2.id) === backstageVendorId;
|
|
1171
|
-
});
|
|
1172
|
-
if (!backstageIntegration) {
|
|
1173
|
-
const integrationKey = await createServiceIntegration({
|
|
1174
|
-
serviceId: entity.serviceId,
|
|
1175
|
-
vendorId: backstageVendorId,
|
|
1176
|
-
account: entity.account
|
|
1177
|
-
});
|
|
1178
|
-
entity.integrationKey = integrationKey;
|
|
1179
|
-
} else {
|
|
1180
|
-
entity.integrationKey = backstageIntegration.integration_key;
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
802
|
const entityMappingId = await store.insertEntityMapping(entity);
|
|
1184
803
|
if (entity.entityRef !== "") {
|
|
1185
|
-
await
|
|
804
|
+
await catalogApi?.refreshEntity(entity.entityRef);
|
|
1186
805
|
}
|
|
1187
806
|
if (oldMapping && oldMapping.entityRef !== "") {
|
|
1188
|
-
await
|
|
807
|
+
await catalogApi?.refreshEntity(oldMapping.entityRef);
|
|
1189
808
|
}
|
|
1190
809
|
response.json({
|
|
1191
810
|
id: entityMappingId,
|
|
@@ -1209,13 +828,16 @@ async function createRouter(options) {
|
|
|
1209
828
|
router.get("/mapping/entity", async (_, response) => {
|
|
1210
829
|
try {
|
|
1211
830
|
const entityMappings = await store.getAllEntityMappings();
|
|
831
|
+
logger.info(`Retrieved ${entityMappings.length} entity mappings from the database.`);
|
|
1212
832
|
const componentEntities = await catalogApi.getEntities({
|
|
1213
833
|
filter: {
|
|
1214
834
|
kind: "Component"
|
|
1215
835
|
}
|
|
1216
836
|
});
|
|
837
|
+
logger.info(`Retrieved ${componentEntities.items.length} entities from the catalog.`);
|
|
1217
838
|
const componentEntitiesDict = await createComponentEntitiesReferenceDict(componentEntities);
|
|
1218
839
|
const pagerDutyServices = await getAllServices();
|
|
840
|
+
logger.info(`Retrieved ${pagerDutyServices.length} services from PagerDuty.`);
|
|
1219
841
|
const result = await buildEntityMappingsResponse(entityMappings, componentEntitiesDict, componentEntities, pagerDutyServices);
|
|
1220
842
|
response.json(result);
|
|
1221
843
|
} catch (error) {
|
|
@@ -1256,32 +878,6 @@ async function createRouter(options) {
|
|
|
1256
878
|
}
|
|
1257
879
|
}
|
|
1258
880
|
});
|
|
1259
|
-
router.get("/mapping/entity/service/:serviceId", async (request, response) => {
|
|
1260
|
-
var _a;
|
|
1261
|
-
try {
|
|
1262
|
-
const serviceId = (_a = request.params.serviceId) != null ? _a : "";
|
|
1263
|
-
if (serviceId === "") {
|
|
1264
|
-
response.status(400).json("Required params not specified.");
|
|
1265
|
-
return;
|
|
1266
|
-
}
|
|
1267
|
-
const entityMapping = await store.findEntityMappingByServiceId(serviceId);
|
|
1268
|
-
if (!entityMapping) {
|
|
1269
|
-
response.status(404).json(`Mapping for serviceId ${serviceId} not found.`);
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
response.json({
|
|
1273
|
-
mapping: entityMapping
|
|
1274
|
-
});
|
|
1275
|
-
} catch (error) {
|
|
1276
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
1277
|
-
response.status(error.status).json({
|
|
1278
|
-
errors: [
|
|
1279
|
-
`${error.message}`
|
|
1280
|
-
]
|
|
1281
|
-
});
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1284
|
-
});
|
|
1285
881
|
router.get("/escalation_policies", async (_, response) => {
|
|
1286
882
|
try {
|
|
1287
883
|
let escalationPolicyList = await getAllEscalationPolicies();
|
|
@@ -1383,31 +979,6 @@ async function createRouter(options) {
|
|
|
1383
979
|
}
|
|
1384
980
|
}
|
|
1385
981
|
});
|
|
1386
|
-
router.post("/services/:serviceId/integration/:vendorId", async (request, response) => {
|
|
1387
|
-
try {
|
|
1388
|
-
const serviceId = request.params.serviceId || "";
|
|
1389
|
-
const vendorId = request.params.vendorId || "";
|
|
1390
|
-
const account = request.query.account || "";
|
|
1391
|
-
if (serviceId === "" || vendorId === "") {
|
|
1392
|
-
response.status(400).json("Bad Request: ':serviceId' and ':vendorId' must be provided as part of the path");
|
|
1393
|
-
}
|
|
1394
|
-
const integrationKey = await createServiceIntegration({
|
|
1395
|
-
serviceId,
|
|
1396
|
-
vendorId,
|
|
1397
|
-
account
|
|
1398
|
-
});
|
|
1399
|
-
response.json(integrationKey);
|
|
1400
|
-
} catch (error) {
|
|
1401
|
-
if (error instanceof backstagePluginCommon.HttpError) {
|
|
1402
|
-
logger.error(`Error occurred while processing request: ${error.message}`);
|
|
1403
|
-
response.status(error.status).json({
|
|
1404
|
-
errors: [
|
|
1405
|
-
`${error.message}`
|
|
1406
|
-
]
|
|
1407
|
-
});
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
});
|
|
1411
982
|
router.get("/services/:serviceId/change-events", async (request, response) => {
|
|
1412
983
|
try {
|
|
1413
984
|
const serviceId = request.params.serviceId || "";
|
|
@@ -1496,7 +1067,7 @@ class PagerDutyBackendDatabase {
|
|
|
1496
1067
|
this.db = db;
|
|
1497
1068
|
}
|
|
1498
1069
|
static async create(knex, options) {
|
|
1499
|
-
if (options
|
|
1070
|
+
if (options?.skipMigrations) {
|
|
1500
1071
|
const migrationsDir = backendPluginApi.resolvePackagePath("@pagerduty/backstage-plugin-backend", "migrations");
|
|
1501
1072
|
await knex.migrate.latest({
|
|
1502
1073
|
directory: migrationsDir
|
|
@@ -1527,28 +1098,6 @@ class PagerDutyBackendDatabase {
|
|
|
1527
1098
|
const rawEntity = await this.db("pagerduty_entity_mapping").where("entityRef", entityRef).first();
|
|
1528
1099
|
return rawEntity;
|
|
1529
1100
|
}
|
|
1530
|
-
async findEntityMappingByServiceId(serviceId) {
|
|
1531
|
-
const rawEntity = await this.db("pagerduty_entity_mapping").where("serviceId", serviceId).first();
|
|
1532
|
-
return rawEntity;
|
|
1533
|
-
}
|
|
1534
|
-
async updateSetting(setting) {
|
|
1535
|
-
const [result] = await this.db("pagerduty_settings").insert({
|
|
1536
|
-
id: setting.id,
|
|
1537
|
-
value: setting.value
|
|
1538
|
-
}).onConflict(["id"]).merge(["value"]).returning("id");
|
|
1539
|
-
return result.id;
|
|
1540
|
-
}
|
|
1541
|
-
async findSetting(settingId) {
|
|
1542
|
-
const rawEntity = await this.db("pagerduty_settings").where("id", settingId).first();
|
|
1543
|
-
return rawEntity;
|
|
1544
|
-
}
|
|
1545
|
-
async getAllSettings() {
|
|
1546
|
-
const rawEntities = await this.db("pagerduty_settings");
|
|
1547
|
-
if (!rawEntities) {
|
|
1548
|
-
return [];
|
|
1549
|
-
}
|
|
1550
|
-
return rawEntities;
|
|
1551
|
-
}
|
|
1552
1101
|
}
|
|
1553
1102
|
|
|
1554
1103
|
class CatalogFetchApi {
|