[Uptime] Use stack version to determine appending synthetics-* (#163800)

Co-authored-by: Abdul Wahab Zahid <awahab07@yahoo.com>
This commit is contained in:
Shahzad 2023-08-15 16:31:24 +02:00 committed by GitHub
parent cd65fbbacb
commit 4c1428377a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 159 additions and 30 deletions

View file

@ -573,6 +573,7 @@ export const RuleForm = ({
}
>
<RuleParamsExpressionComponent
id={rule.id}
ruleParams={rule.params}
ruleInterval={`${ruleInterval ?? 1}${ruleIntervalUnit}`}
ruleThrottle={''}

View file

@ -374,6 +374,7 @@ export interface RuleTypeParamsExpressionProps<
MetaData = Record<string, unknown>,
ActionGroupIds extends string = string
> {
id?: string;
ruleParams: Params;
ruleInterval: string;
ruleThrottle: string;

View file

@ -8,6 +8,7 @@
import * as t from 'io-ts';
export const TLSParamsType = t.partial({
stackVersion: t.string,
search: t.string,
certAgeThreshold: t.number,
certExpirationThreshold: t.number,

View file

@ -22,6 +22,8 @@ import { FILTER_FIELDS } from '../../../../../../common/constants';
const { TYPE, TAGS, LOCATION, PORT } = FILTER_FIELDS;
interface Props {
id?: string;
stackVersion?: string;
ruleParams: { [key: string]: any };
enabled: boolean;
numTimes: number;
@ -33,11 +35,13 @@ interface Props {
}
export const AlertMonitorStatus: React.FC<Props> = ({
id,
enabled,
numTimes,
setRuleParams,
timerange,
ruleParams,
stackVersion,
}) => {
const dispatch = useDispatch();
@ -47,6 +51,12 @@ export const AlertMonitorStatus: React.FC<Props> = ({
}
}, [ruleParams, dispatch]);
useEffect(() => {
if (!id && stackVersion && !ruleParams.stackVersion) {
setRuleParams('stackVersion', stackVersion);
}
}, [ruleParams, id, stackVersion, setRuleParams]);
const { count, loading } = useSnapShotCount({
query: ruleParams.search,
filters: ruleParams.filters,

View file

@ -19,9 +19,11 @@ import { AlertQueryBar } from '../alert_query_bar/query_bar';
import { AlertMonitorCount } from '../monitor_status_alert/alert_monitor_status';
export const AlertTls: React.FC<{
id?: string;
stackVersion?: string;
ruleParams: RuleTypeParamsExpressionProps<TLSParams>['ruleParams'];
setRuleParams: RuleTypeParamsExpressionProps<TLSParams>['setRuleParams'];
}> = ({ ruleParams, setRuleParams }) => {
}> = ({ id, stackVersion, ruleParams, setRuleParams }) => {
const dispatch = useDispatch();
const { settings } = useSelector(selectDynamicSettings);
@ -30,6 +32,12 @@ export const AlertTls: React.FC<{
query: ruleParams.search ?? '',
});
useEffect(() => {
if (!id && stackVersion && !ruleParams.stackVersion) {
setRuleParams('stackVersion', stackVersion);
}
}, [ruleParams, id, stackVersion, setRuleParams]);
useEffect(() => {
if (typeof settings === 'undefined') {
dispatch(getDynamicSettings());

View file

@ -26,11 +26,13 @@ import { DEFAULT_SEVERITY, SelectSeverity, SEVERITY_OPTIONS } from './select_sev
import { monitorIdSelector } from '../../../../state/selectors';
interface Props {
id?: string;
stackVersion?: string;
ruleParams: { [key: string]: any };
setRuleParams: (key: string, value: any) => void;
}
export function AnomalyAlertComponent({ setRuleParams, ruleParams }: Props) {
export function AnomalyAlertComponent({ setRuleParams, ruleParams, id, stackVersion }: Props) {
const [severity, setSeverity] = useState(DEFAULT_SEVERITY);
const monitorIdStore = useSelector(monitorIdSelector);
@ -45,6 +47,12 @@ export function AnomalyAlertComponent({ setRuleParams, ruleParams }: Props) {
setRuleParams('severity', severity.val);
}, [severity, setRuleParams]);
useEffect(() => {
if (!id && stackVersion && !ruleParams.stackVersion) {
setRuleParams('stackVersion', stackVersion);
}
}, [ruleParams, id, stackVersion, setRuleParams]);
useEffect(() => {
if (ruleParams.severity !== undefined) {
setSeverity(SEVERITY_OPTIONS.find(({ val }) => val === ruleParams.severity)!);

View file

@ -16,6 +16,7 @@ import { initDurationAnomalyAlertType } from './duration_anomaly';
export type AlertTypeInitializer<TAlertTypeModel = ObservabilityRuleTypeModel> = (dependencies: {
isHidden: boolean;
stackVersion: string;
core: CoreStart;
plugins: ClientPluginsStart;
}) => TAlertTypeModel;

View file

@ -18,15 +18,16 @@ interface Props {
core: CoreStart;
plugins: ClientPluginsStart;
params: any;
stackVersion?: string;
}
// eslint-disable-next-line import/no-default-export
export default function DurationAnomalyAlert({ core, plugins, params }: Props) {
export default function DurationAnomalyAlert({ core, plugins, params, stackVersion }: Props) {
kibanaService.core = core;
return (
<ReduxProvider store={store}>
<KibanaContextProvider services={{ ...core, ...plugins }}>
<AnomalyAlertComponent {...params} />
<AnomalyAlertComponent {...params} stackVersion={stackVersion} />
</KibanaContextProvider>
</ReduxProvider>
);

View file

@ -19,16 +19,21 @@ interface Props {
core: CoreStart;
plugins: ClientPluginsStart;
params: any;
stackVersion?: string;
}
// eslint-disable-next-line import/no-default-export
export default function MonitorStatusAlert({ core, plugins, params }: Props) {
export default function MonitorStatusAlert({ core, plugins, params, stackVersion }: Props) {
kibanaService.core = core;
return (
<ReduxProvider store={store}>
<KibanaContextProvider services={{ ...core, ...plugins }}>
<UptimeDataViewContextProvider dataViews={plugins.dataViews}>
<AlertMonitorStatus {...params} autocomplete={plugins.unifiedSearch.autocomplete} />
<AlertMonitorStatus
{...params}
autocomplete={plugins.unifiedSearch.autocomplete}
stackVersion={stackVersion}
/>
</UptimeDataViewContextProvider>
</KibanaContextProvider>
</ReduxProvider>

View file

@ -18,6 +18,8 @@ import { kibanaService } from '../../../state/kibana_service';
import { UptimeDataViewContextProvider } from '../../../contexts/uptime_data_view_context';
interface Props {
id?: string;
stackVersion?: string;
core: CoreStart;
plugins: ClientPluginsStart;
ruleParams: RuleTypeParamsExpressionProps<TLSParams>['ruleParams'];
@ -25,13 +27,25 @@ interface Props {
}
// eslint-disable-next-line import/no-default-export
export default function TLSAlert({ core, plugins, ruleParams, setRuleParams }: Props) {
export default function TLSAlert({
id,
stackVersion,
core,
plugins,
ruleParams,
setRuleParams,
}: Props) {
kibanaService.core = core;
return (
<ReduxProvider store={store}>
<KibanaContextProvider services={{ ...core, ...plugins }}>
<UptimeDataViewContextProvider dataViews={plugins.dataViews}>
<AlertTls ruleParams={ruleParams} setRuleParams={setRuleParams} />
<AlertTls
id={id}
stackVersion={stackVersion}
ruleParams={ruleParams}
setRuleParams={setRuleParams}
/>
</UptimeDataViewContextProvider>
</KibanaContextProvider>
</ReduxProvider>

View file

@ -33,6 +33,7 @@ export const initMonitorStatusAlertType: AlertTypeInitializer = ({
core,
plugins,
isHidden,
stackVersion,
}): ObservabilityRuleTypeModel => ({
id: CLIENT_ALERT_TYPES.MONITOR_STATUS,
description,
@ -41,7 +42,7 @@ export const initMonitorStatusAlertType: AlertTypeInitializer = ({
return `${docLinks.links.observability.monitorStatus}`;
},
ruleParamsExpression: (params: any) => (
<MonitorStatusAlert core={core} plugins={plugins} params={params} />
<MonitorStatusAlert core={core} plugins={plugins} params={params} stackVersion={stackVersion} />
),
validate: (ruleParams: any) => {
if (!validateFunc) {

View file

@ -35,6 +35,7 @@ export const initTlsAlertType: AlertTypeInitializer = ({
<TLSAlert
core={core}
plugins={plugins}
id={params.id}
ruleParams={params.ruleParams}
setRuleParams={params.setRuleParams}
/>

View file

@ -213,7 +213,12 @@ export class UptimePlugin
setStartServices(coreStart);
registerUptimeFleetExtensions(registerExtension);
setUptimeAppStatus(coreStart, pluginsStart, this.uptimeAppUpdater);
setUptimeAppStatus(
this.initContext.env.packageInfo.version,
coreStart,
pluginsStart,
this.uptimeAppUpdater
);
}
public stop(): void {}
@ -275,6 +280,7 @@ function registerUptimeFleetExtensions(registerExtension: FleetStart['registerEx
}
function setUptimeAppStatus(
stackVersion: string,
coreStart: CoreStart,
pluginsStart: ClientPluginsStart,
updater: BehaviorSubject<AppUpdater>
@ -283,7 +289,7 @@ function setUptimeAppStatus(
const isEnabled = coreStart.uiSettings.get<boolean>(enableLegacyUptimeApp);
if (isEnabled) {
registerUptimeRoutesWithNavigation(coreStart, pluginsStart);
registerAlertRules(coreStart, pluginsStart, false);
registerAlertRules(coreStart, pluginsStart, stackVersion, false);
updater.next(() => ({ status: AppStatus.accessible }));
} else {
const indexStatusPromise = UptimeDataHelper(coreStart).indexStatus('now-7d', 'now');
@ -291,10 +297,10 @@ function setUptimeAppStatus(
if (indexStatus.indexExists) {
registerUptimeRoutesWithNavigation(coreStart, pluginsStart);
updater.next(() => ({ status: AppStatus.accessible }));
registerAlertRules(coreStart, pluginsStart, false);
registerAlertRules(coreStart, pluginsStart, stackVersion, false);
} else {
updater.next(() => ({ status: AppStatus.inaccessible }));
registerAlertRules(coreStart, pluginsStart, true);
registerAlertRules(coreStart, pluginsStart, stackVersion, true);
}
});
}
@ -304,6 +310,7 @@ function setUptimeAppStatus(
function registerAlertRules(
coreStart: CoreStart,
pluginsStart: ClientPluginsStart,
stackVersion: string,
isHidden = false
) {
uptimeAlertTypeInitializers.forEach((init) => {
@ -311,6 +318,7 @@ function registerAlertRules(
const alertInitializer = init({
isHidden,
stackVersion,
core: coreStart,
plugins: pluginsStart,
});
@ -322,6 +330,7 @@ function registerAlertRules(
legacyAlertTypeInitializers.forEach((init) => {
const alertInitializer = init({
isHidden,
stackVersion,
core: coreStart,
plugins: pluginsStart,
});

View file

@ -104,6 +104,7 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
name: durationAnomalyTranslations.alertFactoryName,
validate: {
params: schema.object({
stackVersion: schema.maybe(schema.string()),
monitorId: schema.string(),
severity: schema.number(),
}),
@ -146,7 +147,7 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
savedObjectsClient,
scopedClusterClient.asCurrentUser,
{
isLegacyAlert: true,
stackVersion: params.stackVersion ?? '8.9.0',
}
);
const { share, basePath } = server;

View file

@ -1069,6 +1069,7 @@ describe('status check alert', () => {
// @ts-ignore the `props` key here isn't described
expect(Object.keys(alert.validate?.params?.props ?? {})).toMatchInlineSnapshot(`
Array [
"stackVersion",
"availability",
"filters",
"locations",

View file

@ -286,6 +286,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
}),
validate: {
params: schema.object({
stackVersion: schema.maybe(schema.string()),
availability: schema.maybe(
schema.object({
range: schema.number(),
@ -293,6 +294,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
threshold: schema.string(),
})
),
// deprecated
filters: schema.maybe(
schema.oneOf([
// deprecated
@ -305,7 +307,6 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
schema.string(),
])
),
// deprecated
locations: schema.maybe(schema.arrayOf(schema.string())),
numTimes: schema.number(),
search: schema.maybe(schema.string()),
@ -362,6 +363,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
startedAt,
}) {
const {
stackVersion = '8.9.0',
availability,
filters,
isAutoGenerated,
@ -380,7 +382,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
savedObjectsClient,
scopedClusterClient.asCurrentUser,
{
isLegacyAlert: true,
stackVersion,
}
);

View file

@ -121,6 +121,7 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
name: tlsTranslations.alertFactoryName,
validate: {
params: schema.object({
stackVersion: schema.maybe(schema.string()),
search: schema.maybe(schema.string()),
certExpirationThreshold: schema.maybe(schema.number()),
certAgeThreshold: schema.maybe(schema.number()),
@ -168,7 +169,7 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
savedObjectsClient,
scopedClusterClient.asCurrentUser,
{
isLegacyAlert: true,
stackVersion: params.stackVersion ?? '8.9.0',
}
);

View file

@ -120,7 +120,7 @@ export const tlsLegacyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (_s
savedObjectsClient,
scopedClusterClient.asCurrentUser,
{
isLegacyAlert: true,
stackVersion: '8.9.0',
}
);
const { certs, total }: CertResult = await libs.requests.getCerts({

View file

@ -147,7 +147,7 @@ describe('UptimeEsClient', () => {
syntheticsIndexRemoved: true,
},
});
uptimeEsClient = new UptimeEsClient(savedObjectsClient, esClient, { isLegacyAlert: true });
uptimeEsClient = new UptimeEsClient(savedObjectsClient, esClient, { stackVersion: '8.9.0' });
const mockSearchParams = {
body: {
@ -180,7 +180,7 @@ describe('UptimeEsClient', () => {
settingsObjectId
);
});
uptimeEsClient = new UptimeEsClient(savedObjectsClient, esClient, { isLegacyAlert: true });
uptimeEsClient = new UptimeEsClient(savedObjectsClient, esClient, { stackVersion: '8.9.0' });
const mockSearchParams = {
body: {
@ -206,7 +206,60 @@ describe('UptimeEsClient', () => {
{ meta: true }
);
});
});
it('does not append synthetics-* to index for stack version 8.10.0 or later', async () => {
savedObjectsClient.get = jest.fn().mockImplementation(() => {
throw SavedObjectsErrorHelpers.createGenericNotFoundError(
umDynamicSettings.name,
settingsObjectId
);
});
uptimeEsClient = new UptimeEsClient(savedObjectsClient, esClient, {
stackVersion: '8.11.0',
});
// Add more tests for other methods and edge cases
await uptimeEsClient.search({
body: {
query: {
match_all: {},
},
},
});
expect(esClient.search).toHaveBeenCalledWith(
{
index: 'heartbeat-8*,heartbeat-7*',
body: {
query: {
match_all: {},
},
},
},
{ meta: true }
);
uptimeEsClient = new UptimeEsClient(savedObjectsClient, esClient, {
stackVersion: '8.10.0',
});
await uptimeEsClient.search({
body: {
query: {
match_all: {},
},
},
});
expect(esClient.search).toHaveBeenLastCalledWith(
{
index: 'heartbeat-8*,heartbeat-7*',
body: {
query: {
match_all: {},
},
},
},
{ meta: true }
);
});
});
});

View file

@ -19,6 +19,7 @@ import { RequestStatus } from '@kbn/inspector-plugin/common';
import { InspectResponse } from '@kbn/observability-plugin/typings/common';
import { enableInspectEsQueries } from '@kbn/observability-plugin/common';
import { getInspectResponse } from '@kbn/observability-shared-plugin/common';
import semver from 'semver/preload';
import { DYNAMIC_SETTINGS_DEFAULT_ATTRIBUTES } from '../../constants/settings';
import { DynamicSettingsAttributes } from '../../runtime_types/settings';
import { settingsObjectId, umDynamicSettings } from './saved_objects/uptime_settings';
@ -52,6 +53,7 @@ export class UptimeEsClient {
uiSettings?: CoreRequestHandlerContext['uiSettings'];
savedObjectsClient: SavedObjectsClientContract;
isLegacyAlert?: boolean;
stackVersion?: string;
constructor(
savedObjectsClient: SavedObjectsClientContract,
@ -61,17 +63,17 @@ export class UptimeEsClient {
uiSettings?: CoreRequestHandlerContext['uiSettings'];
request?: KibanaRequest;
heartbeatIndices?: string;
isLegacyAlert?: boolean;
stackVersion?: string;
}
) {
const {
isLegacyAlert,
stackVersion,
isDev = false,
uiSettings,
request,
heartbeatIndices = '',
} = options ?? {};
this.isLegacyAlert = isLegacyAlert;
this.stackVersion = stackVersion;
this.uiSettings = uiSettings;
this.baseESClient = esClient;
this.savedObjectsClient = savedObjectsClient;
@ -225,17 +227,25 @@ export class UptimeEsClient {
indices = settings?.heartbeatIndices || '';
syntheticsIndexRemoved = settings.syntheticsIndexRemoved ?? false;
}
if (
this.isLegacyAlert &&
!indices.includes('synthetics-') &&
(syntheticsIndexRemoved || !settingsChangedByUser)
) {
if (indices.includes('synthetics-')) {
return indices;
}
const appendSyntheticsIndex = shouldAppendSyntheticsIndex(this.stackVersion);
if (appendSyntheticsIndex && (syntheticsIndexRemoved || !settingsChangedByUser)) {
indices = indices + ',synthetics-*';
}
return indices;
}
}
export const shouldAppendSyntheticsIndex = (stackVersion?: string) => {
if (!stackVersion) {
return false;
}
return semver.lt(stackVersion, '8.10.0');
};
export function createEsParams<T extends estypes.SearchRequest>(params: T): T {
return params;
}