@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mappings-controller.cjs.js","sources":["../../src/controllers/mappings-controller.ts"],"sourcesContent":["import { Request, Response } from 'express';\nimport * as Pagerduty from '../services/pagerduty';\nimport * as CatalogEntityUtils from '../utils/catalog-entity';\nimport { PagerDutyBackendStore } from '../db';\nimport { CatalogApi, GetEntitiesResponse, QueryEntitiesResponse } from '@backstage/catalog-client';\nimport { HttpError, PagerDutyEntityMappingsResponse, PagerDutyService, FormattedBackstageEntity } from '@pagerduty/backstage-plugin-common';\nimport { getServiceByIntegrationKey, getServicesByIds } from '../apis/pagerduty';\nimport { RawDbEntityResultRow } from '../db/PagerDutyBackendDatabase';\n\n// Status order for sorting (from least to most complete)\nconst STATUS_ORDER: Record<NonNullable<FormattedBackstageEntity['status']>, number> = {\n 'ErrorWhenFetchingService': 0,\n 'NotMapped': 1,\n 'OutOfSync': 2,\n 'InSync': 3,\n};\n\n// Maximum number of entities to fetch when post-processing filters are needed\nconst MAX_ENTITIES_FOR_POST_PROCESSING = 10000;\n\nfunction compareEntities(\n a: FormattedBackstageEntity,\n b: FormattedBackstageEntity,\n column: string,\n direction: 'ascending' | 'descending',\n): number {\n let comparison = 0;\n\n const fieldMap: Record<string, keyof FormattedBackstageEntity> = {\n name: 'name',\n team: 'owner',\n serviceName: 'serviceName',\n status: 'status',\n };\n\n const field = fieldMap[column];\n\n if (field === 'status') {\n const aStatus = (a.status || 'NotMapped') as NonNullable<FormattedBackstageEntity['status']>;\n const bStatus = (b.status || 'NotMapped') as NonNullable<FormattedBackstageEntity['status']>;\n const aOrder = STATUS_ORDER[aStatus];\n const bOrder = STATUS_ORDER[bStatus];\n comparison = aOrder - bOrder;\n } else {\n const aValue = ((a[field] || '') as string).toLowerCase();\n const bValue = ((b[field] || '') as string).toLowerCase();\n\n if (aValue < bValue) {\n comparison = -1;\n } else if (aValue > bValue) {\n comparison = 1;\n }\n }\n\n return direction === 'ascending' ? comparison : -comparison;\n}\n\nexport function getMappingEntities(store: PagerDutyBackendStore, catalogApi: CatalogApi) {\n return async function getMappingEntitiesFunction(request: Request, response: Response) {\n try {\n const { offset = 0, limit = 10, filters = {}, sort, account } = request.body;\n\n if (typeof offset !== 'number' || typeof limit !== 'number' || offset < 0 || limit <= 0) {\n response\n .status(400)\n .json({ errors: [\"Bad Request: 'offset' and 'limit' must be valid numbers\"] });\n\n return;\n }\n\n const validSortColumns = ['name', 'team', 'serviceName', 'status'];\n const validSortDirections = ['ascending', 'descending'];\n\n if (sort !== undefined) {\n if (typeof sort !== 'object' || sort === null) {\n response\n .status(400)\n .json({ errors: [\"Bad Request: 'sort' must be an object\"] });\n return;\n }\n\n if (typeof sort.column !== 'string' || !validSortColumns.includes(sort.column)) {\n response\n .status(400)\n .json({ errors: [`Bad Request: 'sort.column' must be one of: ${validSortColumns.join(', ')}`] });\n return;\n }\n\n if (typeof sort.direction !== 'string' || !validSortDirections.includes(sort.direction)) {\n response\n .status(400)\n .json({ errors: [`Bad Request: 'sort.direction' must be one of: ${validSortDirections.join(', ')}`] });\n return;\n }\n }\n\n const hasStatusFilter = filters?.status?.trim();\n const hasNameFilter = filters?.name?.trim();\n const hasTeamNameFilter = filters?.teamName?.trim();\n const needsBothFullTextFilters = hasNameFilter && hasTeamNameFilter;\n const needsSortPostProcessing = !!sort;\n\n const needsPostProcessing = hasStatusFilter || needsBothFullTextFilters || needsSortPostProcessing;\n\n const queryOptions: {\n filter: Array<{\n kind: string;\n 'metadata.namespace'?: string;\n 'metadata.name'?: string;\n }>;\n limit: number;\n offset: number;\n fullTextFilter?: { term: string; fields: string[] };\n } = {\n filter: [{ kind: 'Component' }],\n limit: needsPostProcessing ? MAX_ENTITIES_FOR_POST_PROCESSING : limit,\n offset: needsPostProcessing ? 0 : offset,\n };\n\n const allEntityMappings = await store.getAllEntityMappings();\n\n if (filters?.serviceName?.trim()) {\n const serviceQuery = filters.serviceName.trim();\n\n const matchingPagerDutyServiceIds = await Pagerduty.getServicesIdsByPartialName(serviceQuery);\n\n if (matchingPagerDutyServiceIds.length > 0) { \n const mappingsWithMatchingPagerdutyServices = allEntityMappings.filter(\n mapping => matchingPagerDutyServiceIds.includes(mapping.serviceId),\n );\n\n const entityRefs: Array<string> =\n mappingsWithMatchingPagerdutyServices\n .map(mapping => mapping.entityRef)\n .filter(Boolean);\n\n if (entityRefs.length > 0) {\n // extract shape of { kind: 'Component', 'metadata.namespace': string, 'metadata.name': string }\n queryOptions.filter = entityRefs.map(_extractQueryFilterFromEntityRef).filter(f => f !== null);\n\n if (queryOptions.filter.length === 0) {\n response.json({ entities: [], totalCount: 0 });\n return;\n }\n } else {\n response.json({ entities: [], totalCount: 0 });\n return;\n }\n } else {\n response.json({ entities: [], totalCount: 0 });\n return;\n }\n }\n\n const componentEntities = await _queryEntitiesWithFilters(\n catalogApi,\n queryOptions,\n filters.name,\n filters.teamName,\n );\n \n const currentPageMappings = allEntityMappings.filter(mapping => {\n return componentEntities.items.some(entity => {\n const entityRef = CatalogEntityUtils.entityRef(entity).toLowerCase();\n\n const integrationKey = CatalogEntityUtils.getPagerDutyIntegrationKey(entity);\n\n return (mapping.entityRef === entityRef || mapping.integrationKey === integrationKey);\n });\n });\n\n const currentPagePagerDutyServiceIds = currentPageMappings.map(mapping => mapping.serviceId).filter(Boolean);\n\n const currentPagePagerDutyServices = await getServicesByIds(currentPagePagerDutyServiceIds);\n\n const componentEntitiesDict =\n await CatalogEntityUtils.createComponentEntitiesReferenceDict(componentEntities);\n\n const maps = await _buildEntityMappingsResponse(\n allEntityMappings,\n componentEntitiesDict,\n componentEntities,\n currentPagePagerDutyServices,\n );\n\n let formattedEntities: Array<FormattedBackstageEntity> = await Promise.all(\n componentEntities.items.map(async entity => {\n const annotations = {\n 'pagerduty.com/integration-key': CatalogEntityUtils.getPagerDutyIntegrationKey(entity) ?? '',\n 'pagerduty.com/service-id': CatalogEntityUtils.getPagerDutyServiceId(entity) ?? '',\n };\n\n const formattedEntity = {\n name: entity.metadata?.name,\n id: entity.metadata?.uid ?? '',\n namespace: entity.metadata?.namespace ?? '',\n type: entity.kind ?? '',\n system: entity.spec?.system ? JSON.stringify(entity.spec?.system) : '',\n owner: entity.spec?.owner ? JSON.stringify(entity.spec?.owner) : '',\n lifecycle: entity.spec?.lifecycle ? JSON.stringify(entity.spec?.lifecycle) : '',\n annotations,\n status: 'NotMapped' as NonNullable<FormattedBackstageEntity['status']>,\n serviceName: '',\n serviceUrl: '',\n team: '',\n escalationPolicy: '',\n account: '',\n };\n\n // Try to find a service by service ID or integration key\n let service = null;\n let isServiceError = null;\n\n if (annotations['pagerduty.com/service-id']) {\n const serviceId = annotations['pagerduty.com/service-id'];\n service = currentPagePagerDutyServices.find(s => s.id === serviceId);\n } else if (annotations['pagerduty.com/integration-key']) {\n const integrationKey = annotations['pagerduty.com/integration-key'];\n const entityAccount = entity.metadata?.annotations?.['pagerduty.com/account'] || '';\n\n try {\n service = await getServiceByIntegrationKey(integrationKey, entityAccount);\n } catch (e) {\n if (e instanceof HttpError && e.status !== 404) {\n isServiceError = true;\n }\n }\n }\n\n const entityRef = CatalogEntityUtils.entityRef(entity).toLowerCase();\n\n const entityMapping = maps.mappings.find(\n mapping =>\n mapping.entityRef === entityRef ||\n (mapping.integrationKey && mapping.integrationKey === annotations['pagerduty.com/integration-key']) ||\n (mapping.serviceId && mapping.serviceId === annotations['pagerduty.com/service-id']),\n );\n\n if (service) {\n formattedEntity.serviceName = service.name;\n formattedEntity.serviceUrl = service.html_url;\n formattedEntity.team = service.teams?.[0]?.name ?? '';\n formattedEntity.escalationPolicy = service.escalation_policy?.name ?? '';\n formattedEntity.account = service.account || '';\n\n if (entityMapping) {\n const expectedEntityRef = componentEntitiesDict[service.id]?.ref;\n\n if (expectedEntityRef && expectedEntityRef === entityMapping.entityRef) {\n formattedEntity.status = \n (entityMapping.status || 'NotMapped') as NonNullable<FormattedBackstageEntity['status']>;\n } else {\n formattedEntity.status = 'NotMapped' as NonNullable<FormattedBackstageEntity['status']>;\n }\n }\n } else if (isServiceError) {\n formattedEntity.status = 'ErrorWhenFetchingService';\n }\n\n return formattedEntity;\n }),\n );\n\n if (hasStatusFilter) {\n formattedEntities = formattedEntities.filter(entity => entity.status === filters.status.trim());\n }\n\n if (account) {\n formattedEntities = formattedEntities.filter(entity => {\n const entityRef = CatalogEntityUtils.entityRef({\n kind: entity.type,\n metadata: { name: entity.name, namespace: entity.namespace }\n }).toLowerCase();\n\n const entityMapping = allEntityMappings.find(\n mapping => mapping.entityRef === entityRef\n );\n\n return entityMapping ? entityMapping.account === account : true;\n });\n }\n\n if (sort) {\n formattedEntities.sort((a, b) => compareEntities(a, b, sort.column, sort.direction));\n }\n\n const totalCount = needsPostProcessing ? formattedEntities.length : componentEntities.totalItems;\n\n const paginatedEntities = needsPostProcessing\n ? formattedEntities.slice(offset, offset + limit)\n : formattedEntities;\n\n response.json({\n entities: paginatedEntities,\n totalCount,\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\nfunction _extractQueryFilterFromEntityRef(entityRef: string) {\n const [, namespaceAndName] = entityRef.split(':');\n\n if (!namespaceAndName) {\n return null;\n }\n\n const [namespace, name] = namespaceAndName.split('/');\n\n return {\n kind: 'Component',\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n };\n}\n\nasync function _queryEntitiesWithFilters(\n catalog: CatalogApi,\n baseQueryOptions: {\n filter: Array<{\n kind: string;\n 'metadata.namespace'?: string;\n 'metadata.name'?: string;\n }>;\n limit: number;\n offset: number;\n },\n nameFilter?: string,\n teamNameFilter?: string,\n): Promise<QueryEntitiesResponse> {\n const hasNameFilter = nameFilter?.trim();\n const hasTeamNameFilter = teamNameFilter?.trim();\n\n if (hasNameFilter && hasTeamNameFilter) {\n const [nameResults, teamResults] = await Promise.all([\n catalog.queryEntities({\n ...baseQueryOptions,\n fullTextFilter: {\n term: hasNameFilter,\n fields: ['metadata.name'],\n },\n }),\n catalog.queryEntities({\n ...baseQueryOptions,\n fullTextFilter: {\n term: hasTeamNameFilter,\n fields: ['spec.owner'],\n },\n }),\n ]);\n\n const nameResultUids = new Set(nameResults.items.map(entity => entity.metadata?.uid).filter(Boolean));\n\n const intersectedEntities = teamResults.items.filter(entity => nameResultUids.has(entity.metadata?.uid));\n\n return {\n items: intersectedEntities,\n totalItems: intersectedEntities.length,\n pageInfo: teamResults.pageInfo,\n };\n }\n\n const queryOptions: {\n filter: Array<{\n kind: string;\n 'metadata.namespace'?: string;\n 'metadata.name'?: string;\n }>;\n limit: number;\n offset: number;\n fullTextFilter?: { term: string; fields: string[] };\n } = { ...baseQueryOptions };\n\n if (hasNameFilter) {\n queryOptions.fullTextFilter = {\n term: hasNameFilter,\n fields: ['metadata.name'],\n };\n } else if (hasTeamNameFilter) {\n queryOptions.fullTextFilter = {\n term: hasTeamNameFilter,\n fields: ['spec.owner'],\n };\n }\n\n return catalog.queryEntities(queryOptions);\n}\n\nasync function _buildEntityMappingsResponse(\n entityMappings: RawDbEntityResultRow[],\n componentEntitiesDict: Record<string, { ref: string; name: string; }>,\n componentEntities: GetEntitiesResponse,\n pagerDutyServices: PagerDutyService[],\n): Promise<PagerDutyEntityMappingsResponse> {\n const result: PagerDutyEntityMappingsResponse = {\n mappings: [],\n };\n\n pagerDutyServices.forEach(service => {\n const entityRef = componentEntitiesDict[service.id]?.ref;\n const entityName = componentEntitiesDict[service.id]?.name;\n\n const entityMapping = entityMappings.find(mapping => mapping.serviceId === service.id);\n\n if (entityMapping) {\n if (entityRef === undefined) {\n if (entityMapping.entityRef === '' ||entityMapping.entityRef === undefined) {\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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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: 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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n } else if (entityRef === entityMapping.entityRef) {\n result.mappings.push({\n entityRef: 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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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"],"names":["Pagerduty.getServicesIdsByPartialName","CatalogEntityUtils.entityRef","CatalogEntityUtils.getPagerDutyIntegrationKey","getServicesByIds","CatalogEntityUtils.createComponentEntitiesReferenceDict","CatalogEntityUtils.getPagerDutyServiceId","getServiceByIntegrationKey","HttpError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mappings-controller.cjs.js","sources":["../../src/controllers/mappings-controller.ts"],"sourcesContent":["import { Request, Response } from 'express';\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport * as Pagerduty from '../services/pagerduty';\nimport * as CatalogEntityUtils from '../utils/catalog-entity';\nimport { PagerDutyBackendStore } from '../db';\nimport { CatalogApi, GetEntitiesResponse, QueryEntitiesResponse } from '@backstage/catalog-client';\nimport { HttpError, PagerDutyEntityMappingsResponse, PagerDutyService, FormattedBackstageEntity } from '@pagerduty/backstage-plugin-common';\nimport { getServiceByIntegrationKey, getServicesByIds, isValidServiceId } from '../apis/pagerduty';\nimport { RawDbEntityResultRow } from '../db/PagerDutyBackendDatabase';\n\n// Status order for sorting (from least to most complete)\nconst STATUS_ORDER: Record<NonNullable<FormattedBackstageEntity['status']>, number> = {\n 'ErrorWhenFetchingService': 0,\n 'NotMapped': 1,\n 'OutOfSync': 2,\n 'InSync': 3,\n};\n\n// Maximum number of entities to fetch when post-processing filters are needed\nconst MAX_ENTITIES_FOR_POST_PROCESSING = 10000;\n\nfunction compareEntities(\n a: FormattedBackstageEntity,\n b: FormattedBackstageEntity,\n column: string,\n direction: 'ascending' | 'descending',\n): number {\n let comparison = 0;\n\n const fieldMap: Record<string, keyof FormattedBackstageEntity> = {\n name: 'name',\n team: 'owner',\n serviceName: 'serviceName',\n status: 'status',\n };\n\n const field = fieldMap[column];\n\n if (field === 'status') {\n const aStatus = (a.status || 'NotMapped') as NonNullable<FormattedBackstageEntity['status']>;\n const bStatus = (b.status || 'NotMapped') as NonNullable<FormattedBackstageEntity['status']>;\n const aOrder = STATUS_ORDER[aStatus];\n const bOrder = STATUS_ORDER[bStatus];\n comparison = aOrder - bOrder;\n } else {\n const aValue = ((a[field] || '') as string).toLowerCase();\n const bValue = ((b[field] || '') as string).toLowerCase();\n\n if (aValue < bValue) {\n comparison = -1;\n } else if (aValue > bValue) {\n comparison = 1;\n }\n }\n\n return direction === 'ascending' ? comparison : -comparison;\n}\n\nexport function getMappingEntities(\n store: PagerDutyBackendStore,\n catalogApi: CatalogApi,\n logger?: LoggerService,\n) {\n return async function getMappingEntitiesFunction(request: Request, response: Response) {\n try {\n const { offset = 0, limit = 10, filters = {}, sort, account } = request.body;\n\n if (typeof offset !== 'number' || typeof limit !== 'number' || offset < 0 || limit <= 0) {\n response\n .status(400)\n .json({ errors: [\"Bad Request: 'offset' and 'limit' must be valid numbers\"] });\n\n return;\n }\n\n const validSortColumns = ['name', 'team', 'serviceName', 'status'];\n const validSortDirections = ['ascending', 'descending'];\n\n if (sort !== undefined) {\n if (typeof sort !== 'object' || sort === null) {\n response\n .status(400)\n .json({ errors: [\"Bad Request: 'sort' must be an object\"] });\n return;\n }\n\n if (typeof sort.column !== 'string' || !validSortColumns.includes(sort.column)) {\n response\n .status(400)\n .json({ errors: [`Bad Request: 'sort.column' must be one of: ${validSortColumns.join(', ')}`] });\n return;\n }\n\n if (typeof sort.direction !== 'string' || !validSortDirections.includes(sort.direction)) {\n response\n .status(400)\n .json({ errors: [`Bad Request: 'sort.direction' must be one of: ${validSortDirections.join(', ')}`] });\n return;\n }\n }\n\n const hasStatusFilter = filters?.status?.trim();\n const hasNameFilter = filters?.name?.trim();\n const hasTeamNameFilter = filters?.teamName?.trim();\n const needsBothFullTextFilters = hasNameFilter && hasTeamNameFilter;\n const needsSortPostProcessing = !!sort;\n\n const needsPostProcessing = hasStatusFilter || needsBothFullTextFilters || needsSortPostProcessing;\n\n const queryOptions: {\n filter: Array<{\n kind: string;\n 'metadata.namespace'?: string;\n 'metadata.name'?: string;\n }>;\n limit: number;\n offset: number;\n fullTextFilter?: { term: string; fields: string[] };\n } = {\n filter: [{ kind: 'Component' }],\n limit: needsPostProcessing ? MAX_ENTITIES_FOR_POST_PROCESSING : limit,\n offset: needsPostProcessing ? 0 : offset,\n };\n\n const allEntityMappings = await store.getAllEntityMappings();\n\n if (filters?.serviceName?.trim()) {\n const serviceQuery = filters.serviceName.trim();\n\n const matchingPagerDutyServiceIds = await Pagerduty.getServicesIdsByPartialName(serviceQuery);\n\n if (matchingPagerDutyServiceIds.length > 0) { \n const mappingsWithMatchingPagerdutyServices = allEntityMappings.filter(\n mapping => matchingPagerDutyServiceIds.includes(mapping.serviceId),\n );\n\n const entityRefs: Array<string> =\n mappingsWithMatchingPagerdutyServices\n .map(mapping => mapping.entityRef)\n .filter(Boolean);\n\n if (entityRefs.length > 0) {\n // extract shape of { kind: 'Component', 'metadata.namespace': string, 'metadata.name': string }\n queryOptions.filter = entityRefs.map(_extractQueryFilterFromEntityRef).filter(f => f !== null);\n\n if (queryOptions.filter.length === 0) {\n response.json({ entities: [], totalCount: 0 });\n return;\n }\n } else {\n response.json({ entities: [], totalCount: 0 });\n return;\n }\n } else {\n response.json({ entities: [], totalCount: 0 });\n return;\n }\n }\n\n const componentEntities = await _queryEntitiesWithFilters(\n catalogApi,\n queryOptions,\n filters.name,\n filters.teamName,\n );\n \n const currentPageMappings = allEntityMappings.filter(mapping => {\n return componentEntities.items.some(entity => {\n const entityRef = CatalogEntityUtils.entityRef(entity).toLowerCase();\n\n const integrationKey = CatalogEntityUtils.getPagerDutyIntegrationKey(entity);\n\n return (mapping.entityRef === entityRef || mapping.integrationKey === integrationKey);\n });\n });\n\n // Collect the PagerDuty service ids we need to resolve for this page from\n // both the stored mappings and the service-id annotations on the\n // current-page entities (an entity can carry an annotation without a DB\n // mapping yet).\n const rawPagerDutyServiceIds = [\n ...currentPageMappings.map(mapping => mapping.serviceId),\n ...componentEntities.items.map(entity =>\n CatalogEntityUtils.getPagerDutyServiceId(entity),\n ),\n ].filter(Boolean) as string[];\n\n // Service ids come from user-authored annotations / stored mappings, so a\n // malformed value (pasted URL, whitespace, typo) can appear. getServicesByIds\n // sanitizes again before calling PagerDuty, but surface a warning here so the\n // operator can fix the offending entity annotation. De-duplicate first so each\n // id is fetched and warned about at most once.\n const uniqueTrimmedServiceIds = Array.from(\n new Set(rawPagerDutyServiceIds.map(id => id.trim())),\n );\n\n const currentPagePagerDutyServiceIds = uniqueTrimmedServiceIds.filter(id => {\n if (isValidServiceId(id)) {\n return true;\n }\n logger?.warn(\n `Ignoring malformed PagerDuty service id \"${id}\" while building entity mappings`,\n );\n return false;\n });\n\n const currentPagePagerDutyServices = await getServicesByIds(currentPagePagerDutyServiceIds);\n\n const componentEntitiesDict =\n await CatalogEntityUtils.createComponentEntitiesReferenceDict(componentEntities);\n\n const maps = await _buildEntityMappingsResponse(\n allEntityMappings,\n componentEntitiesDict,\n componentEntities,\n currentPagePagerDutyServices,\n );\n\n let formattedEntities: Array<FormattedBackstageEntity> = await Promise.all(\n componentEntities.items.map(async entity => {\n const annotations = {\n 'pagerduty.com/integration-key': CatalogEntityUtils.getPagerDutyIntegrationKey(entity) ?? '',\n 'pagerduty.com/service-id': CatalogEntityUtils.getPagerDutyServiceId(entity) ?? '',\n };\n\n const formattedEntity = {\n name: entity.metadata?.name,\n id: entity.metadata?.uid ?? '',\n namespace: entity.metadata?.namespace ?? '',\n type: entity.kind ?? '',\n system: entity.spec?.system ? JSON.stringify(entity.spec?.system) : '',\n owner: entity.spec?.owner ? JSON.stringify(entity.spec?.owner) : '',\n lifecycle: entity.spec?.lifecycle ? JSON.stringify(entity.spec?.lifecycle) : '',\n annotations,\n status: 'NotMapped' as NonNullable<FormattedBackstageEntity['status']>,\n serviceName: '',\n serviceUrl: '',\n team: '',\n escalationPolicy: '',\n account: '',\n };\n\n const entityRef = CatalogEntityUtils.entityRef(entity).toLowerCase();\n\n const entityMapping = maps.mappings.find(\n mapping =>\n mapping.entityRef === entityRef ||\n (mapping.integrationKey && mapping.integrationKey === annotations['pagerduty.com/integration-key']) ||\n (mapping.serviceId && mapping.serviceId === annotations['pagerduty.com/service-id']),\n );\n\n // Try to find a service by service ID or integration key\n let service = null;\n let isServiceError = null;\n // Tracks whether the service was resolved from a stored DB mapping\n // rather than from the entity's own annotations.\n let resolvedFromMapping = false;\n\n if (annotations['pagerduty.com/service-id']) {\n const serviceId = annotations['pagerduty.com/service-id'];\n service = currentPagePagerDutyServices.find(s => s.id === serviceId);\n } else if (annotations['pagerduty.com/integration-key']) {\n const integrationKey = annotations['pagerduty.com/integration-key'];\n const entityAccount = entity.metadata?.annotations?.['pagerduty.com/account'] || '';\n\n try {\n service = await getServiceByIntegrationKey(integrationKey, entityAccount);\n } catch (e) {\n if (e instanceof HttpError && e.status !== 404) {\n isServiceError = true;\n }\n }\n }\n\n // The entity's annotations are written back asynchronously by the\n // entity processor after a mapping is created, so a freshly-created\n // mapping has a DB row but no annotation yet. When we matched a stored\n // mapping by entityRef but couldn't resolve the service from the\n // (still-empty) annotations, fall back to the mapping's serviceId so\n // the mapping shows up immediately rather than waiting for the next\n // catalog processing cycle.\n if (\n !service &&\n !isServiceError &&\n entityMapping?.entityRef === entityRef &&\n entityMapping?.serviceId\n ) {\n service = currentPagePagerDutyServices.find(\n s => s.id === entityMapping.serviceId,\n );\n resolvedFromMapping = !!service;\n }\n\n if (service) {\n formattedEntity.serviceName = service.name;\n formattedEntity.serviceUrl = service.html_url;\n formattedEntity.team = service.teams?.[0]?.name ?? '';\n formattedEntity.escalationPolicy = service.escalation_policy?.name ?? '';\n formattedEntity.account = service.account || '';\n\n if (entityMapping) {\n // When resolved from the stored mapping, the mapping's entityRef\n // already equals this entity's ref (that's how it was matched), so\n // trust the mapping's status directly. Otherwise validate against\n // the annotation-derived ref to guard against a stale mapping that\n // points the service at a different entity.\n const expectedEntityRef = resolvedFromMapping\n ? entityMapping.entityRef\n : componentEntitiesDict[service.id]?.ref;\n\n if (expectedEntityRef && expectedEntityRef === entityMapping.entityRef) {\n formattedEntity.status =\n (entityMapping.status || 'NotMapped') as NonNullable<FormattedBackstageEntity['status']>;\n } else {\n formattedEntity.status = 'NotMapped' as NonNullable<FormattedBackstageEntity['status']>;\n }\n }\n } else if (isServiceError) {\n formattedEntity.status = 'ErrorWhenFetchingService';\n }\n\n return formattedEntity;\n }),\n );\n\n if (hasStatusFilter) {\n formattedEntities = formattedEntities.filter(entity => entity.status === filters.status.trim());\n }\n\n if (account) {\n formattedEntities = formattedEntities.filter(entity => {\n const entityRef = CatalogEntityUtils.entityRef({\n kind: entity.type,\n metadata: { name: entity.name, namespace: entity.namespace }\n }).toLowerCase();\n\n const entityMapping = allEntityMappings.find(\n mapping => mapping.entityRef === entityRef\n );\n\n return entityMapping ? entityMapping.account === account : true;\n });\n }\n\n if (sort) {\n formattedEntities.sort((a, b) => compareEntities(a, b, sort.column, sort.direction));\n }\n\n const totalCount = needsPostProcessing ? formattedEntities.length : componentEntities.totalItems;\n\n const paginatedEntities = needsPostProcessing\n ? formattedEntities.slice(offset, offset + limit)\n : formattedEntities;\n\n response.json({\n entities: paginatedEntities,\n totalCount,\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\nfunction _extractQueryFilterFromEntityRef(entityRef: string) {\n const [, namespaceAndName] = entityRef.split(':');\n\n if (!namespaceAndName) {\n return null;\n }\n\n const [namespace, name] = namespaceAndName.split('/');\n\n return {\n kind: 'Component',\n 'metadata.namespace': namespace,\n 'metadata.name': name,\n };\n}\n\nasync function _queryEntitiesWithFilters(\n catalog: CatalogApi,\n baseQueryOptions: {\n filter: Array<{\n kind: string;\n 'metadata.namespace'?: string;\n 'metadata.name'?: string;\n }>;\n limit: number;\n offset: number;\n },\n nameFilter?: string,\n teamNameFilter?: string,\n): Promise<QueryEntitiesResponse> {\n const hasNameFilter = nameFilter?.trim();\n const hasTeamNameFilter = teamNameFilter?.trim();\n\n if (hasNameFilter && hasTeamNameFilter) {\n const [nameResults, teamResults] = await Promise.all([\n catalog.queryEntities({\n ...baseQueryOptions,\n fullTextFilter: {\n term: hasNameFilter,\n fields: ['metadata.name'],\n },\n }),\n catalog.queryEntities({\n ...baseQueryOptions,\n fullTextFilter: {\n term: hasTeamNameFilter,\n fields: ['spec.owner'],\n },\n }),\n ]);\n\n const nameResultUids = new Set(nameResults.items.map(entity => entity.metadata?.uid).filter(Boolean));\n\n const intersectedEntities = teamResults.items.filter(entity => nameResultUids.has(entity.metadata?.uid));\n\n return {\n items: intersectedEntities,\n totalItems: intersectedEntities.length,\n pageInfo: teamResults.pageInfo,\n };\n }\n\n const queryOptions: {\n filter: Array<{\n kind: string;\n 'metadata.namespace'?: string;\n 'metadata.name'?: string;\n }>;\n limit: number;\n offset: number;\n fullTextFilter?: { term: string; fields: string[] };\n } = { ...baseQueryOptions };\n\n if (hasNameFilter) {\n queryOptions.fullTextFilter = {\n term: hasNameFilter,\n fields: ['metadata.name'],\n };\n } else if (hasTeamNameFilter) {\n queryOptions.fullTextFilter = {\n term: hasTeamNameFilter,\n fields: ['spec.owner'],\n };\n }\n\n return catalog.queryEntities(queryOptions);\n}\n\nasync function _buildEntityMappingsResponse(\n entityMappings: RawDbEntityResultRow[],\n componentEntitiesDict: Record<string, { ref: string; name: string; }>,\n componentEntities: GetEntitiesResponse,\n pagerDutyServices: PagerDutyService[],\n): Promise<PagerDutyEntityMappingsResponse> {\n const result: PagerDutyEntityMappingsResponse = {\n mappings: [],\n };\n\n pagerDutyServices.forEach(service => {\n const entityRef = componentEntitiesDict[service.id]?.ref;\n const entityName = componentEntitiesDict[service.id]?.name;\n\n const entityMapping = entityMappings.find(mapping => mapping.serviceId === service.id);\n\n if (entityMapping) {\n if (entityRef === undefined) {\n if (entityMapping.entityRef === '' ||entityMapping.entityRef === undefined) {\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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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: 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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\n serviceUrl: service.html_url,\n account: service.account,\n });\n } else if (entityRef === entityMapping.entityRef) {\n result.mappings.push({\n entityRef: 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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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: service.escalation_policy !== undefined ? service.escalation_policy.name : '',\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"],"names":["Pagerduty.getServicesIdsByPartialName","CatalogEntityUtils.entityRef","CatalogEntityUtils.getPagerDutyIntegrationKey","CatalogEntityUtils.getPagerDutyServiceId","isValidServiceId","getServicesByIds","CatalogEntityUtils.createComponentEntitiesReferenceDict","getServiceByIntegrationKey","HttpError"],"mappings":"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"}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var uuid = require('uuid');
|
|
5
5
|
|
|
6
|
+
const ERROR_SEVERITY_CODES = ["PD_API_ERROR"];
|
|
7
|
+
const INFO_SEVERITY_CODES = ["SYNC_SUCCESS"];
|
|
6
8
|
class PagerDutyBackendDatabase {
|
|
7
9
|
constructor(db) {
|
|
8
10
|
this.db = db;
|
|
@@ -45,10 +47,16 @@ class PagerDutyBackendDatabase {
|
|
|
45
47
|
integrationKey: entity.integrationKey,
|
|
46
48
|
account: entity.account
|
|
47
49
|
}));
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
const CHUNK_SIZE = 200;
|
|
51
|
+
await this.db.transaction(async (trx) => {
|
|
52
|
+
for (let i = 0; i < rows.length; i += CHUNK_SIZE) {
|
|
53
|
+
const chunk = rows.slice(i, i + CHUNK_SIZE);
|
|
54
|
+
await trx("pagerduty_entity_mapping").insert(
|
|
55
|
+
chunk
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return rows.map((r) => r.id);
|
|
52
60
|
}
|
|
53
61
|
async getAllEntityMappings() {
|
|
54
62
|
const rawEntities = await this.db(
|
|
@@ -89,6 +97,196 @@ class PagerDutyBackendDatabase {
|
|
|
89
97
|
}
|
|
90
98
|
return rawEntities;
|
|
91
99
|
}
|
|
100
|
+
toBackstageCustomField(row) {
|
|
101
|
+
return {
|
|
102
|
+
...row,
|
|
103
|
+
pagerdutyCustomFieldEnabled: Boolean(row.pagerdutyCustomFieldEnabled)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async insertCustomField(customField) {
|
|
107
|
+
await this.db("pagerduty_custom_fields").insert({
|
|
108
|
+
pagerdutyCustomFieldId: customField.pagerdutyCustomFieldId,
|
|
109
|
+
pagerdutyCustomFieldDisplayName: customField.pagerdutyCustomFieldDisplayName,
|
|
110
|
+
pagerdutyCustomFieldEnabled: customField.pagerdutyCustomFieldEnabled,
|
|
111
|
+
backstageEntityMappingPath: customField.backstageEntityMappingPath,
|
|
112
|
+
pagerdutySubdomain: customField.pagerdutySubdomain,
|
|
113
|
+
description: customField.description
|
|
114
|
+
});
|
|
115
|
+
const result = await this.db(
|
|
116
|
+
"pagerduty_custom_fields"
|
|
117
|
+
).where({
|
|
118
|
+
pagerdutyCustomFieldId: customField.pagerdutyCustomFieldId,
|
|
119
|
+
pagerdutySubdomain: customField.pagerdutySubdomain
|
|
120
|
+
}).orderBy("createdAt", "desc").first();
|
|
121
|
+
if (!result) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"Failed to retrieve custom field after insert into pagerduty_custom_fields"
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return this.toBackstageCustomField(result);
|
|
127
|
+
}
|
|
128
|
+
async findCustomFieldById(id) {
|
|
129
|
+
const result = await this.db("pagerduty_custom_fields").where("id", id).first();
|
|
130
|
+
if (!result) return void 0;
|
|
131
|
+
return this.toBackstageCustomField(result);
|
|
132
|
+
}
|
|
133
|
+
async updateCustomField(id, updates) {
|
|
134
|
+
const rowsAffected = await this.db("pagerduty_custom_fields").where("id", id).update({
|
|
135
|
+
pagerdutyCustomFieldDisplayName: updates.pagerdutyCustomFieldDisplayName,
|
|
136
|
+
backstageEntityMappingPath: updates.backstageEntityMappingPath,
|
|
137
|
+
description: updates.description,
|
|
138
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
139
|
+
});
|
|
140
|
+
if (rowsAffected === 0) {
|
|
141
|
+
throw new Error(`Custom field with id ${id} does not exist`);
|
|
142
|
+
}
|
|
143
|
+
const result = await this.db("pagerduty_custom_fields").where("id", id).first();
|
|
144
|
+
if (!result) {
|
|
145
|
+
throw new Error(`Failed to retrieve custom field after update for id: ${id}`);
|
|
146
|
+
}
|
|
147
|
+
return this.toBackstageCustomField(result);
|
|
148
|
+
}
|
|
149
|
+
async setCustomFieldEnabled(id, enabled) {
|
|
150
|
+
const rowsAffected = await this.db("pagerduty_custom_fields").where("id", id).update({
|
|
151
|
+
pagerdutyCustomFieldEnabled: enabled,
|
|
152
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
153
|
+
});
|
|
154
|
+
if (rowsAffected === 0) {
|
|
155
|
+
throw new Error(`Custom field with id ${id} does not exist`);
|
|
156
|
+
}
|
|
157
|
+
const result = await this.db("pagerduty_custom_fields").where("id", id).first();
|
|
158
|
+
if (!result) {
|
|
159
|
+
throw new Error(`Failed to retrieve custom field after update for id: ${id}`);
|
|
160
|
+
}
|
|
161
|
+
return this.toBackstageCustomField(result);
|
|
162
|
+
}
|
|
163
|
+
async getAllCustomFields(subdomain, options = {}) {
|
|
164
|
+
const query = this.db("pagerduty_custom_fields").where(
|
|
165
|
+
"pagerdutySubdomain",
|
|
166
|
+
subdomain
|
|
167
|
+
);
|
|
168
|
+
if (options.enabled !== void 0) {
|
|
169
|
+
query.where("pagerdutyCustomFieldEnabled", options.enabled);
|
|
170
|
+
}
|
|
171
|
+
const rawFields = await query;
|
|
172
|
+
if (!rawFields) {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
return rawFields.map((field) => this.toBackstageCustomField(field));
|
|
176
|
+
}
|
|
177
|
+
async deleteCustomField(id) {
|
|
178
|
+
await this.db("pagerduty_custom_fields").where("id", id).delete();
|
|
179
|
+
}
|
|
180
|
+
async updateCustomFieldPagerDutyId(id, pagerdutyCustomFieldId) {
|
|
181
|
+
await this.db("pagerduty_custom_fields").where("id", id).update({
|
|
182
|
+
pagerdutyCustomFieldId,
|
|
183
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
async insertSyncLog(log) {
|
|
187
|
+
await this.db("pagerduty_custom_field_sync_logs").insert({
|
|
188
|
+
errorCode: log.errorCode,
|
|
189
|
+
customFieldId: log.customFieldId,
|
|
190
|
+
customFieldName: log.customFieldName,
|
|
191
|
+
entityPath: log.entityPath,
|
|
192
|
+
serviceId: log.serviceId,
|
|
193
|
+
serviceName: log.serviceName,
|
|
194
|
+
errorMessage: log.errorMessage,
|
|
195
|
+
subdomain: log.subdomain
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async getSyncLogs(subdomain, options) {
|
|
199
|
+
const limit = options?.limit ?? 100;
|
|
200
|
+
const offset = options?.offset ?? 0;
|
|
201
|
+
const baseQuery = () => {
|
|
202
|
+
let q = this.db("pagerduty_custom_field_sync_logs").where("subdomain", subdomain);
|
|
203
|
+
if (options?.severity === "error") {
|
|
204
|
+
q = q.where(
|
|
205
|
+
(builder) => builder.whereIn("errorCode", [...ERROR_SEVERITY_CODES]).orWhereRaw("LOWER(??) LIKE ?", ["errorCode", "%error%"])
|
|
206
|
+
);
|
|
207
|
+
} else if (options?.severity === "info") {
|
|
208
|
+
q = q.whereIn("errorCode", [...INFO_SEVERITY_CODES]);
|
|
209
|
+
} else if (options?.severity === "warning") {
|
|
210
|
+
q = q.whereNotIn("errorCode", [...ERROR_SEVERITY_CODES]).whereNotIn("errorCode", [...INFO_SEVERITY_CODES]).whereRaw("LOWER(??) NOT LIKE ?", ["errorCode", "%error%"]);
|
|
211
|
+
}
|
|
212
|
+
if (options?.customFieldName) {
|
|
213
|
+
q = q.where("customFieldName", options.customFieldName);
|
|
214
|
+
}
|
|
215
|
+
if (options?.entityPath) {
|
|
216
|
+
q = q.where("entityPath", options.entityPath);
|
|
217
|
+
}
|
|
218
|
+
if (options?.serviceName) {
|
|
219
|
+
q = q.where("serviceName", options.serviceName);
|
|
220
|
+
}
|
|
221
|
+
if (options?.search) {
|
|
222
|
+
const pattern = `%${options.search.toLowerCase()}%`;
|
|
223
|
+
q = q.where(
|
|
224
|
+
(builder) => builder.whereRaw("LOWER(??) LIKE ?", ["errorMessage", pattern]).orWhereRaw("LOWER(??) LIKE ?", ["customFieldName", pattern]).orWhereRaw("LOWER(??) LIKE ?", ["entityPath", pattern]).orWhereRaw("LOWER(??) LIKE ?", ["serviceName", pattern]).orWhereRaw("LOWER(??) LIKE ?", ["errorCode", pattern])
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
return q;
|
|
228
|
+
};
|
|
229
|
+
const [logs, countResult, customFields, entityPaths, services] = await Promise.all([
|
|
230
|
+
baseQuery().orderBy("timestamp", "desc").limit(limit).offset(offset),
|
|
231
|
+
baseQuery().count("* as count").first(),
|
|
232
|
+
this.db("pagerduty_custom_field_sync_logs").where("subdomain", subdomain).whereNotNull("customFieldName").distinct("customFieldName").orderBy("customFieldName", "asc"),
|
|
233
|
+
this.db("pagerduty_custom_field_sync_logs").where("subdomain", subdomain).whereNotNull("entityPath").distinct("entityPath").orderBy("entityPath", "asc"),
|
|
234
|
+
this.db("pagerduty_custom_field_sync_logs").where("subdomain", subdomain).whereNotNull("serviceName").distinct("serviceName").orderBy("serviceName", "asc")
|
|
235
|
+
]);
|
|
236
|
+
const total = countResult ? Number(countResult.count) : 0;
|
|
237
|
+
return {
|
|
238
|
+
logs: logs || [],
|
|
239
|
+
total,
|
|
240
|
+
customFieldNames: customFields.map((r) => r.customFieldName).filter(Boolean),
|
|
241
|
+
entityPaths: entityPaths.map((r) => r.entityPath).filter(Boolean),
|
|
242
|
+
serviceNames: services.map((r) => r.serviceName).filter(Boolean)
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
async cleanupSyncLogs(options) {
|
|
246
|
+
const { olderThanDays, maxRows, batchSize, maxBatchesPerRun } = options;
|
|
247
|
+
const table = "pagerduty_custom_field_sync_logs";
|
|
248
|
+
const result = {
|
|
249
|
+
deletedByAge: 0,
|
|
250
|
+
deletedByCap: 0,
|
|
251
|
+
batchesUsed: 0
|
|
252
|
+
};
|
|
253
|
+
const newest = await this.db(table).max("id as id").first();
|
|
254
|
+
if (!newest?.id) {
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
const BATCH_SLEEP_MS = 50;
|
|
258
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
259
|
+
const cutoff = new Date(Date.now() - olderThanDays * 24 * 60 * 60 * 1e3).toISOString().replace("T", " ").replace(/\.\d+Z$/, "");
|
|
260
|
+
const deleteBatch = async (filter) => {
|
|
261
|
+
const subquery = this.db(table).select("id").orderBy("id", "asc").limit(batchSize);
|
|
262
|
+
filter(subquery);
|
|
263
|
+
return this.db(table).whereIn("id", subquery).delete();
|
|
264
|
+
};
|
|
265
|
+
while (result.batchesUsed < maxBatchesPerRun) {
|
|
266
|
+
const deleted = await deleteBatch((q) => q.where("timestamp", "<", cutoff));
|
|
267
|
+
result.deletedByAge += deleted;
|
|
268
|
+
result.batchesUsed += 1;
|
|
269
|
+
if (deleted < batchSize) {
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
await sleep(BATCH_SLEEP_MS);
|
|
273
|
+
}
|
|
274
|
+
const threshold = await this.db(table).select("id").orderBy("id", "desc").offset(maxRows).limit(1).first();
|
|
275
|
+
if (threshold) {
|
|
276
|
+
while (result.batchesUsed < maxBatchesPerRun) {
|
|
277
|
+
const deleted = await deleteBatch(
|
|
278
|
+
(q) => q.where("id", "<=", threshold.id)
|
|
279
|
+
);
|
|
280
|
+
result.deletedByCap += deleted;
|
|
281
|
+
result.batchesUsed += 1;
|
|
282
|
+
if (deleted < batchSize) {
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
await sleep(BATCH_SLEEP_MS);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
92
290
|
}
|
|
93
291
|
|
|
94
292
|
exports.PagerDutyBackendDatabase = PagerDutyBackendDatabase;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PagerDutyBackendDatabase.cjs.js","sources":["../../src/db/PagerDutyBackendDatabase.ts"],"sourcesContent":["import {\n PagerDutyEntityMapping,\n PagerDutySetting,\n} from '@pagerduty/backstage-plugin-common';\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\n\nexport type RawDbEntityResultRow = {\n id: string;\n entityRef: string;\n serviceId: string;\n integrationKey: string;\n account?: string;\n processedDate?: Date;\n};\n\n/** @public */\nexport interface PagerDutyBackendStore {\n insertEntityMapping(entity: PagerDutyEntityMapping): Promise<string>;\n bulkInsertEntityMappings(\n entities: PagerDutyEntityMapping[],\n ): Promise<string[]>;\n getAllEntityMappings(): Promise<RawDbEntityResultRow[]>;\n findEntityMappingByEntityRef(\n entityRef: string,\n ): Promise<RawDbEntityResultRow | undefined>;\n findEntityMappingByServiceId(\n serviceId: string,\n ): Promise<RawDbEntityResultRow | undefined>;\n updateSetting(setting: PagerDutySetting): Promise<string>;\n findSetting(settingId: string): Promise<PagerDutySetting | undefined>;\n getAllSettings(): Promise<PagerDutySetting[]>;\n}\n\ntype Options = {\n skipMigrations?: boolean;\n};\n\n/** @public */\nexport class PagerDutyBackendDatabase implements PagerDutyBackendStore {\n static async create(\n knex: Knex,\n options?: Options,\n ): Promise<PagerDutyBackendStore> {\n if (!options?.skipMigrations) {\n const migrationsDir = resolvePackagePath(\n '@pagerduty/backstage-plugin-backend',\n 'migrations',\n );\n\n await knex.migrate.latest({\n directory: migrationsDir,\n extension: 'js',\n });\n }\n\n return new PagerDutyBackendDatabase(knex);\n }\n\n constructor(private readonly db: Knex) {}\n\n async insertEntityMapping(entity: PagerDutyEntityMapping): Promise<string> {\n const entityMappingId = uuid();\n\n const [result] = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n )\n .insert({\n id: entityMappingId,\n entityRef: entity.entityRef,\n serviceId: entity.serviceId,\n integrationKey: entity.integrationKey,\n account: entity.account,\n processedDate: new Date(),\n })\n .onConflict(['serviceId'])\n .merge(['entityRef', 'integrationKey', 'account', 'processedDate'])\n .returning('id');\n\n return result.id;\n }\n\n async bulkInsertEntityMappings(\n entities: PagerDutyEntityMapping[],\n ): Promise<string[]> {\n if (entities.length === 0) {\n return [];\n }\n\n const rows = entities.map(entity => ({\n id: uuid(),\n entityRef: entity.entityRef,\n serviceId: entity.serviceId,\n integrationKey: entity.integrationKey,\n account: entity.account,\n }));\n\n const results = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n )\n .insert(rows)\n .returning('id');\n\n return results.map(r => r.id);\n }\n\n async getAllEntityMappings(): Promise<RawDbEntityResultRow[]> {\n const rawEntities = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n );\n\n if (!rawEntities) {\n return [];\n }\n\n return rawEntities;\n }\n\n async findEntityMappingByEntityRef(\n entityRef: string,\n ): Promise<RawDbEntityResultRow | undefined> {\n const rawEntity = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n )\n .where('entityRef', entityRef)\n .first();\n\n return rawEntity;\n }\n\n async findEntityMappingByServiceId(\n serviceId: string,\n ): Promise<RawDbEntityResultRow | undefined> {\n const rawEntity = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n )\n .where('serviceId', serviceId)\n .first();\n\n return rawEntity;\n }\n\n async updateSetting(setting: PagerDutySetting): Promise<string> {\n const [result] = await this.db<PagerDutySetting>('pagerduty_settings')\n .insert({\n id: setting.id,\n value: setting.value,\n })\n .onConflict(['id'])\n .merge(['value'])\n .returning('id');\n\n return result.id;\n }\n\n async findSetting(settingId: string): Promise<PagerDutySetting | undefined> {\n const rawEntity = await this.db<PagerDutySetting>('pagerduty_settings')\n .where('id', settingId)\n .first();\n\n return rawEntity;\n }\n\n async getAllSettings(): Promise<PagerDutySetting[]> {\n const rawEntities = await this.db<PagerDutySetting>('pagerduty_settings');\n\n if (!rawEntities) {\n return [];\n }\n\n return rawEntities;\n }\n}\n"],"names":["resolvePackagePath","uuid"],"mappings":";;;;;AAwCO,MAAM,wBAAA,CAA0D;AAAA,EAoBrE,YAA6B,EAAA,EAAU;AAAV,IAAA,IAAA,CAAA,EAAA,GAAA,EAAA;AAAA,EAAW;AAAA,EAnBxC,aAAa,MAAA,CACX,IAAA,EACA,OAAA,EACgC;AAChC,IAAA,IAAI,CAAC,SAAS,cAAA,EAAgB;AAC5B,MAAA,MAAM,aAAA,GAAgBA,mCAAA;AAAA,QACpB,qCAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,MAAM,IAAA,CAAK,QAAQ,MAAA,CAAO;AAAA,QACxB,SAAA,EAAW,aAAA;AAAA,QACX,SAAA,EAAW;AAAA,OACZ,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,IAAI,yBAAyB,IAAI,CAAA;AAAA,EAC1C;AAAA,EAIA,MAAM,oBAAoB,MAAA,EAAiD;AACzE,IAAA,MAAM,kBAAkBC,OAAA,EAAK;AAE7B,IAAA,MAAM,CAAC,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,EAAA;AAAA,MAC1B;AAAA,MAEC,MAAA,CAAO;AAAA,MACN,EAAA,EAAI,eAAA;AAAA,MACJ,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,gBAAgB,MAAA,CAAO,cAAA;AAAA,MACvB,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,aAAA,sBAAmB,IAAA;AAAK,KACzB,CAAA,CACA,UAAA,CAAW,CAAC,WAAW,CAAC,CAAA,CACxB,KAAA,CAAM,CAAC,WAAA,EAAa,kBAAkB,SAAA,EAAW,eAAe,CAAC,CAAA,CACjE,UAAU,IAAI,CAAA;AAEjB,IAAA,OAAO,MAAA,CAAO,EAAA;AAAA,EAChB;AAAA,EAEA,MAAM,yBACJ,QAAA,EACmB;AACnB,IAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,GAAA,CAAI,CAAA,MAAA,MAAW;AAAA,MACnC,IAAIA,OAAA,EAAK;AAAA,MACT,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,WAAW,MAAA,CAAO,SAAA;AAAA,MAClB,gBAAgB,MAAA,CAAO,cAAA;AAAA,MACvB,SAAS,MAAA,CAAO;AAAA,KAClB,CAAE,CAAA;AAEF,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,EAAA;AAAA,MACzB;AAAA,KACF,CACG,MAAA,CAAO,IAAI,CAAA,CACX,UAAU,IAAI,CAAA;AAEjB,IAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,EAAE,CAAA;AAAA,EAC9B;AAAA,EAEA,MAAM,oBAAA,GAAwD;AAC5D,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,EAAA;AAAA,MAC7B;AAAA,KACF;AAEA,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,OAAO,WAAA;AAAA,EACT;AAAA,EAEA,MAAM,6BACJ,SAAA,EAC2C;AAC3C,IAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,EAAA;AAAA,MAC3B;AAAA,KACF,CACG,KAAA,CAAM,WAAA,EAAa,SAAS,EAC5B,KAAA,EAAM;AAET,IAAA,OAAO,SAAA;AAAA,EACT;AAAA,EAEA,MAAM,6BACJ,SAAA,EAC2C;AAC3C,IAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,EAAA;AAAA,MAC3B;AAAA,KACF,CACG,KAAA,CAAM,WAAA,EAAa,SAAS,EAC5B,KAAA,EAAM;AAET,IAAA,OAAO,SAAA;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,OAAA,EAA4C;AAC9D,IAAA,MAAM,CAAC,MAAM,CAAA,GAAI,MAAM,KAAK,EAAA,CAAqB,oBAAoB,EAClE,MAAA,CAAO;AAAA,MACN,IAAI,OAAA,CAAQ,EAAA;AAAA,MACZ,OAAO,OAAA,CAAQ;AAAA,KAChB,CAAA,CACA,UAAA,CAAW,CAAC,IAAI,CAAC,CAAA,CACjB,KAAA,CAAM,CAAC,OAAO,CAAC,CAAA,CACf,UAAU,IAAI,CAAA;AAEjB,IAAA,OAAO,MAAA,CAAO,EAAA;AAAA,EAChB;AAAA,EAEA,MAAM,YAAY,SAAA,EAA0D;AAC1E,IAAA,MAAM,SAAA,GAAY,MAAM,IAAA,CAAK,EAAA,CAAqB,oBAAoB,EACnE,KAAA,CAAM,IAAA,EAAM,SAAS,CAAA,CACrB,KAAA,EAAM;AAET,IAAA,OAAO,SAAA;AAAA,EACT;AAAA,EAEA,MAAM,cAAA,GAA8C;AAClD,IAAA,MAAM,WAAA,GAAc,MAAM,IAAA,CAAK,EAAA,CAAqB,oBAAoB,CAAA;AAExE,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,OAAO,WAAA;AAAA,EACT;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"PagerDutyBackendDatabase.cjs.js","sources":["../../src/db/PagerDutyBackendDatabase.ts"],"sourcesContent":["import {\n PagerDutyEntityMapping,\n PagerDutySetting,\n BackstageCustomField,\n CustomFieldSyncLog,\n CustomFieldSyncLogFilters,\n} from '@pagerduty/backstage-plugin-common';\nimport { resolvePackagePath } from '@backstage/backend-plugin-api';\nimport { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\n\nexport type RawDbEntityResultRow = {\n id: string;\n entityRef: string;\n serviceId: string;\n integrationKey: string;\n account?: string;\n processedDate?: Date;\n};\n\nexport type RawDbCustomFieldRow = {\n id: number;\n pagerdutyCustomFieldId: string;\n pagerdutyCustomFieldDisplayName: string;\n pagerdutyCustomFieldEnabled: boolean;\n backstageEntityMappingPath: string;\n pagerdutySubdomain: string;\n description?: string;\n createdAt: Date;\n updatedAt: Date;\n};\n\nexport type RawDbSyncLogRow = {\n id: number;\n timestamp: Date;\n errorCode: string;\n customFieldId: string;\n customFieldName: string;\n entityPath: string;\n serviceId: string;\n serviceName: string;\n errorMessage: string;\n subdomain: string;\n};\n\n/** @public */\nexport interface PagerDutyBackendStore {\n insertEntityMapping(entity: PagerDutyEntityMapping): Promise<string>;\n bulkInsertEntityMappings(\n entities: PagerDutyEntityMapping[],\n ): Promise<string[]>;\n getAllEntityMappings(): Promise<RawDbEntityResultRow[]>;\n findEntityMappingByEntityRef(\n entityRef: string,\n ): Promise<RawDbEntityResultRow | undefined>;\n findEntityMappingByServiceId(\n serviceId: string,\n ): Promise<RawDbEntityResultRow | undefined>;\n updateSetting(setting: PagerDutySetting): Promise<string>;\n findSetting(settingId: string): Promise<PagerDutySetting | undefined>;\n getAllSettings(): Promise<PagerDutySetting[]>;\n insertCustomField(customField: Omit<BackstageCustomField, 'id' | 'createdAt' | 'updatedAt'>): Promise<BackstageCustomField>;\n getAllCustomFields(\n subdomain: string,\n options?: { enabled?: boolean },\n ): Promise<BackstageCustomField[]>;\n findCustomFieldById(id: number): Promise<BackstageCustomField | undefined>;\n updateCustomField(\n id: number,\n updates: {\n pagerdutyCustomFieldDisplayName: string;\n backstageEntityMappingPath: string;\n description?: string;\n },\n ): Promise<BackstageCustomField>;\n setCustomFieldEnabled(id: number, enabled: boolean): Promise<BackstageCustomField>;\n deleteCustomField(id: number): Promise<void>;\n updateCustomFieldPagerDutyId(id: number, pagerdutyCustomFieldId: string): Promise<void>;\n insertSyncLog(\n log: Omit<CustomFieldSyncLog, 'id' | 'timestamp'>,\n ): Promise<void>;\n getSyncLogs(\n subdomain: string,\n options?: SyncLogQueryOptions,\n ): Promise<{\n logs: CustomFieldSyncLog[];\n total: number;\n customFieldNames: string[];\n entityPaths: string[];\n serviceNames: string[];\n }>;\n cleanupSyncLogs(\n options: SyncLogCleanupOptions,\n ): Promise<SyncLogCleanupResult>;\n}\n\n/** @public */\nexport type SyncLogCleanupOptions = {\n olderThanDays: number;\n maxRows: number;\n batchSize: number;\n maxBatchesPerRun: number;\n};\n\n/** @public */\nexport type SyncLogCleanupResult = {\n deletedByAge: number;\n deletedByCap: number;\n batchesUsed: number;\n};\n\n/** @public */\nexport type SyncLogQueryOptions = CustomFieldSyncLogFilters & {\n limit?: number;\n offset?: number;\n};\n\nconst ERROR_SEVERITY_CODES = ['PD_API_ERROR'] as const;\nconst INFO_SEVERITY_CODES = ['SYNC_SUCCESS'] as const;\n\ntype Options = {\n skipMigrations?: boolean;\n};\n\n/** @public */\nexport class PagerDutyBackendDatabase implements PagerDutyBackendStore {\n static async create(\n knex: Knex,\n options?: Options,\n ): Promise<PagerDutyBackendStore> {\n if (!options?.skipMigrations) {\n const migrationsDir = resolvePackagePath(\n '@pagerduty/backstage-plugin-backend',\n 'migrations',\n );\n\n await knex.migrate.latest({\n directory: migrationsDir,\n extension: 'js',\n });\n }\n\n return new PagerDutyBackendDatabase(knex);\n }\n\n constructor(private readonly db: Knex) {}\n\n async insertEntityMapping(entity: PagerDutyEntityMapping): Promise<string> {\n const entityMappingId = uuid();\n\n const [result] = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n )\n .insert({\n id: entityMappingId,\n entityRef: entity.entityRef,\n serviceId: entity.serviceId,\n integrationKey: entity.integrationKey,\n account: entity.account,\n processedDate: new Date(),\n })\n .onConflict(['serviceId'])\n .merge(['entityRef', 'integrationKey', 'account', 'processedDate'])\n .returning('id');\n\n return result.id;\n }\n\n async bulkInsertEntityMappings(\n entities: PagerDutyEntityMapping[],\n ): Promise<string[]> {\n if (entities.length === 0) {\n return [];\n }\n\n const rows = entities.map(entity => ({\n id: uuid(),\n entityRef: entity.entityRef,\n serviceId: entity.serviceId,\n integrationKey: entity.integrationKey,\n account: entity.account,\n }));\n\n // Insert in chunks inside a single transaction. A single multi-row insert\n // is compiled by the SQLite driver into a `SELECT ... UNION ALL ...` with\n // one term per row, which overflows SQLITE_MAX_COMPOUND_SELECT (default\n // 500) for large batches and fails the whole insert with \"too many terms\n // in compound SELECT\". Chunking keeps each statement under that limit while\n // the transaction preserves the all-or-nothing behavior callers expect.\n // The ids are generated here, so we return them directly (preserving input\n // order) rather than relying on driver-specific RETURNING semantics.\n const CHUNK_SIZE = 200;\n\n await this.db.transaction(async trx => {\n for (let i = 0; i < rows.length; i += CHUNK_SIZE) {\n const chunk = rows.slice(i, i + CHUNK_SIZE);\n await trx<RawDbEntityResultRow>('pagerduty_entity_mapping').insert(\n chunk,\n );\n }\n });\n\n return rows.map(r => r.id);\n }\n\n async getAllEntityMappings(): Promise<RawDbEntityResultRow[]> {\n const rawEntities = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n );\n\n if (!rawEntities) {\n return [];\n }\n\n return rawEntities;\n }\n\n async findEntityMappingByEntityRef(\n entityRef: string,\n ): Promise<RawDbEntityResultRow | undefined> {\n const rawEntity = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n )\n .where('entityRef', entityRef)\n .first();\n\n return rawEntity;\n }\n\n async findEntityMappingByServiceId(\n serviceId: string,\n ): Promise<RawDbEntityResultRow | undefined> {\n const rawEntity = await this.db<RawDbEntityResultRow>(\n 'pagerduty_entity_mapping',\n )\n .where('serviceId', serviceId)\n .first();\n\n return rawEntity;\n }\n\n async updateSetting(setting: PagerDutySetting): Promise<string> {\n const [result] = await this.db<PagerDutySetting>('pagerduty_settings')\n .insert({\n id: setting.id,\n value: setting.value,\n })\n .onConflict(['id'])\n .merge(['value'])\n .returning('id');\n\n return result.id;\n }\n\n async findSetting(settingId: string): Promise<PagerDutySetting | undefined> {\n const rawEntity = await this.db<PagerDutySetting>('pagerduty_settings')\n .where('id', settingId)\n .first();\n\n return rawEntity;\n }\n\n async getAllSettings(): Promise<PagerDutySetting[]> {\n const rawEntities = await this.db<PagerDutySetting>('pagerduty_settings');\n\n if (!rawEntities) {\n return [];\n }\n\n return rawEntities;\n }\n\n private toBackstageCustomField(row: RawDbCustomFieldRow): BackstageCustomField {\n return {\n ...row,\n pagerdutyCustomFieldEnabled: Boolean(row.pagerdutyCustomFieldEnabled),\n };\n }\n\n async insertCustomField(\n customField: Omit<BackstageCustomField, 'id' | 'createdAt' | 'updatedAt'>,\n ): Promise<BackstageCustomField> {\n await this.db<RawDbCustomFieldRow>('pagerduty_custom_fields').insert({\n pagerdutyCustomFieldId: customField.pagerdutyCustomFieldId,\n pagerdutyCustomFieldDisplayName: customField.pagerdutyCustomFieldDisplayName,\n pagerdutyCustomFieldEnabled: customField.pagerdutyCustomFieldEnabled,\n backstageEntityMappingPath: customField.backstageEntityMappingPath,\n pagerdutySubdomain: customField.pagerdutySubdomain,\n description: customField.description,\n });\n\n const result = await this.db<RawDbCustomFieldRow>(\n 'pagerduty_custom_fields',\n )\n .where({\n pagerdutyCustomFieldId: customField.pagerdutyCustomFieldId,\n pagerdutySubdomain: customField.pagerdutySubdomain,\n })\n .orderBy('createdAt', 'desc')\n .first();\n\n if (!result) {\n throw new Error(\n 'Failed to retrieve custom field after insert into pagerduty_custom_fields',\n );\n }\n\n return this.toBackstageCustomField(result);\n }\n\n async findCustomFieldById(id: number): Promise<BackstageCustomField | undefined> {\n const result = await this.db<RawDbCustomFieldRow>('pagerduty_custom_fields')\n .where('id', id)\n .first();\n\n if (!result) return undefined;\n\n return this.toBackstageCustomField(result);\n }\n\n async updateCustomField(\n id: number,\n updates: {\n pagerdutyCustomFieldDisplayName: string;\n backstageEntityMappingPath: string;\n description?: string;\n },\n ): Promise<BackstageCustomField> {\n const rowsAffected = await this.db<RawDbCustomFieldRow>('pagerduty_custom_fields')\n .where('id', id)\n .update({\n pagerdutyCustomFieldDisplayName: updates.pagerdutyCustomFieldDisplayName,\n backstageEntityMappingPath: updates.backstageEntityMappingPath,\n description: updates.description,\n updatedAt: new Date(),\n });\n\n if (rowsAffected === 0) {\n throw new Error(`Custom field with id ${id} does not exist`);\n }\n\n const result = await this.db<RawDbCustomFieldRow>('pagerduty_custom_fields')\n .where('id', id)\n .first();\n\n if (!result) {\n throw new Error(`Failed to retrieve custom field after update for id: ${id}`);\n }\n\n return this.toBackstageCustomField(result);\n }\n\n async setCustomFieldEnabled(\n id: number,\n enabled: boolean,\n ): Promise<BackstageCustomField> {\n const rowsAffected = await this.db<RawDbCustomFieldRow>('pagerduty_custom_fields')\n .where('id', id)\n .update({\n pagerdutyCustomFieldEnabled: enabled,\n updatedAt: new Date(),\n });\n\n if (rowsAffected === 0) {\n throw new Error(`Custom field with id ${id} does not exist`);\n }\n\n const result = await this.db<RawDbCustomFieldRow>('pagerduty_custom_fields')\n .where('id', id)\n .first();\n\n if (!result) {\n throw new Error(`Failed to retrieve custom field after update for id: ${id}`);\n }\n\n return this.toBackstageCustomField(result);\n }\n\n async getAllCustomFields(\n subdomain: string,\n options: { enabled?: boolean } = {},\n ): Promise<BackstageCustomField[]> {\n const query = this.db<RawDbCustomFieldRow>('pagerduty_custom_fields').where(\n 'pagerdutySubdomain',\n subdomain,\n );\n if (options.enabled !== undefined) {\n query.where('pagerdutyCustomFieldEnabled', options.enabled);\n }\n const rawFields = await query;\n\n if (!rawFields) {\n return [];\n }\n\n return rawFields.map(field => this.toBackstageCustomField(field));\n }\n\n async deleteCustomField(id: number): Promise<void> {\n await this.db<RawDbCustomFieldRow>('pagerduty_custom_fields')\n .where('id', id)\n .delete();\n }\n\n async updateCustomFieldPagerDutyId(\n id: number,\n pagerdutyCustomFieldId: string,\n ): Promise<void> {\n await this.db<RawDbCustomFieldRow>('pagerduty_custom_fields')\n .where('id', id)\n .update({\n pagerdutyCustomFieldId,\n updatedAt: new Date(),\n });\n }\n\n async insertSyncLog(\n log: Omit<CustomFieldSyncLog, 'id' | 'timestamp'>,\n ): Promise<void> {\n await this.db<RawDbSyncLogRow>('pagerduty_custom_field_sync_logs').insert({\n errorCode: log.errorCode,\n customFieldId: log.customFieldId,\n customFieldName: log.customFieldName,\n entityPath: log.entityPath,\n serviceId: log.serviceId,\n serviceName: log.serviceName,\n errorMessage: log.errorMessage,\n subdomain: log.subdomain,\n });\n }\n\n async getSyncLogs(\n subdomain: string,\n options?: SyncLogQueryOptions,\n ): Promise<{\n logs: CustomFieldSyncLog[];\n total: number;\n customFieldNames: string[];\n entityPaths: string[];\n serviceNames: string[];\n }> {\n const limit = options?.limit ?? 100;\n const offset = options?.offset ?? 0;\n\n const baseQuery = () => {\n let q = this.db<RawDbSyncLogRow>('pagerduty_custom_field_sync_logs')\n .where('subdomain', subdomain);\n\n if (options?.severity === 'error') {\n q = q.where(builder =>\n builder\n .whereIn('errorCode', [...ERROR_SEVERITY_CODES])\n .orWhereRaw('LOWER(??) LIKE ?', ['errorCode', '%error%']),\n );\n } else if (options?.severity === 'info') {\n q = q.whereIn('errorCode', [...INFO_SEVERITY_CODES]);\n } else if (options?.severity === 'warning') {\n // Warning is the complement of both error and info: anything that is\n // neither a known error/info code nor an error-by-name.\n q = q\n .whereNotIn('errorCode', [...ERROR_SEVERITY_CODES])\n .whereNotIn('errorCode', [...INFO_SEVERITY_CODES])\n .whereRaw('LOWER(??) NOT LIKE ?', ['errorCode', '%error%']);\n }\n\n if (options?.customFieldName) {\n q = q.where('customFieldName', options.customFieldName);\n }\n if (options?.entityPath) {\n q = q.where('entityPath', options.entityPath);\n }\n if (options?.serviceName) {\n q = q.where('serviceName', options.serviceName);\n }\n if (options?.search) {\n const pattern = `%${options.search.toLowerCase()}%`;\n q = q.where(builder =>\n builder\n .whereRaw('LOWER(??) LIKE ?', ['errorMessage', pattern])\n .orWhereRaw('LOWER(??) LIKE ?', ['customFieldName', pattern])\n .orWhereRaw('LOWER(??) LIKE ?', ['entityPath', pattern])\n .orWhereRaw('LOWER(??) LIKE ?', ['serviceName', pattern])\n .orWhereRaw('LOWER(??) LIKE ?', ['errorCode', pattern]),\n );\n }\n\n return q;\n };\n\n const [logs, countResult, customFields, entityPaths, services] =\n await Promise.all([\n baseQuery().orderBy('timestamp', 'desc').limit(limit).offset(offset),\n baseQuery().count<{ count: string | number }>('* as count').first(),\n this.db<RawDbSyncLogRow>('pagerduty_custom_field_sync_logs')\n .where('subdomain', subdomain)\n .whereNotNull('customFieldName')\n .distinct('customFieldName')\n .orderBy('customFieldName', 'asc'),\n this.db<RawDbSyncLogRow>('pagerduty_custom_field_sync_logs')\n .where('subdomain', subdomain)\n .whereNotNull('entityPath')\n .distinct('entityPath')\n .orderBy('entityPath', 'asc'),\n this.db<RawDbSyncLogRow>('pagerduty_custom_field_sync_logs')\n .where('subdomain', subdomain)\n .whereNotNull('serviceName')\n .distinct('serviceName')\n .orderBy('serviceName', 'asc'),\n ]);\n\n const total = countResult ? Number(countResult.count) : 0;\n\n return {\n logs: logs || [],\n total,\n customFieldNames: customFields.map(r => r.customFieldName).filter(Boolean),\n entityPaths: entityPaths.map(r => r.entityPath).filter(Boolean),\n serviceNames: services.map(r => r.serviceName).filter(Boolean),\n };\n }\n\n async cleanupSyncLogs(\n options: SyncLogCleanupOptions,\n ): Promise<SyncLogCleanupResult> {\n const { olderThanDays, maxRows, batchSize, maxBatchesPerRun } = options;\n const table = 'pagerduty_custom_field_sync_logs';\n\n const result: SyncLogCleanupResult = {\n deletedByAge: 0,\n deletedByCap: 0,\n batchesUsed: 0,\n };\n\n const newest = (await this.db<RawDbSyncLogRow>(table)\n .max('id as id')\n .first()) as unknown as { id: number | null } | undefined;\n if (!newest?.id) {\n return result;\n }\n\n const BATCH_SLEEP_MS = 50;\n const sleep = (ms: number) => new Promise(r => setTimeout(r, ms));\n\n // Rows are stamped by the DB clock (CURRENT_TIMESTAMP, UTC on SQLite), so\n // the cutoff is bound as a 'YYYY-MM-DD HH:MM:SS' UTC string: better-sqlite3\n // stores timestamps as strings of that format and would never match a\n // numeric Date binding, while Postgres casts the string to a timestamp.\n // Clock skew between app and DB is irrelevant at multi-day granularity.\n const cutoff = new Date(Date.now() - olderThanDays * 24 * 60 * 60 * 1000)\n .toISOString()\n .replace('T', ' ')\n .replace(/\\.\\d+Z$/, '');\n\n // Delete in id order via an IN subquery: Postgres has no DELETE ... LIMIT,\n // and each batch runs in its own short implicit transaction so concurrent\n // inserts (which append the highest ids) are never blocked for long.\n const deleteBatch = async (filter: (q: Knex.QueryBuilder) => void) => {\n const subquery = this.db<RawDbSyncLogRow>(table)\n .select('id')\n .orderBy('id', 'asc')\n .limit(batchSize);\n filter(subquery);\n return this.db<RawDbSyncLogRow>(table).whereIn('id', subquery).delete();\n };\n\n while (result.batchesUsed < maxBatchesPerRun) {\n const deleted = await deleteBatch(q => q.where('timestamp', '<', cutoff));\n result.deletedByAge += deleted;\n result.batchesUsed += 1;\n if (deleted < batchSize) {\n break;\n }\n await sleep(BATCH_SLEEP_MS);\n }\n\n // Hard cap: keep only the newest maxRows rows. The cap is global across\n // subdomains — a flooding subdomain may evict another's logs, which is\n // acceptable for diagnostic data that the TTL bounds anyway. The threshold\n // id is found with an index-only probe on the primary key (no count(*)).\n const threshold = await this.db<RawDbSyncLogRow>(table)\n .select('id')\n .orderBy('id', 'desc')\n .offset(maxRows)\n .limit(1)\n .first();\n if (threshold) {\n while (result.batchesUsed < maxBatchesPerRun) {\n const deleted = await deleteBatch(q =>\n q.where('id', '<=', threshold.id),\n );\n result.deletedByCap += deleted;\n result.batchesUsed += 1;\n if (deleted < batchSize) {\n break;\n }\n await sleep(BATCH_SLEEP_MS);\n }\n }\n\n return result;\n }\n}\n"],"names":["resolvePackagePath","uuid"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
2
|
import { LoggerService, RootConfigService, DiscoveryService, AuthService, CacheService } from '@backstage/backend-plugin-api';
|
|
3
|
-
import { PagerDutyEntityMapping, PagerDutySetting, PagerDutyService, PagerDutyEntityMappingsResponse } from '@pagerduty/backstage-plugin-common';
|
|
3
|
+
import { PagerDutyEntityMapping, PagerDutySetting, BackstageCustomField, CustomFieldSyncLog, CustomFieldSyncLogFilters, PagerDutyService, PagerDutyEntityMappingsResponse } from '@pagerduty/backstage-plugin-common';
|
|
4
4
|
import * as express from 'express';
|
|
5
5
|
import { CatalogApi, GetEntitiesResponse } from '@backstage/catalog-client';
|
|
6
6
|
|
|
@@ -22,7 +22,47 @@ interface PagerDutyBackendStore {
|
|
|
22
22
|
updateSetting(setting: PagerDutySetting): Promise<string>;
|
|
23
23
|
findSetting(settingId: string): Promise<PagerDutySetting | undefined>;
|
|
24
24
|
getAllSettings(): Promise<PagerDutySetting[]>;
|
|
25
|
+
insertCustomField(customField: Omit<BackstageCustomField, 'id' | 'createdAt' | 'updatedAt'>): Promise<BackstageCustomField>;
|
|
26
|
+
getAllCustomFields(subdomain: string, options?: {
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
}): Promise<BackstageCustomField[]>;
|
|
29
|
+
findCustomFieldById(id: number): Promise<BackstageCustomField | undefined>;
|
|
30
|
+
updateCustomField(id: number, updates: {
|
|
31
|
+
pagerdutyCustomFieldDisplayName: string;
|
|
32
|
+
backstageEntityMappingPath: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
}): Promise<BackstageCustomField>;
|
|
35
|
+
setCustomFieldEnabled(id: number, enabled: boolean): Promise<BackstageCustomField>;
|
|
36
|
+
deleteCustomField(id: number): Promise<void>;
|
|
37
|
+
updateCustomFieldPagerDutyId(id: number, pagerdutyCustomFieldId: string): Promise<void>;
|
|
38
|
+
insertSyncLog(log: Omit<CustomFieldSyncLog, 'id' | 'timestamp'>): Promise<void>;
|
|
39
|
+
getSyncLogs(subdomain: string, options?: SyncLogQueryOptions): Promise<{
|
|
40
|
+
logs: CustomFieldSyncLog[];
|
|
41
|
+
total: number;
|
|
42
|
+
customFieldNames: string[];
|
|
43
|
+
entityPaths: string[];
|
|
44
|
+
serviceNames: string[];
|
|
45
|
+
}>;
|
|
46
|
+
cleanupSyncLogs(options: SyncLogCleanupOptions): Promise<SyncLogCleanupResult>;
|
|
25
47
|
}
|
|
48
|
+
/** @public */
|
|
49
|
+
type SyncLogCleanupOptions = {
|
|
50
|
+
olderThanDays: number;
|
|
51
|
+
maxRows: number;
|
|
52
|
+
batchSize: number;
|
|
53
|
+
maxBatchesPerRun: number;
|
|
54
|
+
};
|
|
55
|
+
/** @public */
|
|
56
|
+
type SyncLogCleanupResult = {
|
|
57
|
+
deletedByAge: number;
|
|
58
|
+
deletedByCap: number;
|
|
59
|
+
batchesUsed: number;
|
|
60
|
+
};
|
|
61
|
+
/** @public */
|
|
62
|
+
type SyncLogQueryOptions = CustomFieldSyncLogFilters & {
|
|
63
|
+
limit?: number;
|
|
64
|
+
offset?: number;
|
|
65
|
+
};
|
|
26
66
|
|
|
27
67
|
interface RouterOptions {
|
|
28
68
|
logger: LoggerService;
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
4
|
var router = require('./service/router.cjs.js');
|
|
5
5
|
var PagerDutyBackendDatabase = require('./db/PagerDutyBackendDatabase.cjs.js');
|
|
6
|
+
var syncLogsCleanup = require('./services/syncLogsCleanup.cjs.js');
|
|
6
7
|
var catalogClient = require('@backstage/catalog-client');
|
|
7
8
|
|
|
8
9
|
class CatalogFetchApi {
|
|
@@ -32,7 +33,8 @@ const pagerDutyPlugin = backendPluginApi.createBackendPlugin({
|
|
|
32
33
|
database: backendPluginApi.coreServices.database,
|
|
33
34
|
discovery: backendPluginApi.coreServices.discovery,
|
|
34
35
|
auth: backendPluginApi.coreServices.auth,
|
|
35
|
-
cache: backendPluginApi.coreServices.cache
|
|
36
|
+
cache: backendPluginApi.coreServices.cache,
|
|
37
|
+
scheduler: backendPluginApi.coreServices.scheduler
|
|
36
38
|
},
|
|
37
39
|
async init({
|
|
38
40
|
config,
|
|
@@ -41,11 +43,27 @@ const pagerDutyPlugin = backendPluginApi.createBackendPlugin({
|
|
|
41
43
|
database,
|
|
42
44
|
discovery,
|
|
43
45
|
auth,
|
|
44
|
-
cache
|
|
46
|
+
cache,
|
|
47
|
+
scheduler
|
|
45
48
|
}) {
|
|
46
49
|
const pagerDutyBackendStore = await PagerDutyBackendDatabase.PagerDutyBackendDatabase.create(await database.getClient(), {
|
|
47
50
|
skipMigrations: false
|
|
48
51
|
});
|
|
52
|
+
const cleanupConfig = syncLogsCleanup.readSyncLogsCleanupConfig(config);
|
|
53
|
+
if (cleanupConfig.enabled) {
|
|
54
|
+
await scheduler.scheduleTask({
|
|
55
|
+
id: syncLogsCleanup.SYNC_LOGS_CLEANUP_TASK_ID,
|
|
56
|
+
frequency: { minutes: cleanupConfig.frequencyMinutes },
|
|
57
|
+
timeout: { minutes: syncLogsCleanup.SYNC_LOGS_CLEANUP_TIMEOUT_MINUTES },
|
|
58
|
+
initialDelay: { minutes: syncLogsCleanup.SYNC_LOGS_CLEANUP_INITIAL_DELAY_MINUTES },
|
|
59
|
+
scope: "global",
|
|
60
|
+
fn: () => syncLogsCleanup.runSyncLogsCleanup({
|
|
61
|
+
store: pagerDutyBackendStore,
|
|
62
|
+
logger,
|
|
63
|
+
cleanupConfig
|
|
64
|
+
})
|
|
65
|
+
});
|
|
66
|
+
}
|
|
49
67
|
httpRouter.use(
|
|
50
68
|
await router.createRouter({
|
|
51
69
|
config,
|
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 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":"
|
|
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 {\n readSyncLogsCleanupConfig,\n runSyncLogsCleanup,\n SYNC_LOGS_CLEANUP_INITIAL_DELAY_MINUTES,\n SYNC_LOGS_CLEANUP_TASK_ID,\n SYNC_LOGS_CLEANUP_TIMEOUT_MINUTES,\n} from './services/syncLogsCleanup';\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 scheduler: coreServices.scheduler,\n },\n async init({\n config,\n logger,\n httpRouter,\n database,\n discovery,\n auth,\n cache,\n scheduler,\n }) {\n const pagerDutyBackendStore: PagerDutyBackendStore =\n await PagerDutyBackendDatabase.create(await database.getClient(), {\n skipMigrations: false,\n });\n\n const cleanupConfig = readSyncLogsCleanupConfig(config);\n if (cleanupConfig.enabled) {\n await scheduler.scheduleTask({\n id: SYNC_LOGS_CLEANUP_TASK_ID,\n frequency: { minutes: cleanupConfig.frequencyMinutes },\n timeout: { minutes: SYNC_LOGS_CLEANUP_TIMEOUT_MINUTES },\n initialDelay: { minutes: SYNC_LOGS_CLEANUP_INITIAL_DELAY_MINUTES },\n scope: 'global',\n fn: () =>\n runSyncLogsCleanup({\n store: pagerDutyBackendStore,\n logger,\n cleanupConfig,\n }),\n });\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","readSyncLogsCleanupConfig","SYNC_LOGS_CLEANUP_TASK_ID","SYNC_LOGS_CLEANUP_TIMEOUT_MINUTES","SYNC_LOGS_CLEANUP_INITIAL_DELAY_MINUTES","runSyncLogsCleanup","createRouter","CatalogClient"],"mappings":"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"}
|