@pagerduty/backstage-plugin
Version:
A Backstage plugin that integrates towards PagerDuty
343 lines (340 loc) • 10.7 kB
JavaScript
import { createApiRef } from '@backstage/core-plugin-api';
import { NotFoundError } from '@backstage/errors';
import { getPagerDutyEntity } from '../components/pagerDutyEntity.esm.js';
class UnauthorizedError extends Error {
}
class ForbiddenError extends Error {
}
const pagerDutyApiRef = createApiRef({
id: "plugin.pagerduty.api"
});
class PagerDutyClient {
constructor(config) {
this.config = config;
}
static fromConfig(configApi, dependencies) {
const { discoveryApi, fetchApi } = dependencies;
const eventsBaseUrl = configApi.getOptionalString("pagerDuty.eventsBaseUrl") ?? "https://events.pagerduty.com/v2";
return new PagerDutyClient({
eventsBaseUrl,
discoveryApi,
fetchApi
});
}
async getServiceByPagerDutyEntity(pagerDutyEntity) {
const { integrationKey, serviceId, account } = pagerDutyEntity;
let response;
let url;
if (integrationKey) {
url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/services?integration_key=${integrationKey}`;
if (account) {
url = `${url}&account=${account}`;
}
const serviceResponse = await this.findByUrl(
url
);
if (serviceResponse.service === void 0) throw new NotFoundError();
response = serviceResponse;
} else if (serviceId) {
url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/services/${serviceId}`;
if (account) {
url = `${url}?account=${account}`;
}
response = await this.findByUrl(url);
} else {
throw new NotFoundError();
}
return response;
}
async getSetting(id) {
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/settings/${id}`;
return await this.findByUrl(url);
}
async storeSettings(settings) {
const body = JSON.stringify(settings);
const options = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
Accept: "application/json, text/plain, */*"
},
body
};
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/settings`;
return this.request(url, options);
}
async getEntityMappingsWithPagination(options) {
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/mapping/entities`;
const body = JSON.stringify({
offset: options.offset,
limit: options.limit,
filters: options.filters || {},
sort: options.sort,
account: options.account
});
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
Accept: "application/json, text/plain, */*"
},
body
};
const response = await this.request(url, requestOptions);
return response.json();
}
async getAllServices() {
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/all-pd-services`;
return await this.findByUrl(url);
}
async getAllTeams(account) {
const baseUrl = await this.config.discoveryApi.getBaseUrl("pagerduty");
const url = account ? `${baseUrl}/teams?account=${encodeURIComponent(account)}` : `${baseUrl}/teams`;
return await this.findByUrl(url);
}
async getFilteredServices(teamIds, query, limit, account) {
const baseUrl = await this.config.discoveryApi.getBaseUrl("pagerduty");
const params = new URLSearchParams();
if (teamIds && teamIds.length > 0) {
params.append("team_id", teamIds[0]);
}
if (query && query.trim() !== "") {
params.append("query", query.trim());
}
if (limit) {
params.append("limit", limit.toString());
}
if (account) {
params.append("account", account);
}
const queryString = params.toString();
const url = queryString ? `${baseUrl}/services?${queryString}` : `${baseUrl}/services`;
return await this.findByUrl(url);
}
async storeServiceMapping(serviceId, integrationKey, backstageEntityRef, account) {
const body = JSON.stringify({
entityRef: backstageEntityRef,
serviceId,
integrationKey,
account
});
const options = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
Accept: "application/json, text/plain, */*"
},
body
};
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/mapping/entity`;
return this.request(url, options);
}
async getEntityMapping(entityRef) {
const match = entityRef.match(/^([^:]+):([^/]+)\/(.+)$/);
if (!match) {
throw new Error(`Invalid entity reference: ${entityRef}`);
}
const [, kind, namespace, name] = match;
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/mapping/entity/${kind}/${namespace}/${name}`;
return await this.findByUrl(url);
}
async storeBulkServiceMappings(mappings) {
const body = JSON.stringify({ mappings });
const options = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
Accept: "application/json, text/plain, */*"
},
body
};
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/mapping/entities/bulk`;
return this.request(url, options);
}
async removeServiceMapping(entityRef) {
const { mapping } = await this.getEntityMapping(entityRef);
await this.storeServiceMapping(
mapping.serviceId,
mapping.integrationKey,
"",
// Empty string = unmap (same as "None" option in admin page)
mapping.account
);
return true;
}
async getServiceByEntity(entity) {
return await this.getServiceByPagerDutyEntity(getPagerDutyEntity(entity));
}
async getServiceById(serviceId, account) {
let url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/services/${serviceId}`;
if (account) {
url = url.concat(`?account=${account}`);
}
return await this.findByUrl(url);
}
async getIncidentsByServiceId(serviceId, account) {
let url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/services/${serviceId}/incidents`;
if (account) {
url = url.concat(`?account=${account}`);
}
return await this.findByUrl(url);
}
async getChangeEventsByServiceId(serviceId, account) {
let url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/services/${serviceId}/change-events`;
if (account) {
url = url.concat(`?account=${account}`);
}
return await this.findByUrl(url);
}
async getServiceStandardsByServiceId(serviceId, account) {
let url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/services/${serviceId}/standards`;
if (account) {
url = url.concat(`?account=${account}`);
}
return await this.findByUrl(url);
}
async getServiceMetricsByServiceId(serviceId, account) {
let url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/services/${serviceId}/metrics`;
if (account) {
url = url.concat(`?account=${account}`);
}
return await this.findByUrl(url);
}
async getOnCallByPolicyId(policyId, account) {
const params = `escalation_policy_ids[]=${policyId}`;
let url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/oncall-users?${params}`;
if (account) {
url = url.concat(`&account=${account}`);
}
const response = await this.findByUrl(url);
return response.users;
}
triggerAlarm(request) {
const { integrationKey, source, description, userName } = request;
const body = JSON.stringify({
event_action: "trigger",
routing_key: integrationKey,
client: "Backstage",
client_url: source,
payload: {
summary: description,
source,
severity: "error",
class: "manual trigger",
custom_details: {
user: userName
}
}
});
const options = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
Accept: "application/json, text/plain, */*"
},
body
};
const url = this.config.eventsBaseUrl ?? "https://events.pagerduty.com/v2";
return this.request(`${url}/enqueue`, options);
}
async startAutoMatchEntityMappings(options) {
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/mapping/entity/auto-match/start`;
const body = JSON.stringify({
team: options.team,
threshold: options.threshold,
bestOnly: true,
account: options.account
});
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=UTF-8",
Accept: "application/json, text/plain, */*"
},
body
};
const response = await this.request(url, requestOptions);
return response.json();
}
async getAutoMatchStatus(jobId) {
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/mapping/entity/auto-match/${encodeURIComponent(jobId)}`;
return await this.findByUrl(url);
}
async getAccounts() {
const url = `${await this.config.discoveryApi.getBaseUrl(
"pagerduty"
)}/accounts`;
const response = await this.findByUrl(url);
return response.accounts;
}
async findByUrl(url) {
const options = {
method: "GET",
headers: {
Accept: "application/vnd.pagerduty+json;version=2",
"Content-Type": "application/json"
}
};
const response = await this.request(url, options);
return response.json();
}
async request(url, options) {
const response = await this.config.fetchApi.fetch(url, options);
if (response.status === 401) {
throw new UnauthorizedError(
"Unauthorized: You don't have access to this resource"
);
}
if (response.status === 403) {
throw new ForbiddenError(
"Forbidden: You are not allowed to perform this action"
);
}
if (response.status === 404) {
throw new NotFoundError("Not Found: Resource not found");
}
if (!response.ok) {
const payload = await response.json();
const errors = payload.errors.map((error) => error).join(" ");
const message = `Request failed with ${response.status}, ${errors}`;
throw new Error(message);
}
return response;
}
}
export { ForbiddenError, PagerDutyClient, UnauthorizedError, pagerDutyApiRef };
//# sourceMappingURL=client.esm.js.map