Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RCA] Start investigation from alert details page #190307

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2711784
create new investigation, save, reload
benakansara Aug 12, 2024
947e5d3
remove comment
benakansara Aug 12, 2024
f1c7e9e
chnage origin type
benakansara Aug 12, 2024
315932e
only show investigation for custom threshold alert
benakansara Aug 12, 2024
cf5ef17
Merge branch 'main' into feat/start-and-save-investigation
benakansara Aug 12, 2024
977ebac
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Aug 12, 2024
6fb3bf6
get investigation ids from saved object
benakansara Aug 13, 2024
b541f88
check alertid not null
benakansara Aug 13, 2024
a030afe
filter investigations by status
benakansara Aug 13, 2024
2dad0ce
revert aad changes
benakansara Aug 13, 2024
2b21a55
pr feedback
benakansara Aug 13, 2024
b811d1b
Merge branch 'main' into feat/start-and-save-investigation
benakansara Aug 13, 2024
1233457
resolve merge conflicts
benakansara Aug 13, 2024
8cef8a4
update query keys
benakansara Aug 13, 2024
1575b45
Merge branch 'main' into feat/start-and-save-investigation
benakansara Aug 13, 2024
adf4f93
rename
benakansara Aug 13, 2024
5ede1af
fix tests
benakansara Aug 13, 2024
530de3e
removing ref to investigate to solve circular dependency
benakansara Aug 13, 2024
4b6a680
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Aug 13, 2024
1544474
resolve cyclic dep
benakansara Aug 13, 2024
34f9331
extend search api
benakansara Aug 13, 2024
8a8a177
Update x-pack/plugins/observability_solution/investigate/common/schem…
benakansara Aug 13, 2024
5a24c0b
pr feedback
benakansara Aug 13, 2024
7e0abe4
Merge branch 'main' into feat/start-and-save-investigation
benakansara Aug 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,11 @@ export type {
export { mergePlainObjects } from './utils/merge_plain_objects';

export { InvestigateWidgetColumnSpan } from './types';

export type { CreateInvestigationInput, CreateInvestigationResponse } from './schema/create';
export type { GetInvestigationParams } from './schema/get';
export type { FindInvestigationsResponse } from './schema/find';

export { createInvestigationParamsSchema } from './schema/create';
export { getInvestigationParamsSchema } from './schema/get';
export { findInvestigationsParamsSchema } from './schema/find';
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
*/
import * as t from 'io-ts';
import { investigationResponseSchema } from './investigation';
import { alertOriginSchema, blankOriginSchema } from './origin';

const createInvestigationParamsSchema = t.type({
body: t.type({
id: t.string,
title: t.string,
parameters: t.type({
params: t.type({
timeRange: t.type({ from: t.number, to: t.number }),
}),
origin: t.union([alertOriginSchema, blankOriginSchema]),
}),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { investigationResponseSchema } from './investigation';

const findInvestigationsParamsSchema = t.partial({
query: t.partial({
alertId: t.string,
page: t.string,
perPage: t.string,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
* 2.0.
*/
import * as t from 'io-ts';
import { alertOriginSchema, blankOriginSchema } from './origin';

const investigationResponseSchema = t.type({
id: t.string,
title: t.string,
createdAt: t.number,
createdBy: t.string,
parameters: t.type({
params: t.type({
timeRange: t.type({ from: t.number, to: t.number }),
}),
origin: t.union([alertOriginSchema, blankOriginSchema]),
status: t.union([t.literal('ongoing'), t.literal('closed')]),
});

type InvestigationResponse = t.OutputOf<typeof investigationResponseSchema>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import * as t from 'io-ts';

const blankOriginSchema = t.type({ type: t.literal('blank') });
const alertOriginSchema = t.type({ type: t.literal('alert'), id: t.string });

type AlertOrigin = t.OutputOf<typeof alertOriginSchema>;
type BlankOrigin = t.OutputOf<typeof blankOriginSchema>;

export { alertOriginSchema, blankOriginSchema };

export type { AlertOrigin, BlankOrigin };
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const investigationKeys = {
all: ['investigation'] as const,
list: (params: { page: number; perPage: number }) =>
[...investigationKeys.all, 'list', params] as const,
fetch: (params: { id: string }) => [...investigationKeys.all, 'fetch', params] as const,
};

export type InvestigationKeys = typeof investigationKeys;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { useQuery } from '@tanstack/react-query';
import { FindInvestigationsResponse } from '../../common/schema/find';
import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common';
import { investigationKeys } from './query_key_factory';
import { useKibana } from './use_kibana';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { useQuery } from '@tanstack/react-query';
import { BASE_RAC_ALERTS_API_PATH, EcsFieldsResponse } from '@kbn/rule-registry-plugin/common';
import { useKibana } from './use_kibana';

export interface AlertParams {
id: string;
}

export interface UseFetchAlertResponse {
isInitialLoading: boolean;
isLoading: boolean;
isRefetching: boolean;
isSuccess: boolean;
isError: boolean;
data: EcsFieldsResponse | undefined | null;
}

export function useFetchAlert({ id }: AlertParams): UseFetchAlertResponse {
const {
core: {
http,
notifications: { toasts },
},
} = useKibana();

const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({
queryKey: ['fetchAlert', id],
queryFn: async ({ signal }) => {
return await http.get<EcsFieldsResponse>(BASE_RAC_ALERTS_API_PATH, {
query: {
id,
},
signal,
});
},
cacheTime: 0,
refetchOnWindowFocus: false,
retry: (failureCount, error) => {
if (String(error) === 'Error: Forbidden') {
return false;
}

return failureCount < 3;
},
onError: (error: Error) => {
toasts.addError(error, {
title: 'Something went wrong while fetching alert',
});
},
enabled: Boolean(id),
});

return {
data,
isInitialLoading,
isLoading,
isRefetching,
isSuccess,
isError,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { useQuery } from '@tanstack/react-query';
import { GetInvestigationResponse } from '@kbn/investigate-plugin/common/schema/get';
import { investigationKeys } from './query_key_factory';
import { useKibana } from './use_kibana';

export interface FetchInvestigationParams {
id: string;
}

export interface UseFetchInvestigationResponse {
isInitialLoading: boolean;
isLoading: boolean;
isRefetching: boolean;
isSuccess: boolean;
isError: boolean;
data: GetInvestigationResponse | undefined;
}

export function useFetchInvestigation({
id,
}: FetchInvestigationParams): UseFetchInvestigationResponse {
const {
core: {
http,
notifications: { toasts },
},
} = useKibana();

const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({
queryKey: investigationKeys.fetch({ id }),
queryFn: async ({ signal }) => {
return await http.get<GetInvestigationResponse>(`/api/observability/investigations/${id}`, {
version: '2023-10-31',
signal,
});
},
cacheTime: 0,
refetchOnWindowFocus: false,
retry: (failureCount, error) => {
if (String(error) === 'Error: Forbidden') {
return false;
}

return failureCount < 3;
},
onError: (error: Error) => {
toasts.addError(error, {
title: 'Something went wrong while fetching Investigation',
});
},
});

return {
data,
isInitialLoading,
isLoading,
isRefetching,
isSuccess,
isError,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
* 2.0.
*/

import { EuiButton } from '@elastic/eui';
import { EuiButton, EuiButtonEmpty, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { ALERT_RULE_CATEGORY } from '@kbn/rule-data-utils/src/default_alerts_as_data';
import { AlertOrigin } from '@kbn/investigate-plugin/common/schema/origin';
import { paths } from '../../../common/paths';
import { useKibana } from '../../hooks/use_kibana';
import { useFetchInvestigation } from '../../hooks/use_get_investigation_details';
import { useInvestigateParams } from '../../hooks/use_investigate_params';
import { useFetchAlert } from '../../hooks/use_get_alert_details';
import { InvestigationDetails } from './components/investigation_details';

export function InvestigationDetailsPage() {
Expand All @@ -22,8 +27,46 @@ export function InvestigationDetailsPage() {
},
} = useKibana();

const {
path: { id },
} = useInvestigateParams('/{id}');

const ObservabilityPageTemplate = observabilityShared.navigation.PageTemplate;

const {
data: investigationDetails,
isLoading: isFetchInvestigationLoading,
isError: isFetchInvestigationError,
} = useFetchInvestigation({ id });

const alertId = investigationDetails ? (investigationDetails.origin as AlertOrigin).id : '';

const {
data: alertDetails,
isLoading: isFetchAlertLoading,
isError: isFetchAlertError,
} = useFetchAlert({ id: alertId });

if (isFetchInvestigationLoading || isFetchAlertLoading) {
return (
<h1>
{i18n.translate('xpack.investigateApp.fetchInvestigation.loadingLabel', {
defaultMessage: 'Loading...',
})}
</h1>
);
}

if (isFetchInvestigationError || isFetchAlertError) {
return (
<h1>
{i18n.translate('xpack.investigateApp.fetchInvestigation.errorLabel', {
defaultMessage: 'Error while fetching investigation',
})}
</h1>
);
}

return (
<ObservabilityPageTemplate
pageHeader={{
Expand All @@ -40,12 +83,26 @@ export function InvestigationDetailsPage() {
}),
},
],
pageTitle: i18n.translate('xpack.investigateApp.detailsPage.title', {
defaultMessage: 'New investigation',
}),
pageTitle: (
<>
{alertDetails && (
<EuiButtonEmpty
data-test-subj="investigationDetailsAlertLink"
iconType="arrowLeft"
size="xs"
href={basePath.prepend(`/app/observability/alerts/${alertId}`)}
>
<EuiText size="s">
{`[Alert] ${alertDetails?.[ALERT_RULE_CATEGORY]} breached`}
</EuiText>
</EuiButtonEmpty>
)}
{investigationDetails && <div>{investigationDetails.title}</div>}
</>
),
rightSideItems: [
<EuiButton fill data-test-subj="investigateAppInvestigateDetailsPageEscalateButton">
{i18n.translate('xpack.investigateApp.investigateDetailsPage.escalateButtonLabel', {
<EuiButton fill data-test-subj="investigationDetailsEscalateButton">
{i18n.translate('xpack.investigateApp.investigationDetails.escalateButtonLabel', {
defaultMessage: 'Escalate',
})}
</EuiButton>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
* 2.0.
*/

import { alertOriginSchema, blankOriginSchema } from '@kbn/investigate-plugin/common/schema/origin';
import * as t from 'io-ts';

export const investigationSchema = t.type({
id: t.string,
title: t.string,
createdAt: t.number,
createdBy: t.string,
parameters: t.type({
params: t.type({
timeRange: t.type({ from: t.number, to: t.number }),
}),
origin: t.union([alertOriginSchema, blankOriginSchema]),
status: t.union([t.literal('ongoing'), t.literal('closed')]),
});

export type Investigation = t.TypeOf<typeof investigationSchema>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
* 2.0.
*/

import { findInvestigationsParamsSchema } from '../../common/schema/find';
import { createInvestigationParamsSchema } from '../../common/schema/create';
import { createInvestigationParamsSchema } from '@kbn/investigate-plugin/common';
import { findInvestigationsParamsSchema } from '@kbn/investigate-plugin/common';
import { getInvestigationParamsSchema } from '@kbn/investigate-plugin/common';
import { createInvestigation } from '../services/create_investigation';
import { investigationRepositoryFactory } from '../services/investigation_repository';
import { createInvestigateAppServerRoute } from './create_investigate_app_server_route';
import { findInvestigations } from '../services/find_investigations';
import { getInvestigationParamsSchema } from '../../common/schema/get';
import { getInvestigation } from '../services/get_investigation';

const createInvestigationRoute = createInvestigateAppServerRoute({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@ export const investigation: SavedObjectsType = {
name: SO_INVESTIGATION_TYPE,
hidden: false,
namespaceType: 'multiple-isolated',
switchToModelVersionAt: '8.10.0',
mappings: {
dynamic: false,
properties: {
id: { type: 'keyword' },
title: { type: 'text' },
origin: {
properties: {
type: { type: 'keyword' },
id: { type: 'keyword' },
},
},
status: { type: 'keyword' },
},
},
management: {
Expand Down
Loading