[Response Ops] Allow _source field for ES DSL query rules (#142223)

* Allowing _source in ES query DSL

* Adding functional test

* Adding to doc

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Ying Mao 2022-10-05 19:18:59 -04:00 committed by GitHub
parent fdea7b14b4
commit 4f649c09c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 3 deletions

View file

@ -26,7 +26,7 @@ the *time window*.
Size:: Specifies the number of documents to pass to the configured actions when
the threshold condition is met.
{es} query:: Specifies the ES DSL query. The number of documents that
match this query is evaluated against the threshold condition. Only the `query`, `fields` and `runtime_mappings`
match this query is evaluated against the threshold condition. Only the `query`, `fields`, `_source` and `runtime_mappings`
fields are used, other DSL fields are not considered.
Threshold:: Defines a threshold value and a comparison operator (`is above`,
`is above or equals`, `is below`, `is below or equals`, or `is between`). The

View file

@ -23,6 +23,7 @@ export interface BuildSortedEventsQuery extends BuildSortedEventsQueryOpts {
timeField: string;
fields?: string[];
runtime_mappings?: unknown;
_source?: unknown;
}
export const buildSortedEventsQuery = ({
@ -40,6 +41,7 @@ export const buildSortedEventsQuery = ({
fields,
// eslint-disable-next-line @typescript-eslint/naming-convention
runtime_mappings,
_source,
}: BuildSortedEventsQuery): ESSearchRequest => {
const sortField = timeField;
const docFields = [timeField].map((tstamp) => ({
@ -89,6 +91,7 @@ export const buildSortedEventsQuery = ({
},
...(runtime_mappings ? { runtime_mappings } : {}),
...(fields ? { fields } : {}),
...(_source != null ? { _source } : {}),
};
if (searchAfterSortId) {

View file

@ -28,7 +28,7 @@ export async function fetchEsQuery(
const esClient = scopedClusterClient.asCurrentUser;
const {
// eslint-disable-next-line @typescript-eslint/naming-convention
parsedQuery: { query, fields, runtime_mappings },
parsedQuery: { query, fields, runtime_mappings, _source },
dateStart,
dateEnd,
} = getSearchParams(params);
@ -76,6 +76,7 @@ export async function fetchEsQuery(
track_total_hits: true,
fields,
runtime_mappings,
_source,
});
logger.debug(

View file

@ -11,5 +11,6 @@ import { FtrProviderContext } from '../../../../../common/ftr_provider_context';
export default function alertingTests({ loadTestFile }: FtrProviderContext) {
describe('es_query', () => {
loadTestFile(require.resolve('./rule'));
loadTestFile(require.resolve('./query_dsl_only'));
});
}

View file

@ -159,7 +159,7 @@ export default function ruleTests({ getService }: FtrProviderContext) {
"fields": [
{
"field": "@timestamp",
"format": "epoch_millis"
"format": "epoch_millis"
}
],
"query": {
@ -190,6 +190,73 @@ export default function ruleTests({ getService }: FtrProviderContext) {
}
});
it(`runs correctly: _source: false field for esQuery search type`, async () => {
// write documents from now to the future end date in groups
await createEsDocumentsInGroups(ES_GROUPS_TO_WRITE, endDate);
await createRule({
name: 'always fire',
esQuery: `
{
"query": {
"match_all": { }
},
"_source": false
}`.replace(`"`, `\"`),
size: 100,
thresholdComparator: '>',
threshold: [-1],
});
const docs = await waitForDocs(2);
for (let i = 0; i < docs.length; i++) {
const doc = docs[i];
const { name, title } = doc._source.params;
expect(name).to.be('always fire');
expect(title).to.be(`rule 'always fire' matched query`);
const hits = JSON.parse(doc._source.hits);
expect(hits).not.to.be.empty();
hits.forEach((hit: any) => {
expect(hit._source).to.be(undefined);
});
}
});
it(`runs correctly: _source field for esQuery search type`, async () => {
// write documents from now to the future end date in groups
await createEsDocumentsInGroups(ES_GROUPS_TO_WRITE, endDate);
await createRule({
name: 'always fire',
esQuery: `
{
"query": {
"match_all": { }
},
"_source": "testedValue*"
}`.replace(`"`, `\"`),
size: 100,
thresholdComparator: '>',
threshold: [-1],
});
const docs = await waitForDocs(2);
for (let i = 0; i < docs.length; i++) {
const doc = docs[i];
const { name, title } = doc._source.params;
expect(name).to.be('always fire');
expect(title).to.be(`rule 'always fire' matched query`);
const hits = JSON.parse(doc._source.hits);
expect(hits).not.to.be.empty();
hits.forEach((hit: any) => {
expect(hit._source).not.to.be.empty();
Object.keys(hit._source).forEach((key) => {
expect(key.startsWith('testedValue')).to.be(true);
});
});
}
});
async function createRule(params: CreateRuleParams): Promise<string> {
const action = {
id: connectorId,