diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index c74cf888a2db66..0fc42895050a53 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -140,6 +140,13 @@ export const UNAUTHENTICATED_USER = 'Unauthenticated'; */ export const MINIMUM_ML_LICENSE = 'platinum'; +/* + Machine Learning constants + */ +export const ML_GROUP_ID = 'security'; +export const LEGACY_ML_GROUP_ID = 'siem'; +export const ML_GROUP_IDS = [ML_GROUP_ID, LEGACY_ML_GROUP_ID]; + /* Rule notifications options */ diff --git a/x-pack/plugins/security_solution/common/machine_learning/is_security_job.test.ts b/x-pack/plugins/security_solution/common/machine_learning/is_security_job.test.ts new file mode 100644 index 00000000000000..abb0c790584af7 --- /dev/null +++ b/x-pack/plugins/security_solution/common/machine_learning/is_security_job.test.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { MlSummaryJob } from '../../../ml/common/types/anomaly_detection_jobs'; +import { isSecurityJob } from './is_security_job'; + +describe('isSecurityJob', () => { + it('counts a job with a group of "siem"', () => { + const job = { groups: ['siem', 'other'] } as MlSummaryJob; + expect(isSecurityJob(job)).toEqual(true); + }); + + it('counts a job with a group of "security"', () => { + const job = { groups: ['security', 'other'] } as MlSummaryJob; + expect(isSecurityJob(job)).toEqual(true); + }); + + it('counts a job in both "security" and "siem"', () => { + const job = { groups: ['siem', 'security'] } as MlSummaryJob; + expect(isSecurityJob(job)).toEqual(true); + }); + + it('does not count a job in a related group', () => { + const job = { groups: ['auditbeat', 'process'] } as MlSummaryJob; + expect(isSecurityJob(job)).toEqual(false); + }); +}); diff --git a/x-pack/plugins/security_solution/common/machine_learning/is_security_job.ts b/x-pack/plugins/security_solution/common/machine_learning/is_security_job.ts new file mode 100644 index 00000000000000..43cfa4ad599640 --- /dev/null +++ b/x-pack/plugins/security_solution/common/machine_learning/is_security_job.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { MlSummaryJob } from '../../../ml/common/types/anomaly_detection_jobs'; +import { ML_GROUP_IDS } from '../constants'; + +export const isSecurityJob = (job: MlSummaryJob): boolean => + job.groups.some((group) => ML_GROUP_IDS.includes(group)); diff --git a/x-pack/plugins/security_solution/server/usage/detections/detections.mocks.ts b/x-pack/plugins/security_solution/server/usage/detections/detections.mocks.ts index e59b1092978daf..7afc185ae07fd1 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/detections.mocks.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detections.mocks.ts @@ -41,7 +41,7 @@ export const getMockJobSummaryResponse = () => [ { id: 'other_job', description: 'a job that is custom', - groups: ['auditbeat', 'process'], + groups: ['auditbeat', 'process', 'security'], processed_record_count: 0, memory_status: 'ok', jobState: 'closed', @@ -54,6 +54,19 @@ export const getMockJobSummaryResponse = () => [ { id: 'another_job', description: 'another job that is custom', + groups: ['auditbeat', 'process', 'security'], + processed_record_count: 0, + memory_status: 'ok', + jobState: 'opened', + hasDatafeed: true, + datafeedId: 'datafeed-another', + datafeedIndices: ['auditbeat-*'], + datafeedState: 'started', + isSingleMetricViewerJob: true, + }, + { + id: 'irrelevant_job', + description: 'a non-security job', groups: ['auditbeat', 'process'], processed_record_count: 0, memory_status: 'ok', diff --git a/x-pack/plugins/security_solution/server/usage/detections/detections_helpers.ts b/x-pack/plugins/security_solution/server/usage/detections/detections_helpers.ts index 80a9dba26df8ed..a6d4dc7a38e14a 100644 --- a/x-pack/plugins/security_solution/server/usage/detections/detections_helpers.ts +++ b/x-pack/plugins/security_solution/server/usage/detections/detections_helpers.ts @@ -15,6 +15,7 @@ import { MlPluginSetup } from '../../../../ml/server'; import { SIGNALS_ID, INTERNAL_IMMUTABLE_KEY } from '../../../common/constants'; import { DetectionRulesUsage, MlJobsUsage } from './index'; import { isJobStarted } from '../../../common/machine_learning/helpers'; +import { isSecurityJob } from '../../../common/machine_learning/is_security_job'; interface DetectionsMetric { isElastic: boolean; @@ -182,11 +183,9 @@ export const getMlJobsUsage = async (ml: MlPluginSetup | undefined): Promise module.jobs); - const jobs = await ml - .jobServiceProvider(internalMlClient, fakeRequest) - .jobsSummary(['siem', 'security']); + const jobs = await ml.jobServiceProvider(internalMlClient, fakeRequest).jobsSummary(); - jobsUsage = jobs.reduce((usage, job) => { + jobsUsage = jobs.filter(isSecurityJob).reduce((usage, job) => { const isElastic = moduleJobs.some((moduleJob) => moduleJob.id === job.id); const isEnabled = isJobStarted(job.jobState, job.datafeedState);