import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey' ; import Boom from '@hapi/boom' ; import type { MlClient } from '../../lib/ml_client' ; import type { Job } from '../../../common/types/anomaly_detection_jobs' ; import type { Filter , FilterStats } from '../../../common/types/filters' ; export interface FormFilter { filterId : string ; description ? : string ; addItems ? : string [ ] ; removeItems ? : string [ ] ; } export interface UpdateFilter { description ? : string ; addItems ? : string [ ] ; removeItems ? : string [ ] ; } export interface FilterRequest { filter_id : string ; description ? : string ; add_items ? : string [ ] ; remove_items ? : string [ ] ; } interface FilterUsage { jobs : string [ ] ; detectors : string [ ] ; } interface FiltersInUse { [ id ] : FilterUsage ; } export class FilterManager { constructor ( private _mlClient ) { } async getFilter ( filterId ) { try { const [ JOBS , FILTERS ] = [ 0 , 1 ] ; const results = await Promise . all ( [ this . _mlClient . getJobs ( ) , this . _mlClient . getFilters ( { filter_id : filterId } ) , ] ) ; if ( results [ FILTERS ] && ( results [ FILTERS ] . body as estypes . MlGetFiltersResponse ) . filters . length ) { let filtersInUse = { } ; if ( results [ JOBS ] && ( results [ JOBS ] . body as estypes . MlGetJobsResponse ) . jobs ) { filtersInUse = this . buildFiltersInUse ( ( results [ JOBS ] . body as estypes . MlGetJobsResponse ) . jobs ) ; } const filter = ( results [ FILTERS ] . body as estypes . MlGetFiltersResponse ) . filters [ 0 ] ; return { ... filter , used_by : filtersInUse [ filter . filter_id ] , item_count : 0 , } as FilterStats ; } else { throw Boom . notFound ( `Filter with the id "${ filterId }" not found` ) ; } } catch ( error ) { throw Boom . badRequest ( error ) ; } } async getAllFilters ( ) { try { const { body } = await this . _mlClient . getFilters ( { size : 1000 } ) ; return body . filters ; } catch ( error ) { throw Boom . badRequest ( error ) ; } } async getAllFilterStats ( ) { try { const [ JOBS , FILTERS ] = [ 0 , 1 ] ; const results = await Promise . all ( [ this . _mlClient . getJobs ( ) , this . _mlClient . getFilters ( { size : 1000 } ) , ] ) ; let filtersInUse = { } ; if ( results [ JOBS ] && ( results [ JOBS ] . body as estypes . MlGetJobsResponse ) . jobs ) { filtersInUse = this . buildFiltersInUse ( ( results [ JOBS ] . body as estypes . MlGetJobsResponse ) . jobs ) ; } const filterStats = [ ] ; if ( results [ FILTERS ] && ( results [ FILTERS ] . body as estypes . MlGetFiltersResponse ) . filters ) { ( results [ FILTERS ] . body as estypes . MlGetFiltersResponse ) . filters . forEach ( ( filter ) => { const stats = { filter_id : filter . filter_id , description : filter . description , item_count : filter . items . length , used_by : filtersInUse [ filter . filter_id ] , } ; filterStats . push ( stats ) ; } ) ; } return filterStats ; } catch ( error ) { throw Boom . badRequest ( error ) ; } } async newFilter ( filter ) { const { filterId , ... body } = filter ; try { const { body : resp } = await this . _mlClient . putFilter ( { filter_id : filterId , body } ) ; return resp ; } catch ( error ) { throw Boom . badRequest ( error ) ; } } async updateFilter ( filterId , filter ) { try { const body = { filter_id : filterId } ; if ( filter . description !== undefined ) { body . description = filter . description ; } if ( filter . addItems !== undefined ) { body . add_items = filter . addItems ; } if ( filter . removeItems !== undefined ) { body . remove_items = filter . removeItems ; } const { body : resp } = await this . _mlClient . updateFilter ( { filter_id : filterId , body , } ) ; return resp ; } catch ( error ) { throw Boom . badRequest ( error ) ; } } async deleteFilter ( filterId ) { const { body } = await this . _mlClient . deleteFilter ( { filter_id : filterId } ) ; return body ; } buildFiltersInUse ( jobsList ) { const filtersInUse = { } ; jobsList . forEach ( ( job ) => { const detectors = job . analysis_config . detectors ; detectors . forEach ( ( detector ) => { if ( detector . custom_rules ) { const rules = detector . custom_rules ; rules . forEach ( ( rule ) => { if ( rule . scope ) { const ruleScope = rule . scope ; const scopeFields = Object . keys ( ruleScope ) ; scopeFields . forEach ( ( scopeField ) => { const filter = ruleScope [ scopeField ] ; const filterId = filter . filter_id ; if ( filtersInUse [ filterId ] === undefined ) { filtersInUse [ filterId ] = { jobs : [ ] , detectors : [ ] } ; } const jobs = filtersInUse [ filterId ] . jobs ; const dtrs = filtersInUse [ filterId ] . detectors ; const jobId = job . job_id ; const detectorLabel = `${ detector . detector_description } (${ jobId })` ; if ( jobs . indexOf ( jobId ) === - 1 ) { jobs . push ( jobId ) ; } if ( dtrs . indexOf ( detectorLabel ) === - 1 ) { dtrs . push ( detectorLabel ) ; } } ) ; } } ) ; } } ) ; } ) ; return filtersInUse ; } }