Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
4 changes: 4 additions & 0 deletions docs/api/alerting/legacy/list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ The API returns the following:
},
"producer":"stackAlerts",
"minimumLicenseRequired":"basic",
"isExportable":true,
"enabledInLicense":true,
"authorizedConsumers":{
"alerts":{
Expand Down Expand Up @@ -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.

Expand Down
4 changes: 4 additions & 0 deletions docs/api/alerting/list_rule_types.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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":{
Expand Down Expand Up @@ -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.

Expand Down
19 changes: 19 additions & 0 deletions docs/user/alerting/create-and-manage-rules.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a step we should mention in scenarios they are using connectors with their rules?

[role="screenshot"]
image::images/rules-imported-banner.png[Rules import banner, width=50%]

[float]
[[rule-details]]
=== Drilldown to rule details
Expand Down
16 changes: 16 additions & 0 deletions src/core/server/saved_objects/routes/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/core/server/saved_objects/routes/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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([]),
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/alerting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -262,6 +263,7 @@ const myRuleType: AlertType<
],
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor({
alertId,
startedAt,
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/alerting/common/alert_type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface AlertType<
defaultActionGroupId: ActionGroupIds;
producer: string;
minimumLicenseRequired: LicenseType;
isExportable: boolean;
}

export interface ActionGroup<ActionGroupIds extends string> {
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/alerting/public/alert_api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('loadAlertTypes', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
},
Expand All @@ -49,6 +50,7 @@ describe('loadAlertType', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
};
Expand All @@ -71,6 +73,7 @@ describe('loadAlertType', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const mockAlertType = (id: string): AlertType => ({
defaultActionGroupId: 'default',
producer: 'alerts',
minimumLicenseRequired: 'basic',
isExportable: true,
});

describe('AlertNavigationRegistry', () => {
Expand Down
16 changes: 16 additions & 0 deletions x-pack/plugins/alerting/server/alert_type_registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe('has()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
});
Expand All @@ -67,6 +68,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
Expand Down Expand Up @@ -99,6 +101,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
Expand Down Expand Up @@ -129,6 +132,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
Expand Down Expand Up @@ -159,6 +163,7 @@ describe('register()', () => {
executor: jest.fn(),
producer: 'alerts',
minimumLicenseRequired: 'basic',
isExportable: true,
};
const registry = new AlertTypeRegistry(alertTypeRegistryParams);
registry.register(alertType);
Expand Down Expand Up @@ -203,6 +208,7 @@ describe('register()', () => {
},
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
Expand All @@ -227,6 +233,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
Expand Down Expand Up @@ -257,6 +264,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
};
Expand All @@ -279,6 +287,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
});
Expand All @@ -294,6 +303,7 @@ describe('register()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
})
Expand All @@ -315,6 +325,7 @@ describe('get()', () => {
],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
executor: jest.fn(),
producer: 'alerts',
});
Expand All @@ -339,6 +350,7 @@ describe('get()', () => {
"defaultActionGroupId": "default",
"executor": [MockFunction],
"id": "test",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "Test",
"producer": "alerts",
Expand Down Expand Up @@ -377,6 +389,7 @@ describe('list()', () => {
},
],
defaultActionGroupId: 'testActionGroup',
isExportable: true,
minimumLicenseRequired: 'basic',
executor: jest.fn(),
producer: 'alerts',
Expand All @@ -403,6 +416,7 @@ describe('list()', () => {
"defaultActionGroupId": "testActionGroup",
"enabledInLicense": false,
"id": "test",
"isExportable": true,
"minimumLicenseRequired": "basic",
"name": "Test",
"producer": "alerts",
Expand Down Expand Up @@ -467,6 +481,7 @@ describe('ensureAlertTypeEnabled', () => {
defaultActionGroupId: 'default',
executor: jest.fn(),
producer: 'alerts',
isExportable: true,
minimumLicenseRequired: 'basic',
recoveryActionGroup: { id: 'recovered', name: 'Recovered' },
});
Expand Down Expand Up @@ -497,6 +512,7 @@ function alertTypeWithVariables<ActionGroupIds extends string>(
name: `${id}-name`,
actionGroups: [],
defaultActionGroupId: id,
isExportable: true,
minimumLicenseRequired: 'basic',
async executor() {},
producer: 'alerts',
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/alerting/server/alert_type_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface RegistryAlertType
| 'actionVariables'
| 'producer'
| 'minimumLicenseRequired'
| 'isExportable'
> {
id: string;
enabledInLicense: boolean;
Expand Down Expand Up @@ -250,6 +251,7 @@ export class AlertTypeRegistry {
actionVariables,
producer,
minimumLicenseRequired,
isExportable,
},
]: [string, UntypedNormalizedAlertType]) => ({
id,
Expand All @@ -260,6 +262,7 @@ export class AlertTypeRegistry {
actionVariables,
producer,
minimumLicenseRequired,
isExportable,
enabledInLicense: !!this.licenseState.getLicenseCheckForAlertType(
id,
name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe('aggregate()', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
id: 'myType',
name: 'myType',
Expand Down Expand Up @@ -110,6 +111,7 @@ describe('aggregate()', () => {
actionGroups: [{ id: 'default', name: 'Default' }],
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
recoveryActionGroup: RecoveredActionGroup,
producer: 'alerts',
authorizedConsumers: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1293,6 +1293,7 @@ describe('create()', () => {
}),
},
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
producer: 'alerts',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ describe('find()', () => {
actionVariables: undefined,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
id: 'myType',
name: 'myType',
producer: 'myApp',
Expand Down Expand Up @@ -126,6 +127,7 @@ describe('find()', () => {
recoveryActionGroup: RecoveredActionGroup,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
producer: 'alerts',
authorizedConsumers: {
myApp: { read: true, all: true },
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/alerting/server/alerts_client/tests/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export function getBeforeSetup(
recoveryActionGroup: RecoveredActionGroup,
defaultActionGroupId: 'default',
minimumLicenseRequired: 'basic',
isExportable: true,
async executor() {},
producer: 'alerts',
}));
Expand Down
Loading