@ -1,6 +1,7 @@
import { cloneDeep , find , first as _first , isNumber , isObject , isString , map as _map } from 'lodash' ;
import { generate , lastValueFrom , Observable , of , throwError } from 'rxjs' ;
import { catchError , first , map , mergeMap , skipWhile , throwIfEmpty , tap } from 'rxjs/operators' ;
import { SemVer } from 'semver' ;
import {
DataFrame ,
@ -49,7 +50,7 @@ import { metricAggregationConfig } from './components/QueryEditor/MetricAggregat
import { defaultBucketAgg , hasMetricOfType } from './queryDef' ;
import { trackQuery } from './tracking' ;
import { Logs , BucketAggregation , DataLinkConfig , ElasticsearchOptions , ElasticsearchQuery , TermsQuery } from './types' ;
import { coerceESVersion , getScriptValue , isSupportedVersion } from './utils' ;
import { coerceESVersion , getScriptValue , isSupportedVersion , unsupportedVersionMessage } from './utils' ;
export const REF_ID_STARTER_LOG_VOLUME = 'log-volume-' ;
// Those are metadata fields as defined in https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-fields.html#_identity_metadata_fields.
@ -92,6 +93,7 @@ export class ElasticDatasource
includeFrozen : boolean ;
isProxyAccess : boolean ;
timeSrv : TimeSrv ;
databaseVersion : SemVer | null ;
constructor (
instanceSettings : DataSourceInstanceSettings < ElasticsearchOptions > ,
@ -119,6 +121,7 @@ export class ElasticDatasource
this . logLevelField = settingsData . logLevelField || '' ;
this . dataLinks = settingsData . dataLinks || [ ] ;
this . includeFrozen = settingsData . includeFrozen ? ? false ;
this . databaseVersion = null ;
this . annotations = {
QueryEditor : ElasticsearchAnnotationsQueryEditor ,
} ;
@ -147,13 +150,6 @@ export class ElasticDatasource
return throwError ( ( ) = > error ) ;
}
if ( ! isSupportedVersion ( this . esVersion ) ) {
const error = new Error (
'Support for Elasticsearch versions after their end-of-life (currently versions < 7.10) was removed.'
) ;
return throwError ( ( ) = > error ) ;
}
const options : BackendSrvRequest = {
url : this.url + '/' + url ,
method ,
@ -395,16 +391,24 @@ export class ElasticDatasource
return queries . map ( ( q ) = > this . applyTemplateVariables ( q , scopedVars ) ) ;
}
testDatasource() {
async testDatasource() {
// we explicitly ask for uncached, "fresh" data here
const dbVersion = await this . getDatabaseVersion ( false ) ;
// if we are not able to determine the elastic-version, we assume it is a good version.
const isSupported = dbVersion != null ? isSupportedVersion ( dbVersion ) : true ;
const versionMessage = isSupported ? '' : ` WARNING: ${ unsupportedVersionMessage } ` ;
// validate that the index exist and has date field
return lastValueFrom (
this . getFields ( [ 'date' ] ) . pipe (
mergeMap ( ( dateFields ) = > {
const timeField : any = find ( dateFields , { text : this.timeField } ) ;
if ( ! timeField ) {
return of ( { status : 'error' , message : 'No date field named ' + this . timeField + ' found' } ) ;
return of ( {
status : 'error' ,
message : 'No date field named ' + this . timeField + ' found' ,
} ) ;
}
return of ( { status : 'success' , message : 'Index OK. Time field name OK.' } ) ;
return of ( { status : 'success' , message : ` ${ versionMessage } Index OK. Time field name OK ` } ) ;
} ) ,
catchError ( ( err ) = > {
console . error ( err ) ;
@ -1040,6 +1044,41 @@ export class ElasticDatasource
const finalQuery = JSON . parse ( this . templateSrv . replace ( JSON . stringify ( expandedQuery ) , scopedVars ) ) ;
return finalQuery ;
}
private getDatabaseVersionUncached ( ) : Promise < SemVer | null > {
// we want this function to never fail
return lastValueFrom ( this . request ( 'GET' , '/' ) ) . then (
( data ) = > {
const versionNumber = data ? . version ? . number ;
if ( typeof versionNumber !== 'string' ) {
return null ;
}
try {
return new SemVer ( versionNumber ) ;
} catch ( error ) {
console . error ( error ) ;
return null ;
}
} ,
( error ) = > {
console . error ( error ) ;
return null ;
}
) ;
}
async getDatabaseVersion ( useCachedData = true ) : Promise < SemVer | null > {
if ( useCachedData ) {
const cached = this . databaseVersion ;
if ( cached != null ) {
return cached ;
}
}
const freshDatabaseVersion = await this . getDatabaseVersionUncached ( ) ;
this . databaseVersion = freshDatabaseVersion ;
return freshDatabaseVersion ;
}
}
/ * *