Skip to content

Commit

Permalink
Merge branch 'master' into api-stats-new-client
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Nov 9, 2020
2 parents 27a623c + 8560b2d commit 54306fc
Show file tree
Hide file tree
Showing 129 changed files with 2,099 additions and 366 deletions.
3 changes: 2 additions & 1 deletion test/functional/apps/discover/_discover.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ export default function ({ getService, getPageObjects }) {
defaultIndex: 'logstash-*',
};

describe('discover test', function describeIndexTests() {
// Failing: See https://github.com/elastic/kibana/issues/82915
describe.skip('discover test', function describeIndexTests() {
before(async function () {
log.debug('load kibana index with default index pattern');
await esArchiver.load('discover');
Expand Down
34 changes: 27 additions & 7 deletions x-pack/plugins/alerts/common/alert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ export interface IntervalSchedule extends SavedObjectAttributes {
export const AlertExecutionStatusValues = ['ok', 'active', 'error', 'pending', 'unknown'] as const;
export type AlertExecutionStatuses = typeof AlertExecutionStatusValues[number];

export const AlertExecutionStatusErrorReasonValues = [
'read',
'decrypt',
'execute',
'unknown',
] as const;
export type AlertExecutionStatusErrorReasons = typeof AlertExecutionStatusErrorReasonValues[number];
export enum AlertExecutionStatusErrorReasons {
Read = 'read',
Decrypt = 'decrypt',
Execute = 'execute',
Unknown = 'unknown',
}

export interface AlertExecutionStatus {
status: AlertExecutionStatuses;
Expand Down Expand Up @@ -74,3 +73,24 @@ export interface Alert {
}

export type SanitizedAlert = Omit<Alert, 'apiKey'>;

export enum HealthStatus {
OK = 'ok',
Warning = 'warn',
Error = 'error',
}

export interface AlertsHealth {
decryptionHealth: {
status: HealthStatus;
timestamp: string;
};
executionHealth: {
status: HealthStatus;
timestamp: string;
};
readHealth: {
status: HealthStatus;
timestamp: string;
};
}
3 changes: 3 additions & 0 deletions x-pack/plugins/alerts/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { AlertsHealth } from './alert';

export * from './alert';
export * from './alert_type';
export * from './alert_instance';
Expand All @@ -19,6 +21,7 @@ export interface ActionGroup {
export interface AlertingFrameworkHealth {
isSufficientlySecure: boolean;
hasPermanentEncryptionKey: boolean;
alertingFrameworkHeath: AlertsHealth;
}

export const BASE_ALERT_API_PATH = '/api/alerts';
Expand Down
19 changes: 19 additions & 0 deletions x-pack/plugins/alerts/server/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { configSchema } from './config';

describe('config validation', () => {
test('alerts defaults', () => {
const config: Record<string, unknown> = {};
expect(configSchema.validate(config)).toMatchInlineSnapshot(`
Object {
"healthCheck": Object {
"interval": "60m",
},
}
`);
});
});
16 changes: 16 additions & 0 deletions x-pack/plugins/alerts/server/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { schema, TypeOf } from '@kbn/config-schema';
import { validateDurationSchema } from './lib';

export const configSchema = schema.object({
healthCheck: schema.object({
interval: schema.string({ validate: validateDurationSchema, defaultValue: '60m' }),
}),
});

export type AlertsConfig = TypeOf<typeof configSchema>;
221 changes: 221 additions & 0 deletions x-pack/plugins/alerts/server/health/get_health.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { savedObjectsRepositoryMock } from '../../../../../src/core/server/mocks';
import { AlertExecutionStatusErrorReasons, HealthStatus } from '../types';
import { getHealth } from './get_health';

const savedObjectsRepository = savedObjectsRepositoryMock.create();

describe('getHealth()', () => {
test('return true if some of alerts has a decryption error', async () => {
const lastExecutionDateError = new Date().toISOString();
const lastExecutionDate = new Date().toISOString();
savedObjectsRepository.find.mockResolvedValueOnce({
total: 1,
per_page: 1,
page: 1,
saved_objects: [
{
id: '1',
type: 'alert',
attributes: {
alertTypeId: 'myType',
schedule: { interval: '10s' },
params: {
bar: true,
},
createdAt: new Date().toISOString(),
actions: [
{
group: 'default',
actionRef: 'action_0',
params: {
foo: true,
},
},
],
executionStatus: {
status: 'error',
lastExecutionDate: lastExecutionDateError,
error: {
reason: AlertExecutionStatusErrorReasons.Decrypt,
message: 'Failed decrypt',
},
},
},
score: 1,
references: [
{
name: 'action_0',
type: 'action',
id: '1',
},
],
},
],
});
savedObjectsRepository.find.mockResolvedValueOnce({
total: 0,
per_page: 10,
page: 1,
saved_objects: [],
});

savedObjectsRepository.find.mockResolvedValueOnce({
total: 0,
per_page: 10,
page: 1,
saved_objects: [],
});

savedObjectsRepository.find.mockResolvedValueOnce({
total: 1,
per_page: 1,
page: 1,
saved_objects: [
{
id: '2',
type: 'alert',
attributes: {
alertTypeId: 'myType',
schedule: { interval: '1s' },
params: {
bar: true,
},
createdAt: new Date().toISOString(),
actions: [],
executionStatus: {
status: 'ok',
lastExecutionDate,
},
},
score: 1,
references: [],
},
],
});
const result = await getHealth(savedObjectsRepository);
expect(result).toStrictEqual({
executionHealth: {
status: HealthStatus.OK,
timestamp: lastExecutionDate,
},
readHealth: {
status: HealthStatus.OK,
timestamp: lastExecutionDate,
},
decryptionHealth: {
status: HealthStatus.Warning,
timestamp: lastExecutionDateError,
},
});
expect(savedObjectsRepository.find).toHaveBeenCalledTimes(4);
});

test('return false if no alerts with a decryption error', async () => {
const lastExecutionDateError = new Date().toISOString();
const lastExecutionDate = new Date().toISOString();
savedObjectsRepository.find.mockResolvedValueOnce({
total: 0,
per_page: 10,
page: 1,
saved_objects: [],
});

savedObjectsRepository.find.mockResolvedValueOnce({
total: 1,
per_page: 1,
page: 1,
saved_objects: [
{
id: '1',
type: 'alert',
attributes: {
alertTypeId: 'myType',
schedule: { interval: '10s' },
params: {
bar: true,
},
createdAt: new Date().toISOString(),
actions: [
{
group: 'default',
actionRef: 'action_0',
params: {
foo: true,
},
},
],
executionStatus: {
status: 'error',
lastExecutionDate: lastExecutionDateError,
error: {
reason: AlertExecutionStatusErrorReasons.Execute,
message: 'Failed',
},
},
},
score: 1,
references: [
{
name: 'action_0',
type: 'action',
id: '1',
},
],
},
],
});
savedObjectsRepository.find.mockResolvedValueOnce({
total: 0,
per_page: 10,
page: 1,
saved_objects: [],
});

savedObjectsRepository.find.mockResolvedValueOnce({
total: 1,
per_page: 1,
page: 1,
saved_objects: [
{
id: '2',
type: 'alert',
attributes: {
alertTypeId: 'myType',
schedule: { interval: '1s' },
params: {
bar: true,
},
createdAt: new Date().toISOString(),
actions: [],
executionStatus: {
status: 'ok',
lastExecutionDate,
},
},
score: 1,
references: [],
},
],
});
const result = await getHealth(savedObjectsRepository);
expect(result).toStrictEqual({
executionHealth: {
status: HealthStatus.Warning,
timestamp: lastExecutionDateError,
},
readHealth: {
status: HealthStatus.OK,
timestamp: lastExecutionDate,
},
decryptionHealth: {
status: HealthStatus.OK,
timestamp: lastExecutionDate,
},
});
});
});
Loading

0 comments on commit 54306fc

Please sign in to comment.