@pagerduty/backstage-plugin-backend 0.11.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 CHANGED
@@ -1,5 +1,35 @@
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
+
22
+ ## 0.12.0
23
+
24
+ ### Minor Changes
25
+
26
+ - ae2a9c3: Refactor the service mappings screen and add an auto-matching functionality to mass map PagerDuty service to Backstage entities
27
+
28
+ ### Patch Changes
29
+
30
+ - Updated dependencies [ae2a9c3]
31
+ - @pagerduty/backstage-plugin-common@0.3.0
32
+
3
33
  ## 0.11.0
4
34
 
5
35
  ### Minor Changes
@@ -350,6 +350,92 @@ async function getAllEscalationPolicies() {
350
350
  );
351
351
  return results;
352
352
  }
353
+ async function getTeams(offset, limit, account) {
354
+ let response;
355
+ const params = `total=true&sort_by=name&offset=${offset}&limit=${limit}`;
356
+ const options = {
357
+ method: "GET",
358
+ headers: {
359
+ Authorization: await auth.getAuthToken(account),
360
+ Accept: "application/vnd.pagerduty+json;version=2",
361
+ "Content-Type": "application/json"
362
+ }
363
+ };
364
+ const apiBaseUrl = getApiBaseUrl(account);
365
+ const baseUrl = `${apiBaseUrl}/teams`;
366
+ try {
367
+ response = await fetchWithRetries(`${baseUrl}?${params}`, options);
368
+ } catch (error) {
369
+ throw new Error(`Failed to retrieve teams: ${error}`);
370
+ }
371
+ if (response.status >= 500) {
372
+ throw new backstagePluginCommon.HttpError(
373
+ `Failed to list teams. PagerDuty API returned a server error. Retrying with the same arguments will not work.`,
374
+ response.status
375
+ );
376
+ }
377
+ switch (response.status) {
378
+ case 400:
379
+ throw new backstagePluginCommon.HttpError(
380
+ "Failed to list teams. Caller provided invalid arguments.",
381
+ 400
382
+ );
383
+ case 401:
384
+ throw new backstagePluginCommon.HttpError(
385
+ "Failed to list teams. Caller did not supply credentials or did not provide the correct credentials.",
386
+ 401
387
+ );
388
+ case 403:
389
+ throw new backstagePluginCommon.HttpError(
390
+ "Failed to list teams. Caller is not authorized to view the requested resource.",
391
+ 403
392
+ );
393
+ case 429:
394
+ throw new backstagePluginCommon.HttpError("Failed to list teams. Rate limit exceeded.", 429);
395
+ }
396
+ let result;
397
+ try {
398
+ result = await response.json();
399
+ return [result.more ?? false, result.teams];
400
+ } catch (error) {
401
+ throw new backstagePluginCommon.HttpError(`Failed to parse team information: ${error}`, 500);
402
+ }
403
+ }
404
+ async function getAllTeams(account) {
405
+ const limit = 50;
406
+ let offset = 0;
407
+ let moreResults = false;
408
+ let results = [];
409
+ const accountsToFetch = account ? [account] : Object.keys(EndpointConfig);
410
+ await Promise.all(
411
+ accountsToFetch.map(async (acc) => {
412
+ try {
413
+ offset = 0;
414
+ do {
415
+ const res = await getTeams(offset, limit, acc);
416
+ res[1].forEach((team) => {
417
+ team.account = acc;
418
+ });
419
+ results = results.concat(res[1]);
420
+ if (res[0] === true) {
421
+ moreResults = true;
422
+ offset += limit;
423
+ } else {
424
+ moreResults = false;
425
+ }
426
+ } while (moreResults === true);
427
+ } catch (error) {
428
+ if (error instanceof backstagePluginCommon.HttpError) {
429
+ throw error;
430
+ } else {
431
+ throw new backstagePluginCommon.HttpError(`${error}`, 500);
432
+ }
433
+ }
434
+ })
435
+ );
436
+ results.sort((a, b) => a.name.localeCompare(b.name));
437
+ return results;
438
+ }
353
439
  async function getOncallUsers(escalationPolicy, account) {
354
440
  let response;
355
441
  const params = `time_zone=UTC&include[]=users&escalation_policy_ids[]=${escalationPolicy}`;
@@ -469,6 +555,63 @@ async function getServiceById(serviceId, account) {
469
555
  throw new backstagePluginCommon.HttpError(`Failed to parse service information: ${error}`, 500);
470
556
  }
471
557
  }
558
+ async function getSerivcesByIdsAndAccount(serviceIds, account) {
559
+ let response;
560
+ const token = await auth.getAuthToken(account);
561
+ const options = {
562
+ method: "GET",
563
+ headers: {
564
+ Authorization: token,
565
+ Accept: "application/vnd.pagerduty+json;version=2",
566
+ "Content-Type": "application/json"
567
+ }
568
+ };
569
+ const apiBaseUrl = getApiBaseUrl(account);
570
+ const baseUrl = `${apiBaseUrl}/services`;
571
+ try {
572
+ response = await fetchWithRetries(
573
+ `${baseUrl}?id[]=${serviceIds.join("&id[]=")}`,
574
+ options
575
+ );
576
+ } catch (error) {
577
+ throw new Error(`Failed to retrieve service: ${error}`);
578
+ }
579
+ if (response.status >= 500) {
580
+ throw new backstagePluginCommon.HttpError(
581
+ `Failed to get service. PagerDuty API returned a server error. Retrying with the same arguments will not work.`,
582
+ response.status
583
+ );
584
+ }
585
+ switch (response.status) {
586
+ case 400:
587
+ throw new backstagePluginCommon.HttpError(
588
+ "Failed to get service. Caller provided invalid arguments.",
589
+ 400
590
+ );
591
+ case 401:
592
+ throw new backstagePluginCommon.HttpError(
593
+ "Failed to get service. Caller did not supply credentials or did not provide the correct credentials.",
594
+ 401
595
+ );
596
+ case 403:
597
+ throw new backstagePluginCommon.HttpError(
598
+ "Failed to get service. Caller is not authorized to view the requested resource.",
599
+ 403
600
+ );
601
+ case 404:
602
+ throw new backstagePluginCommon.HttpError(
603
+ "Failed to get service. The requested resource was not found.",
604
+ 404
605
+ );
606
+ }
607
+ let result;
608
+ try {
609
+ result = await response.json();
610
+ return result.services ?? [];
611
+ } catch (error) {
612
+ throw new backstagePluginCommon.HttpError(`Failed to parse service information: ${error}`, 500);
613
+ }
614
+ }
472
615
  async function getServiceByIntegrationKey(integrationKey, account) {
473
616
  let response;
474
617
  const params = `query=${integrationKey}&time_zone=UTC&include[]=integrations&include[]=escalation_policies`;
@@ -525,6 +668,15 @@ async function getServiceByIntegrationKey(integrationKey, account) {
525
668
  }
526
669
  return result.services[0];
527
670
  }
671
+ async function getServicesByIds(ids) {
672
+ let services = [];
673
+ await Promise.all(
674
+ Object.entries(EndpointConfig).map(async ([account, _]) => {
675
+ services = await getSerivcesByIdsAndAccount(ids, account);
676
+ })
677
+ );
678
+ return services;
679
+ }
528
680
  async function getAllServices() {
529
681
  const allServices = [];
530
682
  await Promise.all(
@@ -583,6 +735,134 @@ async function getAllServices() {
583
735
  );
584
736
  return allServices;
585
737
  }
738
+ async function getServicesByPartialName(partialName) {
739
+ const allServices = [];
740
+ await Promise.all(
741
+ Object.entries(EndpointConfig).map(async ([account, _]) => {
742
+ let response;
743
+ const params = `query=${encodeURIComponent(partialName)}&time_zone=UTC&include[]=integrations&include[]=escalation_policies&include[]=teams&total=true`;
744
+ const token = await auth.getAuthToken(account);
745
+ const options = {
746
+ method: "GET",
747
+ headers: {
748
+ Authorization: token,
749
+ Accept: "application/vnd.pagerduty+json;version=2",
750
+ "Content-Type": "application/json"
751
+ }
752
+ };
753
+ const apiBaseUrl = getApiBaseUrl(account);
754
+ const baseUrl = `${apiBaseUrl}/services`;
755
+ let offset = 0;
756
+ const limit = 50;
757
+ let result;
758
+ try {
759
+ do {
760
+ const paginatedUrl = `${baseUrl}?${params}&offset=${offset}&limit=${limit}`;
761
+ response = await fetchWithRetries(paginatedUrl, options);
762
+ if (response.status >= 500) {
763
+ throw new backstagePluginCommon.HttpError(
764
+ `Failed to get services. PagerDuty API returned a server error. Retrying with the same arguments will not work.`,
765
+ response.status
766
+ );
767
+ }
768
+ switch (response.status) {
769
+ case 400:
770
+ throw new backstagePluginCommon.HttpError(
771
+ "Failed to get services. Caller provided invalid arguments.",
772
+ 400
773
+ );
774
+ case 401:
775
+ throw new backstagePluginCommon.HttpError(
776
+ "Failed to get services. Caller did not supply credentials or did not provide the correct credentials.",
777
+ 401
778
+ );
779
+ case 403:
780
+ throw new backstagePluginCommon.HttpError(
781
+ "Failed to get services. Caller is not authorized to view the requested resource.",
782
+ 403
783
+ );
784
+ default:
785
+ break;
786
+ }
787
+ result = await response.json();
788
+ result.services.forEach((service) => {
789
+ service.account = account;
790
+ });
791
+ allServices.push(...result.services);
792
+ offset += limit;
793
+ } while (offset < result.total);
794
+ } catch (error) {
795
+ throw error;
796
+ }
797
+ })
798
+ );
799
+ return allServices;
800
+ }
801
+ async function getFilteredServices(teamIds, query, maxLimit, account) {
802
+ const allServices = [];
803
+ const limit = maxLimit;
804
+ const accountsToFetch = account ? [account] : Object.keys(EndpointConfig);
805
+ await Promise.all(
806
+ accountsToFetch.map(async (acc) => {
807
+ let response;
808
+ let params = `time_zone=UTC&limit=${limit}`;
809
+ if (teamIds && teamIds.length > 0) {
810
+ const teamIdsParam = teamIds.map((id) => `team_ids[]=${id}`).join("&");
811
+ params += `&${teamIdsParam}`;
812
+ }
813
+ if (query && query.trim() !== "") {
814
+ params += `&query=${encodeURIComponent(query.trim())}`;
815
+ }
816
+ const token = await auth.getAuthToken(acc);
817
+ const options = {
818
+ method: "GET",
819
+ headers: {
820
+ Authorization: token,
821
+ Accept: "application/vnd.pagerduty+json;version=2",
822
+ "Content-Type": "application/json"
823
+ }
824
+ };
825
+ const apiBaseUrl = getApiBaseUrl(acc);
826
+ const baseUrl = `${apiBaseUrl}/services`;
827
+ try {
828
+ response = await fetchWithRetries(`${baseUrl}?${params}`, options);
829
+ if (response.status >= 500) {
830
+ throw new backstagePluginCommon.HttpError(
831
+ `Failed to get services. PagerDuty API returned a server error. Retrying with the same arguments will not work.`,
832
+ response.status
833
+ );
834
+ }
835
+ switch (response.status) {
836
+ case 400:
837
+ throw new backstagePluginCommon.HttpError(
838
+ "Failed to get services. Caller provided invalid arguments.",
839
+ 400
840
+ );
841
+ case 401:
842
+ throw new backstagePluginCommon.HttpError(
843
+ "Failed to get services. Caller did not supply credentials or did not provide the correct credentials.",
844
+ 401
845
+ );
846
+ case 403:
847
+ throw new backstagePluginCommon.HttpError(
848
+ "Failed to get services. Caller is not authorized to view the requested resource.",
849
+ 403
850
+ );
851
+ default:
852
+ break;
853
+ }
854
+ const result = await response.json();
855
+ result.services.forEach((service) => {
856
+ service.account = acc;
857
+ });
858
+ allServices.push(...result.services);
859
+ } catch (error) {
860
+ throw error;
861
+ }
862
+ })
863
+ );
864
+ return allServices;
865
+ }
586
866
  async function getChangeEvents(serviceId, account) {
587
867
  let response;
588
868
  const params = `limit=5&time_zone=UTC&sort_by=timestamp`;
@@ -884,14 +1164,19 @@ exports.createServiceIntegration = createServiceIntegration;
884
1164
  exports.fetchWithRetries = fetchWithRetries;
885
1165
  exports.getAllEscalationPolicies = getAllEscalationPolicies;
886
1166
  exports.getAllServices = getAllServices;
1167
+ exports.getAllTeams = getAllTeams;
887
1168
  exports.getChangeEvents = getChangeEvents;
1169
+ exports.getFilteredServices = getFilteredServices;
888
1170
  exports.getIncidents = getIncidents;
889
1171
  exports.getOncallUsers = getOncallUsers;
1172
+ exports.getSerivcesByIdsAndAccount = getSerivcesByIdsAndAccount;
890
1173
  exports.getServiceById = getServiceById;
891
1174
  exports.getServiceByIntegrationKey = getServiceByIntegrationKey;
892
1175
  exports.getServiceMetrics = getServiceMetrics;
893
1176
  exports.getServiceRelationshipsById = getServiceRelationshipsById;
894
1177
  exports.getServiceStandards = getServiceStandards;
1178
+ exports.getServicesByIds = getServicesByIds;
1179
+ exports.getServicesByPartialName = getServicesByPartialName;
895
1180
  exports.insertAccountConfig = insertAccountConfig;
896
1181
  exports.loadPagerDutyEndpointsFromConfig = loadPagerDutyEndpointsFromConfig;
897
1182
  exports.removeServiceRelationsFromService = removeServiceRelationsFromService;