Skip to content

Commit

Permalink
[alerting] migrates the old alerting consumer to be alerts (#69982)
Browse files Browse the repository at this point in the history
This PR migrates all old alerts with the `alerting` consumer to have `alerts` instead.
This is because in 7.9 we changed the feature ID and we need these to remain in sync otherwise the RBAC work (#67157) will break old alerts.
  • Loading branch information
gmmorris committed Jun 26, 2020
1 parent 41ecf39 commit 1ab5b4a
Show file tree
Hide file tree
Showing 10 changed files with 562 additions and 2 deletions.
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
87 changes: 87 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,87 @@
/*
* 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.9.0', () => {
beforeEach(() => {
jest.resetAllMocks();
encryptedSavedObjectsSetup.createMigration.mockImplementation(
(shouldMigrateWhenPredicate, migration) => migration
);
});

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

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

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

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',
};
}
49 changes: 49 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,49 @@
/*
* 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,
} from '../../../../../src/core/server';
import { RawAlert } from '../types';
import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';

export function getMigrations(
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup
): SavedObjectMigrationMap {
return {
'7.9.0': changeAlertingConsumer(encryptedSavedObjects),
};
}

/**
* In v7.9.0 we changed the Alerting plugin so it uses the `consumer` value of `alerts`
* prior to that we were using `alerting` and we need to keep these in sync
*/
function changeAlertingConsumer(
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup
): SavedObjectMigrationFn<RawAlert, RawAlert> {
const consumerMigration = new Map<string, string>();
consumerMigration.set('alerting', 'alerts');

return encryptedSavedObjects.createMigration<RawAlert, RawAlert>(
function shouldBeMigrated(doc): doc is SavedObjectUnsanitizedDoc<RawAlert> {
return consumerMigration.has(doc.attributes.consumer);
},
(doc: SavedObjectUnsanitizedDoc<RawAlert>): SavedObjectUnsanitizedDoc<RawAlert> => {
const {
attributes: { consumer },
} = doc;
return {
...doc,
attributes: {
...doc.attributes,
consumer: consumerMigration.get(consumer) ?? consumer,
},
};
}
);
}
1 change: 1 addition & 0 deletions x-pack/test/alerting_api_integration/common/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions)
'localhost',
'some.non.existent.com',
])}`,
'--xpack.encryptedSavedObjects.encryptionKey="wuGNaIhoMpk5sO4UBxgr3NyW1sFcLgIf"',
`--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`,
'--xpack.eventLog.logEntries=true',
`--xpack.actions.preconfigured=${JSON.stringify({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export default function typeNotEnabledTests({ getService }: FtrProviderContext)

describe('actionType not enabled', () => {
// loads action PREWRITTEN_ACTION_ID with actionType DISABLED_ACTION_TYPE
before(() => esArchiver.load('alerting'));
after(() => esArchiver.unload('alerting'));
before(() => esArchiver.load('actions'));
after(() => esArchiver.unload('actions'));

it('should handle create action with disabled actionType request appropriately', async () => {
const response = await supertest.post(`/api/actions/action`).set('kbn-xsrf', 'foo').send({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./alerts_space1'));
loadTestFile(require.resolve('./alerts_default_space'));
loadTestFile(require.resolve('./builtin_alert_types'));
loadTestFile(require.resolve('./migrations'));
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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.9.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');
});
});
}
41 changes: 41 additions & 0 deletions x-pack/test/functional/es_archives/alerts/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"type": "doc",
"value": {
"id": "alert:74f3e6d7-b7bb-477d-ac28-92ee22728e6e",
"index": ".kibana_1",
"source": {
"alert": {
"actions": [
],
"alertTypeId": "example.always-firing",
"apiKey": "QIUT8u0/kbOakEHSj50jDpVR90MrqOxanEscboYOoa8PxQvcA5jfHash+fqH3b+KNjJ1LpnBcisGuPkufY9j1e32gKzwGZV5Bfys87imHvygJvIM8uKiFF8bQ8Y4NTaxOJO9fAmZPrFy07ZcQMCAQz+DUTgBFqs=",
"apiKeyOwner": "elastic",
"consumer": "alerting",
"createdAt": "2020-06-17T15:35:38.497Z",
"createdBy": "elastic",
"enabled": true,
"muteAll": false,
"mutedInstanceIds": [
],
"name": "always-firing-alert",
"params": {
},
"schedule": {
"interval": "1m"
},
"scheduledTaskId": "329798f0-b0b0-11ea-9510-fdf248d5f2a4",
"tags": [
],
"throttle": null,
"updatedBy": "elastic"
},
"migrationVersion": {
"alert": "7.8.0"
},
"references": [
],
"type": "alert",
"updated_at": "2020-06-17T15:35:39.839Z"
}
}
}
Loading

0 comments on commit 1ab5b4a

Please sign in to comment.