@pagerduty/backstage-plugin-backend 0.13.0 → 0.14.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 +11 -0
- package/config.d.ts +43 -0
- package/dist/apis/pagerduty.cjs.js +364 -24
- package/dist/apis/pagerduty.cjs.js.map +1 -1
- package/dist/controllers/mappings-controller.cjs.js +31 -7
- package/dist/controllers/mappings-controller.cjs.js.map +1 -1
- package/dist/db/PagerDutyBackendDatabase.cjs.js +202 -4
- package/dist/db/PagerDutyBackendDatabase.cjs.js.map +1 -1
- package/dist/index.d.ts +41 -1
- package/dist/plugin.cjs.js +20 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/service/customFieldsController.cjs.js +459 -0
- package/dist/service/customFieldsController.cjs.js.map +1 -0
- package/dist/service/router.cjs.js +54 -18
- package/dist/service/router.cjs.js.map +1 -1
- package/dist/services/autoMatchRunner.cjs.js +3 -2
- package/dist/services/autoMatchRunner.cjs.js.map +1 -1
- package/dist/services/dataLoader.cjs.js +3 -3
- package/dist/services/dataLoader.cjs.js.map +1 -1
- package/dist/services/syncLogsCleanup.cjs.js +77 -0
- package/dist/services/syncLogsCleanup.cjs.js.map +1 -0
- package/migrations/20260225113251_add_pagerduty_custom_fields_table.js +31 -0
- package/migrations/20260313_add_custom_fields_unique_indexes.js +27 -0
- package/migrations/20260515_add_custom_field_sync_logs_table.js +32 -0
- package/migrations/20260612_add_sync_logs_timestamp_index.js +19 -0
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @pagerduty/backstage-plugin-backend
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- bee64f1: Release the service mappings feature
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [bee64f1]
|
|
12
|
+
- @pagerduty/backstage-plugin-common@0.5.0
|
|
13
|
+
|
|
3
14
|
## 0.13.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/config.d.ts
CHANGED
|
@@ -50,5 +50,48 @@ export interface Config {
|
|
|
50
50
|
* @deepVisibility secret
|
|
51
51
|
*/
|
|
52
52
|
accounts?: PagerDutyAccountConfig[];
|
|
53
|
+
/**
|
|
54
|
+
* Optional retention and cleanup settings for custom field sync logs.
|
|
55
|
+
* @visibility backend
|
|
56
|
+
*/
|
|
57
|
+
customFieldsSyncLogs?: {
|
|
58
|
+
/**
|
|
59
|
+
* Number of days to keep sync logs before they are deleted. Defaults to 30.
|
|
60
|
+
* @visibility backend
|
|
61
|
+
*/
|
|
62
|
+
retentionDays?: number;
|
|
63
|
+
/**
|
|
64
|
+
* Maximum number of sync log rows to keep across all accounts; the
|
|
65
|
+
* oldest rows beyond this count are deleted. Defaults to 500000.
|
|
66
|
+
* @visibility backend
|
|
67
|
+
*/
|
|
68
|
+
maxRows?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Settings for the scheduled cleanup task.
|
|
71
|
+
* @visibility backend
|
|
72
|
+
*/
|
|
73
|
+
cleanup?: {
|
|
74
|
+
/**
|
|
75
|
+
* Whether the scheduled cleanup task runs. Defaults to true.
|
|
76
|
+
* @visibility backend
|
|
77
|
+
*/
|
|
78
|
+
enabled?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* How often the cleanup task runs, in minutes. Defaults to 15.
|
|
81
|
+
* @visibility backend
|
|
82
|
+
*/
|
|
83
|
+
frequencyMinutes?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Number of rows deleted per batch. Defaults to 10000.
|
|
86
|
+
* @visibility backend
|
|
87
|
+
*/
|
|
88
|
+
batchSize?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Maximum number of delete batches per run. Defaults to 500.
|
|
91
|
+
* @visibility backend
|
|
92
|
+
*/
|
|
93
|
+
maxBatchesPerRun?: number;
|
|
94
|
+
};
|
|
95
|
+
};
|
|
53
96
|
};
|
|
54
97
|
}
|
|
@@ -102,6 +102,31 @@ async function getDefaultHeaders(account) {
|
|
|
102
102
|
"X-PagerDuty-Client": clientHeader
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
+
const SERVICES_CACHE_TTL_MS = 20 * 60 * 1e3;
|
|
106
|
+
const ALL_SERVICES_CACHE_KEY = "pagerduty:services:all";
|
|
107
|
+
const serviceCacheKey = (serviceId, account) => `pagerduty:service:${account || "default"}:${serviceId}`;
|
|
108
|
+
async function readCache(cache, key) {
|
|
109
|
+
if (!cache) {
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
return await cache.get(key);
|
|
113
|
+
}
|
|
114
|
+
async function writeCache(cache, key, value) {
|
|
115
|
+
if (!cache) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
await cache.set(
|
|
119
|
+
key,
|
|
120
|
+
value,
|
|
121
|
+
{ ttl: SERVICES_CACHE_TTL_MS }
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
async function deleteCache(cache, key) {
|
|
125
|
+
if (!cache) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
await cache.delete(key);
|
|
129
|
+
}
|
|
105
130
|
async function addServiceRelationsToService(serviceRelations, account) {
|
|
106
131
|
let response;
|
|
107
132
|
const options = {
|
|
@@ -219,7 +244,7 @@ async function getServiceRelationshipsById(serviceId, account) {
|
|
|
219
244
|
headers: await getDefaultHeaders(account)
|
|
220
245
|
};
|
|
221
246
|
const apiBaseUrl = getApiBaseUrl(account);
|
|
222
|
-
const baseUrl = `${apiBaseUrl}/service_dependencies/technical_services/${serviceId}`;
|
|
247
|
+
const baseUrl = `${apiBaseUrl}/service_dependencies/technical_services/${encodeURIComponent(serviceId)}`;
|
|
223
248
|
try {
|
|
224
249
|
response = await fetchWithRetries(baseUrl, options);
|
|
225
250
|
} catch (error) {
|
|
@@ -502,7 +527,12 @@ async function getOncallUsers(escalationPolicy, account) {
|
|
|
502
527
|
throw new backstagePluginCommon.HttpError(`Failed to parse oncall information: ${error}`, 500);
|
|
503
528
|
}
|
|
504
529
|
}
|
|
505
|
-
async function getServiceById(serviceId, account) {
|
|
530
|
+
async function getServiceById(serviceId, account, cache, logger) {
|
|
531
|
+
const cacheKey = serviceCacheKey(serviceId, account);
|
|
532
|
+
const cached = await readCache(cache, cacheKey);
|
|
533
|
+
if (cached) {
|
|
534
|
+
return cached;
|
|
535
|
+
}
|
|
506
536
|
let response;
|
|
507
537
|
const params = `time_zone=UTC&include[]=integrations&include[]=escalation_policies`;
|
|
508
538
|
const options = {
|
|
@@ -513,7 +543,7 @@ async function getServiceById(serviceId, account) {
|
|
|
513
543
|
const baseUrl = `${apiBaseUrl}/services`;
|
|
514
544
|
try {
|
|
515
545
|
response = await fetchWithRetries(
|
|
516
|
-
`${baseUrl}/${serviceId}?${params}`,
|
|
546
|
+
`${baseUrl}/${encodeURIComponent(serviceId)}?${params}`,
|
|
517
547
|
options
|
|
518
548
|
);
|
|
519
549
|
} catch (error) {
|
|
@@ -550,12 +580,21 @@ async function getServiceById(serviceId, account) {
|
|
|
550
580
|
let result;
|
|
551
581
|
try {
|
|
552
582
|
result = await response.json();
|
|
583
|
+
await writeCache(cache, serviceCacheKey(serviceId, account), result.service);
|
|
553
584
|
return result.service;
|
|
554
585
|
} catch (error) {
|
|
555
586
|
throw new backstagePluginCommon.HttpError(`Failed to parse service information: ${error}`, 500);
|
|
556
587
|
}
|
|
557
588
|
}
|
|
558
|
-
|
|
589
|
+
const SERVICE_IDS_BATCH_SIZE = 50;
|
|
590
|
+
const SERVICE_ID_PATTERN = /^[A-Z0-9]{6,}$/;
|
|
591
|
+
function isValidServiceId(id) {
|
|
592
|
+
if (typeof id !== "string") {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
return SERVICE_ID_PATTERN.test(id.trim());
|
|
596
|
+
}
|
|
597
|
+
async function getServicesByIdsBatch(serviceIds, account) {
|
|
559
598
|
let response;
|
|
560
599
|
const token = await auth.getAuthToken(account);
|
|
561
600
|
const options = {
|
|
@@ -568,11 +607,11 @@ async function getSerivcesByIdsAndAccount(serviceIds, account) {
|
|
|
568
607
|
};
|
|
569
608
|
const apiBaseUrl = getApiBaseUrl(account);
|
|
570
609
|
const baseUrl = `${apiBaseUrl}/services`;
|
|
610
|
+
const params = new URLSearchParams();
|
|
611
|
+
serviceIds.forEach((id) => params.append("id[]", id));
|
|
612
|
+
params.append("limit", String(SERVICE_IDS_BATCH_SIZE));
|
|
571
613
|
try {
|
|
572
|
-
response = await fetchWithRetries(
|
|
573
|
-
`${baseUrl}?id[]=${serviceIds.join("&id[]=")}`,
|
|
574
|
-
options
|
|
575
|
-
);
|
|
614
|
+
response = await fetchWithRetries(`${baseUrl}?${params}`, options);
|
|
576
615
|
} catch (error) {
|
|
577
616
|
throw new Error(`Failed to retrieve service: ${error}`);
|
|
578
617
|
}
|
|
@@ -584,10 +623,7 @@ async function getSerivcesByIdsAndAccount(serviceIds, account) {
|
|
|
584
623
|
}
|
|
585
624
|
switch (response.status) {
|
|
586
625
|
case 400:
|
|
587
|
-
|
|
588
|
-
"Failed to get service. Caller provided invalid arguments.",
|
|
589
|
-
400
|
|
590
|
-
);
|
|
626
|
+
return [];
|
|
591
627
|
case 401:
|
|
592
628
|
throw new backstagePluginCommon.HttpError(
|
|
593
629
|
"Failed to get service. Caller did not supply credentials or did not provide the correct credentials.",
|
|
@@ -612,6 +648,24 @@ async function getSerivcesByIdsAndAccount(serviceIds, account) {
|
|
|
612
648
|
throw new backstagePluginCommon.HttpError(`Failed to parse service information: ${error}`, 500);
|
|
613
649
|
}
|
|
614
650
|
}
|
|
651
|
+
async function getSerivcesByIdsAndAccount(serviceIds, account) {
|
|
652
|
+
const sanitizedServiceIds = Array.from(
|
|
653
|
+
new Set(
|
|
654
|
+
serviceIds.map((id) => typeof id === "string" ? id.trim() : "").filter((id) => isValidServiceId(id))
|
|
655
|
+
)
|
|
656
|
+
);
|
|
657
|
+
if (sanitizedServiceIds.length === 0) {
|
|
658
|
+
return [];
|
|
659
|
+
}
|
|
660
|
+
const batches = [];
|
|
661
|
+
for (let i = 0; i < sanitizedServiceIds.length; i += SERVICE_IDS_BATCH_SIZE) {
|
|
662
|
+
batches.push(sanitizedServiceIds.slice(i, i + SERVICE_IDS_BATCH_SIZE));
|
|
663
|
+
}
|
|
664
|
+
const results = await Promise.all(
|
|
665
|
+
batches.map((batch) => getServicesByIdsBatch(batch, account))
|
|
666
|
+
);
|
|
667
|
+
return results.flat();
|
|
668
|
+
}
|
|
615
669
|
async function getServiceByIntegrationKey(integrationKey, account) {
|
|
616
670
|
let response;
|
|
617
671
|
const params = `query=${integrationKey}&time_zone=UTC&include[]=integrations&include[]=escalation_policies`;
|
|
@@ -669,15 +723,21 @@ async function getServiceByIntegrationKey(integrationKey, account) {
|
|
|
669
723
|
return result.services[0];
|
|
670
724
|
}
|
|
671
725
|
async function getServicesByIds(ids) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
})
|
|
726
|
+
const servicesPerAccount = await Promise.all(
|
|
727
|
+
Object.keys(EndpointConfig).map(
|
|
728
|
+
(account) => getSerivcesByIdsAndAccount(ids, account)
|
|
729
|
+
)
|
|
677
730
|
);
|
|
678
|
-
return
|
|
731
|
+
return servicesPerAccount.flat();
|
|
679
732
|
}
|
|
680
|
-
async function getAllServices() {
|
|
733
|
+
async function getAllServices(cache) {
|
|
734
|
+
const cached = await readCache(
|
|
735
|
+
cache,
|
|
736
|
+
ALL_SERVICES_CACHE_KEY
|
|
737
|
+
);
|
|
738
|
+
if (cached !== void 0) {
|
|
739
|
+
return cached;
|
|
740
|
+
}
|
|
681
741
|
const allServices = [];
|
|
682
742
|
await Promise.all(
|
|
683
743
|
Object.entries(EndpointConfig).map(async ([account, _]) => {
|
|
@@ -733,6 +793,12 @@ async function getAllServices() {
|
|
|
733
793
|
}
|
|
734
794
|
})
|
|
735
795
|
);
|
|
796
|
+
await writeCache(cache, ALL_SERVICES_CACHE_KEY, allServices);
|
|
797
|
+
await Promise.all(
|
|
798
|
+
allServices.map(
|
|
799
|
+
(service) => writeCache(cache, serviceCacheKey(service.id, service.account), service)
|
|
800
|
+
)
|
|
801
|
+
);
|
|
736
802
|
return allServices;
|
|
737
803
|
}
|
|
738
804
|
async function getServicesByPartialName(partialName) {
|
|
@@ -874,7 +940,7 @@ async function getChangeEvents(serviceId, account) {
|
|
|
874
940
|
const baseUrl = `${apiBaseUrl}/services`;
|
|
875
941
|
try {
|
|
876
942
|
response = await fetchWithRetries(
|
|
877
|
-
`${baseUrl}/${serviceId}/change_events?${params}`,
|
|
943
|
+
`${baseUrl}/${encodeURIComponent(serviceId)}/change_events?${params}`,
|
|
878
944
|
options
|
|
879
945
|
);
|
|
880
946
|
} catch (error) {
|
|
@@ -921,7 +987,7 @@ async function getChangeEvents(serviceId, account) {
|
|
|
921
987
|
}
|
|
922
988
|
async function getIncidents(serviceId, account) {
|
|
923
989
|
let response;
|
|
924
|
-
const params = `time_zone=UTC&sort_by=created_at&statuses[]=triggered&statuses[]=acknowledged&service_ids[]=${serviceId}`;
|
|
990
|
+
const params = `time_zone=UTC&sort_by=created_at&statuses[]=triggered&statuses[]=acknowledged&service_ids[]=${encodeURIComponent(serviceId)}`;
|
|
925
991
|
const options = {
|
|
926
992
|
method: "GET",
|
|
927
993
|
headers: await getDefaultHeaders(account)
|
|
@@ -981,7 +1047,7 @@ async function getServiceStandards(serviceId, account) {
|
|
|
981
1047
|
headers: await getDefaultHeaders(account)
|
|
982
1048
|
};
|
|
983
1049
|
const apiBaseUrl = getApiBaseUrl(account);
|
|
984
|
-
const baseUrl = `${apiBaseUrl}/standards/scores/technical_services/${serviceId}`;
|
|
1050
|
+
const baseUrl = `${apiBaseUrl}/standards/scores/technical_services/${encodeURIComponent(serviceId)}`;
|
|
985
1051
|
try {
|
|
986
1052
|
response = await fetchWithRetries(baseUrl, options);
|
|
987
1053
|
} catch (error) {
|
|
@@ -1076,7 +1142,8 @@ async function getServiceMetrics(serviceId, account) {
|
|
|
1076
1142
|
async function createServiceIntegration({
|
|
1077
1143
|
serviceId,
|
|
1078
1144
|
vendorId,
|
|
1079
|
-
account
|
|
1145
|
+
account,
|
|
1146
|
+
cache
|
|
1080
1147
|
}) {
|
|
1081
1148
|
let response;
|
|
1082
1149
|
const apiBaseUrl = getApiBaseUrl(account);
|
|
@@ -1100,7 +1167,7 @@ async function createServiceIntegration({
|
|
|
1100
1167
|
};
|
|
1101
1168
|
try {
|
|
1102
1169
|
response = await fetchWithRetries(
|
|
1103
|
-
`${baseUrl}/${serviceId}/integrations`,
|
|
1170
|
+
`${baseUrl}/${encodeURIComponent(serviceId)}/integrations`,
|
|
1104
1171
|
options
|
|
1105
1172
|
);
|
|
1106
1173
|
} catch (error) {
|
|
@@ -1132,12 +1199,41 @@ async function createServiceIntegration({
|
|
|
1132
1199
|
let result;
|
|
1133
1200
|
try {
|
|
1134
1201
|
result = await response.json();
|
|
1202
|
+
await deleteCache(cache, serviceCacheKey(serviceId, account));
|
|
1203
|
+
await deleteCache(cache, ALL_SERVICES_CACHE_KEY);
|
|
1135
1204
|
return result.integration.integration_key ?? "";
|
|
1136
1205
|
} catch (error) {
|
|
1137
1206
|
throw new Error(`Failed to parse service information: ${error}`);
|
|
1138
1207
|
}
|
|
1139
1208
|
}
|
|
1209
|
+
function getAllowedApiOrigins() {
|
|
1210
|
+
const origins = /* @__PURE__ */ new Set();
|
|
1211
|
+
const addOrigin = (apiBaseUrl) => {
|
|
1212
|
+
if (!apiBaseUrl) {
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
try {
|
|
1216
|
+
origins.add(new URL(apiBaseUrl).origin);
|
|
1217
|
+
} catch {
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
Object.values(EndpointConfig).forEach((cfg) => addOrigin(cfg.apiBaseUrl));
|
|
1221
|
+
addOrigin(fallbackEndpointConfig?.apiBaseUrl);
|
|
1222
|
+
origins.add("https://api.pagerduty.com");
|
|
1223
|
+
return origins;
|
|
1224
|
+
}
|
|
1140
1225
|
async function fetchWithRetries(url, options) {
|
|
1226
|
+
let requestOrigin;
|
|
1227
|
+
try {
|
|
1228
|
+
requestOrigin = new URL(url).origin;
|
|
1229
|
+
} catch {
|
|
1230
|
+
throw new Error("Refusing to fetch invalid URL.");
|
|
1231
|
+
}
|
|
1232
|
+
if (!getAllowedApiOrigins().has(requestOrigin)) {
|
|
1233
|
+
throw new Error(
|
|
1234
|
+
`Refusing to fetch URL with disallowed origin: ${requestOrigin}`
|
|
1235
|
+
);
|
|
1236
|
+
}
|
|
1141
1237
|
let response;
|
|
1142
1238
|
let error = new Error();
|
|
1143
1239
|
const maxRetries = 5;
|
|
@@ -1158,9 +1254,250 @@ async function fetchWithRetries(url, options) {
|
|
|
1158
1254
|
`Failed to fetch data after ${maxRetries} retries. Last error: ${error}`
|
|
1159
1255
|
);
|
|
1160
1256
|
}
|
|
1257
|
+
async function createCustomField({
|
|
1258
|
+
request,
|
|
1259
|
+
account
|
|
1260
|
+
}) {
|
|
1261
|
+
let response;
|
|
1262
|
+
const apiBaseUrl = getApiBaseUrl(account);
|
|
1263
|
+
const baseUrl = `${apiBaseUrl}/services/custom_fields`;
|
|
1264
|
+
const token = await auth.getAuthToken(account);
|
|
1265
|
+
const options = {
|
|
1266
|
+
method: "POST",
|
|
1267
|
+
body: JSON.stringify(request),
|
|
1268
|
+
headers: {
|
|
1269
|
+
Authorization: token,
|
|
1270
|
+
Accept: "application/vnd.pagerduty+json;version=2",
|
|
1271
|
+
"Content-Type": "application/json"
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1274
|
+
try {
|
|
1275
|
+
response = await fetchWithRetries(baseUrl, options);
|
|
1276
|
+
} catch (error) {
|
|
1277
|
+
throw new Error(`Failed to create custom field: ${error}`);
|
|
1278
|
+
}
|
|
1279
|
+
if (response.status >= 500) {
|
|
1280
|
+
throw new backstagePluginCommon.HttpError(
|
|
1281
|
+
`Failed to create custom field. PagerDuty API returned a server error.`,
|
|
1282
|
+
response.status
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
switch (response.status) {
|
|
1286
|
+
case 400: {
|
|
1287
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1288
|
+
throw new backstagePluginCommon.HttpError(
|
|
1289
|
+
`Failed to create custom field. Invalid arguments: ${JSON.stringify(errorData)}`,
|
|
1290
|
+
400
|
|
1291
|
+
);
|
|
1292
|
+
}
|
|
1293
|
+
case 401:
|
|
1294
|
+
throw new backstagePluginCommon.HttpError(
|
|
1295
|
+
`Failed to create custom field. Invalid credentials provided.`,
|
|
1296
|
+
401
|
|
1297
|
+
);
|
|
1298
|
+
case 403:
|
|
1299
|
+
throw new backstagePluginCommon.HttpError(
|
|
1300
|
+
`Failed to create custom field. Not authorized to perform this action.`,
|
|
1301
|
+
403
|
|
1302
|
+
);
|
|
1303
|
+
case 409: {
|
|
1304
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1305
|
+
throw new backstagePluginCommon.HttpError(
|
|
1306
|
+
`Custom field with this name already exists: ${JSON.stringify(errorData)}`,
|
|
1307
|
+
409
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
case 429:
|
|
1311
|
+
throw new backstagePluginCommon.HttpError(`Rate limit exceeded.`, 429);
|
|
1312
|
+
}
|
|
1313
|
+
try {
|
|
1314
|
+
const result = await response.json();
|
|
1315
|
+
return result;
|
|
1316
|
+
} catch (error) {
|
|
1317
|
+
throw new Error(`Failed to parse custom field response: ${error}`);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
async function updateCustomField({
|
|
1321
|
+
fieldId,
|
|
1322
|
+
request,
|
|
1323
|
+
account
|
|
1324
|
+
}) {
|
|
1325
|
+
const apiBaseUrl = getApiBaseUrl(account);
|
|
1326
|
+
const baseUrl = `${apiBaseUrl}/services/custom_fields/${encodeURIComponent(fieldId)}`;
|
|
1327
|
+
const token = await auth.getAuthToken(account);
|
|
1328
|
+
const options = {
|
|
1329
|
+
method: "PUT",
|
|
1330
|
+
body: JSON.stringify(request),
|
|
1331
|
+
headers: {
|
|
1332
|
+
Authorization: token,
|
|
1333
|
+
Accept: "application/vnd.pagerduty+json;version=2",
|
|
1334
|
+
"Content-Type": "application/json"
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
let response;
|
|
1338
|
+
try {
|
|
1339
|
+
response = await fetchWithRetries(baseUrl, options);
|
|
1340
|
+
} catch (error) {
|
|
1341
|
+
throw new Error(`Failed to update custom field: ${error}`);
|
|
1342
|
+
}
|
|
1343
|
+
if (response.status >= 500) {
|
|
1344
|
+
throw new backstagePluginCommon.HttpError(
|
|
1345
|
+
`Failed to update custom field. PagerDuty API returned a server error.`,
|
|
1346
|
+
response.status
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
switch (response.status) {
|
|
1350
|
+
case 400: {
|
|
1351
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1352
|
+
throw new backstagePluginCommon.HttpError(
|
|
1353
|
+
`Failed to update custom field. Invalid arguments: ${JSON.stringify(errorData)}`,
|
|
1354
|
+
400
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
case 401:
|
|
1358
|
+
throw new backstagePluginCommon.HttpError(
|
|
1359
|
+
`Failed to update custom field. Invalid credentials provided.`,
|
|
1360
|
+
401
|
|
1361
|
+
);
|
|
1362
|
+
case 403:
|
|
1363
|
+
throw new backstagePluginCommon.HttpError(
|
|
1364
|
+
`Failed to update custom field. Not authorized to perform this action.`,
|
|
1365
|
+
403
|
|
1366
|
+
);
|
|
1367
|
+
case 404:
|
|
1368
|
+
throw new backstagePluginCommon.HttpError(
|
|
1369
|
+
`Failed to update custom field. Custom field not found.`,
|
|
1370
|
+
404
|
|
1371
|
+
);
|
|
1372
|
+
case 409: {
|
|
1373
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1374
|
+
throw new backstagePluginCommon.HttpError(
|
|
1375
|
+
`Custom field with this name already exists: ${JSON.stringify(errorData)}`,
|
|
1376
|
+
409
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
case 429:
|
|
1380
|
+
throw new backstagePluginCommon.HttpError(`Rate limit exceeded.`, 429);
|
|
1381
|
+
}
|
|
1382
|
+
try {
|
|
1383
|
+
const result = await response.json();
|
|
1384
|
+
return result;
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
throw new Error(`Failed to parse custom field response: ${error}`);
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
async function deleteCustomField({
|
|
1390
|
+
fieldId,
|
|
1391
|
+
account
|
|
1392
|
+
}) {
|
|
1393
|
+
const apiBaseUrl = getApiBaseUrl(account);
|
|
1394
|
+
const baseUrl = `${apiBaseUrl}/services/custom_fields/${encodeURIComponent(fieldId)}`;
|
|
1395
|
+
const token = await auth.getAuthToken(account);
|
|
1396
|
+
const options = {
|
|
1397
|
+
method: "DELETE",
|
|
1398
|
+
headers: {
|
|
1399
|
+
Authorization: token,
|
|
1400
|
+
Accept: "application/vnd.pagerduty+json;version=2"
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
let response;
|
|
1404
|
+
try {
|
|
1405
|
+
response = await fetchWithRetries(baseUrl, options);
|
|
1406
|
+
} catch (error) {
|
|
1407
|
+
throw new Error(`Failed to delete custom field: ${error}`);
|
|
1408
|
+
}
|
|
1409
|
+
if (response.status >= 500) {
|
|
1410
|
+
throw new backstagePluginCommon.HttpError(
|
|
1411
|
+
`Failed to delete custom field. PagerDuty API returned a server error.`,
|
|
1412
|
+
response.status
|
|
1413
|
+
);
|
|
1414
|
+
}
|
|
1415
|
+
switch (response.status) {
|
|
1416
|
+
case 401:
|
|
1417
|
+
throw new backstagePluginCommon.HttpError(
|
|
1418
|
+
`Failed to delete custom field. Invalid credentials provided.`,
|
|
1419
|
+
401
|
|
1420
|
+
);
|
|
1421
|
+
case 403:
|
|
1422
|
+
throw new backstagePluginCommon.HttpError(
|
|
1423
|
+
`Failed to delete custom field. Caller is not authorized to delete this custom field.`,
|
|
1424
|
+
403
|
|
1425
|
+
);
|
|
1426
|
+
case 404:
|
|
1427
|
+
throw new backstagePluginCommon.HttpError(`Custom field not found.`, 404);
|
|
1428
|
+
case 429:
|
|
1429
|
+
throw new backstagePluginCommon.HttpError(`Rate limit exceeded.`, 429);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
async function setServiceCustomFieldValues({
|
|
1433
|
+
serviceId,
|
|
1434
|
+
request,
|
|
1435
|
+
account
|
|
1436
|
+
}) {
|
|
1437
|
+
const apiBaseUrl = getApiBaseUrl(account);
|
|
1438
|
+
const baseUrl = `${apiBaseUrl}/services/${encodeURIComponent(serviceId)}/custom_fields/values`;
|
|
1439
|
+
const token = await auth.getAuthToken(account);
|
|
1440
|
+
const options = {
|
|
1441
|
+
method: "PUT",
|
|
1442
|
+
body: JSON.stringify(request),
|
|
1443
|
+
headers: {
|
|
1444
|
+
Authorization: token,
|
|
1445
|
+
Accept: "application/vnd.pagerduty+json;version=2",
|
|
1446
|
+
"Content-Type": "application/json"
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
let response;
|
|
1450
|
+
try {
|
|
1451
|
+
response = await fetchWithRetries(baseUrl, options);
|
|
1452
|
+
} catch (error) {
|
|
1453
|
+
throw new Error(`Failed to set service custom field values: ${error}`);
|
|
1454
|
+
}
|
|
1455
|
+
if (response.status >= 500) {
|
|
1456
|
+
throw new backstagePluginCommon.HttpError(
|
|
1457
|
+
`Failed to set service custom field values. PagerDuty API returned a server error.`,
|
|
1458
|
+
response.status
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
switch (response.status) {
|
|
1462
|
+
case 400: {
|
|
1463
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1464
|
+
throw new backstagePluginCommon.HttpError(
|
|
1465
|
+
`Failed to set service custom field values. Invalid arguments: ${JSON.stringify(errorData)}`,
|
|
1466
|
+
400
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
case 401:
|
|
1470
|
+
throw new backstagePluginCommon.HttpError(
|
|
1471
|
+
`Failed to set service custom field values. Invalid credentials provided.`,
|
|
1472
|
+
401
|
|
1473
|
+
);
|
|
1474
|
+
case 403:
|
|
1475
|
+
throw new backstagePluginCommon.HttpError(
|
|
1476
|
+
`Failed to set service custom field values. Not authorized to perform this action.`,
|
|
1477
|
+
403
|
|
1478
|
+
);
|
|
1479
|
+
case 404:
|
|
1480
|
+
throw new backstagePluginCommon.HttpError(
|
|
1481
|
+
`Failed to set service custom field values. Service or custom field not found.`,
|
|
1482
|
+
404
|
|
1483
|
+
);
|
|
1484
|
+
case 429:
|
|
1485
|
+
throw new backstagePluginCommon.HttpError(`Rate limit exceeded.`, 429);
|
|
1486
|
+
}
|
|
1487
|
+
try {
|
|
1488
|
+
const result = await response.json();
|
|
1489
|
+
return result;
|
|
1490
|
+
} catch (error) {
|
|
1491
|
+
throw new Error(
|
|
1492
|
+
`Failed to parse set service custom field values response: ${error}`
|
|
1493
|
+
);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1161
1496
|
|
|
1162
1497
|
exports.addServiceRelationsToService = addServiceRelationsToService;
|
|
1498
|
+
exports.createCustomField = createCustomField;
|
|
1163
1499
|
exports.createServiceIntegration = createServiceIntegration;
|
|
1500
|
+
exports.deleteCustomField = deleteCustomField;
|
|
1164
1501
|
exports.fetchWithRetries = fetchWithRetries;
|
|
1165
1502
|
exports.getAllEscalationPolicies = getAllEscalationPolicies;
|
|
1166
1503
|
exports.getAllServices = getAllServices;
|
|
@@ -1178,7 +1515,10 @@ exports.getServiceStandards = getServiceStandards;
|
|
|
1178
1515
|
exports.getServicesByIds = getServicesByIds;
|
|
1179
1516
|
exports.getServicesByPartialName = getServicesByPartialName;
|
|
1180
1517
|
exports.insertAccountConfig = insertAccountConfig;
|
|
1518
|
+
exports.isValidServiceId = isValidServiceId;
|
|
1181
1519
|
exports.loadPagerDutyEndpointsFromConfig = loadPagerDutyEndpointsFromConfig;
|
|
1182
1520
|
exports.removeServiceRelationsFromService = removeServiceRelationsFromService;
|
|
1183
1521
|
exports.setFallbackAccountConfig = setFallbackAccountConfig;
|
|
1522
|
+
exports.setServiceCustomFieldValues = setServiceCustomFieldValues;
|
|
1523
|
+
exports.updateCustomField = updateCustomField;
|
|
1184
1524
|
//# sourceMappingURL=pagerduty.cjs.js.map
|