import { IScopedClusterClient } from 'kibana/server' ; import { ES_FIELD_TYPES } from '../../../../../../src/plugins/data/server' ; import { parseInterval } from '../../../common/util/parse_interval' ; import { CombinedJob } from '../../../common/types/anomaly_detection_jobs' ; import { validateJobObject } from './validate_job_object' ; interface ValidateTimeRangeMessage { id : string ; timeField ? : string ; minTimeSpanReadable ? : string ; bucketSpanCompareFactor ? : number ; } interface TimeRange { start : number ; end : number ; } const BUCKET_SPAN_COMPARE_FACTOR = 25 ; const MIN_TIME_SPAN_MS = 7200000 ; const MIN_TIME_SPAN_READABLE = '2 hours' ; export async function isValidTimeField ( { asCurrentUser } , job ) { const index = job . datafeed_config . indices . join ( ',' ) ; const timeField = job . data_description . time_field ! ; const { body : fieldCaps } = await asCurrentUser . fieldCaps ( { index , fields : [ timeField ] , } ) ; let fieldType = fieldCaps ?. fields [ timeField ] ?. date ?. type ; if ( fieldType === undefined ) { fieldType = fieldCaps ?. fields [ timeField ] ?. date_nanos ?. type ; } return fieldType === ES_FIELD_TYPES . DATE || fieldType === ES_FIELD_TYPES . DATE_NANOS ; } export async function validateTimeRange ( mlClientCluster , job , timeRange ? ) { const messages = [ ] ; validateJobObject ( job ) ; if ( ! ( await isValidTimeField ( mlClientCluster , job ) ) ) { messages . push ( { id : 'time_field_invalid' , timeField : job . data_description . time_field , } ) ; return messages ; } if ( typeof timeRange === 'undefined' || typeof timeRange . start === 'undefined' || typeof timeRange . end === 'undefined' ) { return messages ; } if ( timeRange . start < 0 || timeRange . end < 0 ) { messages . push ( { id : 'time_range_before_epoch' } ) ; } const interval = parseInterval ( job . analysis_config . bucket_span , true ) ; if ( interval === null ) { messages . push ( { id : 'bucket_span_invalid' } ) ; } else { const bucketSpan = interval . asMilliseconds ( ) ; const minTimeSpanBasedOnBucketSpan = bucketSpan * BUCKET_SPAN_COMPARE_FACTOR ; const timeSpan = timeRange . end - timeRange . start ; const minRequiredTimeSpan = Math . max ( MIN_TIME_SPAN_MS , minTimeSpanBasedOnBucketSpan ) ; if ( minRequiredTimeSpan > timeSpan ) { messages . push ( { id : 'time_range_short' , minTimeSpanReadable : MIN_TIME_SPAN_READABLE , bucketSpanCompareFactor : BUCKET_SPAN_COMPARE_FACTOR , } ) ; } } if ( messages . length === 0 ) { messages . push ( { id : 'success_time_range' } ) ; } return messages ; }