[wip] support 'splunk.com/on-call-routing-key' annotation
Extends the Splunk On Call plugin Entity card to infer the corresponding team names from a `splunk.com/on-call-routing-key` annotation. This seeks to enable the use of the Splunk On Call plugin on entity pages for those orgs who associate a component with a routing key rather than a team name. Signed-off-by: Mike Ball <mikedball@gmail.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
OnCall,
|
||||
User,
|
||||
EscalationPolicyInfo,
|
||||
RoutingKey,
|
||||
Team,
|
||||
} from '../components/types';
|
||||
import {
|
||||
@@ -30,6 +31,7 @@ import {
|
||||
RequestOptions,
|
||||
ListUserResponse,
|
||||
EscalationPolicyResponse,
|
||||
ListRoutingKeyResponse,
|
||||
} from './types';
|
||||
import {
|
||||
createApiRef,
|
||||
@@ -82,6 +84,15 @@ export class SplunkOnCallClient implements SplunkOnCallApi {
|
||||
return teams;
|
||||
}
|
||||
|
||||
async getRoutingKeys(): Promise<RoutingKey[]> {
|
||||
const url = `${await this.config.discoveryApi.getBaseUrl(
|
||||
'proxy',
|
||||
)}/splunk-on-call/v1/org/routing-keys`;
|
||||
const { routingKeys } = await this.getByUrl<ListRoutingKeyResponse>(url);
|
||||
|
||||
return routingKeys;
|
||||
}
|
||||
|
||||
async getUsers(): Promise<User[]> {
|
||||
const url = `${await this.config.discoveryApi.getBaseUrl(
|
||||
'proxy',
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
EscalationPolicyInfo,
|
||||
Incident,
|
||||
OnCall,
|
||||
RoutingKey,
|
||||
Team,
|
||||
User,
|
||||
} from '../components/types';
|
||||
@@ -65,6 +66,11 @@ export interface SplunkOnCallApi {
|
||||
*/
|
||||
getTeams(): Promise<Team[]>;
|
||||
|
||||
/**
|
||||
* Get a list of routing keys for your organization.
|
||||
*/
|
||||
getRoutingKeys(): Promise<RoutingKey[]>;
|
||||
|
||||
/**
|
||||
* Get a list of escalation policies for your organization.
|
||||
*/
|
||||
@@ -80,6 +86,11 @@ export type ListUserResponse = {
|
||||
_selfUrl?: string;
|
||||
};
|
||||
|
||||
export type ListRoutingKeyResponse = {
|
||||
routingKeys: RoutingKey[];
|
||||
_selfUrl?: string;
|
||||
};
|
||||
|
||||
export type IncidentsResponse = {
|
||||
incidents: Incident[];
|
||||
};
|
||||
|
||||
@@ -45,9 +45,18 @@ import {
|
||||
} from '@backstage/core-components';
|
||||
|
||||
export const SPLUNK_ON_CALL_TEAM = 'splunk.com/on-call-team';
|
||||
export const SPLUNK_ON_CALL_ROUTING_KEY = 'splunk.com/on-call-routing-key';
|
||||
|
||||
export const MissingTeamAnnotation = () => (
|
||||
<MissingAnnotationEmptyState annotation={SPLUNK_ON_CALL_TEAM} />
|
||||
export const MissingAnnotation = () => (
|
||||
<div>
|
||||
<Typography>
|
||||
The Splunk On Call plugin requires setting either the{' '}
|
||||
<code>{SPLUNK_ON_CALL_TEAM}</code> or the{' '}
|
||||
<code>{SPLUNK_ON_CALL_ROUTING_KEY}</code> annotation.
|
||||
</Typography>
|
||||
<MissingAnnotationEmptyState annotation={SPLUNK_ON_CALL_TEAM} />
|
||||
<MissingAnnotationEmptyState annotation={SPLUNK_ON_CALL_ROUTING_KEY} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const InvalidTeamAnnotation = ({ teamName }: { teamName: string }) => (
|
||||
@@ -71,7 +80,8 @@ export const MissingEventsRestEndpoint = () => (
|
||||
);
|
||||
|
||||
export const isSplunkOnCallAvailable = (entity: Entity) =>
|
||||
Boolean(entity.metadata.annotations?.[SPLUNK_ON_CALL_TEAM]);
|
||||
Boolean(entity.metadata.annotations?.[SPLUNK_ON_CALL_TEAM]) ||
|
||||
Boolean(entity.metadata.annotations?.[SPLUNK_ON_CALL_ROUTING_KEY]);
|
||||
|
||||
export const EntitySplunkOnCallCard = () => {
|
||||
const config = useApi(configApiRef);
|
||||
@@ -79,7 +89,12 @@ export const EntitySplunkOnCallCard = () => {
|
||||
const { entity } = useEntity();
|
||||
const [showDialog, setShowDialog] = useState<boolean>(false);
|
||||
const [refreshIncidents, setRefreshIncidents] = useState<boolean>(false);
|
||||
const team = entity.metadata.annotations![SPLUNK_ON_CALL_TEAM];
|
||||
const teamAnnotation = entity
|
||||
? entity.metadata.annotations![SPLUNK_ON_CALL_TEAM]
|
||||
: undefined;
|
||||
const routingKeyAnnotation = entity
|
||||
? entity.metadata.annotations![SPLUNK_ON_CALL_ROUTING_KEY]
|
||||
: undefined;
|
||||
|
||||
const eventsRestEndpoint =
|
||||
config.getOptionalString('splunkOnCall.eventsRestEndpoint') || null;
|
||||
@@ -108,7 +123,20 @@ export const EntitySplunkOnCallCard = () => {
|
||||
{},
|
||||
);
|
||||
const teams = await api.getTeams();
|
||||
const foundTeam = teams.find(teamValue => teamValue.name === team);
|
||||
let foundTeam = teams.find(teamValue => teamValue.name === teamAnnotation);
|
||||
|
||||
if (!foundTeam && routingKeyAnnotation) {
|
||||
const routingKeys = await api.getRoutingKeys();
|
||||
const foundRoutingKey = routingKeys.find(
|
||||
key => key.routingKey === routingKeyAnnotation,
|
||||
);
|
||||
const teamUrlParts = foundRoutingKey
|
||||
? foundRoutingKey.targets[0]._teamUrl.split('/')
|
||||
: [];
|
||||
const teamSlug = teamUrlParts[teamUrlParts.length - 1];
|
||||
foundTeam = teams.find(teamValue => teamValue.slug === teamSlug);
|
||||
}
|
||||
|
||||
return { usersHashMap, foundTeam };
|
||||
});
|
||||
|
||||
@@ -128,13 +156,22 @@ export const EntitySplunkOnCallCard = () => {
|
||||
return <Progress />;
|
||||
}
|
||||
|
||||
const team =
|
||||
usersAndTeam?.foundTeam && usersAndTeam?.foundTeam.name
|
||||
? usersAndTeam?.foundTeam.name
|
||||
: '';
|
||||
|
||||
const Content = () => {
|
||||
if (!team) {
|
||||
return <MissingTeamAnnotation />;
|
||||
if (!teamAnnotation && !routingKeyAnnotation) {
|
||||
return <MissingAnnotation />;
|
||||
}
|
||||
|
||||
if (!usersAndTeam?.foundTeam) {
|
||||
return <InvalidTeamAnnotation teamName={team} />;
|
||||
return (
|
||||
<InvalidTeamAnnotation
|
||||
teamName={teamAnnotation || routingKeyAnnotation || ''}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!eventsRestEndpoint) {
|
||||
|
||||
@@ -117,3 +117,15 @@ export type EscalationPolicyTeam = {
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
|
||||
export type RoutingKey = {
|
||||
routingKey: string;
|
||||
targets: RoutingKeyTarget[];
|
||||
isDefault: boolean;
|
||||
};
|
||||
|
||||
export type RoutingKeyTarget = {
|
||||
policyName: string;
|
||||
policySlug: string;
|
||||
_teamUrl: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user