[Alerting] Enable rule import/export and allow rule types to exclude themselves from export (#102999) (#103598)

* Removing feature flag changes

* Adding isExportable flag to rule type definition

* Adding isExportable flag to rule type definition

* Adding isExportable flag to rule type definition

* Filtering rule on export by rule type isExportable flag

* Fixing types

* Adding docs

* Fix condition when exportCount is 0

* Unit test for fix condition when exportCount is 0

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: ymao1 <ying.mao@elastic.co>
This commit is contained in:
Kibana Machine 2021-06-28 22:41:08 -04:00 committed by GitHub
parent 40027878d5
commit 0fd977acc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 489 additions and 139 deletions

View file

@ -80,6 +80,7 @@ The API returns the following:
},
"producer":"stackAlerts",
"minimumLicenseRequired":"basic",
"isExportable":true,
"enabledInLicense":true,
"authorizedConsumers":{
"alerts":{
@ -113,6 +114,9 @@ Each alert type contains the following properties:
| `minimumLicenseRequired`
| The license required to use the alert type.
| `isExportable`
| Whether the rule type is exportable through the Saved Objects Management UI.
| `enabledInLicense`
| Whether the alert type is enabled or disabled based on the license.

View file

@ -82,6 +82,7 @@ The API returns the following:
},
"producer":"stackAlerts",
"minimum_license_required":"basic",
"is_exportable":true,
"enabled_in_license":true,
"authorized_consumers":{
"alerts":{
@ -115,6 +116,9 @@ Each rule type contains the following properties:
| `minimum_license_required`
| The license required to use the rule type.
| `is_exportable`
| Whether the rule type is exportable through the Saved Objects Management UI.
| `enabled_in_license`
| Whether the rule type is enabled or disabled based on the license.

View file

@ -152,6 +152,25 @@ You can perform these operations in bulk by multi-selecting rules, and then clic
[role="screenshot"]
image:images/bulk-mute-disable.png[The Manage rules button lets you mute/unmute, enable/disable, and delete in bulk,width=75%]
[float]
[[importing-and-exporting-rules]]
=== Import and export rules
To import and export rules, use the <<managing-saved-objects, Saved Objects Management UI>>.
[NOTE]
==============================================
Some rule types cannot be exported through this interface:
**Security rules** can be imported and exported using the {security-guide}/rules-ui-management.html#import-export-rules-ui[Security UI].
**Stack monitoring rules** are <<kibana-alerts, automatically created>> for you and therefore cannot be managed via the Saved Objects Management UI.
==============================================
Rules are disabled on export. You are prompted to re-enable rule on successful import.
[role="screenshot"]
image::images/rules-imported-banner.png[Rules import banner, width=50%]
[float]
[[rule-details]]
=== Drilldown to rule details

View file

@ -101,6 +101,22 @@ describe('createSavedObjectsStreamFromNdJson', () => {
},
]);
});
it('handles an ndjson stream that only contains excluded saved objects', async () => {
const savedObjectsStream = await createSavedObjectsStreamFromNdJson(
new Readable({
read() {
this.push(
'{"excludedObjects":[{"id":"foo","reason":"excluded","type":"foo-type"}],"excludedObjectsCount":1,"exportedCount":0,"missingRefCount":0,"missingReferences":[]}\n'
);
this.push(null);
},
})
);
const result = await readStreamToCompletion(savedObjectsStream);
expect(result).toEqual([]);
});
});
describe('validateTypes', () => {

View file

@ -32,7 +32,7 @@ export async function createSavedObjectsStreamFromNdJson(ndJsonStream: Readable)
}
}),
createFilterStream<SavedObject | SavedObjectsExportResultDetails>(
(obj) => !!obj && !(obj as SavedObjectsExportResultDetails).exportedCount
(obj) => !!obj && (obj as SavedObjectsExportResultDetails).exportedCount === undefined
),
createConcatStream([]),
]);

View file

@ -53,6 +53,7 @@ export const alertType: AlertType<
],
defaultActionGroupId: DEFAULT_ACTION_GROUP,
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({
services,
params: { instances = DEFAULT_INSTANCES_TO_GENERATE, thresholds },

View file

@ -51,6 +51,7 @@ export const alertType: AlertType<
name: 'People In Space Right Now',
actionGroups: [{ id: 'default', name: 'default' }],
minimumLicenseRequired: 'basic',
isExportable: true,
defaultActionGroupId: 'default',
recoveryActionGroup: {
id: 'hasLandedBackOnEarth',

View file

@ -118,6 +118,7 @@ The following table describes the properties of the `options` object.
|executor|This is where the code for the rule type lives. This is a function to be called when executing a rule on an interval basis. For full details, see the executor section below.|Function|
|producer|The id of the application producing this rule type.|string|
|minimumLicenseRequired|The value of a minimum license. Most of the rules are licensed as "basic".|string|
|isExportable|Whether the rule type is exportable from the Saved Objects Management UI.|boolean|
### Executor
@ -262,6 +263,7 @@ const myRuleType: AlertType<
],
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({
alertId,
startedAt,

View file

@ -20,6 +20,7 @@ export interface AlertType<
defaultActionGroupId: ActionGroupIds;
producer: string;
minimumLicenseRequired: LicenseType;
isExportable: boolean;
}
export interface ActionGroup<ActionGroupIds extends string> {

View file

@ -24,6 +24,7 @@ describe('loadAlertTypes', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
},
@ -49,6 +50,7 @@ describe('loadAlertType', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
};
@ -71,6 +73,7 @@ describe('loadAlertType', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
};

View file

@ -20,6 +20,7 @@ const mockAlertType = (id: string): AlertType => ({
defaultActionGroupId: 'default',
producer: 'alerts',
minimumLicenseRequired: 'basic',
isExportable: true,
});
describe('AlertNavigationRegistry', () => {

View file

@ -47,6 +47,7 @@ describe('has()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
});
@ -67,6 +68,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
@ -99,6 +101,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
@ -129,6 +132,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
@ -159,6 +163,7 @@ describe('register()', () => {
executor: jest.fn(),
producer: 'alerts',
minimumLicenseRequired: 'basic',
isExportable: true,
};
const registry = new AlertTypeRegistry(alertTypeRegistryParams);
registry.register(alertType);
@ -203,6 +208,7 @@ describe('register()', () => {
},
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
@ -227,6 +233,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
@ -257,6 +264,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
@ -279,6 +287,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
});
@ -294,6 +303,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
})
@ -315,6 +325,7 @@ describe('get()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
});
@ -339,6 +350,7 @@ describe('get()', () => {
"defaultActionGroupId": "default",
"executor": [MockFunction],
"id": "test",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "Test",
"producer": "alerts",
@ -377,6 +389,7 @@ describe('list()', () => {
},
],
defaultActionGroupId: 'testActionGroup',
isExportable: true,
minimumLicenseRequired: 'basic',
executor: jest.fn(),
producer: 'alerts',
@ -403,6 +416,7 @@ describe('list()', () => {
"defaultActionGroupId": "testActionGroup",
"enabledInLicense": false,
"id": "test",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "Test",
"producer": "alerts",
@ -467,6 +481,7 @@ describe('ensureAlertTypeEnabled', () => {
defaultActionGroupId: 'default',
executor: jest.fn(),
producer: 'alerts',
isExportable: true,
minimumLicenseRequired: 'basic',
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
});
@ -497,6 +512,7 @@ function alertTypeWithVariables<ActionGroupIds extends string>(
name: `${id}-name`,
actionGroups: [],
defaultActionGroupId: id,
isExportable: true,
minimumLicenseRequired: 'basic',
async executor() {},
producer: 'alerts',

View file

@ -46,6 +46,7 @@ export interface RegistryAlertType
| 'actionVariables'
| 'producer'
| 'minimumLicenseRequired'
| 'isExportable'
> {
id: string;
enabledInLicense: boolean;
@ -250,6 +251,7 @@ export class AlertTypeRegistry {
actionVariables,
producer,
minimumLicenseRequired,
isExportable,
},
]: [string, UntypedNormalizedAlertType]) => ({
id,
@ -260,6 +262,7 @@ export class AlertTypeRegistry {
actionVariables,
producer,
minimumLicenseRequired,
isExportable,
enabledInLicense: !!this.licenseState.getLicenseCheckForAlertType(
id,
name,

View file

@ -58,6 +58,7 @@ describe('aggregate()', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myType',
name: 'myType',
@ -110,6 +111,7 @@ describe('aggregate()', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
authorizedConsumers: {

View file

@ -1293,6 +1293,7 @@ describe('create()', () => {
}),
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
producer: 'alerts',
});

View file

@ -67,6 +67,7 @@ describe('find()', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
id: 'myType',
name: 'myType',
producer: 'myApp',
@ -126,6 +127,7 @@ describe('find()', () => {
recoveryActionGroup: RecoveredActionGroup,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
producer: 'alerts',
authorizedConsumers: {
myApp: { read: true, all: true },

View file

@ -88,6 +88,7 @@ export function getBeforeSetup(
recoveryActionGroup: RecoveredActionGroup,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
producer: 'alerts',
}));

View file

@ -58,6 +58,7 @@ describe('listAlertTypes', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'alertingAlertType',
name: 'alertingAlertType',
@ -69,6 +70,7 @@ describe('listAlertTypes', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myAppAlertType',
name: 'myAppAlertType',
@ -110,6 +112,7 @@ describe('listAlertTypes', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myType',
name: 'myType',
@ -122,6 +125,7 @@ describe('listAlertTypes', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
enabledInLicense: true,
@ -139,6 +143,7 @@ describe('listAlertTypes', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
authorizedConsumers: {

View file

@ -127,6 +127,7 @@ describe('update()', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
async executor() {},
producer: 'alerts',
@ -773,6 +774,7 @@ describe('update()', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
validate: {
params: schema.object({
@ -1096,6 +1098,7 @@ describe('update()', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
async executor() {},
producer: 'alerts',

View file

@ -335,6 +335,7 @@ beforeEach(() => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
async executor() {},
producer: 'alerts',
@ -346,6 +347,7 @@ beforeEach(() => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
async executor() {},
producer: 'alerts',

View file

@ -203,6 +203,7 @@ beforeEach(() => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
async executor() {},
producer: 'myApp',
@ -892,6 +893,7 @@ describe('AlertingAuthorization', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myOtherAppAlertType',
name: 'myOtherAppAlertType',
@ -903,6 +905,7 @@ describe('AlertingAuthorization', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myAppAlertType',
name: 'myAppAlertType',
@ -914,6 +917,7 @@ describe('AlertingAuthorization', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'mySecondAppAlertType',
name: 'mySecondAppAlertType',
@ -1242,6 +1246,7 @@ describe('AlertingAuthorization', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myOtherAppAlertType',
name: 'myOtherAppAlertType',
@ -1253,6 +1258,7 @@ describe('AlertingAuthorization', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myAppAlertType',
name: 'myAppAlertType',
@ -1300,6 +1306,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myAppAlertType",
"producer": "myApp",
@ -1328,6 +1335,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myOtherAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myOtherAppAlertType",
"producer": "myOtherApp",
@ -1387,6 +1395,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myAppAlertType",
"producer": "myApp",
@ -1423,6 +1432,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myOtherAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myOtherAppAlertType",
"producer": "myOtherApp",
@ -1502,6 +1512,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myOtherAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myOtherAppAlertType",
"producer": "myOtherApp",
@ -1526,6 +1537,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myAppAlertType",
"producer": "myApp",
@ -1605,6 +1617,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myOtherAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myOtherAppAlertType",
"producer": "myOtherApp",
@ -1633,6 +1646,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myAppAlertType",
"producer": "myApp",
@ -1703,6 +1717,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myAppAlertType",
"producer": "myApp",
@ -1807,6 +1822,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myOtherAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myOtherAppAlertType",
"producer": "myOtherApp",
@ -1831,6 +1847,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myAppAlertType",
"producer": "myApp",
@ -1914,6 +1931,7 @@ describe('AlertingAuthorization', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "myOtherAppAlertType",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "myOtherAppAlertType",
"producer": "myOtherApp",

View file

@ -26,6 +26,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => {
name: 'myAppAlertType',
producer: 'myApp',
minimumLicenseRequired: 'basic',
isExportable: true,
authorizedConsumers: {
myApp: { read: true, all: true },
},
@ -53,6 +54,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => {
actionGroups: [],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myAppAlertType',
name: 'myAppAlertType',
@ -88,6 +90,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => {
actionGroups: [],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myAppAlertType',
name: 'myAppAlertType',
@ -104,6 +107,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => {
actionGroups: [],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myOtherAppAlertType',
name: 'myOtherAppAlertType',
@ -120,6 +124,7 @@ describe('asKqlFiltersByRuleTypeAndConsumer', () => {
actionGroups: [],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'mySecondAppAlertType',
name: 'mySecondAppAlertType',
@ -162,6 +167,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => {
name: 'myAppAlertType',
producer: 'myApp',
minimumLicenseRequired: 'basic',
isExportable: true,
authorizedConsumers: {
myApp: { read: true, all: true },
},
@ -216,6 +222,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => {
actionGroups: [],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myAppAlertType',
name: 'myAppAlertType',
@ -283,6 +290,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => {
actionGroups: [],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myAppAlertType',
name: 'myAppAlertType',
@ -299,6 +307,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => {
actionGroups: [],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myOtherAppAlertType',
name: 'myOtherAppAlertType',
@ -315,6 +324,7 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => {
actionGroups: [],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'mySecondAppAlertType',
name: 'mySecondAppAlertType',

View file

@ -12,7 +12,6 @@ describe('config validation', () => {
const config: Record<string, unknown> = {};
expect(configSchema.validate(config)).toMatchInlineSnapshot(`
Object {
"enableImportExport": false,
"healthCheck": Object {
"interval": "60m",
},

View file

@ -16,7 +16,6 @@ export const configSchema = schema.object({
interval: schema.string({ validate: validateDurationSchema, defaultValue: '5m' }),
removalDelay: schema.string({ validate: validateDurationSchema, defaultValue: '1h' }),
}),
enableImportExport: schema.boolean({ defaultValue: false }),
});
export type AlertsConfig = TypeOf<typeof configSchema>;

View file

@ -71,7 +71,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
}),
pollInterval
).subscribe();
@ -105,7 +104,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
}),
pollInterval,
retryDelay
@ -150,7 +148,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
})
).toPromise();
@ -181,7 +178,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
})
).toPromise();
@ -212,7 +208,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
})
).toPromise();
@ -240,7 +235,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
}),
retryDelay
).subscribe((status) => {
@ -271,7 +265,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
}),
retryDelay
).subscribe((status) => {
@ -308,7 +301,6 @@ describe('getHealthServiceStatusWithRetryAndErrorHandling', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
})
).toPromise();

View file

@ -70,6 +70,7 @@ describe('getLicenseCheckForAlertType', () => {
executor: jest.fn(),
producer: 'alerts',
minimumLicenseRequired: 'gold',
isExportable: true,
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
};
@ -204,6 +205,7 @@ describe('ensureLicenseForAlertType()', () => {
executor: jest.fn(),
producer: 'alerts',
minimumLicenseRequired: 'gold',
isExportable: true,
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
};

View file

@ -18,7 +18,6 @@ import { AlertsConfig } from './config';
import { AlertType } from './types';
import { eventLogMock } from '../../event_log/server/mocks';
import { actionsMock } from '../../actions/server/mocks';
import mappings from './saved_objects/mappings.json';
describe('Alerting Plugin', () => {
describe('setup()', () => {
@ -37,7 +36,6 @@ describe('Alerting Plugin', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
});
plugin = new AlertingPlugin(context);
@ -61,78 +59,13 @@ describe('Alerting Plugin', () => {
);
});
it('should register saved object with no management capability if enableImportExport is false', async () => {
const context = coreMock.createPluginInitializerContext<AlertsConfig>({
healthCheck: {
interval: '5m',
},
invalidateApiKeysTask: {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
});
plugin = new AlertingPlugin(context);
const setupMocks = coreMock.createSetup();
await plugin.setup(setupMocks, {
licensing: licensingMock.createSetup(),
encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(),
taskManager: taskManagerMock.createSetup(),
eventLog: eventLogServiceMock.create(),
actions: actionsMock.createSetup(),
statusService: statusServiceMock.createSetupContract(),
});
expect(setupMocks.savedObjects.registerType).toHaveBeenCalledTimes(2);
const registerAlertingSavedObject = setupMocks.savedObjects.registerType.mock.calls[0][0];
expect(registerAlertingSavedObject.name).toEqual('alert');
expect(registerAlertingSavedObject.hidden).toBe(true);
expect(registerAlertingSavedObject.mappings).toEqual(mappings.alert);
expect(registerAlertingSavedObject.management).toBeUndefined();
});
it('should register saved object with import/export capability if enableImportExport is true', async () => {
const context = coreMock.createPluginInitializerContext<AlertsConfig>({
healthCheck: {
interval: '5m',
},
invalidateApiKeysTask: {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: true,
});
plugin = new AlertingPlugin(context);
const setupMocks = coreMock.createSetup();
await plugin.setup(setupMocks, {
licensing: licensingMock.createSetup(),
encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(),
taskManager: taskManagerMock.createSetup(),
eventLog: eventLogServiceMock.create(),
actions: actionsMock.createSetup(),
statusService: statusServiceMock.createSetupContract(),
});
expect(setupMocks.savedObjects.registerType).toHaveBeenCalledTimes(2);
const registerAlertingSavedObject = setupMocks.savedObjects.registerType.mock.calls[0][0];
expect(registerAlertingSavedObject.name).toEqual('alert');
expect(registerAlertingSavedObject.hidden).toBe(true);
expect(registerAlertingSavedObject.mappings).toEqual(mappings.alert);
expect(registerAlertingSavedObject.management).not.toBeUndefined();
expect(registerAlertingSavedObject.management?.importableAndExportable).toBe(true);
expect(registerAlertingSavedObject.management?.getTitle).not.toBeUndefined();
expect(registerAlertingSavedObject.management?.onImport).not.toBeUndefined();
expect(registerAlertingSavedObject.management?.onExport).not.toBeUndefined();
});
describe('registerType()', () => {
let setup: PluginSetupContract;
const sampleAlertType: AlertType<never, never, never, never, 'default'> = {
id: 'test',
name: 'test',
minimumLicenseRequired: 'basic',
isExportable: true,
actionGroups: [],
defaultActionGroupId: 'default',
producer: 'test',
@ -189,7 +122,6 @@ describe('Alerting Plugin', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
});
const plugin = new AlertingPlugin(context);
@ -229,7 +161,6 @@ describe('Alerting Plugin', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
});
const plugin = new AlertingPlugin(context);
@ -283,7 +214,6 @@ describe('Alerting Plugin', () => {
interval: '5m',
removalDelay: '1h',
},
enableImportExport: false,
});
const plugin = new AlertingPlugin(context);

View file

@ -192,8 +192,6 @@ export class AlertingPlugin {
event: { provider: EVENT_LOG_PROVIDER },
});
setupSavedObjects(core.savedObjects, plugins.encryptedSavedObjects, this.config);
this.eventLogService = plugins.eventLog;
plugins.eventLog.registerProviderActions(EVENT_LOG_PROVIDER, Object.values(EVENT_LOG_ACTIONS));
@ -221,6 +219,13 @@ export class AlertingPlugin {
});
}
setupSavedObjects(
core.savedObjects,
plugins.encryptedSavedObjects,
this.alertTypeRegistry,
this.logger
);
initializeApiKeyInvalidator(
this.logger,
core.getStartServices(),

View file

@ -47,6 +47,7 @@ describe('listAlertTypesRoute', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
authorizedConsumers: {},
actionVariables: {
@ -79,6 +80,7 @@ describe('listAlertTypesRoute', () => {
"defaultActionGroupId": "default",
"enabledInLicense": true,
"id": "1",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "name",
"producer": "test",
@ -120,6 +122,7 @@ describe('listAlertTypesRoute', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
authorizedConsumers: {},
actionVariables: {
@ -172,6 +175,7 @@ describe('listAlertTypesRoute', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
authorizedConsumers: {},
actionVariables: {

View file

@ -48,6 +48,7 @@ describe('ruleTypesRoute', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
authorizedConsumers: {},
actionVariables: {
@ -70,6 +71,7 @@ describe('ruleTypesRoute', () => {
],
default_action_group_id: 'default',
minimum_license_required: 'basic',
is_exportable: true,
recovery_action_group: RecoveredActionGroup,
authorized_consumers: {},
action_variables: {
@ -102,6 +104,7 @@ describe('ruleTypesRoute', () => {
"default_action_group_id": "default",
"enabled_in_license": true,
"id": "1",
"is_exportable": true,
"minimum_license_required": "basic",
"name": "name",
"producer": "test",
@ -143,6 +146,7 @@ describe('ruleTypesRoute', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
authorizedConsumers: {},
actionVariables: {
@ -195,6 +199,7 @@ describe('ruleTypesRoute', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
authorizedConsumers: {},
actionVariables: {

View file

@ -19,6 +19,7 @@ const rewriteBodyRes: RewriteResponseCase<RegistryAlertTypeWithAuth[]> = (result
actionGroups,
defaultActionGroupId,
minimumLicenseRequired,
isExportable,
actionVariables,
authorizedConsumers,
...rest
@ -29,6 +30,7 @@ const rewriteBodyRes: RewriteResponseCase<RegistryAlertTypeWithAuth[]> = (result
action_groups: actionGroups,
default_action_group_id: defaultActionGroupId,
minimum_license_required: minimumLicenseRequired,
is_exportable: isExportable,
action_variables: actionVariables,
authorized_consumers: authorizedConsumers,
})

View file

@ -6,6 +6,7 @@
*/
import type {
Logger,
SavedObject,
SavedObjectsExportTransformContext,
SavedObjectsServiceSetup,
@ -17,7 +18,9 @@ import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objec
import { transformRulesForExport } from './transform_rule_for_export';
import { RawAlert } from '../types';
import { getImportWarnings } from './get_import_warnings';
import { AlertsConfig } from '../config';
import { isRuleExportable } from './is_rule_exportable';
import { AlertTypeRegistry } from '../alert_type_registry';
export { partiallyUpdateAlert } from './partially_update_alert';
export const AlertAttributesExcludedFromAAD = [
@ -44,65 +47,63 @@ export type AlertAttributesExcludedFromAADType =
export function setupSavedObjects(
savedObjects: SavedObjectsServiceSetup,
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup,
alertingConfig: Promise<AlertsConfig>
ruleTypeRegistry: AlertTypeRegistry,
logger: Logger
) {
alertingConfig.then((config: AlertsConfig) => {
savedObjects.registerType({
name: 'alert',
hidden: true,
namespaceType: 'single',
migrations: getMigrations(encryptedSavedObjects),
mappings: mappings.alert as SavedObjectsTypeMappingDefinition,
...(config.enableImportExport
? {
management: {
importableAndExportable: true,
getTitle(ruleSavedObject: SavedObject<RawAlert>) {
return `Rule: [${ruleSavedObject.attributes.name}]`;
},
onImport(ruleSavedObjects) {
return {
warnings: getImportWarnings(ruleSavedObjects),
};
},
onExport<RawAlert>(
context: SavedObjectsExportTransformContext,
objects: Array<SavedObject<RawAlert>>
) {
return transformRulesForExport(objects);
},
},
}
: {}),
});
savedObjects.registerType({
name: 'alert',
hidden: true,
namespaceType: 'single',
migrations: getMigrations(encryptedSavedObjects),
mappings: mappings.alert as SavedObjectsTypeMappingDefinition,
management: {
importableAndExportable: true,
getTitle(ruleSavedObject: SavedObject<RawAlert>) {
return `Rule: [${ruleSavedObject.attributes.name}]`;
},
onImport(ruleSavedObjects) {
return {
warnings: getImportWarnings(ruleSavedObjects),
};
},
onExport<RawAlert>(
context: SavedObjectsExportTransformContext,
objects: Array<SavedObject<RawAlert>>
) {
return transformRulesForExport(objects);
},
isExportable<RawAlert>(ruleSavedObject: SavedObject<RawAlert>) {
return isRuleExportable(ruleSavedObject, ruleTypeRegistry, logger);
},
},
});
savedObjects.registerType({
name: 'api_key_pending_invalidation',
hidden: true,
namespaceType: 'agnostic',
mappings: {
properties: {
apiKeyId: {
type: 'keyword',
},
createdAt: {
type: 'date',
},
savedObjects.registerType({
name: 'api_key_pending_invalidation',
hidden: true,
namespaceType: 'agnostic',
mappings: {
properties: {
apiKeyId: {
type: 'keyword',
},
createdAt: {
type: 'date',
},
},
});
},
});
// Encrypted attributes
encryptedSavedObjects.registerType({
type: 'alert',
attributesToEncrypt: new Set(['apiKey']),
attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD),
});
// Encrypted attributes
encryptedSavedObjects.registerType({
type: 'alert',
attributesToEncrypt: new Set(['apiKey']),
attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD),
});
// Encrypted attributes
encryptedSavedObjects.registerType({
type: 'api_key_pending_invalidation',
attributesToEncrypt: new Set(['apiKeyId']),
});
// Encrypted attributes
encryptedSavedObjects.registerType({
type: 'api_key_pending_invalidation',
attributesToEncrypt: new Set(['apiKeyId']),
});
}

View file

@ -0,0 +1,208 @@
/*
* 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 { MockedLogger, loggerMock } from '@kbn/logging/target/mocks';
import { TaskRunnerFactory } from '../task_runner';
import { AlertTypeRegistry, ConstructorOptions } from '../alert_type_registry';
import { taskManagerMock } from '../../../task_manager/server/mocks';
import { ILicenseState } from '../lib/license_state';
import { licenseStateMock } from '../lib/license_state.mock';
import { licensingMock } from '../../../licensing/server/mocks';
import { isRuleExportable } from './is_rule_exportable';
let ruleTypeRegistryParams: ConstructorOptions;
let logger: MockedLogger;
let mockedLicenseState: jest.Mocked<ILicenseState>;
const taskManager = taskManagerMock.createSetup();
beforeEach(() => {
jest.resetAllMocks();
mockedLicenseState = licenseStateMock.create();
logger = loggerMock.create();
ruleTypeRegistryParams = {
taskManager,
taskRunnerFactory: new TaskRunnerFactory(),
licenseState: mockedLicenseState,
licensing: licensingMock.createSetup(),
};
});
describe('isRuleExportable', () => {
it('should return true if rule type isExportable is true', () => {
const registry = new AlertTypeRegistry(ruleTypeRegistryParams);
registry.register({
id: 'foo',
name: 'Foo',
actionGroups: [
{
id: 'default',
name: 'Default',
},
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
});
expect(
isRuleExportable(
{
id: '1',
type: 'alert',
attributes: {
enabled: true,
name: 'rule-name',
tags: ['tag-1', 'tag-2'],
alertTypeId: 'foo',
consumer: 'alert-consumer',
schedule: { interval: '1m' },
actions: [],
params: {},
createdBy: 'me',
updatedBy: 'me',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
apiKey: '4tndskbuhewotw4klrhgjewrt9u',
apiKeyOwner: 'me',
throttle: null,
notifyWhen: 'onActionGroupChange',
muteAll: false,
mutedInstanceIds: [],
executionStatus: {
status: 'active',
lastExecutionDate: '2020-08-20T19:23:38Z',
error: null,
},
scheduledTaskId: '2q5tjbf3q45twer',
},
references: [],
},
registry,
logger
)
).toEqual(true);
});
it('should return false and log warning if rule type isExportable is false', () => {
const registry = new AlertTypeRegistry(ruleTypeRegistryParams);
registry.register({
id: 'foo',
name: 'Foo',
actionGroups: [
{
id: 'default',
name: 'Default',
},
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: false,
executor: jest.fn(),
producer: 'alerts',
});
expect(
isRuleExportable(
{
id: '1',
type: 'alert',
attributes: {
enabled: true,
name: 'rule-name',
tags: ['tag-1', 'tag-2'],
alertTypeId: 'foo',
consumer: 'alert-consumer',
schedule: { interval: '1m' },
actions: [],
params: {},
createdBy: 'me',
updatedBy: 'me',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
apiKey: '4tndskbuhewotw4klrhgjewrt9u',
apiKeyOwner: 'me',
throttle: null,
notifyWhen: 'onActionGroupChange',
muteAll: false,
mutedInstanceIds: [],
executionStatus: {
status: 'active',
lastExecutionDate: '2020-08-20T19:23:38Z',
error: null,
},
scheduledTaskId: '2q5tjbf3q45twer',
},
references: [],
},
registry,
logger
)
).toEqual(false);
expect(logger.warn).toHaveBeenCalledWith(
`Skipping export of rule \"1\" because rule type \"foo\" is not exportable through this interface.`
);
});
it('should return false and log warning if rule type is not registered', () => {
const registry = new AlertTypeRegistry(ruleTypeRegistryParams);
registry.register({
id: 'foo',
name: 'Foo',
actionGroups: [
{
id: 'default',
name: 'Default',
},
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: false,
executor: jest.fn(),
producer: 'alerts',
});
expect(
isRuleExportable(
{
id: '1',
type: 'alert',
attributes: {
enabled: true,
name: 'rule-name',
tags: ['tag-1', 'tag-2'],
alertTypeId: 'bar',
consumer: 'alert-consumer',
schedule: { interval: '1m' },
actions: [],
params: {},
createdBy: 'me',
updatedBy: 'me',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
apiKey: '4tndskbuhewotw4klrhgjewrt9u',
apiKeyOwner: 'me',
throttle: null,
notifyWhen: 'onActionGroupChange',
muteAll: false,
mutedInstanceIds: [],
executionStatus: {
status: 'active',
lastExecutionDate: '2020-08-20T19:23:38Z',
error: null,
},
scheduledTaskId: '2q5tjbf3q45twer',
},
references: [],
},
registry,
logger
)
).toEqual(false);
expect(logger.warn).toHaveBeenCalledWith(
`Skipping export of rule \"1\" because rule type \"bar\" is not recognized.`
);
});
});

View file

@ -0,0 +1,33 @@
/*
* 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 { Logger, SavedObject } from 'kibana/server';
import { RawAlert } from '../types';
import { AlertTypeRegistry } from '../alert_type_registry';
export function isRuleExportable(
rule: SavedObject,
ruleTypeRegistry: AlertTypeRegistry,
logger: Logger
): boolean {
const ruleSO = rule as SavedObject<RawAlert>;
try {
const ruleType = ruleTypeRegistry.get(ruleSO.attributes.alertTypeId);
if (!ruleType.isExportable) {
logger.warn(
`Skipping export of rule "${ruleSO.id}" because rule type "${ruleSO.attributes.alertTypeId}" is not exportable through this interface.`
);
}
return ruleType.isExportable;
} catch (err) {
logger.warn(
`Skipping export of rule "${ruleSO.id}" because rule type "${ruleSO.attributes.alertTypeId}" is not recognized.`
);
return false;
}
}

View file

@ -44,6 +44,7 @@ const alertType: NormalizedAlertType<
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: {
id: 'recovered',
name: 'Recovered',

View file

@ -44,6 +44,7 @@ const alertType: jest.Mocked<UntypedNormalizedAlertType> = {
actionGroups: [{ id: 'default', name: 'Default' }, RecoveredActionGroup],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
executor: jest.fn(),
producer: 'alerts',

View file

@ -26,6 +26,7 @@ const alertType: UntypedNormalizedAlertType = {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: {
id: 'recovered',
name: 'Recovered',

View file

@ -146,6 +146,7 @@ export interface AlertType<
params?: ActionVariable[];
};
minimumLicenseRequired: LicenseType;
isExportable: boolean;
}
export type UntypedAlertType = AlertType<

View file

@ -33,6 +33,7 @@ export const ALERT_TYPES_CONFIG: Record<
actionGroups: Array<ActionGroup<ThresholdMetActionGroupId>>;
defaultActionGroupId: ThresholdMetActionGroupId;
minimumLicenseRequired: string;
isExportable: boolean;
producer: string;
}
> = {
@ -44,6 +45,7 @@ export const ALERT_TYPES_CONFIG: Record<
defaultActionGroupId: THRESHOLD_MET_GROUP_ID,
minimumLicenseRequired: 'basic',
producer: 'apm',
isExportable: true,
},
[AlertType.TransactionDuration]: {
name: i18n.translate('xpack.apm.transactionDurationAlert.name', {
@ -53,6 +55,7 @@ export const ALERT_TYPES_CONFIG: Record<
defaultActionGroupId: THRESHOLD_MET_GROUP_ID,
minimumLicenseRequired: 'basic',
producer: 'apm',
isExportable: true,
},
[AlertType.TransactionDurationAnomaly]: {
name: i18n.translate('xpack.apm.transactionDurationAnomalyAlert.name', {
@ -62,6 +65,7 @@ export const ALERT_TYPES_CONFIG: Record<
defaultActionGroupId: THRESHOLD_MET_GROUP_ID,
minimumLicenseRequired: 'basic',
producer: 'apm',
isExportable: true,
},
[AlertType.TransactionErrorRate]: {
name: i18n.translate('xpack.apm.transactionErrorRateAlert.name', {
@ -71,6 +75,7 @@ export const ALERT_TYPES_CONFIG: Record<
defaultActionGroupId: THRESHOLD_MET_GROUP_ID,
minimumLicenseRequired: 'basic',
producer: 'apm',
isExportable: true,
},
};

View file

@ -71,6 +71,7 @@ export function registerErrorCountAlertType({
},
producer: 'apm',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: async ({ services, params }) => {
const config = await config$.pipe(take(1)).toPromise();
const alertParams = params;

View file

@ -79,6 +79,7 @@ export function registerTransactionDurationAlertType({
},
producer: 'apm',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: async ({ services, params }) => {
const config = await config$.pipe(take(1)).toPromise();
const alertParams = params;

View file

@ -87,6 +87,7 @@ export function registerTransactionDurationAnomalyAlertType({
},
producer: 'apm',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: async ({ services, params }) => {
if (!ml) {
return {};

View file

@ -77,6 +77,7 @@ export function registerTransactionErrorRateAlertType({
},
producer: 'apm',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: async ({ services, params: alertParams }) => {
const config = await config$.pipe(take(1)).toPromise();
const indices = await getApmIndices({

View file

@ -89,6 +89,7 @@ export const registerMetricInventoryThresholdAlertType = (
actionGroups: [FIRED_ACTIONS, WARNING_ACTIONS],
producer: 'infrastructure',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: createInventoryMetricThresholdExecutor(libs),
actionVariables: {
context: [

View file

@ -107,6 +107,7 @@ export async function registerLogThresholdAlertType(
defaultActionGroupId: FIRED_ACTIONS.id,
actionGroups: [FIRED_ACTIONS],
minimumLicenseRequired: 'basic',
isExportable: true,
executor: createLogThresholdExecutor(libs),
actionVariables: {
context: [

View file

@ -64,6 +64,7 @@ export const registerMetricAnomalyAlertType = (
actionGroups: [FIRED_ACTIONS],
producer: 'infrastructure',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: createMetricAnomalyExecutor(libs, ml),
actionVariables: {
context: [

View file

@ -100,6 +100,7 @@ export function registerMetricThresholdAlertType(libs: InfraBackendLibs): Metric
defaultActionGroupId: FIRED_ACTIONS.id,
actionGroups: [FIRED_ACTIONS, WARNING_ACTIONS],
minimumLicenseRequired: 'basic',
isExportable: true,
executor: createMetricThresholdExecutor(libs),
actionVariables: {
context: [

View file

@ -119,6 +119,7 @@ export function registerAnomalyDetectionAlertType({
},
producer: PLUGIN_ID,
minimumLicenseRequired: MINIMUM_FULL_LICENSE,
isExportable: true,
async executor({ services, params, alertId, state, previousStartedAt, startedAt }) {
const fakeRequest = {} as KibanaRequest;
const { execute } = mlSharedServices.alertingServiceProvider(

View file

@ -96,6 +96,7 @@ export class BaseAlert {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: false,
executor: (
options: AlertExecutorOptions<never, never, AlertInstanceState, never, 'default'> & {
state: ExecutedState;

View file

@ -40,6 +40,7 @@ function createRule() {
},
id: 'test_type',
minimumLicenseRequired: 'basic',
isExportable: true,
name: 'Test type',
producer: 'test',
actionVariables: {

View file

@ -37,6 +37,7 @@ export const rulesNotificationAlertType = ({
}),
},
minimumLicenseRequired: 'basic',
isExportable: false,
async executor({ startedAt, previousStartedAt, alertId, services, params }) {
const ruleAlertSavedObject = await services.savedObjectsClient.get<AlertAttributes>(
'alert',

View file

@ -45,6 +45,7 @@ export const createEqlAlertType = (ruleDataClient: RuleDataClient, logger: Logge
context: [{ name: 'server', description: 'the server' }],
},
minimumLicenseRequired: 'basic',
isExportable: false,
producer: 'security-solution',
async executor({
startedAt,

View file

@ -57,6 +57,7 @@ export const mlAlertType = createSecurityMlRuleType({
context: [{ name: 'server', description: 'the server' }],
},
minimumLicenseRequired: 'basic',
isExportable: false,
producer: 'security-solution',
async executor({
services: { alertWithPersistence, findAlerts },

View file

@ -43,6 +43,7 @@ export const createQueryAlertType = (ruleDataClient: RuleDataClient, logger: Log
context: [{ name: 'server', description: 'the server' }],
},
minimumLicenseRequired: 'basic',
isExportable: false,
producer: 'security-solution',
async executor({
services: { alertWithPersistence, findAlerts },

View file

@ -113,6 +113,7 @@ export const createThresholdAlertType = (ruleDataClient: RuleDataClient, logger:
context: [{ name: 'server', description: 'the server' }],
},
minimumLicenseRequired: 'basic',
isExportable: false,
producer: 'security-solution',
async executor({ startedAt, services, params, alertId }) {
const fromDate = moment(startedAt).subtract(moment.duration(5, 'm')); // hardcoded 5-minute rule interval

View file

@ -103,6 +103,7 @@ export const signalRulesAlertType = ({
},
producer: SERVER_APP_ID,
minimumLicenseRequired: 'basic',
isExportable: false,
async executor({
previousStartedAt,
startedAt,

View file

@ -140,6 +140,7 @@ export function getAlertType(
],
},
minimumLicenseRequired: 'basic',
isExportable: true,
executor,
producer: STACK_ALERTS_FEATURE_ID,
};

View file

@ -177,5 +177,6 @@ export function getAlertType(logger: Logger): GeoContainmentAlertType {
},
actionVariables,
minimumLicenseRequired: 'gold',
isExportable: true,
};
}

View file

@ -125,6 +125,7 @@ export function getAlertType(
],
},
minimumLicenseRequired: 'basic',
isExportable: true,
executor,
producer: STACK_ALERTS_FEATURE_ID,
};

View file

@ -89,6 +89,7 @@ export const durationAnomalyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds>
state: [...durationAnomalyTranslations.actionVariables, ...commonStateTranslations],
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({ options, uptimeEsClient, savedObjectsClient, dynamicSettings }) {
const {
services: { alertInstanceFactory },

View file

@ -258,6 +258,7 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (
state: [...commonMonitorStateI18, ...commonStateTranslations],
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({
options: {
params: rawParams,

View file

@ -112,6 +112,7 @@ export const tlsAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (_server,
state: [...tlsTranslations.actionVariables, ...commonStateTranslations],
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({ options, dynamicSettings, uptimeEsClient }) {
const {
services: { alertInstanceFactory },

View file

@ -103,6 +103,7 @@ export const tlsLegacyAlertFactory: UptimeAlertTypeFactory<ActionGroupIds> = (_s
state: [...tlsTranslations.actionVariables, ...commonStateTranslations],
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({ options, dynamicSettings, uptimeEsClient }) {
const {
services: { alertInstanceFactory },

View file

@ -81,6 +81,7 @@ function getAlwaysFiringAlertType() {
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
actionVariables: {
state: [{ name: 'instanceStateValue', description: 'the instance state value' }],
params: [{ name: 'instanceParamsValue', description: 'the instance params value' }],
@ -167,6 +168,7 @@ function getCumulativeFiringAlertType() {
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor(alertExecutorOptions) {
const { services, state } = alertExecutorOptions;
const group = 'default';
@ -212,6 +214,7 @@ function getNeverFiringAlertType() {
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({ services, params, state }) {
await services.scopedClusterClient.asCurrentUser.index({
index: params.index,
@ -252,6 +255,7 @@ function getFailingAlertType() {
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({ services, params, state }) {
await services.scopedClusterClient.asCurrentUser.index({
index: params.index,
@ -290,6 +294,7 @@ function getAuthorizationAlertType(core: CoreSetup<FixtureStartDeps>) {
defaultActionGroupId: 'default',
producer: 'alertsFixture',
minimumLicenseRequired: 'basic',
isExportable: true,
validate: {
params: paramsSchema,
},
@ -376,6 +381,7 @@ function getValidationAlertType() {
],
producer: 'alertsFixture',
minimumLicenseRequired: 'basic',
isExportable: true,
defaultActionGroupId: 'default',
validate: {
params: paramsSchema,
@ -404,6 +410,7 @@ function getPatternFiringAlertType() {
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor(alertExecutorOptions) {
const { services, state, params } = alertExecutorOptions;
const pattern = params.pattern;
@ -468,6 +475,7 @@ export function defineAlertTypes(
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
};
const goldNoopAlertType: AlertType<{}, {}, {}, {}, 'default'> = {
@ -477,6 +485,7 @@ export function defineAlertTypes(
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'gold',
isExportable: true,
async executor() {},
};
const onlyContextVariablesAlertType: AlertType<{}, {}, {}, {}, 'default'> = {
@ -486,6 +495,7 @@ export function defineAlertTypes(
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
actionVariables: {
context: [{ name: 'aContextVariable', description: 'this is a context variable' }],
},
@ -501,6 +511,7 @@ export function defineAlertTypes(
state: [{ name: 'aStateVariable', description: 'this is a state variable' }],
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
};
const throwAlertType: AlertType<{}, {}, {}, {}, 'default'> = {
@ -515,6 +526,7 @@ export function defineAlertTypes(
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {
throw new Error('this alert is intended to fail');
},
@ -531,6 +543,7 @@ export function defineAlertTypes(
producer: 'alertsFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {
await new Promise((resolve) => setTimeout(resolve, 5000));
},

View file

@ -20,6 +20,7 @@ export function defineAlertTypes(
producer: 'alertsRestrictedFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: { id: 'restrictedRecovered', name: 'Restricted Recovery' },
async executor() {},
};
@ -30,6 +31,7 @@ export function defineAlertTypes(
producer: 'alertsRestrictedFixture',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
};
alerting.registerType(noopRestrictedAlertType);

View file

@ -30,6 +30,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) {
},
producer: 'alertsFixture',
minimum_license_required: 'basic',
is_exportable: true,
recovery_action_group: {
id: 'recovered',
name: 'Recovered',
@ -56,6 +57,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) {
},
producer: 'alertsRestrictedFixture',
minimum_license_required: 'basic',
is_exportable: true,
enabled_in_license: true,
};

View file

@ -42,6 +42,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) {
},
producer: 'alertsFixture',
minimum_license_required: 'basic',
is_exportable: true,
enabled_in_license: true,
});
expect(Object.keys(authorizedConsumers)).to.contain('alertsFixture');
@ -126,6 +127,7 @@ export default function listAlertTypes({ getService }: FtrProviderContext) {
},
producer: 'alertsFixture',
minimumLicenseRequired: 'basic',
isExportable: true,
enabledInLicense: true,
});
expect(Object.keys(authorizedConsumers)).to.contain('alertsFixture');

View file

@ -24,6 +24,7 @@ export const noopAlertType: AlertType<{}, {}, {}, {}, 'default'> = {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
producer: 'alerts',
};
@ -47,6 +48,7 @@ export const alwaysFiringAlertType: AlertType<
defaultActionGroupId: 'default',
producer: 'alerts',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor(alertExecutorOptions) {
const { services, state, params } = alertExecutorOptions;
@ -76,6 +78,7 @@ export const failingAlertType: AlertType<never, never, never, never, 'default' |
producer: 'alerts',
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {
throw new Error('Failed to execute alert type');
},