-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Actions] Connector Adapters MVP #166101
[Actions] Connector Adapters MVP #166101
Changes from 6 commits
e59eab0
aca0ac7
620751d
2e7a0ec
5195504
753eae3
36c1602
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -108,6 +108,19 @@ export interface AlertsFilter extends SavedObjectAttributes { | |
|
||
export type RuleActionAlertsFilterProperty = AlertsFilterTimeframe | RuleActionParam; | ||
|
||
/** | ||
* The RuleActionTypes is being used in versioned | ||
* routes and rule client's schemas. Renaming | ||
* or removing a type will introduce a | ||
* breaking change | ||
*/ | ||
export const RuleActionTypes = { | ||
DEFAULT: 'default' as const, | ||
SYSTEM: 'system' as const, | ||
} as const; | ||
|
||
export type RuleActionTypes = typeof RuleActionTypes[keyof typeof RuleActionTypes]; | ||
|
||
export interface RuleAction { | ||
uuid?: string; | ||
group: string; | ||
|
@@ -116,6 +129,7 @@ export interface RuleAction { | |
params: RuleActionParams; | ||
frequency?: RuleActionFrequency; | ||
alertsFilter?: AlertsFilter; | ||
type?: typeof RuleActionTypes.DEFAULT; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The system action will be
|
||
} | ||
|
||
export interface AggregateOptions { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* 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 { schema } from '@kbn/config-schema'; | ||
import { ConnectorAdapterRegistry } from './connector_adapter_registry'; | ||
import type { ConnectorAdapter } from './types'; | ||
|
||
describe('ConnectorAdapterRegistry', () => { | ||
const connectorAdapter: ConnectorAdapter = { | ||
connectorTypeId: '.test', | ||
ruleActionParamsSchema: schema.object({}), | ||
buildActionParams: jest.fn(), | ||
}; | ||
|
||
let registry: ConnectorAdapterRegistry; | ||
|
||
beforeEach(() => { | ||
registry = new ConnectorAdapterRegistry(); | ||
}); | ||
|
||
describe('has', () => { | ||
it('returns true if the connector adapter is registered', () => { | ||
registry.register(connectorAdapter); | ||
expect(registry.has('.test')).toBe(true); | ||
}); | ||
|
||
it('returns false if the connector adapter is not registered', () => { | ||
expect(registry.has('.not-exist')).toBe(false); | ||
}); | ||
}); | ||
|
||
describe('register', () => { | ||
it('registers a connector adapter correctly', () => { | ||
registry.register(connectorAdapter); | ||
expect(registry.get('.test')).toEqual(connectorAdapter); | ||
}); | ||
|
||
it('throws an error if the connector adapter exists', () => { | ||
registry.register(connectorAdapter); | ||
|
||
expect(() => registry.register(connectorAdapter)).toThrowErrorMatchingInlineSnapshot( | ||
`".test is already registered to the ConnectorAdapterRegistry"` | ||
); | ||
}); | ||
}); | ||
|
||
describe('get', () => { | ||
it('gets a connector adapter correctly', () => { | ||
registry.register(connectorAdapter); | ||
expect(registry.get('.test')).toEqual(connectorAdapter); | ||
}); | ||
|
||
it('throws an error if the connector adapter does not exists', () => { | ||
expect(() => registry.get('.not-exists')).toThrowErrorMatchingInlineSnapshot( | ||
`"Connector adapter \\".not-exists\\" is not registered."` | ||
); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* | ||
ymao1 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* 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 Boom from '@hapi/boom'; | ||
import { i18n } from '@kbn/i18n'; | ||
|
||
import { ConnectorAdapter } from './types'; | ||
|
||
export class ConnectorAdapterRegistry { | ||
private readonly connectorAdapters: Map<string, ConnectorAdapter> = new Map(); | ||
|
||
public has(connectorTypeId: string): boolean { | ||
return this.connectorAdapters.has(connectorTypeId); | ||
} | ||
|
||
public register(connectorAdapter: ConnectorAdapter) { | ||
if (this.has(connectorAdapter.connectorTypeId)) { | ||
throw new Error( | ||
`${connectorAdapter.connectorTypeId} is already registered to the ConnectorAdapterRegistry` | ||
); | ||
} | ||
|
||
this.connectorAdapters.set(connectorAdapter.connectorTypeId, connectorAdapter); | ||
} | ||
|
||
public get(connectorTypeId: string): ConnectorAdapter { | ||
if (!this.connectorAdapters.has(connectorTypeId)) { | ||
throw Boom.badRequest( | ||
i18n.translate( | ||
'xpack.alerting.connectorAdapterRegistry.get.missingConnectorAdapterErrorMessage', | ||
{ | ||
defaultMessage: 'Connector adapter "{connectorTypeId}" is not registered.', | ||
values: { | ||
connectorTypeId, | ||
}, | ||
} | ||
) | ||
); | ||
} | ||
|
||
return this.connectorAdapters.get(connectorTypeId)!; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* 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 { ObjectType } from '@kbn/config-schema'; | ||
import type { | ||
RuleActionParams as GenericRuleActionParams, | ||
RuleTypeParams, | ||
SanitizedRule, | ||
} from '../../common'; | ||
import { CombinedSummarizedAlerts } from '../types'; | ||
|
||
type ActionTypeParams = Record<string, unknown>; | ||
|
||
type Rule = Pick<SanitizedRule<RuleTypeParams>, 'id' | 'name' | 'tags'>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the MVP this should be enough. If a connector adapter needs more attributes from the rule we can extend it in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: do we need to extend or can we pass-through |
||
|
||
interface BuildActionParamsArgs< | ||
RuleActionParams extends GenericRuleActionParams = GenericRuleActionParams | ||
> { | ||
alerts: CombinedSummarizedAlerts; | ||
rule: Rule; | ||
params: RuleActionParams; | ||
spaceId: string; | ||
ruleUrl?: string; | ||
} | ||
|
||
export interface ConnectorAdapter { | ||
connectorTypeId: string; | ||
/** | ||
* The schema of the action persisted | ||
* in the rule. The schema will be validated | ||
* when a rule is created or updated. | ||
* The schema should be backwards compatible | ||
* and should never introduce any breaking | ||
* changes. | ||
*/ | ||
ruleActionParamsSchema: ObjectType; | ||
buildActionParams: <RuleActionParams extends GenericRuleActionParams>( | ||
args: BuildActionParamsArgs<RuleActionParams> | ||
) => ActionTypeParams; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Do we have a follow up issue / task for the feature branch to split DEFAULT into two? (something that associates with each alert and something that associates with summaries).