Skip to content

Commit

Permalink
Revert back ESO migration for alerting, added try/catch logic to avoi…
Browse files Browse the repository at this point in the history
…d failing Kibana on start (elastic#76220)

* Revert back ESO migration for alerting, added try/catch logic to avoid failing Kibana on start

* Revert back ESO migration for alerting, added try/catch logic to avoid failing Kibana on start

* fixed due to comments

* removed unused logger

* fixed type checks

* did renaming from 7.9 to 7.10

* Added migration failure unit test
  • Loading branch information
YulNaumenko committed Sep 4, 2020
1 parent 71ee3bd commit 05fba9b
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 3 deletions.
7 changes: 4 additions & 3 deletions x-pack/plugins/alerts/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,14 @@ export class AlertingPlugin {
);
}

this.eventLogger = plugins.eventLog.getLogger({
event: { provider: EVENT_LOG_PROVIDER },
});

setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects);

this.eventLogService = plugins.eventLog;
plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS));
this.eventLogger = plugins.eventLog.getLogger({
event: { provider: EVENT_LOG_PROVIDER },
});

const alertTypeRegistry = new AlertTypeRegistry({
taskManager: plugins.taskManager,
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/alerts/server/saved_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { SavedObjectsServiceSetup } from 'kibana/server';
import mappings from './mappings.json';
import { getMigrations } from './migrations';
import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';

export function setupSavedObjects(
Expand All @@ -16,6 +17,7 @@ export function setupSavedObjects(
name: 'alert',
hidden: true,
namespaceType: 'single',
migrations: getMigrations(encryptedSavedObjects),
mappings: mappings.alert,
});

Expand Down
135 changes: 135 additions & 0 deletions x-pack/plugins/alerts/server/saved_objects/migrations.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* 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 uuid from 'uuid';
import { getMigrations } from './migrations';
import { RawAlert } from '../types';
import { SavedObjectUnsanitizedDoc } from 'kibana/server';
import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks';
import { migrationMocks } from 'src/core/server/mocks';

const { log } = migrationMocks.createContext();
const encryptedSavedObjectsSetup = encryptedSavedObjectsMock.createSetup();

describe('7.10.0', () => {
beforeEach(() => {
jest.resetAllMocks();
encryptedSavedObjectsSetup.createMigration.mockImplementation(
(shouldMigrateWhenPredicate, migration) => migration
);
});

test('changes nothing on alerts by other plugins', () => {
const migration710 = getMigrations(encryptedSavedObjectsSetup)['7.10.0'];
const alert = getMockData({});
expect(migration710(alert, { log })).toMatchObject(alert);

expect(encryptedSavedObjectsSetup.createMigration).toHaveBeenCalledWith(
expect.any(Function),
expect.any(Function)
);
});

test('migrates the consumer for metrics', () => {
const migration710 = getMigrations(encryptedSavedObjectsSetup)['7.10.0'];
const alert = getMockData({
consumer: 'metrics',
});
expect(migration710(alert, { log })).toMatchObject({
...alert,
attributes: {
...alert.attributes,
consumer: 'infrastructure',
},
});
});

test('migrates the consumer for alerting', () => {
const migration710 = getMigrations(encryptedSavedObjectsSetup)['7.10.0'];
const alert = getMockData({
consumer: 'alerting',
});
expect(migration710(alert, { log })).toMatchObject({
...alert,
attributes: {
...alert.attributes,
consumer: 'alerts',
},
});
});
});

describe('7.10.0 migrates with failure', () => {
beforeEach(() => {
jest.resetAllMocks();
encryptedSavedObjectsSetup.createMigration.mockRejectedValueOnce(
new Error(`Can't migrate!`) as never
);
});

test('should show the proper exception', () => {
const migration710 = getMigrations(encryptedSavedObjectsSetup)['7.10.0'];
const alert = getMockData({
consumer: 'alerting',
});
const res = migration710(alert, { log });
expect(res).toMatchObject({
...alert,
attributes: {
...alert.attributes,
},
});
expect(log.error).toHaveBeenCalledWith(
`encryptedSavedObject migration failed for alert ${alert.id} with error: migrationFunc is not a function`,
{
alertDocument: {
...alert,
attributes: {
...alert.attributes,
},
},
}
);
});
});

function getMockData(
overwrites: Record<string, unknown> = {}
): SavedObjectUnsanitizedDoc<RawAlert> {
return {
attributes: {
enabled: true,
name: 'abc',
tags: ['foo'],
alertTypeId: '123',
consumer: 'bar',
apiKey: '',
apiKeyOwner: '',
schedule: { interval: '10s' },
throttle: null,
params: {
bar: true,
},
muteAll: false,
mutedInstanceIds: [],
createdBy: new Date().toISOString(),
updatedBy: new Date().toISOString(),
createdAt: new Date().toISOString(),
actions: [
{
group: 'default',
actionRef: '1',
actionTypeId: '1',
params: {
foo: true,
},
},
],
...overwrites,
},
id: uuid.v4(),
type: 'alert',
};
}
76 changes: 76 additions & 0 deletions x-pack/plugins/alerts/server/saved_objects/migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 {
SavedObjectMigrationMap,
SavedObjectUnsanitizedDoc,
SavedObjectMigrationFn,
SavedObjectMigrationContext,
} from '../../../../../src/core/server';
import { RawAlert } from '../types';
import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';

export function getMigrations(
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup
): SavedObjectMigrationMap {
const alertsMigration = changeAlertingConsumer(encryptedSavedObjects, 'alerting', 'alerts');

const infrastructureMigration = changeAlertingConsumer(
encryptedSavedObjects,
'metrics',
'infrastructure'
);

return {
'7.10.0': (doc: SavedObjectUnsanitizedDoc<RawAlert>, context: SavedObjectMigrationContext) => {
if (doc.attributes.consumer === 'alerting') {
return executeMigration(doc, context, alertsMigration);
} else if (doc.attributes.consumer === 'metrics') {
return executeMigration(doc, context, infrastructureMigration);
}
return doc;
},
};
}

function executeMigration(
doc: SavedObjectUnsanitizedDoc<RawAlert>,
context: SavedObjectMigrationContext,
migrationFunc: SavedObjectMigrationFn<RawAlert, RawAlert>
) {
try {
return migrationFunc(doc, context);
} catch (ex) {
context.log.error(
`encryptedSavedObject migration failed for alert ${doc.id} with error: ${ex.message}`,
{ alertDocument: doc }
);
}
return doc;
}

function changeAlertingConsumer(
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup,
from: string,
to: string
): SavedObjectMigrationFn<RawAlert, RawAlert> {
return encryptedSavedObjects.createMigration<RawAlert, RawAlert>(
function shouldBeMigrated(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> {
return doc.attributes.consumer === from;
},
(doc: SavedObjectUnsanitizedDoc<RawAlert>): SavedObjectUnsanitizedDoc<RawAlert> => {
const {
attributes: { consumer },
} = doc;
return {
...doc,
attributes: {
...doc.attributes,
consumer: consumer === from ? to : consumer,
},
};
}
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./alerts_space1'));
loadTestFile(require.resolve('./alerts_default_space'));
loadTestFile(require.resolve('./builtin_alert_types'));

// note that this test will destroy existing spaces
loadTestFile(require.resolve('./migrations'));
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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 expect from '@kbn/expect';
import { getUrlPrefix } from '../../../common/lib';
import { FtrProviderContext } from '../../../common/ftr_provider_context';

// eslint-disable-next-line import/no-default-export
export default function createGetTests({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');

describe('migrations', () => {
before(async () => {
await esArchiver.load('alerts');
});

after(async () => {
await esArchiver.unload('alerts');
});

it('7.10.0 migrates the `alerting` consumer to be the `alerts`', async () => {
const response = await supertest.get(
`${getUrlPrefix(``)}/api/alerts/alert/74f3e6d7-b7bb-477d-ac28-92ee22728e6e`
);

expect(response.status).to.eql(200);
expect(response.body.consumer).to.equal('alerts');
});

it('7.10.0 migrates the `metrics` consumer to be the `infrastructure`', async () => {
const response = await supertest.get(
`${getUrlPrefix(``)}/api/alerts/alert/74f3e6d7-b7bb-477d-ac28-fdf248d5f2a4`
);

expect(response.status).to.eql(200);
expect(response.body.consumer).to.equal('infrastructure');
});
});
}

0 comments on commit 05fba9b

Please sign in to comment.