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

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

Merged
merged 5 commits into from
Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/user/alerting/rule-types/es-query.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface BuildSortedEventsQuery extends BuildSortedEventsQueryOpts {
timeField: string;
fields?: string[];
runtime_mappings?: unknown;
_source?: unknown;
}

export const buildSortedEventsQuery = ({
Expand All @@ -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) => ({
Expand Down Expand Up @@ -89,6 +91,7 @@ export const buildSortedEventsQuery = ({
},
...(runtime_mappings ? { runtime_mappings } : {}),
...(fields ? { fields } : {}),
...(_source != null ? { _source } : {}),
};

if (searchAfterSortId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -76,6 +76,7 @@ export async function fetchEsQuery(
track_total_hits: true,
fields,
runtime_mappings,
_source,
});

logger.debug(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export default function ruleTests({ getService }: FtrProviderContext) {
"fields": [
{
"field": "@timestamp",
"format": "epoch_millis"
"format": "epoch_millis"
}
],
"query": {
Expand Down Expand Up @@ -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,
Expand Down