diff --git a/dist/module.js b/dist/module.js index 0debbd9..983348b 100644 --- a/dist/module.js +++ b/dist/module.js @@ -683,6 +683,9 @@ define(['lodash', 'moment', 'app/core/app_events', 'app/plugins/sdk'], function( (e.prototype.query = function(e) { var t = this, r = u()(e.targets) + .filter(function(e) { + return !e.hide; + }) .map(w) .map(function(r) { return t.prepareQuery(r, e); diff --git a/dist/module.js.map b/dist/module.js.map index 6842001..36c0c40 100644 --- a/dist/module.js.map +++ b/dist/module.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///external \"lodash\"","webpack:///external \"moment\"","webpack:///external \"app/core/app_events\"","webpack:///external \"app/plugins/sdk\"","webpack:///./types.ts","webpack:///./sensu/sensu.ts","webpack:///./constants.ts","webpack:///./utils/datasource_filter_util.ts","webpack:///./utils/query_util.ts","webpack:///./transformer/table_transformer.ts","webpack:///./transformer/index.ts","webpack:///./transformer/timeseries_transformer.ts","webpack:///./utils/config_migration_util.ts","webpack:///./utils/data_aggregation_util.ts","webpack:///./datasource.ts","webpack:///./FieldSelector.ts","webpack:///./query_ctrl.ts","webpack:///./config_ctrl.ts"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","__WEBPACK_EXTERNAL_MODULE__0__","__WEBPACK_EXTERNAL_MODULE__1__","__WEBPACK_EXTERNAL_MODULE__2__","__WEBPACK_EXTERNAL_MODULE__3__","ServerSideFilterType","FIELD","LABEL","sensu","Sensu","query","datasource","options","_this","this","namespaces","external_lodash_default","a","isEmpty","url","push","queries","map","namespace","_doQuery","Promise","all","then","data","flatten","retryCount","fullUrl","method","apiBaseUrl","requestParameters","_getParameters","_authenticate","_request","result","catch","error","instanceSettings","tokens","delay","Math","floor","random","resolve","setTimeout","_isTokenExpired","_acquireAccessToken","token","timestampNow","Date","now","expiresAt","expires_at","expires_offset","tokenExpireOffset_s","expiresOffset","tokenTimeout_s","req","headers","Content-Type","apiKeyUrlPrefix","has","Authorization","access_token","params","backendSrv","datasourceRequest","_handleRequestResult","_handleRequestError","message","err","status","config","statusText","limit","responseFilters","fieldSelector","_buildFilterParameter","filter","type","labelSelector","filters","matcher","join","AGGREGATION_TYPES","text","requiresTarget","API_ENDPOINTS","fieldSelectors","QUERY_TYPES","FORMATS","TIME_PROPERTIES","_stringToRegex","regex","match","RegExp","datasource_filter_util","filterValue","operator","dataValue","test","_matchRegExp","filterNumber","Number","isFinite","console","warn","_matchNumber","components","_convertTimestamps","rows","each","row","attribute","index","length","time","defaultTo","external_moment_default","format","table_transformer","dataMatrix","vertical","columns","isArrayMarker","_a","isArray","times","isNil","uniq","_extractColumns","columnIndexMap","column","dataRow","constant","element","isPlainObject","JSON","stringify","columnName","dataColumns","dataRows","idx","_asVerticalTable","transformer","target","datapoints","timeseries_transformer","config_migration_util","version","clientSideFilters","serverSideFilters","init","log","filterSegments","segments","toVersion2","sum","SensuDatasource","templateSrv","prepareQuery","queryOptions","preparedTarget","apiUrl","_getApiUrl","clientFilters","cloneDeep","serverFilters","_resolveTemplateVariables","replace","scopedVars","split","forEach","apiEndpoint","find","apiEndpoints","_timeCorrection","dataElement","set","unset","_queryGroupAndAggregate","prepTarget","alias","aggregationAlias","aggregationType","groupAttribute","groupBy","groups","dataGroup","groupKey","_queryAggregation","groupResult","groupAlias","_mergeTableAggregation","groupData","groupByAttribute","group","point","data_aggregation_util","Error","targetField","sumBy","aggregationField","_queryFieldSelection","columnMappings","_extractColumnMappings","mapping","path","flatMap","selector","resolvePaths","paths","_filterData","every","_matches","filterKey","elementValue","selection","lastSelector","basePath","fieldSegments","_deepResolve","keys","nestedKeys","_query","queryComponents","queryRegExp","matchResult","apiKey","selectedField","parseInt","filterRegExp","SERVER_FILTER_REG_EXP","whereClause","exec","query_util","_transformQueryComponentsToQueryOptions","resultAsPlainArray","queryType","isNaN","String","trim","$inject","targets","queryTargets","parsedLimit","queryResults","queryResult","metricFindQuery","testDatasource","useApiKey","testUrl","FieldSelector","ctrl","initPath","refresh","dataPreview","slice","fieldType","uiSegmentSrv","newKey","attributePath","getPath","segment","restore","query_ctrl_SensuQueryCtrl","_super","SensuQueryCtrl","$scope","$injector","$q","aggregationTypes","queryTypes","formats","dataPreviewBuffer","clientFilterSegments","newOperator","newKeyValue","_createServerFilterSegments","newCondition","onAggregationFieldChange","segmentAggregationTarget","panelCtrl","onAggregationTypeChange","aggregationRequiresTarget","getCurrentAggregationType","_resetAggregation","removeGroupBy","newFake","getTargetOptions","getAllDeepKeys","option","newSegment","when","getGroupByOptions","onGroupByChange","groupBySegment","newPlusButton","unshift","variables","variable","onNamespaceChange","namespaceSegment","_reset","FieldSelector_0","serverFilterSegments","_updateFilterTarget","onApiChange","onQueryTypeChange","isServerFilter","splice","parentIndex","segmentValue","_addClientFilterSegment","sourceSegment","segmentArray","pop","_addServerFilterSegment","getFilterSegmentOptions","newOperators","options_1","filterKey_1","fake","combineKeys","e","getFieldSelectorOptions","currentSelection","fieldSegment","concat","sort","addFieldSegment","removeField","onAliasChange","_getCurrentApi","currentApi","field","response","endsWith","onRefresh","_createClientFilterSegments","aggregation","app_events_default","on","onResponseReceived","events","__extends","getCollapsedText","toUpperCase","queryLimit","targetToQueryString","templateUrl","SensuConfigCtrl","current","jsonData","basicAuth","resetApiKey","secureJsonFields","secureJsonData","currentUrl","$watch"],"mappings":"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","file":"module.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 4);\n","module.exports = __WEBPACK_EXTERNAL_MODULE__0__;","module.exports = __WEBPACK_EXTERNAL_MODULE__1__;","module.exports = __WEBPACK_EXTERNAL_MODULE__2__;","module.exports = __WEBPACK_EXTERNAL_MODULE__3__;","import FieldSelector from './FieldSelector';\r\n\r\nexport interface AggregationType {\r\n readonly value: string;\r\n readonly text: string;\r\n readonly requiresTarget: boolean;\r\n}\r\n\r\nexport interface ApiEndpoint {\r\n readonly text: string;\r\n readonly value: string;\r\n readonly url: string;\r\n readonly fieldSelectors: string[];\r\n}\r\n\r\nexport interface ColumnMapping {\r\n path: string;\r\n alias: string;\r\n}\r\n\r\nexport interface DataPoint {\r\n readonly value: any;\r\n readonly name: string;\r\n}\r\n\r\nexport interface BaseFilter {\r\n key: string;\r\n value: string;\r\n matcher: string;\r\n}\r\n\r\nexport type ClientSideFilter = BaseFilter;\r\n\r\nexport interface ServerSideFilter extends BaseFilter {\r\n type: ServerSideFilterType;\r\n}\r\n\r\nexport enum ServerSideFilterType {\r\n FIELD = 0,\r\n LABEL = 1,\r\n}\r\n\r\nexport interface InstanceSettings {\r\n // the datasource url\r\n url: string;\r\n\r\n // whether basic auth is used\r\n basicAuth: boolean;\r\n\r\n // additional data\r\n jsonData: JsonData;\r\n\r\n // additional secured data\r\n secureJsonData: SecureJsonData;\r\n\r\n // map defining which secured data element is set\r\n secureJsonFields: SecureJsonFields;\r\n}\r\n\r\nexport interface JsonData {\r\n // copy of the current datasource url - used for dynamic routing\r\n currentUrl: string;\r\n\r\n // whether an API key should be used\r\n useApiKey: boolean;\r\n}\r\n\r\nexport interface SecureJsonData {\r\n // the specified API key\r\n apiKey?: string;\r\n}\r\n\r\nexport interface SecureJsonFields {\r\n // whether an API key has been stored by Grafana\r\n apiKey?: boolean;\r\n}\r\n\r\nexport interface PreparedTarget {\r\n readonly apiUrl: string;\r\n readonly clientFilters: ClientSideFilter[];\r\n readonly serverFilters: ServerSideFilter[];\r\n readonly target: GrafanaTarget;\r\n}\r\n\r\nexport interface QueryComponents {\r\n readonly apiKey: string;\r\n readonly namespace: string;\r\n readonly selectedField: string;\r\n readonly clientFilters: ClientSideFilter[];\r\n readonly serverFilters: ServerSideFilter[];\r\n readonly limit: number;\r\n}\r\n\r\nexport interface TextValue {\r\n readonly text: string;\r\n readonly value: string;\r\n}\r\n\r\nexport interface QueryOptions {\r\n method: string;\r\n url: string;\r\n namespaces: string[];\r\n limit: number;\r\n forceAccessTokenRefresh?: boolean;\r\n responseFilters: ServerSideFilter[];\r\n}\r\n\r\nexport interface AccessToken {\r\n readonly access_token: string;\r\n readonly expires_at: number;\r\n readonly refresh_token: string;\r\n expires_offset?: number;\r\n}\r\n\r\nexport interface GrafanaTarget {\r\n /** @deprecated */\r\n filterSegments?: any[];\r\n /** @deprecated */\r\n aggregation?: string;\r\n\r\n aggregationAlias?: string;\r\n aggregationField?: string;\r\n aggregationRequiresTarget?: boolean;\r\n aggregationType?: string;\r\n apiEndpoints: string;\r\n fieldSelectors: FieldSelector[];\r\n format: string;\r\n groupAlias?: string;\r\n groupBy?: string;\r\n limit?: string;\r\n namespace: string;\r\n namespaces: string[]; // splitted and resolved namespace attribute\r\n queryType: string;\r\n refId: string;\r\n\r\n version: number;\r\n clientSideFilters: ClientSideFilter[];\r\n serverSideFilters: ServerSideFilter[];\r\n}\r\n\r\nexport interface GrafanaUiSegment {\r\n value: string;\r\n}\r\n\r\nexport interface GrafanaTimeSeries {\r\n target: string; // time series name\r\n datapoints: unknown[];\r\n}\r\n\r\nexport interface GrafanaTable {\r\n columns: unknown[];\r\n rows: unknown[][];\r\n type: string;\r\n}\r\n","import _ from 'lodash';\r\nimport {\r\n AccessToken,\r\n QueryOptions,\r\n ServerSideFilter,\r\n ServerSideFilterType,\r\n} from '../types';\r\n\r\n/**\r\n * Class which encapsulates the query mechanism against the Sensu Go API.\r\n */\r\nexport default class Sensu {\r\n /**\r\n * The max duration a token is valid in seconds.\r\n */\r\n static readonly tokenTimeout_s = 600;\r\n /**\r\n * This duration will be susbtracted of the `tokenTimeout_s` duration.\r\n */\r\n static readonly tokenExpireOffset_s = 60;\r\n /**\r\n * The API's base url.\r\n */\r\n static readonly apiBaseUrl = '/api/core/v2';\r\n\r\n /**\r\n * The data source route used for API key authentication. See also the plugin.json file.\r\n */\r\n static readonly apiKeyUrlPrefix = '/api_key_auth';\r\n\r\n /**\r\n * Executes a query against the given datasource. An access token will be gathered if needed.\r\n * For each namespace specified in the passed options, a separate query will be executed.\r\n *\r\n * @param datasource the datasource to use\r\n * @param options the options specifying the query's request\r\n */\r\n static query(datasource: any, options: QueryOptions) {\r\n const {namespaces} = options;\r\n\r\n if (_.isEmpty(namespaces) && options.url === '/namespaces') {\r\n namespaces.push(''); // dummy element to execute a query\r\n }\r\n\r\n const queries = _.map(namespaces, namespace =>\r\n this._doQuery(datasource, options, namespace)\r\n );\r\n\r\n return Promise.all(queries).then(data => {\r\n return _.flatten(data);\r\n });\r\n }\r\n\r\n /**\r\n * Executes a query against the given datasource. An access token will be gathered if needed.\r\n *\r\n * @param datasource the datasource to use\r\n * @param options the options specifying the query's request\r\n * @param namespace the namespace used by this query\r\n */\r\n static _doQuery(\r\n datasource: any,\r\n options: QueryOptions,\r\n namespace: string,\r\n retryCount = 0\r\n ) {\r\n const {method, url} = options;\r\n\r\n let fullUrl: string;\r\n if (url === '/namespaces') {\r\n fullUrl = Sensu.apiBaseUrl + '/namespaces';\r\n } else {\r\n const namespacePath = namespace === '*' ? '' : '/namespaces/' + namespace;\r\n fullUrl = Sensu.apiBaseUrl + namespacePath + url;\r\n }\r\n\r\n const requestParameters = this._getParameters(options);\r\n\r\n return Sensu._authenticate(datasource)\r\n .then(() => Sensu._request(datasource, method, fullUrl, requestParameters))\r\n .then(result => result.data)\r\n .catch(error => {\r\n // we'll retry once\r\n if (retryCount >= 1) {\r\n throw error;\r\n }\r\n\r\n // delete token details in order to refresh the token in case of basic auth\r\n delete datasource.instanceSettings.tokens;\r\n\r\n // the retry is not immediatly done in order to prevent some race conditions\r\n const delay = Math.floor(1000 + Math.random() * 1000);\r\n\r\n return new Promise(resolve => setTimeout(resolve, delay)).then(() =>\r\n this._doQuery(datasource, options, namespace, retryCount + 1)\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Checks whether an access token exist. If none exists or it is expired a new one will be fetched.\r\n * In case an api key auth is used, this method will never fetch a token.\r\n *\r\n * @param datasource the datasource to use\r\n */\r\n static _authenticate(datasource: any) {\r\n const {tokens} = datasource.instanceSettings;\r\n const useApiKey = _.get(datasource.instanceSettings, 'jsonData.useApiKey', false);\r\n\r\n // never aquire token in case of api key auth\r\n if (useApiKey) {\r\n return Promise.resolve(true);\r\n }\r\n\r\n const acquireToken = !tokens || Sensu._isTokenExpired(tokens);\r\n if (acquireToken) {\r\n return Sensu._acquireAccessToken(datasource);\r\n } else {\r\n return Promise.resolve(true);\r\n }\r\n }\r\n\r\n /**\r\n * Returns whether the given token is already expired.\r\n *\r\n * @param token the token to check\r\n */\r\n static _isTokenExpired(token: AccessToken) {\r\n const timestampNow: number = Math.floor(Date.now() / 1000);\r\n let expiresAt: number = token.expires_at;\r\n\r\n if (token.expires_offset) {\r\n expiresAt = expiresAt - token.expires_offset - Sensu.tokenExpireOffset_s;\r\n }\r\n\r\n return expiresAt < timestampNow;\r\n }\r\n\r\n /**\r\n * Fetches and stores an access token.\r\n *\r\n * @param datasource the datasource to use\r\n */\r\n static _acquireAccessToken(datasource: any) {\r\n return Sensu._request(datasource, 'GET', '/auth').then(result => {\r\n const tokens: AccessToken = result.data;\r\n\r\n const timestampNow: number = Math.floor(Date.now() / 1000);\r\n const expiresOffset: number =\r\n tokens.expires_at - timestampNow - Sensu.tokenTimeout_s;\r\n\r\n tokens.expires_offset = expiresOffset;\r\n\r\n datasource.instanceSettings.tokens = tokens;\r\n });\r\n }\r\n\r\n /**\r\n * Executes a (potential authenticated) request against the specified url using the given datasource (server) and HTTP method.\r\n *\r\n * @param datasource the datasource to use\r\n * @param method the method of the HTTP request (GET, POST, ...)\r\n * @param url the url to send the request to\r\n */\r\n static _request(\r\n datasource: any,\r\n method: string,\r\n url: string,\r\n requestParameters: Record = {}\r\n ) {\r\n const useApiKey = _.get(datasource.instanceSettings, 'jsonData.useApiKey', false);\r\n\r\n const req: any = {\r\n method: method,\r\n };\r\n\r\n req.headers = {\r\n 'Content-Type': 'application/json',\r\n };\r\n\r\n if (useApiKey) {\r\n // authentication via api key using authentication route\r\n req.url = datasource.url + Sensu.apiKeyUrlPrefix + url;\r\n } else {\r\n // authentication via bearer token\r\n req.url = datasource.url + url;\r\n\r\n if (_.has(datasource.instanceSettings, 'tokens')) {\r\n req.headers.Authorization =\r\n 'Bearer ' + datasource.instanceSettings.tokens.access_token;\r\n }\r\n }\r\n\r\n req.params = requestParameters;\r\n\r\n return datasource.backendSrv\r\n .datasourceRequest(req)\r\n .then(Sensu._handleRequestResult, Sensu._handleRequestError);\r\n }\r\n\r\n /**\r\n * Is called when the request is ending successfully. In case of a 401 error, the request is not throwing an error but returning no result object.\r\n *\r\n * @param result the request's result object\r\n */\r\n static _handleRequestResult(result: any) {\r\n if (result) {\r\n return result;\r\n } else {\r\n throw {\r\n message: 'Credentials Invalid: Could not logged in using credentials',\r\n data: 'access_error',\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Is called if the request's promise is getting an error.\r\n *\r\n * @param err the request's error object\r\n */\r\n static _handleRequestError(err: any) {\r\n if (err.status !== 0 || err.status >= 300) {\r\n if (err.data && err.data.message) {\r\n throw {\r\n message: 'Sensu Go Error: ' + err.data.message,\r\n data: err.data,\r\n config: err.config,\r\n };\r\n } else {\r\n throw {\r\n message: 'Network Error: ' + err.statusText + '(' + err.status + ')',\r\n data: err.data,\r\n config: err.config,\r\n };\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Returns an object which represents the request parameters that should be used\r\n * by the request representing the data source query.\r\n *\r\n * @param options the query options to use as basis for the parameters\r\n */\r\n static _getParameters(options: QueryOptions) {\r\n const {limit, responseFilters} = options;\r\n const result: any = {};\r\n\r\n // build the response filter parameters\r\n const fieldSelector = this._buildFilterParameter(\r\n responseFilters.filter(filter => filter.type === ServerSideFilterType.FIELD)\r\n );\r\n if (fieldSelector !== '') {\r\n result.fieldSelector = fieldSelector;\r\n }\r\n\r\n const labelSelector = this._buildFilterParameter(\r\n responseFilters.filter(filter => filter.type === ServerSideFilterType.LABEL)\r\n );\r\n if (labelSelector !== '') {\r\n result.labelSelector = labelSelector;\r\n }\r\n\r\n // build the limit option\r\n if (limit > 0) {\r\n result.limit = limit;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Creates the parameter value for a response (server-side) filter. More details regarding its\r\n * format can be found in the documentation: https://docs.sensu.io/sensu-go/latest/api/#response-filtering\r\n *\r\n * @param filters the filters which will be included in the filter parameter\r\n */\r\n static _buildFilterParameter(filters: ServerSideFilter[]) {\r\n return _(filters)\r\n .map(filter => filter.key + ' ' + filter.matcher + ' ' + filter.value)\r\n .join(' && ');\r\n }\r\n}\r\n","import {AggregationType, ApiEndpoint, TextValue} from './types';\r\n\r\n/**\r\n * The default limit.\r\n */\r\nexport const DEFAULT_LIMIT = 100;\r\n\r\n/**\r\n * The default limit for aggregation queries.\r\n */\r\nexport const DEFAULT_AGGREGATION_LIMIT = 0;\r\n\r\n/**\r\n * Supported aggregation functions.\r\n */\r\nexport const AGGREGATION_TYPES = [\r\n {\r\n value: 'count',\r\n text: 'Count',\r\n requiresTarget: false,\r\n },\r\n {\r\n value: 'sum',\r\n text: 'Sum',\r\n requiresTarget: true,\r\n },\r\n];\r\n\r\n/**\r\n * Sensu API endpoints.\r\n */\r\nexport const API_ENDPOINTS = [\r\n {\r\n text: 'Entity API',\r\n value: 'entity',\r\n url: '/entities',\r\n fieldSelectors: [\r\n // defined by the response filter feature (see: https://docs.sensu.io/sensu-go/latest/api/#response-filtering)\r\n 'entity.name',\r\n 'entity.namespace',\r\n 'entity.deregister',\r\n 'entity.entity_class',\r\n 'entity.subscriptions',\r\n ],\r\n },\r\n {\r\n text: 'Events API',\r\n value: 'events',\r\n url: '/events',\r\n fieldSelectors: [\r\n 'event.is_silenced',\r\n 'event.name',\r\n 'event.namespace',\r\n 'event.check.handlers',\r\n 'event.check.is_silenced',\r\n 'event.check.name',\r\n 'event.check.publish',\r\n 'event.check.round_robin',\r\n 'event.check.runtime_assets',\r\n 'event.check.status',\r\n 'event.check.subscriptions',\r\n 'event.entity.deregister',\r\n 'event.entity.entity_class',\r\n 'event.entity.name',\r\n 'event.entity.subscriptions',\r\n ],\r\n },\r\n {\r\n text: 'Namespaces API',\r\n value: 'namespaces',\r\n url: '/namespaces',\r\n fieldSelectors: ['namespace.name'],\r\n },\r\n];\r\n\r\n/**\r\n * Supported query types.\r\n */\r\nexport const QUERY_TYPES = [\r\n {\r\n value: 'field',\r\n text: 'Field Selection',\r\n },\r\n {\r\n value: 'aggregation',\r\n text: 'Aggregation',\r\n },\r\n];\r\n\r\n/**\r\n * Supported result data formats.\r\n */\r\nexport const FORMATS = [\r\n {\r\n value: 'table',\r\n text: 'Table',\r\n },\r\n {\r\n value: 'table-v',\r\n text: 'Table (Vertical)',\r\n },\r\n {\r\n value: 'series',\r\n text: 'Time Series',\r\n },\r\n];\r\n\r\n/**\r\n * Properties containing a timestamp and should converted (from seconds to miliseconds).\r\n */\r\nexport const TIME_PROPERTIES: string[] = [\r\n 'timestamp',\r\n 'check.executed',\r\n 'check.issued',\r\n 'check.last_ok',\r\n 'entity.last_seen',\r\n 'last_seen',\r\n];\r\n","import _ from 'lodash';\r\n\r\n/**\r\n * Returns whether the given data value matchs the filter specified by the filter value in combination with the given operator.\r\n * @param filterValue the filter value\r\n * @param operator the operator used for comparision\r\n * @param dataValue the data value to test\r\n */\r\nexport const matchs = (\r\n filterValue: string,\r\n operator: string,\r\n dataValue: number | string | boolean\r\n): boolean => {\r\n if (operator === '==') {\r\n return filterValue == dataValue;\r\n }\r\n if (operator === '!=') {\r\n return filterValue != dataValue;\r\n }\r\n if (operator === '=~' || operator === '!~') {\r\n return _matchRegExp(filterValue, operator, dataValue);\r\n }\r\n if (operator === '<' || operator === '>') {\r\n return _matchNumber(filterValue, operator, dataValue);\r\n }\r\n\r\n throw 'Unsupported operator \"' + operator + '\"';\r\n};\r\n\r\n/**\r\n * Matching using '>' and '<' operators.\r\n */\r\nconst _matchNumber = (filterValue: string, operator: string, dataValue: any) => {\r\n const filterNumber = Number(filterValue);\r\n\r\n if (!_.isFinite(filterNumber)) {\r\n console.warn(\r\n 'The specified filter value (' +\r\n filterValue +\r\n ') is not compatible to filter on a numeric attribute.'\r\n );\r\n return false;\r\n }\r\n\r\n if (operator === '<') {\r\n return dataValue < filterNumber;\r\n } else {\r\n return dataValue > filterNumber;\r\n }\r\n};\r\n\r\n/**\r\n * Matching using regular expressions.\r\n */\r\nconst _matchRegExp = (filterValue: string, operator: string, dataValue: any) => {\r\n const regex: RegExp = _stringToRegex(filterValue);\r\n\r\n if (operator === '=~') {\r\n return regex.test(dataValue);\r\n } else {\r\n return !regex.test(dataValue);\r\n }\r\n};\r\n\r\n/**\r\n * Converts a string to a RegExp instance and keeps optional modifiers.\r\n * @param value the string to convert\r\n */\r\nconst _stringToRegex = (value: string) => {\r\n const regex = value.match(/\\/(.*)\\/(\\w*)/);\r\n if (regex) {\r\n return new RegExp(regex[1], regex[2]);\r\n } else {\r\n return new RegExp(value);\r\n }\r\n};\r\n\r\nexport default {matchs};\r\n","import _ from 'lodash';\r\nimport {DEFAULT_LIMIT, DEFAULT_AGGREGATION_LIMIT} from '../constants';\r\n\r\nimport {\r\n QueryComponents,\r\n GrafanaTarget,\r\n ServerSideFilterType,\r\n ServerSideFilter,\r\n ClientSideFilter,\r\n} from '../types';\r\n\r\n/** RegEx matching a in-browser filter of the WHERE-clause. */\r\nconst CLIENT_FILTER_REG_EXP = '([^\\\\s:=!]+)\\\\s*(==|=~|!=|>|<|!~|=)\\\\s*(\\\\S+)';\r\n\r\n/** RegExp of a filter key or value of the server-side filter. */\r\nconst SERVER_FILTER_VALUE_REG_EXP = '\\\\[[^[]+\\\\]|\"[^\"]+\"|\\\\S+';\r\n\r\n/** RegEx matching a response filter (server-side) of the WHERE-clause. */\r\nconst SERVER_FILTER_REG_EXP =\r\n '(fieldSelector|labelSelector):(' +\r\n SERVER_FILTER_VALUE_REG_EXP +\r\n ')\\\\s*(==|!=|IN|NOTIN|MATCHES)\\\\s*(' +\r\n SERVER_FILTER_VALUE_REG_EXP +\r\n ')';\r\n\r\n/** RegEx representing a single element of the WHERE-clause. */\r\nconst QUERY_SINGLE_FILTER_REG_EXP =\r\n '(' + SERVER_FILTER_REG_EXP + '|' + CLIENT_FILTER_REG_EXP + ')';\r\n\r\n/** RegEx representing the whole query string. */\r\nconst QUERY_FULL_REG_EXP =\r\n '^\\\\s*QUERY\\\\s+API\\\\s+(entity|events|namespaces)\\\\s+(IN\\\\s+NAMESPACE\\\\s+(\\\\S+)\\\\s+)?SELECT\\\\s+(\\\\S+)(\\\\s+WHERE\\\\s+(' +\r\n QUERY_SINGLE_FILTER_REG_EXP +\r\n '(\\\\s+AND\\\\s+' +\r\n QUERY_SINGLE_FILTER_REG_EXP +\r\n ')*))?(\\\\s+LIMIT\\\\s+(\\\\d+))?\\\\s*$';\r\n\r\n/**\r\n * Creates a query string based on the target definition.\r\n * @param target the data used by the query\r\n */\r\nexport function targetToQueryString(target: GrafanaTarget): string {\r\n let query: string = 'QUERY API ' + target.apiEndpoints;\r\n\r\n query += _namespace(target);\r\n\r\n if (target.queryType === 'field') {\r\n query += _queryTypeField(target);\r\n } else if (target.queryType === 'aggregation') {\r\n query += _queryTypeAggregation(target);\r\n }\r\n\r\n query += _whereClause(target);\r\n query += _limit(target);\r\n\r\n return query;\r\n}\r\n\r\n/**\r\n * Return the \"select\" statement based on the given target.\r\n * E.g.: SELECT field, another.field AS myField\r\n */\r\nconst _queryTypeField = (target: GrafanaTarget) => {\r\n const fields = _(target.fieldSelectors)\r\n .flatMap(selector => {\r\n if (selector.alias) {\r\n return selector.getPath() + ' AS ' + selector.alias;\r\n } else {\r\n return selector.getPath();\r\n }\r\n })\r\n .join(', ');\r\n\r\n return ' SELECT ' + fields;\r\n};\r\n\r\n/**\r\n * Return the \"aggregation\" statement based on the given target.\r\n * E.g.: AGGREGATE sum ON field\r\n */\r\nconst _queryTypeAggregation = (target: GrafanaTarget) => {\r\n let query: string = ' AGGREGATE ' + target.aggregationType;\r\n\r\n if (target.aggregationRequiresTarget) {\r\n query += ' ON ' + target.aggregationField;\r\n }\r\n\r\n return query;\r\n};\r\n\r\n/**\r\n * Return the namespace statement based on the given target.\r\n * E.g.: IN NAMESPACE default\r\n */\r\nconst _namespace = (target: GrafanaTarget) => {\r\n if (target.namespace === 'default') {\r\n return '';\r\n } else {\r\n return ' IN NAMESPACE ' + target.namespace;\r\n }\r\n};\r\n\r\n/**\r\n * Return the where clause based on the given target.\r\n * E.g.: WHERE field=value AND status>0\r\n */\r\nconst _whereClause = (target: GrafanaTarget) => {\r\n const {clientSideFilters, serverSideFilters} = target;\r\n\r\n const serverFilters = _(serverSideFilters)\r\n .map(\r\n filter =>\r\n (filter.type == ServerSideFilterType.FIELD ? 'fieldSelector' : 'labelSelector') +\r\n ':' +\r\n filter.key +\r\n ' ' +\r\n filter.matcher.toUpperCase() +\r\n ' ' +\r\n filter.value\r\n )\r\n .value();\r\n\r\n const clientFilters = _(clientSideFilters)\r\n .map(filter => filter.key + ' ' + filter.matcher + ' ' + filter.value)\r\n .value();\r\n\r\n const whereClause = _([serverFilters, clientFilters])\r\n .flatten()\r\n .join(' AND ');\r\n\r\n if (whereClause) {\r\n return ' WHERE ' + whereClause;\r\n } else {\r\n return '';\r\n }\r\n};\r\n\r\n/**\r\n * Return the limit statement based on the given target. If no limit is specified the default limit will be used.\r\n * E.g.: LIMIT 100\r\n */\r\nconst _limit = (target: GrafanaTarget) => {\r\n let queryLimit: number;\r\n\r\n if (target.limit) {\r\n queryLimit = _.defaultTo(parseInt(target.limit), DEFAULT_LIMIT);\r\n } else {\r\n // Use a special default limit in aggregation queries\r\n if (target.queryType === 'aggregation') {\r\n queryLimit = DEFAULT_AGGREGATION_LIMIT;\r\n } else {\r\n queryLimit = DEFAULT_LIMIT;\r\n }\r\n }\r\n\r\n if (queryLimit > 0) {\r\n return ' LIMIT ' + queryLimit;\r\n } else {\r\n return '';\r\n }\r\n};\r\n\r\nexport const extractQueryComponents = (query: string): QueryComponents | null => {\r\n const queryRegExp = new RegExp(QUERY_FULL_REG_EXP, 'i');\r\n const matchResult = query.match(queryRegExp);\r\n\r\n if (!matchResult) {\r\n return null;\r\n }\r\n\r\n let namespace: string;\r\n if (matchResult[3] !== undefined) {\r\n namespace = matchResult[3];\r\n } else {\r\n namespace = 'default';\r\n }\r\n\r\n const components: QueryComponents = {\r\n apiKey: matchResult[1],\r\n namespace: namespace,\r\n selectedField: matchResult[4],\r\n clientFilters: [],\r\n serverFilters: [],\r\n limit: parseInt(matchResult[25]),\r\n };\r\n\r\n if (matchResult[6] !== undefined) {\r\n const filterRegExp = new RegExp(\r\n SERVER_FILTER_REG_EXP + '|' + CLIENT_FILTER_REG_EXP,\r\n 'gi'\r\n );\r\n\r\n const whereClause: string = matchResult[6];\r\n\r\n let match: RegExpExecArray | null;\r\n while ((match = filterRegExp.exec(whereClause)) !== null) {\r\n const isServerFilter = match[1] !== undefined;\r\n\r\n if (isServerFilter) {\r\n // add response filter\r\n const filter: ServerSideFilter = {\r\n type:\r\n match[1] === 'fieldSelector'\r\n ? ServerSideFilterType.FIELD\r\n : ServerSideFilterType.LABEL,\r\n key: match[2],\r\n matcher: match[3],\r\n value: match[4],\r\n };\r\n\r\n components.serverFilters.push(filter);\r\n } else {\r\n // add in-browser filter\r\n const filter: ClientSideFilter = {\r\n key: match[5],\r\n matcher: match[6] === '=' ? '==' : match[6],\r\n value: match[7],\r\n };\r\n\r\n components.clientFilters.push(filter);\r\n }\r\n }\r\n }\r\n\r\n return components;\r\n};\r\n\r\nexport default {targetToQueryString, extractQueryComponents};\r\n","import {DataPoint, GrafanaTable} from '../types';\r\nimport {TIME_PROPERTIES} from '../constants';\r\nimport _ from 'lodash';\r\nimport moment from 'moment';\r\n\r\n/**\r\n * Transforms the given data into a table representation.\r\n */\r\nconst transform = (dataMatrix: DataPoint[][], vertical: boolean): GrafanaTable => {\r\n const columns = _extractColumns(dataMatrix);\r\n\r\n // create column index mapping\r\n const columnIndexMap = {};\r\n _.each(columns, (column, index) => (columnIndexMap[column.text] = index));\r\n\r\n // generate data rows\r\n const rows: any[][] = _.map(dataMatrix, dataRow => {\r\n const row = _.times(columns.length, _.constant(null));\r\n\r\n _(dataRow)\r\n .map(({name, value}) => {\r\n if (_.isArray(value)) {\r\n return _.map(value, (element, index) => [name + '[' + index + ']', element]);\r\n } else {\r\n return [[name, value]];\r\n }\r\n })\r\n .flatten()\r\n .map(data => {\r\n if (_.isPlainObject(data[1]) || _.isArray(data[1])) {\r\n data[1] = JSON.stringify(data[1]);\r\n }\r\n return data;\r\n })\r\n .each(([columnName, value]) => {\r\n row[columnIndexMap[columnName]] = value;\r\n });\r\n\r\n return row;\r\n });\r\n\r\n if (vertical) {\r\n return _asVerticalTable(columns, rows);\r\n }\r\n\r\n // create grafana result object\r\n return {\r\n columns,\r\n rows,\r\n type: 'table',\r\n };\r\n};\r\n\r\nconst _asVerticalTable = (dataColumns, dataRows: any[][]): GrafanaTable => {\r\n // fixed table headers\r\n const columns = [\r\n {\r\n text: 'Attribute',\r\n },\r\n {\r\n text: 'Value',\r\n },\r\n ];\r\n\r\n const rows = _(dataRows)\r\n .flatten()\r\n .map((value, idx) => [dataColumns[idx].text, value])\r\n .value();\r\n\r\n // this is done because users cannot define a time formatting based on rows\r\n _convertTimestamps(rows);\r\n\r\n return {\r\n columns,\r\n rows,\r\n type: 'table',\r\n };\r\n};\r\n\r\nconst _convertTimestamps = (rows: any[][]) => {\r\n _.each(rows, row => {\r\n const attribute = row[0];\r\n const value = row[1];\r\n\r\n for (let index = 0; index < TIME_PROPERTIES.length; index++) {\r\n if (attribute === TIME_PROPERTIES[index]) {\r\n const time = _.defaultTo(value, -1);\r\n if (time > 0) {\r\n row[1] = moment(time).format('YYYY-MM-DD HH:mm:ss');\r\n }\r\n break;\r\n }\r\n }\r\n });\r\n};\r\n\r\n/**\r\n * Returns an array of columns which exist in the given data matrix. Each data point attribute will be\r\n * represents by a column.\r\n *\r\n * @param dataMatrix the data basis\r\n */\r\nconst _extractColumns = (dataMatrix: DataPoint[][]) => {\r\n const isArrayMarker = {};\r\n\r\n // extract existing columns\r\n return _(dataMatrix)\r\n .flatten()\r\n .map(({name, value}) => {\r\n if (_.isArray(value)) {\r\n isArrayMarker[name] = true;\r\n return _.times(value.length, index => name + '[' + index + ']');\r\n } else {\r\n if (_.isNil(value) && _.get(isArrayMarker, name, false)) {\r\n return [];\r\n }\r\n return [name];\r\n }\r\n })\r\n .flatten()\r\n .uniq()\r\n .map(name => {\r\n return {\r\n text: name,\r\n };\r\n })\r\n .value();\r\n};\r\n\r\nexport default transform;\r\n","import {DataPoint, GrafanaTable, GrafanaTimeSeries} from '../types';\r\nimport table_transform from './table_transformer';\r\nimport timeseries_transform from './timeseries_transformer';\r\n\r\nexport default {\r\n toTable: (dataMatrix: DataPoint[][], vertical: boolean): GrafanaTable => {\r\n return table_transform(dataMatrix, vertical);\r\n },\r\n toTimeSeries: (dataMatrix: DataPoint[][]): GrafanaTimeSeries[] => {\r\n return timeseries_transform(dataMatrix);\r\n },\r\n};\r\n","import {DataPoint, GrafanaTimeSeries} from '../types';\r\nimport _ from 'lodash';\r\n\r\n/**\r\n * Transforms the given data into a time series representation.\r\n */\r\nconst transform = (dataMatrix: DataPoint[][]): GrafanaTimeSeries[] => {\r\n const now: number = Date.now();\r\n\r\n // maps the data to a series - skips all values which are not finite\r\n // - name => series name\r\n // - value => value\r\n return _(dataMatrix)\r\n .flatten()\r\n .filter(data => _.isFinite(data.value))\r\n .map(data => {\r\n return {\r\n target: data.name,\r\n datapoints: [[data.value, now]],\r\n };\r\n })\r\n .value();\r\n};\r\n\r\nexport default transform;\r\n","import _ from 'lodash';\r\nimport {ClientSideFilter, GrafanaTarget} from '../types';\r\n\r\n/** The latest configuration version. */\r\nconst LATEST_VERSION = 2;\r\n\r\n/** Migrates the passed configuration target to the latest version. The passed object will be mutated. */\r\nconst migrate = (target: GrafanaTarget): GrafanaTarget => {\r\n const {version} = target;\r\n\r\n if (version === undefined) {\r\n init(target);\r\n }\r\n if (version === 1) {\r\n toVersion2(target);\r\n }\r\n\r\n return target;\r\n};\r\n\r\n/** Initializes the configuration target. */\r\nconst init = (target: GrafanaTarget) => {\r\n target.version = LATEST_VERSION;\r\n target.clientSideFilters = [];\r\n target.serverSideFilters = [];\r\n};\r\n\r\n/** Migrates the passed configuration target from version 1 to version 2. */\r\nconst toVersion2 = (target: GrafanaTarget) => {\r\n console.log('Migrating data source configuration to version 2.');\r\n\r\n const {filterSegments} = target;\r\n\r\n const filters = _(filterSegments)\r\n .filter(segments => segments.length === 3)\r\n .filter(segments => !_.get(segments[2], 'fake', false))\r\n .map(segments => {\r\n const matcher = segments[1].value === '=' ? '==' : segments[1].value;\r\n\r\n return {\r\n key: segments[0].value,\r\n matcher,\r\n value: segments[2].value,\r\n };\r\n })\r\n .value();\r\n\r\n delete target.filterSegments;\r\n\r\n target.clientSideFilters = filters;\r\n target.serverSideFilters = [];\r\n\r\n target.version = 2;\r\n};\r\n\r\nexport default {\r\n migrate,\r\n};\r\n","import _ from 'lodash';\r\nimport {DataPoint} from '../types';\r\n\r\n/**\r\n * Does a count aggregation. The number of elements in the given data is returned.\r\n *\r\n * @param data the data to aggregate\r\n * @param name the name of the resulting value\r\n */\r\nconst count = (data: any[], name: string): DataPoint[] => {\r\n return [\r\n {\r\n name,\r\n value: data.length,\r\n },\r\n ];\r\n};\r\n\r\n/**\r\n * Does a sum aggregation. The sum of the specified attribute of all elements in the given data is calculated.\r\n *\r\n * @param data the data to aggregate\r\n * @param name the name of the resulting value\r\n * @param targetField the field which should be summed up\r\n */\r\nconst sum = (\r\n data: any[],\r\n name: string,\r\n targetField: string | undefined\r\n): DataPoint[] | null => {\r\n if (!targetField) {\r\n return [];\r\n }\r\n\r\n let sum: number | null = _.sumBy(data, targetField);\r\n\r\n if (!_.isFinite(sum)) {\r\n sum = null;\r\n }\r\n\r\n return [\r\n {\r\n name,\r\n value: sum,\r\n },\r\n ];\r\n};\r\n\r\nexport default {count, sum};\r\n","import _ from 'lodash';\n\nimport sensu from './sensu/sensu';\nimport {\n API_ENDPOINTS,\n DEFAULT_LIMIT,\n DEFAULT_AGGREGATION_LIMIT,\n TIME_PROPERTIES,\n} from './constants';\nimport FieldSelector from './FieldSelector';\nimport FilterUtils from './utils/datasource_filter_util';\nimport QueryUtils from './utils/query_util';\nimport transformer from './transformer';\nimport ConfigMigration from './utils/config_migration_util';\nimport AggregationUtils from './utils/data_aggregation_util';\n\nimport {\n PreparedTarget,\n ColumnMapping,\n DataPoint,\n ClientSideFilter,\n QueryComponents,\n InstanceSettings,\n QueryOptions,\n GrafanaTarget,\n} from './types';\n\nexport default class SensuDatasource {\n url: string;\n\n /** @ngInject */\n constructor(\n public instanceSettings: InstanceSettings,\n public backendSrv,\n private templateSrv\n ) {\n this.url = instanceSettings.url.trim();\n }\n\n /**\n * Preprocces the query targets like resolving template variables.\n */\n prepareQuery = (target: GrafanaTarget, queryOptions) => {\n // resolve API url\n const apiUrl = this._getApiUrl(target);\n // resolve filters\n const clientFilters = _.cloneDeep(target.clientSideFilters);\n const serverFilters = _.cloneDeep(target.serverSideFilters);\n\n const preparedTarget: PreparedTarget = {\n apiUrl,\n clientFilters,\n serverFilters,\n target: _.cloneDeep(target), //ensure modifications are not globally propagated\n };\n\n this._resolveTemplateVariables(preparedTarget, queryOptions);\n\n return preparedTarget;\n };\n\n /**\n * Resolves template variables in the given prepared target.\n */\n _resolveTemplateVariables = (preparedTarget: PreparedTarget, queryOptions) => {\n const {target, clientFilters, serverFilters} = preparedTarget;\n\n // resolve variables in namespaces\n const namespaces: string[] = this.templateSrv\n .replace(target.namespace, queryOptions.scopedVars, 'pipe')\n .split('|');\n\n target.namespaces = namespaces;\n\n // resolve variables in filters\n [clientFilters, serverFilters].forEach(filters =>\n filters.forEach(filter => {\n filter.key = this.templateSrv.replace(filter.key, queryOptions.scopedVars, 'csv');\n filter.value = this.templateSrv.replace(\n filter.value,\n queryOptions.scopedVars,\n 'regex'\n );\n })\n );\n };\n\n /**\n * Returns the url of the API used by the given target.\n */\n _getApiUrl = (target: GrafanaTarget) => {\n const apiEndpoint: any = _.find(API_ENDPOINTS, {value: target.apiEndpoints});\n if (apiEndpoint) {\n return apiEndpoint.url;\n } else {\n return API_ENDPOINTS[0].url;\n }\n };\n\n /**\n * Executes a query.\n */\n query(queryOptions) {\n const queryTargets = _(queryOptions.targets)\n .map(ConfigMigration.migrate)\n .map(target => this.prepareQuery(target, queryOptions))\n .value();\n\n // empty result in case there is no query defined\n if (queryTargets.length === 0) {\n return Promise.resolve({data: []});\n }\n\n const queries = queryTargets.map(prepTarget => {\n const {\n apiUrl,\n clientFilters,\n serverFilters,\n target: {queryType, fieldSelectors, namespaces, limit},\n } = prepTarget;\n\n // verify and set correct limit\n let parsedLimit: number = _.defaultTo(parseInt(limit || ''), -1);\n if (parsedLimit < 0) {\n if (queryType === 'aggregation') {\n parsedLimit = DEFAULT_AGGREGATION_LIMIT;\n } else {\n parsedLimit = DEFAULT_LIMIT;\n }\n }\n\n const queryOptions: QueryOptions = {\n method: 'GET',\n url: apiUrl,\n namespaces,\n limit: parsedLimit,\n responseFilters: serverFilters,\n };\n\n return sensu\n .query(this, queryOptions)\n .then(this._timeCorrection)\n .then(data => this._filterData(data, clientFilters))\n .then(data => {\n if (queryType === 'field') {\n return this._queryFieldSelection(data, fieldSelectors);\n } else if (queryType === 'aggregation') {\n return this._queryGroupAndAggregate(data, prepTarget);\n } else {\n return [];\n }\n });\n });\n\n return Promise.all(queries).then((queryResults: any) => {\n if (queryOptions.resultAsPlainArray) {\n // return only values - e.g. for template variables\n const result = _(queryResults)\n .map(result => transformer.toTable(result, false))\n .map(result => result.rows)\n .flatten()\n .flatten()\n .filter()\n .map(value => {\n return {text: value};\n })\n .value();\n\n return result;\n } else {\n const resultDataList: any[] = _.flatMap(queryResults, (queryResult, index) => {\n const {target: {format}} = queryTargets[index];\n\n if (format === 'series') {\n // return time series format\n return transformer.toTimeSeries(queryResult);\n } else {\n const isVertical = format === 'table-v';\n // return table format\n return transformer.toTable(queryResult, isVertical);\n }\n });\n\n return {\n data: resultDataList,\n };\n }\n });\n }\n\n /**\n * Converting the timestamps from seconds to miliseconds because Sensu's timestamp\n * resolution is in seconds but Grafana uses miliseconds.\n */\n _timeCorrection = (data: any) => {\n _.each(data, dataElement => {\n // iterate over all time properties\n _.each(TIME_PROPERTIES, property => {\n // fetch the properties value\n const time = _.get(dataElement, property, -1);\n // in case a time is set, we multiply them by 1000 to get miliseconds.\n // in case the time is 0, we'll remove it, otherwise Grafana will display the epoch's starting times\n if (time > 0) {\n _.set(dataElement, property, time * 1000);\n } else {\n _.unset(dataElement, property);\n }\n });\n });\n return data;\n };\n\n /**\n * This function will group the given data (if specified in the PreparedTarget) and aggregate it accordingly.\n *\n * @param data the data to group and aggregate\n * @param prepTarget the settings for the grouping and aggregation\n */\n _queryGroupAndAggregate = (data: any[], prepTarget: PreparedTarget) => {\n const {\n target: {\n aggregationAlias: alias,\n aggregationType: type,\n format,\n groupBy: groupAttribute,\n },\n } = prepTarget;\n // the name of the result value (the metric name if timeseries format is used, otherwise the column header)\n const name = alias ? alias : type || 'value';\n\n if (!groupAttribute) {\n // just aggregate without grouping\n const aggregationResult = this._queryAggregation(data, name, prepTarget);\n return [aggregationResult];\n } else {\n // first group the data..\n const groups = _.groupBy(data, groupAttribute);\n\n // ..then aggregate the individual groups\n const groupResult = _(groups)\n .map((dataGroup, groupKey) =>\n this._queryAggregation(dataGroup, groupKey, prepTarget)\n )\n .value();\n\n if ((format === 'table' || format === 'table-v') && groupResult) {\n const {groupAlias} = prepTarget.target;\n // we transform the groups into multiple columns in case the table format is used\n return this._mergeTableAggregation(\n groupResult,\n groupAlias || groupAttribute,\n name\n );\n } else {\n return groupResult;\n }\n }\n };\n\n /**\n * We merge the seperate aggregation result into a single one, thus we get a nicer visualization\n * in the table panel, where the group-attribute and value have their own column.\n */\n _mergeTableAggregation = (\n groupData: (DataPoint[] | null)[],\n groupByAttribute: string,\n alias: string\n ) => {\n return _(groupData)\n .map(group => {\n if (!group || group.length == 0) {\n return null;\n }\n const point: DataPoint = group[0];\n return [\n {\n name: groupByAttribute,\n value: point.name,\n },\n {\n name: alias,\n value: point.value,\n },\n ];\n })\n .filter() // null values\n .value();\n };\n\n /**\n * Process the data if the query type is 'aggregation'.\n */\n _queryAggregation = (data: any[], name: string, prepTarget: PreparedTarget) => {\n const {aggregationType: type} = prepTarget.target;\n\n if (type === 'count') {\n return AggregationUtils.count(data, name);\n } else if (type === 'sum') {\n const {aggregationField} = prepTarget.target;\n return AggregationUtils.sum(data, name, aggregationField);\n } else {\n throw new Error('The aggreation type \"' + type + '\" is not supported.');\n }\n };\n\n /**\n * Process the data if the query type is 'field'.\n */\n _queryFieldSelection = (data: any, fieldSelectors: FieldSelector[]) => {\n const columnMappings: ColumnMapping[] = this._extractColumnMappings(\n data,\n fieldSelectors\n );\n\n const resultData = _.map(data, dataElement => {\n // extract selected data\n return _.map(columnMappings, mapping => {\n const value: any = _.get(dataElement, mapping.path);\n\n return {\n name: mapping.alias,\n value: value,\n };\n });\n });\n\n return resultData;\n };\n\n /**\n * Creates a column mapping - which object attribute/path is related to which column.\n */\n _extractColumnMappings = (data: any, fieldSelectors: FieldSelector[]) => {\n const result: ColumnMapping[] = _.flatMap(fieldSelectors, selector => {\n const paths = _(data)\n .map(dataElement => this.resolvePaths(selector, dataElement))\n .flatMap()\n .uniq()\n .value();\n\n if (selector.alias) {\n if (paths.length > 1) {\n // use the alias in combination with an index as column name\n return _.map(paths, (path, index) => {\n return {\n path: path,\n alias: selector.alias + '.' + index,\n };\n });\n } else {\n // use the alias instead the path as column name\n return _.map(paths, path => {\n return {\n path: path,\n alias: selector.alias,\n };\n });\n }\n } else {\n // use the path itself as column name\n return _.map(paths, path => {\n return {\n path: path,\n alias: path,\n };\n });\n }\n });\n\n return result;\n };\n\n /**\n * Returns a filtered representation of the given data.\n */\n _filterData = (data: any, filters: ClientSideFilter[]) => {\n return _.filter(data, dataElement =>\n _.every(filters, filter => this._matches(dataElement, filter))\n );\n };\n\n /**\n * Returns whether the given element matches the given filter.\n */\n _matches = (element: any, filter: ClientSideFilter) => {\n const filterKey: string = filter.key;\n const matcher: string = filter.matcher;\n const filterValue: string = filter.value;\n\n const elementValue: any = _.get(element, filterKey);\n\n return FilterUtils.matchs(filterValue, matcher, elementValue);\n };\n\n /**\n * Resolves all existing paths of the specified selector based on the given data.\n * Example: if the selector is '*' all possible attibutes (including nested) will be returned.\n */\n resolvePaths = (selector: any, data: any) => {\n let selection: any = data;\n let lastSelector = '';\n let basePath = '';\n\n for (let i = 0; i < selector.fieldSegments.length; i++) {\n const segment: any = selector.fieldSegments[i];\n lastSelector = segment.value;\n\n if (lastSelector !== '*') {\n if (basePath === '') {\n basePath = lastSelector;\n } else {\n basePath = basePath + '.' + lastSelector;\n }\n selection = _.get(selection, lastSelector);\n }\n }\n\n if (lastSelector === '*') {\n const paths = this._deepResolve(selection);\n if (basePath === '') {\n return paths;\n } else {\n return _.map(paths, path => basePath + '.' + path);\n }\n } else {\n return [basePath];\n }\n };\n\n _deepResolve = data => {\n const keys: string[] = Object.keys(data);\n\n return _.flatMap(keys, key => {\n if (_.isPlainObject(data[key])) {\n return _.map(this._deepResolve(data[key]), nestedKeys => {\n return key + '.' + nestedKeys;\n });\n } else {\n return key;\n }\n });\n };\n\n /**\n * Executes a query based on the given query command which is a string representation of it.\n */\n metricFindQuery(query: string) {\n return this._query(query);\n }\n\n /**\n * Executes the given query command.\n */\n _query = (query: string) => {\n const queryComponents = QueryUtils.extractQueryComponents(query);\n\n if (queryComponents === null) {\n return Promise.resolve([]);\n }\n const options: any = this._transformQueryComponentsToQueryOptions(queryComponents);\n options.resultAsPlainArray = true;\n\n return this.query(options);\n };\n\n /**\n * Transforms the given query components into an options object which can be used by the `query(..)` function.\n */\n _transformQueryComponentsToQueryOptions = (queryComponents: QueryComponents) => {\n const {\n apiKey,\n selectedField,\n clientFilters,\n serverFilters,\n namespace,\n limit,\n } = queryComponents;\n\n const options = {\n targets: [\n {\n apiEndpoints: apiKey,\n queryType: 'field',\n namespace: namespace,\n limit: _.isNaN(limit) ? null : new String(limit),\n fieldSelectors: [\n {\n fieldSegments: [\n {\n value: selectedField,\n },\n ],\n },\n ],\n format: 'table',\n clientSideFilters: clientFilters,\n serverSideFilters: serverFilters,\n version: 2,\n },\n ],\n };\n\n return options;\n };\n\n /**\n * Used by the config UI to test a datasource.\n */\n testDatasource() {\n const useApiKey = _.get(this.instanceSettings, 'jsonData.useApiKey', false);\n\n // the /auth/test endpoint is only available for testing basic auth credentials\n const testUrl = useApiKey ? '/api/core/v2/namespaces' : '/auth/test';\n\n return sensu\n ._request(this, 'GET', testUrl)\n .then(() => {\n return {\n status: 'success',\n message: 'Successfully connected against the Sensu Go API',\n };\n })\n .catch(error => {\n if (useApiKey && error.data === 'access_error') {\n return {\n status: 'error',\n message: 'API Key Invalid: Could not logged in using API key',\n };\n }\n return {status: 'error', message: error.message};\n });\n }\n}\n","import _ from 'lodash';\r\nimport {SensuQueryCtrl} from './query_ctrl';\r\n\r\n/**\r\n * Helper class for building field selectors.\r\n * This class should be refactored => no segments should be in `target` but directly in the query controller.\r\n */\r\nexport default class FieldSelector {\r\n fieldSegments: any[];\r\n\r\n fieldType: string;\r\n\r\n attributePath: string;\r\n\r\n alias: string;\r\n\r\n /**\r\n * Restores the segments based on the given parameters.\r\n */\r\n static restore = (ctrl: SensuQueryCtrl, segments: FieldSelector): FieldSelector => {\r\n const path = _(segments.fieldSegments)\r\n .map(segment => segment.value)\r\n .join('.');\r\n\r\n const selector: FieldSelector = new FieldSelector(ctrl, path);\r\n\r\n selector.alias = segments.alias;\r\n\r\n return selector;\r\n };\r\n\r\n constructor(ctrl: SensuQueryCtrl, initPath: string) {\r\n this.fieldSegments = _.map(initPath.split('.'), path =>\r\n ctrl.uiSegmentSrv.newKey(path)\r\n );\r\n this.refresh(ctrl);\r\n }\r\n\r\n /**\r\n * Refreshes the selectors UI elements - if a segment changes its value.\r\n */\r\n refresh = (ctrl: SensuQueryCtrl): void => {\r\n if (!ctrl.dataPreview || ctrl.dataPreview.length <= 0) {\r\n return;\r\n }\r\n let selection = ctrl.dataPreview[0];\r\n\r\n for (let i = 0; i < this.fieldSegments.length; i++) {\r\n const segment: any = this.fieldSegments[i];\r\n const value: string = segment.value;\r\n\r\n if (selection) {\r\n selection = _.get(selection, value);\r\n }\r\n\r\n if (value === '*') {\r\n this.fieldSegments = this.fieldSegments.slice(0, i + 1);\r\n }\r\n }\r\n\r\n if (selection === undefined) {\r\n this.fieldType = 'undefined';\r\n } else if (_.isPlainObject(selection)) {\r\n this.fieldSegments.push(ctrl.uiSegmentSrv.newKey('*'));\r\n this.fieldType = 'object';\r\n } else if (_.isArray(selection)) {\r\n this.fieldType = 'array';\r\n } else if (typeof selection === 'number') {\r\n this.fieldType = 'number';\r\n } else {\r\n this.fieldType = 'string';\r\n }\r\n\r\n this.attributePath = this.getPath();\r\n };\r\n\r\n /**\r\n * Returns the current attribute path of this selector.\r\n */\r\n getPath = (): string => {\r\n return _(this.fieldSegments)\r\n .map(segment => segment.value)\r\n .join('.');\r\n };\r\n}\r\n","import appEvents from 'grafana/app/core/app_events';\nimport {QueryCtrl} from 'grafana/app/plugins/sdk';\nimport _ from 'lodash';\n\nimport {\n ApiEndpoint,\n AggregationType,\n TextValue,\n GrafanaTarget,\n ClientSideFilter,\n ServerSideFilter,\n ServerSideFilterType,\n} from './types';\n\nimport FieldSelector from './FieldSelector';\nimport {AGGREGATION_TYPES, API_ENDPOINTS, QUERY_TYPES, FORMATS} from './constants';\nimport {targetToQueryString} from './utils/query_util';\nimport Sensu from './sensu/sensu';\nimport ConfigMigration from './utils/config_migration_util';\n\nexport class SensuQueryCtrl extends QueryCtrl {\n static templateUrl = 'partials/query.editor.html';\n\n // Will be stored by Grafana\n target: GrafanaTarget;\n\n // Constants\n readonly aggregationTypes: AggregationType[] = AGGREGATION_TYPES;\n readonly queryTypes: TextValue[] = QUERY_TYPES;\n readonly formats: TextValue[] = FORMATS;\n\n segmentAggregationTarget: any;\n dataPreview: any = {};\n dataPreviewBuffer: any[] = [];\n\n apiEndpoints: ApiEndpoint[] = API_ENDPOINTS; // used in the partial\n addFieldSegment: any;\n namespaceSegment: any;\n groupBySegment: any;\n\n clientFilterSegments: any[] = [];\n serverFilterSegments: any[] = [];\n\n /** @ngInject **/\n constructor($scope, $injector, private $q, public uiSegmentSrv, private templateSrv) {\n super($scope, $injector);\n\n // Migrate existing configurations to the latest model version\n ConfigMigration.migrate(this.target);\n\n const {clientSideFilters, serverSideFilters} = this.target;\n\n // restore client filter segments\n _(clientSideFilters)\n .map(this._createClientFilterSegments)\n .each(segmentArray => this.clientFilterSegments.push(segmentArray));\n\n this.clientFilterSegments.push([this.uiSegmentSrv.newPlusButton()]);\n\n //restore server filter segments\n _(serverSideFilters)\n .map(this._createServerFilterSegments)\n .each(segmentArray => this.serverFilterSegments.push(segmentArray));\n\n this.serverFilterSegments.push([this.uiSegmentSrv.newPlusButton()]);\n\n // create field selectors\n if (this.target.fieldSelectors === undefined) {\n this.target.fieldSelectors = [new FieldSelector(this, '*')];\n } else {\n this.target.fieldSelectors = _.map(this.target.fieldSelectors, selector =>\n FieldSelector.restore(this, selector)\n );\n }\n\n if (this.target.apiEndpoints === undefined) {\n this.target.apiEndpoints = API_ENDPOINTS[0].value;\n }\n\n if (this.target.queryType === undefined) {\n this.target.queryType = this.queryTypes[0].value;\n }\n\n if (this.target.format === undefined) {\n this.target.format = this.formats[0].value;\n }\n\n this.addFieldSegment = this.uiSegmentSrv.newPlusButton();\n\n if (this.target.aggregation !== undefined) {\n delete this.target.aggregation;\n }\n\n if (this.target.aggregationType === undefined) {\n this.target.aggregationType = AGGREGATION_TYPES[0].value;\n }\n\n if (this.target.aggregationRequiresTarget === undefined) {\n this.target.aggregationRequiresTarget = AGGREGATION_TYPES[0].requiresTarget;\n }\n\n if (this.target.aggregationField === undefined) {\n this.segmentAggregationTarget = this.uiSegmentSrv.newFake(\n 'select target attribute',\n 'value',\n 'query-segment-value'\n );\n } else {\n this.segmentAggregationTarget = this.uiSegmentSrv.newSegment({\n value: this.target.aggregationField,\n });\n }\n\n if (this.target.groupBy === undefined) {\n this.groupBySegment = this.uiSegmentSrv.newPlusButton();\n } else {\n this.groupBySegment = this.uiSegmentSrv.newSegment({\n value: this.target.groupBy,\n });\n }\n\n if (this.target.namespace === undefined) {\n this.target.namespace = 'default';\n }\n\n this.namespaceSegment = this.uiSegmentSrv.newSegment({value: this.target.namespace});\n\n appEvents.on('ds-request-response', this.onResponseReceived, $scope);\n this.panelCtrl.events.on('refresh', this.onRefresh, $scope);\n this.panelCtrl.events.on('data-received', this.onDataReceived, $scope);\n\n this.panelCtrl.refresh();\n }\n\n /**\n * Creates an array containg segments which represent a in-browser filter. The first segment represents the filter-key,\n * the second the operator and the third the filter-value.\n */\n _createClientFilterSegments = (filter: ClientSideFilter) => {\n const segmentArray = [\n this.uiSegmentSrv.newKey(filter.key),\n this.uiSegmentSrv.newOperator(filter.matcher),\n this.uiSegmentSrv.newKeyValue(filter.value),\n ];\n\n return segmentArray;\n };\n\n /**\n * Creates an array containg segments which represent a response filter (sever-side). The first segment represents the type\n * of the filer (labelSelector or fieldSelector), the second the filter-key, the third the operator and the fourth the filter-value.\n */\n _createServerFilterSegments = (filter: ServerSideFilter) => {\n const type =\n filter.type === ServerSideFilterType.FIELD ? 'fieldSelector' : 'labelSelector';\n\n const segmentArray = [\n this.uiSegmentSrv.newCondition(type),\n this.uiSegmentSrv.newKey(filter.key),\n this.uiSegmentSrv.newOperator(filter.matcher),\n this.uiSegmentSrv.newKeyValue(filter.value),\n ];\n\n return segmentArray;\n };\n\n /**\n * Returns the currently selected aggregation type.\n */\n getCurrentAggregationType = () => {\n return _.find(AGGREGATION_TYPES, {\n value: this.target.aggregationType,\n });\n };\n\n /**\n * Called if the aggregation field changes.\n */\n onAggregationFieldChange = () => {\n this.target.aggregationField = this.segmentAggregationTarget.value;\n this.panelCtrl.refresh();\n };\n\n /**\n * Called if the aggregation type changes.\n */\n onAggregationTypeChange = () => {\n this.target.aggregationRequiresTarget = this.getCurrentAggregationType().requiresTarget;\n this._resetAggregation();\n this.panelCtrl.refresh();\n };\n\n /**\n * Resets the aggregation options.\n */\n _resetAggregation = () => {\n delete this.target.aggregationAlias;\n delete this.target.aggregationField;\n\n this.removeGroupBy();\n\n this.segmentAggregationTarget = this.uiSegmentSrv.newFake(\n 'select target attribute',\n 'value',\n 'query-segment-value'\n );\n };\n\n /**\n * Returns selectable options (all existing keys) for the aggregation field segment.\n */\n getTargetOptions = () => {\n const options: string[] = this.getAllDeepKeys();\n const segments: any[] = _.map(options, option =>\n this.uiSegmentSrv.newSegment({value: option})\n );\n\n return this.$q.when(segments);\n };\n\n /**\n * Returns selectable options (all existing keys) for the group-by segment.\n */\n getGroupByOptions = () => {\n const options: string[] = this.getAllDeepKeys();\n const segments: any[] = _.map(options, option =>\n this.uiSegmentSrv.newSegment({value: option})\n );\n\n return this.$q.when(segments);\n };\n\n /**\n * Called when the user changes the groupBy attribute.\n */\n onGroupByChange = () => {\n this.target.groupBy = this.groupBySegment.value;\n this.panelCtrl.refresh();\n };\n\n /**\n * Removes the groupBy attribute.\n */\n removeGroupBy = () => {\n this.groupBySegment = this.uiSegmentSrv.newPlusButton();\n delete this.target.groupBy;\n delete this.target.groupAlias;\n this.panelCtrl.refresh();\n };\n\n /**\n * Returns selectable options for the namespace segment.\n */\n getNamespaceOptions = () => {\n return Sensu.query(this.datasource, {\n method: 'GET',\n url: '/namespaces',\n namespaces: [],\n limit: 0,\n responseFilters: [],\n })\n .then(result => {\n // get existing namespaces based on query result\n const namespaces = _.map(result, namespace => namespace.name);\n\n // add all option\n namespaces.unshift('*');\n\n // add template variables\n _.each(this.templateSrv.variables, variable =>\n namespaces.unshift('$' + variable.name)\n );\n\n return _.map(namespaces, option => this.uiSegmentSrv.newSegment({value: option}));\n })\n .catch(() => {\n return [];\n });\n };\n\n /**\n * Called of the namespace is changing.\n */\n onNamespaceChange = () => {\n this.target.namespace = this.namespaceSegment.value;\n this.panelCtrl.refresh();\n };\n\n /**\n * Resets the field and filter segments.\n */\n _reset = () => {\n this.target.fieldSelectors = [new FieldSelector(this, '*')];\n this.clientFilterSegments = [[this.uiSegmentSrv.newPlusButton()]];\n this.serverFilterSegments = [[this.uiSegmentSrv.newPlusButton()]];\n this._updateFilterTarget();\n };\n\n /**\n * Called when the api is changing.\n */\n onApiChange = () => {\n this._reset();\n this.panelCtrl.refresh();\n };\n\n /**\n * Called when the query type is changing.\n */\n onQueryTypeChange = () => {\n this._resetAggregation();\n this.panelCtrl.refresh();\n };\n\n /**\n * Removes the filter at the given index.\n */\n removeFilter = (index: number, isServerFilter: boolean) => {\n const targetArray = isServerFilter\n ? this.serverFilterSegments\n : this.clientFilterSegments;\n targetArray.splice(index, 1);\n this._updateFilterTarget();\n this.panelCtrl.refresh();\n };\n\n /**\n * Called when a filter is changing.\n */\n onFilterSegmentUpdate = (segment, parentIndex, index) => {\n if (segment.type === 'plus-button') {\n this._addClientFilterSegment(segment);\n return;\n }\n\n if (index == 2) {\n const segmentValue = segment.value;\n if (/\\/.*\\/\\w*/.test(segmentValue)) {\n this.clientFilterSegments[parentIndex][1] = this.uiSegmentSrv.newOperator('=~');\n }\n }\n\n this._updateFilterTarget();\n this.panelCtrl.refresh();\n };\n\n /**\n * Adds a new in-browser filter.\n */\n _addClientFilterSegment = (sourceSegment: any) => {\n const segmentArray: any[] = [\n this.uiSegmentSrv.newKey(sourceSegment.value),\n this.uiSegmentSrv.newOperator('=='),\n this.uiSegmentSrv.newFake('select filter value', 'value', 'query-segment-value'),\n ];\n\n this.clientFilterSegments.pop();\n this.clientFilterSegments.push(segmentArray);\n this.clientFilterSegments.push([this.uiSegmentSrv.newPlusButton()]);\n };\n\n /**\n * Adds a new response filter.\n */\n _addServerFilterSegment = (sourceSegment: any) => {\n const segmentArray: any[] = [\n this.uiSegmentSrv.newCondition(sourceSegment.value),\n this.uiSegmentSrv.newFake('select filter key', 'value', 'query-segment-value'),\n this.uiSegmentSrv.newOperator('=='),\n this.uiSegmentSrv.newFake('select filter value', 'value', 'query-segment-value'),\n ];\n\n this.serverFilterSegments.pop();\n this.serverFilterSegments.push(segmentArray);\n this.serverFilterSegments.push([this.uiSegmentSrv.newPlusButton()]);\n };\n\n /**\n * Called when a response filter configuration is changed.\n *\n * @param segment the segment which has been changed\n */\n onServerFilterSegmentUpdate = segment => {\n if (segment.type === 'plus-button') {\n this._addServerFilterSegment(segment);\n return;\n }\n\n this._updateFilterTarget();\n this.panelCtrl.refresh();\n };\n\n /**\n * Returns selectable options for filter segments.\n */\n getFilterSegmentOptions = (segment, parentIndex, index) => {\n let segments: any[] = [];\n\n if (segment.type === 'operator') {\n segments = this.uiSegmentSrv.newOperators(['==', '=~', '!=', '!~', '<', '>']);\n } else if (this.dataPreview && this.dataPreview.length > 0) {\n let options: string[] = [];\n if (index === 0) {\n options = this.getAllDeepKeys();\n } else if (index === 2) {\n const filterKey = this.clientFilterSegments[parentIndex][0].value;\n options = _(this.dataPreview)\n .map(data => _.get(data, filterKey))\n .uniq()\n .value();\n\n _.each(this.templateSrv.variables, variable =>\n options.unshift('/$' + variable.name + '/')\n );\n }\n segments = _.map(options, option => this.uiSegmentSrv.newSegment(String(option)));\n }\n\n return this.$q.when(segments);\n };\n\n /**\n * The segments which represents the specified filters will not be persisted and passed to the data source.\n * Instead, an object is created which represents the filters which is passed to the data source and\n * persisted by Grafana. Calling this method syncs the object (target) and updates its value to match the\n * segments' values specified by the user.\n */\n _updateFilterTarget = () => {\n const target = this.target;\n\n // update client filters\n const clientFilters = _(this.clientFilterSegments)\n .filter(segmentArray => segmentArray.length === 3)\n .filter(segmentArray => !segmentArray[2].fake)\n .map(segmentArray => {\n return {\n key: segmentArray[0].value,\n matcher: segmentArray[1].value,\n value: segmentArray[2].value,\n };\n })\n .value();\n\n target.clientSideFilters = clientFilters;\n\n // update server filters\n const serverFilters = _(this.serverFilterSegments)\n .filter(segmentArray => segmentArray.length === 4)\n .filter(segmentArray => !segmentArray[1].fake && !segmentArray[3].fake)\n .map(segmentArray => {\n let type;\n switch (segmentArray[0].value) {\n case 'fieldSelector':\n type = ServerSideFilterType.FIELD;\n break;\n case 'labelSelector':\n type = ServerSideFilterType.LABEL;\n break;\n default:\n return {};\n }\n\n return {\n key: segmentArray[1].value,\n matcher: segmentArray[2].value,\n value: segmentArray[3].value,\n type,\n };\n })\n .filter(filter => filter.type !== undefined)\n .value();\n\n target.serverSideFilters = serverFilters;\n };\n\n /**\n * Returns all existing keys of the current data preview.\n */\n getAllDeepKeys = () => {\n return _.flatMap(this.combineKeys(this.dataPreview[0]), e => e);\n };\n\n /**\n * Returns selectable options for the field segments.\n */\n getFieldSelectorOptions = (segment, parentIndex, index) => {\n let segments: any[] = [];\n\n if (this.dataPreview && this.dataPreview.length > 0) {\n let options: string[] = [];\n\n let currentSelection: any = this.dataPreview[0];\n\n if (index > 0) {\n for (let i = 0; i < index; i++) {\n const fieldSegment = this.target.fieldSelectors[parentIndex].fieldSegments[i];\n currentSelection = _.get(currentSelection, fieldSegment.value);\n }\n }\n\n options = _.concat(options, ['*']);\n options = _.concat(options, Object.keys(currentSelection));\n\n options.sort();\n\n segments = _.map(options, option => this.uiSegmentSrv.newSegment({value: option}));\n }\n\n return this.$q.when(segments);\n };\n\n /**\n * Called if a field segment is changed.\n */\n onFieldSelectorSegmentUpdate = (segment, parentIndex) => {\n if (segment == this.addFieldSegment) {\n this.target.fieldSelectors.push(new FieldSelector(this, segment.value));\n this.addFieldSegment = this.uiSegmentSrv.newPlusButton();\n } else {\n this.target.fieldSelectors[parentIndex].refresh(this);\n }\n\n this.panelCtrl.refresh();\n };\n\n /**\n * Removes the field selector on the specified index.\n */\n removeField = index => {\n this.target.fieldSelectors.splice(index, 1);\n this.panelCtrl.refresh();\n };\n\n /**\n * Called if an alias is changing.\n */\n onAliasChange = () => {\n this.panelCtrl.refresh();\n };\n\n combineKeys = object => {\n const keys: string[] = Object.keys(object);\n\n return _.flatMap(keys, key => {\n if (_.isPlainObject(object[key])) {\n return _.map(this.combineKeys(object[key]), nestedKeys => {\n return key + '.' + nestedKeys;\n });\n } else {\n return key;\n }\n });\n };\n\n /**\n * Returns the currently selected api endpoint.\n */\n _getCurrentApi = () => {\n return _.find(API_ENDPOINTS, {value: this.target.apiEndpoints});\n };\n\n getServerFilterOptions = (segment, parentIndex) => {\n if (segment.type === 'operator') {\n return this.$q.when(\n this.uiSegmentSrv.newOperators(['==', '!=', 'in', 'notin', 'matches'])\n );\n } else if (segment.type === 'plus-button' || segment.type === 'condition') {\n return this.$q.when(\n _.map(['fieldSelector', 'labelSelector'], value =>\n this.uiSegmentSrv.newSegment({value})\n )\n );\n }\n\n const options: string[] = _.map(\n this.templateSrv.variables,\n variable => '\"$' + variable.name + '\"'\n );\n\n const filterType = this.serverFilterSegments[parentIndex][0].value;\n\n if (filterType === 'fieldSelector') {\n const currentApi = this._getCurrentApi();\n if (currentApi) {\n currentApi.fieldSelectors.forEach(field => options.push(field));\n }\n }\n\n const segments = _.map(options, option =>\n this.uiSegmentSrv.newSegment(new String(option))\n );\n\n return this.$q.when(segments);\n };\n\n onDataReceived = () => {\n if (this.dataPreviewBuffer.length > 0) {\n // this is done so that we get the response from all querys. otherwise the last query could override the\n // data which we need\n //\n // TODO only store the data related to the current query\n this.dataPreview = _.flatten(this.dataPreviewBuffer);\n this.dataPreviewBuffer = [];\n }\n };\n\n /**\n * Called when a request is finished. The requests data is stored and used as a data preview which is basis for auto completions.\n */\n onResponseReceived = response => {\n if (!response.config.url.endsWith('/auth')) {\n this.dataPreviewBuffer.push(response.data);\n }\n };\n\n onRefresh = () => {\n //TODO\n this.dataPreview = {};\n };\n\n /**\n * Returns a string representation of the current query configuration.\n */\n getCollapsedText() {\n return targetToQueryString(this.target);\n }\n}\n","import {InstanceSettings} from './types';\r\n\r\n/**\r\n * Controller responsible for the configuration ui.\r\n */\r\nexport class SensuConfigCtrl {\r\n static templateUrl = 'partials/config.html';\r\n\r\n // the current datasource settings\r\n current: InstanceSettings;\r\n\r\n /** @ngInject **/\r\n constructor($scope) {\r\n $scope.$watch(\r\n () => this.current.url,\r\n value => (this.current.jsonData.currentUrl = value)\r\n );\r\n $scope.$watch(\r\n () => this.current.basicAuth,\r\n value => {\r\n if (value) {\r\n this.current.jsonData.useApiKey = false;\r\n }\r\n }\r\n );\r\n }\r\n\r\n /**\r\n * When the \"Use API Key\" option is toggled.\r\n */\r\n onUseApiKeyToggle = () => {\r\n const current = this.current;\r\n if (current.jsonData.useApiKey) {\r\n current.basicAuth = false;\r\n this.resetApiKey();\r\n }\r\n };\r\n\r\n /**\r\n * Resets the currely set API key.\r\n */\r\n resetApiKey = () => {\r\n this.current.secureJsonFields.apiKey = false;\r\n this.current.secureJsonData = this.current.secureJsonData || {};\r\n this.current.secureJsonData.apiKey = '';\r\n };\r\n}\r\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///external \"lodash\"","webpack:///external \"moment\"","webpack:///external \"app/core/app_events\"","webpack:///external \"app/plugins/sdk\"","webpack:///./types.ts","webpack:///./sensu/sensu.ts","webpack:///./constants.ts","webpack:///./utils/datasource_filter_util.ts","webpack:///./utils/query_util.ts","webpack:///./transformer/table_transformer.ts","webpack:///./transformer/index.ts","webpack:///./transformer/timeseries_transformer.ts","webpack:///./utils/config_migration_util.ts","webpack:///./utils/data_aggregation_util.ts","webpack:///./datasource.ts","webpack:///./FieldSelector.ts","webpack:///./query_ctrl.ts","webpack:///./config_ctrl.ts"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","__WEBPACK_EXTERNAL_MODULE__0__","__WEBPACK_EXTERNAL_MODULE__1__","__WEBPACK_EXTERNAL_MODULE__2__","__WEBPACK_EXTERNAL_MODULE__3__","ServerSideFilterType","FIELD","LABEL","sensu","Sensu","query","datasource","options","_this","this","namespaces","external_lodash_default","a","isEmpty","url","push","queries","map","namespace","_doQuery","Promise","all","then","data","flatten","retryCount","fullUrl","method","apiBaseUrl","requestParameters","_getParameters","_authenticate","_request","result","catch","error","instanceSettings","tokens","delay","Math","floor","random","resolve","setTimeout","_isTokenExpired","_acquireAccessToken","token","timestampNow","Date","now","expiresAt","expires_at","expires_offset","tokenExpireOffset_s","expiresOffset","tokenTimeout_s","req","headers","Content-Type","apiKeyUrlPrefix","has","Authorization","access_token","params","backendSrv","datasourceRequest","_handleRequestResult","_handleRequestError","message","err","status","config","statusText","limit","responseFilters","fieldSelector","_buildFilterParameter","filter","type","labelSelector","filters","matcher","join","AGGREGATION_TYPES","text","requiresTarget","API_ENDPOINTS","fieldSelectors","QUERY_TYPES","FORMATS","TIME_PROPERTIES","_stringToRegex","regex","match","RegExp","datasource_filter_util","filterValue","operator","dataValue","test","_matchRegExp","filterNumber","Number","isFinite","console","warn","_matchNumber","components","_convertTimestamps","rows","each","row","attribute","index","length","time","defaultTo","external_moment_default","format","table_transformer","dataMatrix","vertical","columns","isArrayMarker","_a","isArray","times","isNil","uniq","_extractColumns","columnIndexMap","column","dataRow","constant","element","isPlainObject","JSON","stringify","columnName","dataColumns","dataRows","idx","_asVerticalTable","transformer","target","datapoints","timeseries_transformer","config_migration_util","version","clientSideFilters","serverSideFilters","init","log","filterSegments","segments","toVersion2","sum","SensuDatasource","templateSrv","prepareQuery","queryOptions","preparedTarget","apiUrl","_getApiUrl","clientFilters","cloneDeep","serverFilters","_resolveTemplateVariables","replace","scopedVars","split","forEach","apiEndpoint","find","apiEndpoints","_timeCorrection","dataElement","set","unset","_queryGroupAndAggregate","prepTarget","alias","aggregationAlias","aggregationType","groupAttribute","groupBy","groups","dataGroup","groupKey","_queryAggregation","groupResult","groupAlias","_mergeTableAggregation","groupData","groupByAttribute","group","point","data_aggregation_util","Error","targetField","sumBy","aggregationField","_queryFieldSelection","columnMappings","_extractColumnMappings","mapping","path","flatMap","selector","resolvePaths","paths","_filterData","every","_matches","filterKey","elementValue","selection","lastSelector","basePath","fieldSegments","_deepResolve","keys","nestedKeys","_query","queryComponents","queryRegExp","matchResult","apiKey","selectedField","parseInt","filterRegExp","SERVER_FILTER_REG_EXP","whereClause","exec","query_util","_transformQueryComponentsToQueryOptions","resultAsPlainArray","queryType","isNaN","String","trim","$inject","targets","hide","queryTargets","parsedLimit","queryResults","queryResult","metricFindQuery","testDatasource","useApiKey","testUrl","FieldSelector","ctrl","initPath","refresh","dataPreview","slice","fieldType","uiSegmentSrv","newKey","attributePath","getPath","segment","restore","query_ctrl_SensuQueryCtrl","_super","SensuQueryCtrl","$scope","$injector","$q","aggregationTypes","queryTypes","formats","dataPreviewBuffer","clientFilterSegments","newOperator","newKeyValue","_createServerFilterSegments","newCondition","onAggregationFieldChange","segmentAggregationTarget","panelCtrl","onAggregationTypeChange","aggregationRequiresTarget","getCurrentAggregationType","_resetAggregation","removeGroupBy","newFake","getTargetOptions","getAllDeepKeys","option","newSegment","when","getGroupByOptions","onGroupByChange","groupBySegment","newPlusButton","unshift","variables","variable","onNamespaceChange","namespaceSegment","_reset","FieldSelector_0","serverFilterSegments","_updateFilterTarget","onApiChange","onQueryTypeChange","isServerFilter","splice","parentIndex","segmentValue","_addClientFilterSegment","sourceSegment","segmentArray","pop","_addServerFilterSegment","getFilterSegmentOptions","newOperators","options_1","filterKey_1","fake","combineKeys","e","getFieldSelectorOptions","currentSelection","fieldSegment","concat","sort","addFieldSegment","removeField","onAliasChange","_getCurrentApi","currentApi","field","response","endsWith","onRefresh","_createClientFilterSegments","aggregation","app_events_default","on","onResponseReceived","events","__extends","getCollapsedText","toUpperCase","queryLimit","targetToQueryString","templateUrl","SensuConfigCtrl","current","jsonData","basicAuth","resetApiKey","secureJsonFields","secureJsonData","currentUrl","$watch"],"mappings":"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","file":"module.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 4);\n","module.exports = __WEBPACK_EXTERNAL_MODULE__0__;","module.exports = __WEBPACK_EXTERNAL_MODULE__1__;","module.exports = __WEBPACK_EXTERNAL_MODULE__2__;","module.exports = __WEBPACK_EXTERNAL_MODULE__3__;","import FieldSelector from './FieldSelector';\r\n\r\nexport interface AggregationType {\r\n readonly value: string;\r\n readonly text: string;\r\n readonly requiresTarget: boolean;\r\n}\r\n\r\nexport interface ApiEndpoint {\r\n readonly text: string;\r\n readonly value: string;\r\n readonly url: string;\r\n readonly fieldSelectors: string[];\r\n}\r\n\r\nexport interface ColumnMapping {\r\n path: string;\r\n alias: string;\r\n}\r\n\r\nexport interface DataPoint {\r\n readonly value: any;\r\n readonly name: string;\r\n}\r\n\r\nexport interface BaseFilter {\r\n key: string;\r\n value: string;\r\n matcher: string;\r\n}\r\n\r\nexport type ClientSideFilter = BaseFilter;\r\n\r\nexport interface ServerSideFilter extends BaseFilter {\r\n type: ServerSideFilterType;\r\n}\r\n\r\nexport enum ServerSideFilterType {\r\n FIELD = 0,\r\n LABEL = 1,\r\n}\r\n\r\nexport interface InstanceSettings {\r\n // the datasource url\r\n url: string;\r\n\r\n // whether basic auth is used\r\n basicAuth: boolean;\r\n\r\n // additional data\r\n jsonData: JsonData;\r\n\r\n // additional secured data\r\n secureJsonData: SecureJsonData;\r\n\r\n // map defining which secured data element is set\r\n secureJsonFields: SecureJsonFields;\r\n}\r\n\r\nexport interface JsonData {\r\n // copy of the current datasource url - used for dynamic routing\r\n currentUrl: string;\r\n\r\n // whether an API key should be used\r\n useApiKey: boolean;\r\n}\r\n\r\nexport interface SecureJsonData {\r\n // the specified API key\r\n apiKey?: string;\r\n}\r\n\r\nexport interface SecureJsonFields {\r\n // whether an API key has been stored by Grafana\r\n apiKey?: boolean;\r\n}\r\n\r\nexport interface PreparedTarget {\r\n readonly apiUrl: string;\r\n readonly clientFilters: ClientSideFilter[];\r\n readonly serverFilters: ServerSideFilter[];\r\n readonly target: GrafanaTarget;\r\n}\r\n\r\nexport interface QueryComponents {\r\n readonly apiKey: string;\r\n readonly namespace: string;\r\n readonly selectedField: string;\r\n readonly clientFilters: ClientSideFilter[];\r\n readonly serverFilters: ServerSideFilter[];\r\n readonly limit: number;\r\n}\r\n\r\nexport interface TextValue {\r\n readonly text: string;\r\n readonly value: string;\r\n}\r\n\r\nexport interface QueryOptions {\r\n method: string;\r\n url: string;\r\n namespaces: string[];\r\n limit: number;\r\n forceAccessTokenRefresh?: boolean;\r\n responseFilters: ServerSideFilter[];\r\n}\r\n\r\nexport interface AccessToken {\r\n readonly access_token: string;\r\n readonly expires_at: number;\r\n readonly refresh_token: string;\r\n expires_offset?: number;\r\n}\r\n\r\nexport interface GrafanaTarget {\r\n /** @deprecated */\r\n filterSegments?: any[];\r\n /** @deprecated */\r\n aggregation?: string;\r\n\r\n aggregationAlias?: string;\r\n aggregationField?: string;\r\n aggregationRequiresTarget?: boolean;\r\n aggregationType?: string;\r\n apiEndpoints: string;\r\n fieldSelectors: FieldSelector[];\r\n format: string;\r\n groupAlias?: string;\r\n groupBy?: string;\r\n limit?: string;\r\n namespace: string;\r\n namespaces: string[]; // splitted and resolved namespace attribute\r\n queryType: string;\r\n refId: string;\r\n\r\n version: number;\r\n clientSideFilters: ClientSideFilter[];\r\n serverSideFilters: ServerSideFilter[];\r\n}\r\n\r\nexport interface GrafanaUiSegment {\r\n value: string;\r\n}\r\n\r\nexport interface GrafanaTimeSeries {\r\n target: string; // time series name\r\n datapoints: unknown[];\r\n}\r\n\r\nexport interface GrafanaTable {\r\n columns: unknown[];\r\n rows: unknown[][];\r\n type: string;\r\n}\r\n","import _ from 'lodash';\r\nimport {\r\n AccessToken,\r\n QueryOptions,\r\n ServerSideFilter,\r\n ServerSideFilterType,\r\n} from '../types';\r\n\r\n/**\r\n * Class which encapsulates the query mechanism against the Sensu Go API.\r\n */\r\nexport default class Sensu {\r\n /**\r\n * The max duration a token is valid in seconds.\r\n */\r\n static readonly tokenTimeout_s = 600;\r\n /**\r\n * This duration will be susbtracted of the `tokenTimeout_s` duration.\r\n */\r\n static readonly tokenExpireOffset_s = 60;\r\n /**\r\n * The API's base url.\r\n */\r\n static readonly apiBaseUrl = '/api/core/v2';\r\n\r\n /**\r\n * The data source route used for API key authentication. See also the plugin.json file.\r\n */\r\n static readonly apiKeyUrlPrefix = '/api_key_auth';\r\n\r\n /**\r\n * Executes a query against the given datasource. An access token will be gathered if needed.\r\n * For each namespace specified in the passed options, a separate query will be executed.\r\n *\r\n * @param datasource the datasource to use\r\n * @param options the options specifying the query's request\r\n */\r\n static query(datasource: any, options: QueryOptions) {\r\n const {namespaces} = options;\r\n\r\n if (_.isEmpty(namespaces) && options.url === '/namespaces') {\r\n namespaces.push(''); // dummy element to execute a query\r\n }\r\n\r\n const queries = _.map(namespaces, namespace =>\r\n this._doQuery(datasource, options, namespace)\r\n );\r\n\r\n return Promise.all(queries).then(data => {\r\n return _.flatten(data);\r\n });\r\n }\r\n\r\n /**\r\n * Executes a query against the given datasource. An access token will be gathered if needed.\r\n *\r\n * @param datasource the datasource to use\r\n * @param options the options specifying the query's request\r\n * @param namespace the namespace used by this query\r\n */\r\n static _doQuery(\r\n datasource: any,\r\n options: QueryOptions,\r\n namespace: string,\r\n retryCount = 0\r\n ) {\r\n const {method, url} = options;\r\n\r\n let fullUrl: string;\r\n if (url === '/namespaces') {\r\n fullUrl = Sensu.apiBaseUrl + '/namespaces';\r\n } else {\r\n const namespacePath = namespace === '*' ? '' : '/namespaces/' + namespace;\r\n fullUrl = Sensu.apiBaseUrl + namespacePath + url;\r\n }\r\n\r\n const requestParameters = this._getParameters(options);\r\n\r\n return Sensu._authenticate(datasource)\r\n .then(() => Sensu._request(datasource, method, fullUrl, requestParameters))\r\n .then(result => result.data)\r\n .catch(error => {\r\n // we'll retry once\r\n if (retryCount >= 1) {\r\n throw error;\r\n }\r\n\r\n // delete token details in order to refresh the token in case of basic auth\r\n delete datasource.instanceSettings.tokens;\r\n\r\n // the retry is not immediatly done in order to prevent some race conditions\r\n const delay = Math.floor(1000 + Math.random() * 1000);\r\n\r\n return new Promise(resolve => setTimeout(resolve, delay)).then(() =>\r\n this._doQuery(datasource, options, namespace, retryCount + 1)\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Checks whether an access token exist. If none exists or it is expired a new one will be fetched.\r\n * In case an api key auth is used, this method will never fetch a token.\r\n *\r\n * @param datasource the datasource to use\r\n */\r\n static _authenticate(datasource: any) {\r\n const {tokens} = datasource.instanceSettings;\r\n const useApiKey = _.get(datasource.instanceSettings, 'jsonData.useApiKey', false);\r\n\r\n // never aquire token in case of api key auth\r\n if (useApiKey) {\r\n return Promise.resolve(true);\r\n }\r\n\r\n const acquireToken = !tokens || Sensu._isTokenExpired(tokens);\r\n if (acquireToken) {\r\n return Sensu._acquireAccessToken(datasource);\r\n } else {\r\n return Promise.resolve(true);\r\n }\r\n }\r\n\r\n /**\r\n * Returns whether the given token is already expired.\r\n *\r\n * @param token the token to check\r\n */\r\n static _isTokenExpired(token: AccessToken) {\r\n const timestampNow: number = Math.floor(Date.now() / 1000);\r\n let expiresAt: number = token.expires_at;\r\n\r\n if (token.expires_offset) {\r\n expiresAt = expiresAt - token.expires_offset - Sensu.tokenExpireOffset_s;\r\n }\r\n\r\n return expiresAt < timestampNow;\r\n }\r\n\r\n /**\r\n * Fetches and stores an access token.\r\n *\r\n * @param datasource the datasource to use\r\n */\r\n static _acquireAccessToken(datasource: any) {\r\n return Sensu._request(datasource, 'GET', '/auth').then(result => {\r\n const tokens: AccessToken = result.data;\r\n\r\n const timestampNow: number = Math.floor(Date.now() / 1000);\r\n const expiresOffset: number =\r\n tokens.expires_at - timestampNow - Sensu.tokenTimeout_s;\r\n\r\n tokens.expires_offset = expiresOffset;\r\n\r\n datasource.instanceSettings.tokens = tokens;\r\n });\r\n }\r\n\r\n /**\r\n * Executes a (potential authenticated) request against the specified url using the given datasource (server) and HTTP method.\r\n *\r\n * @param datasource the datasource to use\r\n * @param method the method of the HTTP request (GET, POST, ...)\r\n * @param url the url to send the request to\r\n */\r\n static _request(\r\n datasource: any,\r\n method: string,\r\n url: string,\r\n requestParameters: Record = {}\r\n ) {\r\n const useApiKey = _.get(datasource.instanceSettings, 'jsonData.useApiKey', false);\r\n\r\n const req: any = {\r\n method: method,\r\n };\r\n\r\n req.headers = {\r\n 'Content-Type': 'application/json',\r\n };\r\n\r\n if (useApiKey) {\r\n // authentication via api key using authentication route\r\n req.url = datasource.url + Sensu.apiKeyUrlPrefix + url;\r\n } else {\r\n // authentication via bearer token\r\n req.url = datasource.url + url;\r\n\r\n if (_.has(datasource.instanceSettings, 'tokens')) {\r\n req.headers.Authorization =\r\n 'Bearer ' + datasource.instanceSettings.tokens.access_token;\r\n }\r\n }\r\n\r\n req.params = requestParameters;\r\n\r\n return datasource.backendSrv\r\n .datasourceRequest(req)\r\n .then(Sensu._handleRequestResult, Sensu._handleRequestError);\r\n }\r\n\r\n /**\r\n * Is called when the request is ending successfully. In case of a 401 error, the request is not throwing an error but returning no result object.\r\n *\r\n * @param result the request's result object\r\n */\r\n static _handleRequestResult(result: any) {\r\n if (result) {\r\n return result;\r\n } else {\r\n throw {\r\n message: 'Credentials Invalid: Could not logged in using credentials',\r\n data: 'access_error',\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Is called if the request's promise is getting an error.\r\n *\r\n * @param err the request's error object\r\n */\r\n static _handleRequestError(err: any) {\r\n if (err.status !== 0 || err.status >= 300) {\r\n if (err.data && err.data.message) {\r\n throw {\r\n message: 'Sensu Go Error: ' + err.data.message,\r\n data: err.data,\r\n config: err.config,\r\n };\r\n } else {\r\n throw {\r\n message: 'Network Error: ' + err.statusText + '(' + err.status + ')',\r\n data: err.data,\r\n config: err.config,\r\n };\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Returns an object which represents the request parameters that should be used\r\n * by the request representing the data source query.\r\n *\r\n * @param options the query options to use as basis for the parameters\r\n */\r\n static _getParameters(options: QueryOptions) {\r\n const {limit, responseFilters} = options;\r\n const result: any = {};\r\n\r\n // build the response filter parameters\r\n const fieldSelector = this._buildFilterParameter(\r\n responseFilters.filter(filter => filter.type === ServerSideFilterType.FIELD)\r\n );\r\n if (fieldSelector !== '') {\r\n result.fieldSelector = fieldSelector;\r\n }\r\n\r\n const labelSelector = this._buildFilterParameter(\r\n responseFilters.filter(filter => filter.type === ServerSideFilterType.LABEL)\r\n );\r\n if (labelSelector !== '') {\r\n result.labelSelector = labelSelector;\r\n }\r\n\r\n // build the limit option\r\n if (limit > 0) {\r\n result.limit = limit;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Creates the parameter value for a response (server-side) filter. More details regarding its\r\n * format can be found in the documentation: https://docs.sensu.io/sensu-go/latest/api/#response-filtering\r\n *\r\n * @param filters the filters which will be included in the filter parameter\r\n */\r\n static _buildFilterParameter(filters: ServerSideFilter[]) {\r\n return _(filters)\r\n .map(filter => filter.key + ' ' + filter.matcher + ' ' + filter.value)\r\n .join(' && ');\r\n }\r\n}\r\n","import {AggregationType, ApiEndpoint, TextValue} from './types';\r\n\r\n/**\r\n * The default limit.\r\n */\r\nexport const DEFAULT_LIMIT = 100;\r\n\r\n/**\r\n * The default limit for aggregation queries.\r\n */\r\nexport const DEFAULT_AGGREGATION_LIMIT = 0;\r\n\r\n/**\r\n * Supported aggregation functions.\r\n */\r\nexport const AGGREGATION_TYPES = [\r\n {\r\n value: 'count',\r\n text: 'Count',\r\n requiresTarget: false,\r\n },\r\n {\r\n value: 'sum',\r\n text: 'Sum',\r\n requiresTarget: true,\r\n },\r\n];\r\n\r\n/**\r\n * Sensu API endpoints.\r\n */\r\nexport const API_ENDPOINTS = [\r\n {\r\n text: 'Entity API',\r\n value: 'entity',\r\n url: '/entities',\r\n fieldSelectors: [\r\n // defined by the response filter feature (see: https://docs.sensu.io/sensu-go/latest/api/#response-filtering)\r\n 'entity.name',\r\n 'entity.namespace',\r\n 'entity.deregister',\r\n 'entity.entity_class',\r\n 'entity.subscriptions',\r\n ],\r\n },\r\n {\r\n text: 'Events API',\r\n value: 'events',\r\n url: '/events',\r\n fieldSelectors: [\r\n 'event.is_silenced',\r\n 'event.name',\r\n 'event.namespace',\r\n 'event.check.handlers',\r\n 'event.check.is_silenced',\r\n 'event.check.name',\r\n 'event.check.publish',\r\n 'event.check.round_robin',\r\n 'event.check.runtime_assets',\r\n 'event.check.status',\r\n 'event.check.subscriptions',\r\n 'event.entity.deregister',\r\n 'event.entity.entity_class',\r\n 'event.entity.name',\r\n 'event.entity.subscriptions',\r\n ],\r\n },\r\n {\r\n text: 'Namespaces API',\r\n value: 'namespaces',\r\n url: '/namespaces',\r\n fieldSelectors: ['namespace.name'],\r\n },\r\n];\r\n\r\n/**\r\n * Supported query types.\r\n */\r\nexport const QUERY_TYPES = [\r\n {\r\n value: 'field',\r\n text: 'Field Selection',\r\n },\r\n {\r\n value: 'aggregation',\r\n text: 'Aggregation',\r\n },\r\n];\r\n\r\n/**\r\n * Supported result data formats.\r\n */\r\nexport const FORMATS = [\r\n {\r\n value: 'table',\r\n text: 'Table',\r\n },\r\n {\r\n value: 'table-v',\r\n text: 'Table (Vertical)',\r\n },\r\n {\r\n value: 'series',\r\n text: 'Time Series',\r\n },\r\n];\r\n\r\n/**\r\n * Properties containing a timestamp and should converted (from seconds to miliseconds).\r\n */\r\nexport const TIME_PROPERTIES: string[] = [\r\n 'timestamp',\r\n 'check.executed',\r\n 'check.issued',\r\n 'check.last_ok',\r\n 'entity.last_seen',\r\n 'last_seen',\r\n];\r\n","import _ from 'lodash';\r\n\r\n/**\r\n * Returns whether the given data value matchs the filter specified by the filter value in combination with the given operator.\r\n * @param filterValue the filter value\r\n * @param operator the operator used for comparision\r\n * @param dataValue the data value to test\r\n */\r\nexport const matchs = (\r\n filterValue: string,\r\n operator: string,\r\n dataValue: number | string | boolean\r\n): boolean => {\r\n if (operator === '==') {\r\n return filterValue == dataValue;\r\n }\r\n if (operator === '!=') {\r\n return filterValue != dataValue;\r\n }\r\n if (operator === '=~' || operator === '!~') {\r\n return _matchRegExp(filterValue, operator, dataValue);\r\n }\r\n if (operator === '<' || operator === '>') {\r\n return _matchNumber(filterValue, operator, dataValue);\r\n }\r\n\r\n throw 'Unsupported operator \"' + operator + '\"';\r\n};\r\n\r\n/**\r\n * Matching using '>' and '<' operators.\r\n */\r\nconst _matchNumber = (filterValue: string, operator: string, dataValue: any) => {\r\n const filterNumber = Number(filterValue);\r\n\r\n if (!_.isFinite(filterNumber)) {\r\n console.warn(\r\n 'The specified filter value (' +\r\n filterValue +\r\n ') is not compatible to filter on a numeric attribute.'\r\n );\r\n return false;\r\n }\r\n\r\n if (operator === '<') {\r\n return dataValue < filterNumber;\r\n } else {\r\n return dataValue > filterNumber;\r\n }\r\n};\r\n\r\n/**\r\n * Matching using regular expressions.\r\n */\r\nconst _matchRegExp = (filterValue: string, operator: string, dataValue: any) => {\r\n const regex: RegExp = _stringToRegex(filterValue);\r\n\r\n if (operator === '=~') {\r\n return regex.test(dataValue);\r\n } else {\r\n return !regex.test(dataValue);\r\n }\r\n};\r\n\r\n/**\r\n * Converts a string to a RegExp instance and keeps optional modifiers.\r\n * @param value the string to convert\r\n */\r\nconst _stringToRegex = (value: string) => {\r\n const regex = value.match(/\\/(.*)\\/(\\w*)/);\r\n if (regex) {\r\n return new RegExp(regex[1], regex[2]);\r\n } else {\r\n return new RegExp(value);\r\n }\r\n};\r\n\r\nexport default {matchs};\r\n","import _ from 'lodash';\r\nimport {DEFAULT_LIMIT, DEFAULT_AGGREGATION_LIMIT} from '../constants';\r\n\r\nimport {\r\n QueryComponents,\r\n GrafanaTarget,\r\n ServerSideFilterType,\r\n ServerSideFilter,\r\n ClientSideFilter,\r\n} from '../types';\r\n\r\n/** RegEx matching a in-browser filter of the WHERE-clause. */\r\nconst CLIENT_FILTER_REG_EXP = '([^\\\\s:=!]+)\\\\s*(==|=~|!=|>|<|!~|=)\\\\s*(\\\\S+)';\r\n\r\n/** RegExp of a filter key or value of the server-side filter. */\r\nconst SERVER_FILTER_VALUE_REG_EXP = '\\\\[[^[]+\\\\]|\"[^\"]+\"|\\\\S+';\r\n\r\n/** RegEx matching a response filter (server-side) of the WHERE-clause. */\r\nconst SERVER_FILTER_REG_EXP =\r\n '(fieldSelector|labelSelector):(' +\r\n SERVER_FILTER_VALUE_REG_EXP +\r\n ')\\\\s*(==|!=|IN|NOTIN|MATCHES)\\\\s*(' +\r\n SERVER_FILTER_VALUE_REG_EXP +\r\n ')';\r\n\r\n/** RegEx representing a single element of the WHERE-clause. */\r\nconst QUERY_SINGLE_FILTER_REG_EXP =\r\n '(' + SERVER_FILTER_REG_EXP + '|' + CLIENT_FILTER_REG_EXP + ')';\r\n\r\n/** RegEx representing the whole query string. */\r\nconst QUERY_FULL_REG_EXP =\r\n '^\\\\s*QUERY\\\\s+API\\\\s+(entity|events|namespaces)\\\\s+(IN\\\\s+NAMESPACE\\\\s+(\\\\S+)\\\\s+)?SELECT\\\\s+(\\\\S+)(\\\\s+WHERE\\\\s+(' +\r\n QUERY_SINGLE_FILTER_REG_EXP +\r\n '(\\\\s+AND\\\\s+' +\r\n QUERY_SINGLE_FILTER_REG_EXP +\r\n ')*))?(\\\\s+LIMIT\\\\s+(\\\\d+))?\\\\s*$';\r\n\r\n/**\r\n * Creates a query string based on the target definition.\r\n * @param target the data used by the query\r\n */\r\nexport function targetToQueryString(target: GrafanaTarget): string {\r\n let query: string = 'QUERY API ' + target.apiEndpoints;\r\n\r\n query += _namespace(target);\r\n\r\n if (target.queryType === 'field') {\r\n query += _queryTypeField(target);\r\n } else if (target.queryType === 'aggregation') {\r\n query += _queryTypeAggregation(target);\r\n }\r\n\r\n query += _whereClause(target);\r\n query += _limit(target);\r\n\r\n return query;\r\n}\r\n\r\n/**\r\n * Return the \"select\" statement based on the given target.\r\n * E.g.: SELECT field, another.field AS myField\r\n */\r\nconst _queryTypeField = (target: GrafanaTarget) => {\r\n const fields = _(target.fieldSelectors)\r\n .flatMap(selector => {\r\n if (selector.alias) {\r\n return selector.getPath() + ' AS ' + selector.alias;\r\n } else {\r\n return selector.getPath();\r\n }\r\n })\r\n .join(', ');\r\n\r\n return ' SELECT ' + fields;\r\n};\r\n\r\n/**\r\n * Return the \"aggregation\" statement based on the given target.\r\n * E.g.: AGGREGATE sum ON field\r\n */\r\nconst _queryTypeAggregation = (target: GrafanaTarget) => {\r\n let query: string = ' AGGREGATE ' + target.aggregationType;\r\n\r\n if (target.aggregationRequiresTarget) {\r\n query += ' ON ' + target.aggregationField;\r\n }\r\n\r\n return query;\r\n};\r\n\r\n/**\r\n * Return the namespace statement based on the given target.\r\n * E.g.: IN NAMESPACE default\r\n */\r\nconst _namespace = (target: GrafanaTarget) => {\r\n if (target.namespace === 'default') {\r\n return '';\r\n } else {\r\n return ' IN NAMESPACE ' + target.namespace;\r\n }\r\n};\r\n\r\n/**\r\n * Return the where clause based on the given target.\r\n * E.g.: WHERE field=value AND status>0\r\n */\r\nconst _whereClause = (target: GrafanaTarget) => {\r\n const {clientSideFilters, serverSideFilters} = target;\r\n\r\n const serverFilters = _(serverSideFilters)\r\n .map(\r\n filter =>\r\n (filter.type == ServerSideFilterType.FIELD ? 'fieldSelector' : 'labelSelector') +\r\n ':' +\r\n filter.key +\r\n ' ' +\r\n filter.matcher.toUpperCase() +\r\n ' ' +\r\n filter.value\r\n )\r\n .value();\r\n\r\n const clientFilters = _(clientSideFilters)\r\n .map(filter => filter.key + ' ' + filter.matcher + ' ' + filter.value)\r\n .value();\r\n\r\n const whereClause = _([serverFilters, clientFilters])\r\n .flatten()\r\n .join(' AND ');\r\n\r\n if (whereClause) {\r\n return ' WHERE ' + whereClause;\r\n } else {\r\n return '';\r\n }\r\n};\r\n\r\n/**\r\n * Return the limit statement based on the given target. If no limit is specified the default limit will be used.\r\n * E.g.: LIMIT 100\r\n */\r\nconst _limit = (target: GrafanaTarget) => {\r\n let queryLimit: number;\r\n\r\n if (target.limit) {\r\n queryLimit = _.defaultTo(parseInt(target.limit), DEFAULT_LIMIT);\r\n } else {\r\n // Use a special default limit in aggregation queries\r\n if (target.queryType === 'aggregation') {\r\n queryLimit = DEFAULT_AGGREGATION_LIMIT;\r\n } else {\r\n queryLimit = DEFAULT_LIMIT;\r\n }\r\n }\r\n\r\n if (queryLimit > 0) {\r\n return ' LIMIT ' + queryLimit;\r\n } else {\r\n return '';\r\n }\r\n};\r\n\r\nexport const extractQueryComponents = (query: string): QueryComponents | null => {\r\n const queryRegExp = new RegExp(QUERY_FULL_REG_EXP, 'i');\r\n const matchResult = query.match(queryRegExp);\r\n\r\n if (!matchResult) {\r\n return null;\r\n }\r\n\r\n let namespace: string;\r\n if (matchResult[3] !== undefined) {\r\n namespace = matchResult[3];\r\n } else {\r\n namespace = 'default';\r\n }\r\n\r\n const components: QueryComponents = {\r\n apiKey: matchResult[1],\r\n namespace: namespace,\r\n selectedField: matchResult[4],\r\n clientFilters: [],\r\n serverFilters: [],\r\n limit: parseInt(matchResult[25]),\r\n };\r\n\r\n if (matchResult[6] !== undefined) {\r\n const filterRegExp = new RegExp(\r\n SERVER_FILTER_REG_EXP + '|' + CLIENT_FILTER_REG_EXP,\r\n 'gi'\r\n );\r\n\r\n const whereClause: string = matchResult[6];\r\n\r\n let match: RegExpExecArray | null;\r\n while ((match = filterRegExp.exec(whereClause)) !== null) {\r\n const isServerFilter = match[1] !== undefined;\r\n\r\n if (isServerFilter) {\r\n // add response filter\r\n const filter: ServerSideFilter = {\r\n type:\r\n match[1] === 'fieldSelector'\r\n ? ServerSideFilterType.FIELD\r\n : ServerSideFilterType.LABEL,\r\n key: match[2],\r\n matcher: match[3],\r\n value: match[4],\r\n };\r\n\r\n components.serverFilters.push(filter);\r\n } else {\r\n // add in-browser filter\r\n const filter: ClientSideFilter = {\r\n key: match[5],\r\n matcher: match[6] === '=' ? '==' : match[6],\r\n value: match[7],\r\n };\r\n\r\n components.clientFilters.push(filter);\r\n }\r\n }\r\n }\r\n\r\n return components;\r\n};\r\n\r\nexport default {targetToQueryString, extractQueryComponents};\r\n","import {DataPoint, GrafanaTable} from '../types';\r\nimport {TIME_PROPERTIES} from '../constants';\r\nimport _ from 'lodash';\r\nimport moment from 'moment';\r\n\r\n/**\r\n * Transforms the given data into a table representation.\r\n */\r\nconst transform = (dataMatrix: DataPoint[][], vertical: boolean): GrafanaTable => {\r\n const columns = _extractColumns(dataMatrix);\r\n\r\n // create column index mapping\r\n const columnIndexMap = {};\r\n _.each(columns, (column, index) => (columnIndexMap[column.text] = index));\r\n\r\n // generate data rows\r\n const rows: any[][] = _.map(dataMatrix, dataRow => {\r\n const row = _.times(columns.length, _.constant(null));\r\n\r\n _(dataRow)\r\n .map(({name, value}) => {\r\n if (_.isArray(value)) {\r\n return _.map(value, (element, index) => [name + '[' + index + ']', element]);\r\n } else {\r\n return [[name, value]];\r\n }\r\n })\r\n .flatten()\r\n .map(data => {\r\n if (_.isPlainObject(data[1]) || _.isArray(data[1])) {\r\n data[1] = JSON.stringify(data[1]);\r\n }\r\n return data;\r\n })\r\n .each(([columnName, value]) => {\r\n row[columnIndexMap[columnName]] = value;\r\n });\r\n\r\n return row;\r\n });\r\n\r\n if (vertical) {\r\n return _asVerticalTable(columns, rows);\r\n }\r\n\r\n // create grafana result object\r\n return {\r\n columns,\r\n rows,\r\n type: 'table',\r\n };\r\n};\r\n\r\nconst _asVerticalTable = (dataColumns, dataRows: any[][]): GrafanaTable => {\r\n // fixed table headers\r\n const columns = [\r\n {\r\n text: 'Attribute',\r\n },\r\n {\r\n text: 'Value',\r\n },\r\n ];\r\n\r\n const rows = _(dataRows)\r\n .flatten()\r\n .map((value, idx) => [dataColumns[idx].text, value])\r\n .value();\r\n\r\n // this is done because users cannot define a time formatting based on rows\r\n _convertTimestamps(rows);\r\n\r\n return {\r\n columns,\r\n rows,\r\n type: 'table',\r\n };\r\n};\r\n\r\nconst _convertTimestamps = (rows: any[][]) => {\r\n _.each(rows, row => {\r\n const attribute = row[0];\r\n const value = row[1];\r\n\r\n for (let index = 0; index < TIME_PROPERTIES.length; index++) {\r\n if (attribute === TIME_PROPERTIES[index]) {\r\n const time = _.defaultTo(value, -1);\r\n if (time > 0) {\r\n row[1] = moment(time).format('YYYY-MM-DD HH:mm:ss');\r\n }\r\n break;\r\n }\r\n }\r\n });\r\n};\r\n\r\n/**\r\n * Returns an array of columns which exist in the given data matrix. Each data point attribute will be\r\n * represents by a column.\r\n *\r\n * @param dataMatrix the data basis\r\n */\r\nconst _extractColumns = (dataMatrix: DataPoint[][]) => {\r\n const isArrayMarker = {};\r\n\r\n // extract existing columns\r\n return _(dataMatrix)\r\n .flatten()\r\n .map(({name, value}) => {\r\n if (_.isArray(value)) {\r\n isArrayMarker[name] = true;\r\n return _.times(value.length, index => name + '[' + index + ']');\r\n } else {\r\n if (_.isNil(value) && _.get(isArrayMarker, name, false)) {\r\n return [];\r\n }\r\n return [name];\r\n }\r\n })\r\n .flatten()\r\n .uniq()\r\n .map(name => {\r\n return {\r\n text: name,\r\n };\r\n })\r\n .value();\r\n};\r\n\r\nexport default transform;\r\n","import {DataPoint, GrafanaTable, GrafanaTimeSeries} from '../types';\r\nimport table_transform from './table_transformer';\r\nimport timeseries_transform from './timeseries_transformer';\r\n\r\nexport default {\r\n toTable: (dataMatrix: DataPoint[][], vertical: boolean): GrafanaTable => {\r\n return table_transform(dataMatrix, vertical);\r\n },\r\n toTimeSeries: (dataMatrix: DataPoint[][]): GrafanaTimeSeries[] => {\r\n return timeseries_transform(dataMatrix);\r\n },\r\n};\r\n","import {DataPoint, GrafanaTimeSeries} from '../types';\r\nimport _ from 'lodash';\r\n\r\n/**\r\n * Transforms the given data into a time series representation.\r\n */\r\nconst transform = (dataMatrix: DataPoint[][]): GrafanaTimeSeries[] => {\r\n const now: number = Date.now();\r\n\r\n // maps the data to a series - skips all values which are not finite\r\n // - name => series name\r\n // - value => value\r\n return _(dataMatrix)\r\n .flatten()\r\n .filter(data => _.isFinite(data.value))\r\n .map(data => {\r\n return {\r\n target: data.name,\r\n datapoints: [[data.value, now]],\r\n };\r\n })\r\n .value();\r\n};\r\n\r\nexport default transform;\r\n","import _ from 'lodash';\r\nimport {ClientSideFilter, GrafanaTarget} from '../types';\r\n\r\n/** The latest configuration version. */\r\nconst LATEST_VERSION = 2;\r\n\r\n/** Migrates the passed configuration target to the latest version. The passed object will be mutated. */\r\nconst migrate = (target: GrafanaTarget): GrafanaTarget => {\r\n const {version} = target;\r\n\r\n if (version === undefined) {\r\n init(target);\r\n }\r\n if (version === 1) {\r\n toVersion2(target);\r\n }\r\n\r\n return target;\r\n};\r\n\r\n/** Initializes the configuration target. */\r\nconst init = (target: GrafanaTarget) => {\r\n target.version = LATEST_VERSION;\r\n target.clientSideFilters = [];\r\n target.serverSideFilters = [];\r\n};\r\n\r\n/** Migrates the passed configuration target from version 1 to version 2. */\r\nconst toVersion2 = (target: GrafanaTarget) => {\r\n console.log('Migrating data source configuration to version 2.');\r\n\r\n const {filterSegments} = target;\r\n\r\n const filters = _(filterSegments)\r\n .filter(segments => segments.length === 3)\r\n .filter(segments => !_.get(segments[2], 'fake', false))\r\n .map(segments => {\r\n const matcher = segments[1].value === '=' ? '==' : segments[1].value;\r\n\r\n return {\r\n key: segments[0].value,\r\n matcher,\r\n value: segments[2].value,\r\n };\r\n })\r\n .value();\r\n\r\n delete target.filterSegments;\r\n\r\n target.clientSideFilters = filters;\r\n target.serverSideFilters = [];\r\n\r\n target.version = 2;\r\n};\r\n\r\nexport default {\r\n migrate,\r\n};\r\n","import _ from 'lodash';\r\nimport {DataPoint} from '../types';\r\n\r\n/**\r\n * Does a count aggregation. The number of elements in the given data is returned.\r\n *\r\n * @param data the data to aggregate\r\n * @param name the name of the resulting value\r\n */\r\nconst count = (data: any[], name: string): DataPoint[] => {\r\n return [\r\n {\r\n name,\r\n value: data.length,\r\n },\r\n ];\r\n};\r\n\r\n/**\r\n * Does a sum aggregation. The sum of the specified attribute of all elements in the given data is calculated.\r\n *\r\n * @param data the data to aggregate\r\n * @param name the name of the resulting value\r\n * @param targetField the field which should be summed up\r\n */\r\nconst sum = (\r\n data: any[],\r\n name: string,\r\n targetField: string | undefined\r\n): DataPoint[] | null => {\r\n if (!targetField) {\r\n return [];\r\n }\r\n\r\n let sum: number | null = _.sumBy(data, targetField);\r\n\r\n if (!_.isFinite(sum)) {\r\n sum = null;\r\n }\r\n\r\n return [\r\n {\r\n name,\r\n value: sum,\r\n },\r\n ];\r\n};\r\n\r\nexport default {count, sum};\r\n","import _ from 'lodash';\n\nimport sensu from './sensu/sensu';\nimport {\n API_ENDPOINTS,\n DEFAULT_LIMIT,\n DEFAULT_AGGREGATION_LIMIT,\n TIME_PROPERTIES,\n} from './constants';\nimport FieldSelector from './FieldSelector';\nimport FilterUtils from './utils/datasource_filter_util';\nimport QueryUtils from './utils/query_util';\nimport transformer from './transformer';\nimport ConfigMigration from './utils/config_migration_util';\nimport AggregationUtils from './utils/data_aggregation_util';\n\nimport {\n PreparedTarget,\n ColumnMapping,\n DataPoint,\n ClientSideFilter,\n QueryComponents,\n InstanceSettings,\n QueryOptions,\n GrafanaTarget,\n} from './types';\n\nexport default class SensuDatasource {\n url: string;\n\n /** @ngInject */\n constructor(\n public instanceSettings: InstanceSettings,\n public backendSrv,\n private templateSrv\n ) {\n this.url = instanceSettings.url.trim();\n }\n\n /**\n * Preprocces the query targets like resolving template variables.\n */\n prepareQuery = (target: GrafanaTarget, queryOptions) => {\n // resolve API url\n const apiUrl = this._getApiUrl(target);\n // resolve filters\n const clientFilters = _.cloneDeep(target.clientSideFilters);\n const serverFilters = _.cloneDeep(target.serverSideFilters);\n\n const preparedTarget: PreparedTarget = {\n apiUrl,\n clientFilters,\n serverFilters,\n target: _.cloneDeep(target), //ensure modifications are not globally propagated\n };\n\n this._resolveTemplateVariables(preparedTarget, queryOptions);\n\n return preparedTarget;\n };\n\n /**\n * Resolves template variables in the given prepared target.\n */\n _resolveTemplateVariables = (preparedTarget: PreparedTarget, queryOptions) => {\n const {target, clientFilters, serverFilters} = preparedTarget;\n\n // resolve variables in namespaces\n const namespaces: string[] = this.templateSrv\n .replace(target.namespace, queryOptions.scopedVars, 'pipe')\n .split('|');\n\n target.namespaces = namespaces;\n\n // resolve variables in filters\n [clientFilters, serverFilters].forEach(filters =>\n filters.forEach(filter => {\n filter.key = this.templateSrv.replace(filter.key, queryOptions.scopedVars, 'csv');\n filter.value = this.templateSrv.replace(\n filter.value,\n queryOptions.scopedVars,\n 'regex'\n );\n })\n );\n };\n\n /**\n * Returns the url of the API used by the given target.\n */\n _getApiUrl = (target: GrafanaTarget) => {\n const apiEndpoint: any = _.find(API_ENDPOINTS, {value: target.apiEndpoints});\n if (apiEndpoint) {\n return apiEndpoint.url;\n } else {\n return API_ENDPOINTS[0].url;\n }\n };\n\n /**\n * Executes a query.\n */\n query(queryOptions) {\n const queryTargets = _(queryOptions.targets)\n .filter(target => !target.hide)\n .map(ConfigMigration.migrate)\n .map(target => this.prepareQuery(target, queryOptions))\n .value();\n\n // empty result in case there is no query defined\n if (queryTargets.length === 0) {\n return Promise.resolve({data: []});\n }\n\n const queries = queryTargets.map(prepTarget => {\n const {\n apiUrl,\n clientFilters,\n serverFilters,\n target: {queryType, fieldSelectors, namespaces, limit},\n } = prepTarget;\n\n // verify and set correct limit\n let parsedLimit: number = _.defaultTo(parseInt(limit || ''), -1);\n if (parsedLimit < 0) {\n if (queryType === 'aggregation') {\n parsedLimit = DEFAULT_AGGREGATION_LIMIT;\n } else {\n parsedLimit = DEFAULT_LIMIT;\n }\n }\n\n const queryOptions: QueryOptions = {\n method: 'GET',\n url: apiUrl,\n namespaces,\n limit: parsedLimit,\n responseFilters: serverFilters,\n };\n\n return sensu\n .query(this, queryOptions)\n .then(this._timeCorrection)\n .then(data => this._filterData(data, clientFilters))\n .then(data => {\n if (queryType === 'field') {\n return this._queryFieldSelection(data, fieldSelectors);\n } else if (queryType === 'aggregation') {\n return this._queryGroupAndAggregate(data, prepTarget);\n } else {\n return [];\n }\n });\n });\n\n return Promise.all(queries).then((queryResults: any) => {\n if (queryOptions.resultAsPlainArray) {\n // return only values - e.g. for template variables\n const result = _(queryResults)\n .map(result => transformer.toTable(result, false))\n .map(result => result.rows)\n .flatten()\n .flatten()\n .filter()\n .map(value => {\n return {text: value};\n })\n .value();\n\n return result;\n } else {\n const resultDataList: any[] = _.flatMap(queryResults, (queryResult, index) => {\n const {target: {format}} = queryTargets[index];\n\n if (format === 'series') {\n // return time series format\n return transformer.toTimeSeries(queryResult);\n } else {\n const isVertical = format === 'table-v';\n // return table format\n return transformer.toTable(queryResult, isVertical);\n }\n });\n\n return {\n data: resultDataList,\n };\n }\n });\n }\n\n /**\n * Converting the timestamps from seconds to miliseconds because Sensu's timestamp\n * resolution is in seconds but Grafana uses miliseconds.\n */\n _timeCorrection = (data: any) => {\n _.each(data, dataElement => {\n // iterate over all time properties\n _.each(TIME_PROPERTIES, property => {\n // fetch the properties value\n const time = _.get(dataElement, property, -1);\n // in case a time is set, we multiply them by 1000 to get miliseconds.\n // in case the time is 0, we'll remove it, otherwise Grafana will display the epoch's starting times\n if (time > 0) {\n _.set(dataElement, property, time * 1000);\n } else {\n _.unset(dataElement, property);\n }\n });\n });\n return data;\n };\n\n /**\n * This function will group the given data (if specified in the PreparedTarget) and aggregate it accordingly.\n *\n * @param data the data to group and aggregate\n * @param prepTarget the settings for the grouping and aggregation\n */\n _queryGroupAndAggregate = (data: any[], prepTarget: PreparedTarget) => {\n const {\n target: {\n aggregationAlias: alias,\n aggregationType: type,\n format,\n groupBy: groupAttribute,\n },\n } = prepTarget;\n // the name of the result value (the metric name if timeseries format is used, otherwise the column header)\n const name = alias ? alias : type || 'value';\n\n if (!groupAttribute) {\n // just aggregate without grouping\n const aggregationResult = this._queryAggregation(data, name, prepTarget);\n return [aggregationResult];\n } else {\n // first group the data..\n const groups = _.groupBy(data, groupAttribute);\n\n // ..then aggregate the individual groups\n const groupResult = _(groups)\n .map((dataGroup, groupKey) =>\n this._queryAggregation(dataGroup, groupKey, prepTarget)\n )\n .value();\n\n if ((format === 'table' || format === 'table-v') && groupResult) {\n const {groupAlias} = prepTarget.target;\n // we transform the groups into multiple columns in case the table format is used\n return this._mergeTableAggregation(\n groupResult,\n groupAlias || groupAttribute,\n name\n );\n } else {\n return groupResult;\n }\n }\n };\n\n /**\n * We merge the seperate aggregation result into a single one, thus we get a nicer visualization\n * in the table panel, where the group-attribute and value have their own column.\n */\n _mergeTableAggregation = (\n groupData: (DataPoint[] | null)[],\n groupByAttribute: string,\n alias: string\n ) => {\n return _(groupData)\n .map(group => {\n if (!group || group.length == 0) {\n return null;\n }\n const point: DataPoint = group[0];\n return [\n {\n name: groupByAttribute,\n value: point.name,\n },\n {\n name: alias,\n value: point.value,\n },\n ];\n })\n .filter() // null values\n .value();\n };\n\n /**\n * Process the data if the query type is 'aggregation'.\n */\n _queryAggregation = (data: any[], name: string, prepTarget: PreparedTarget) => {\n const {aggregationType: type} = prepTarget.target;\n\n if (type === 'count') {\n return AggregationUtils.count(data, name);\n } else if (type === 'sum') {\n const {aggregationField} = prepTarget.target;\n return AggregationUtils.sum(data, name, aggregationField);\n } else {\n throw new Error('The aggreation type \"' + type + '\" is not supported.');\n }\n };\n\n /**\n * Process the data if the query type is 'field'.\n */\n _queryFieldSelection = (data: any, fieldSelectors: FieldSelector[]) => {\n const columnMappings: ColumnMapping[] = this._extractColumnMappings(\n data,\n fieldSelectors\n );\n\n const resultData = _.map(data, dataElement => {\n // extract selected data\n return _.map(columnMappings, mapping => {\n const value: any = _.get(dataElement, mapping.path);\n\n return {\n name: mapping.alias,\n value: value,\n };\n });\n });\n\n return resultData;\n };\n\n /**\n * Creates a column mapping - which object attribute/path is related to which column.\n */\n _extractColumnMappings = (data: any, fieldSelectors: FieldSelector[]) => {\n const result: ColumnMapping[] = _.flatMap(fieldSelectors, selector => {\n const paths = _(data)\n .map(dataElement => this.resolvePaths(selector, dataElement))\n .flatMap()\n .uniq()\n .value();\n\n if (selector.alias) {\n if (paths.length > 1) {\n // use the alias in combination with an index as column name\n return _.map(paths, (path, index) => {\n return {\n path: path,\n alias: selector.alias + '.' + index,\n };\n });\n } else {\n // use the alias instead the path as column name\n return _.map(paths, path => {\n return {\n path: path,\n alias: selector.alias,\n };\n });\n }\n } else {\n // use the path itself as column name\n return _.map(paths, path => {\n return {\n path: path,\n alias: path,\n };\n });\n }\n });\n\n return result;\n };\n\n /**\n * Returns a filtered representation of the given data.\n */\n _filterData = (data: any, filters: ClientSideFilter[]) => {\n return _.filter(data, dataElement =>\n _.every(filters, filter => this._matches(dataElement, filter))\n );\n };\n\n /**\n * Returns whether the given element matches the given filter.\n */\n _matches = (element: any, filter: ClientSideFilter) => {\n const filterKey: string = filter.key;\n const matcher: string = filter.matcher;\n const filterValue: string = filter.value;\n\n const elementValue: any = _.get(element, filterKey);\n\n return FilterUtils.matchs(filterValue, matcher, elementValue);\n };\n\n /**\n * Resolves all existing paths of the specified selector based on the given data.\n * Example: if the selector is '*' all possible attibutes (including nested) will be returned.\n */\n resolvePaths = (selector: any, data: any) => {\n let selection: any = data;\n let lastSelector = '';\n let basePath = '';\n\n for (let i = 0; i < selector.fieldSegments.length; i++) {\n const segment: any = selector.fieldSegments[i];\n lastSelector = segment.value;\n\n if (lastSelector !== '*') {\n if (basePath === '') {\n basePath = lastSelector;\n } else {\n basePath = basePath + '.' + lastSelector;\n }\n selection = _.get(selection, lastSelector);\n }\n }\n\n if (lastSelector === '*') {\n const paths = this._deepResolve(selection);\n if (basePath === '') {\n return paths;\n } else {\n return _.map(paths, path => basePath + '.' + path);\n }\n } else {\n return [basePath];\n }\n };\n\n _deepResolve = data => {\n const keys: string[] = Object.keys(data);\n\n return _.flatMap(keys, key => {\n if (_.isPlainObject(data[key])) {\n return _.map(this._deepResolve(data[key]), nestedKeys => {\n return key + '.' + nestedKeys;\n });\n } else {\n return key;\n }\n });\n };\n\n /**\n * Executes a query based on the given query command which is a string representation of it.\n */\n metricFindQuery(query: string) {\n return this._query(query);\n }\n\n /**\n * Executes the given query command.\n */\n _query = (query: string) => {\n const queryComponents = QueryUtils.extractQueryComponents(query);\n\n if (queryComponents === null) {\n return Promise.resolve([]);\n }\n const options: any = this._transformQueryComponentsToQueryOptions(queryComponents);\n options.resultAsPlainArray = true;\n\n return this.query(options);\n };\n\n /**\n * Transforms the given query components into an options object which can be used by the `query(..)` function.\n */\n _transformQueryComponentsToQueryOptions = (queryComponents: QueryComponents) => {\n const {\n apiKey,\n selectedField,\n clientFilters,\n serverFilters,\n namespace,\n limit,\n } = queryComponents;\n\n const options = {\n targets: [\n {\n apiEndpoints: apiKey,\n queryType: 'field',\n namespace: namespace,\n limit: _.isNaN(limit) ? null : new String(limit),\n fieldSelectors: [\n {\n fieldSegments: [\n {\n value: selectedField,\n },\n ],\n },\n ],\n format: 'table',\n clientSideFilters: clientFilters,\n serverSideFilters: serverFilters,\n version: 2,\n },\n ],\n };\n\n return options;\n };\n\n /**\n * Used by the config UI to test a datasource.\n */\n testDatasource() {\n const useApiKey = _.get(this.instanceSettings, 'jsonData.useApiKey', false);\n\n // the /auth/test endpoint is only available for testing basic auth credentials\n const testUrl = useApiKey ? '/api/core/v2/namespaces' : '/auth/test';\n\n return sensu\n ._request(this, 'GET', testUrl)\n .then(() => {\n return {\n status: 'success',\n message: 'Successfully connected against the Sensu Go API',\n };\n })\n .catch(error => {\n if (useApiKey && error.data === 'access_error') {\n return {\n status: 'error',\n message: 'API Key Invalid: Could not logged in using API key',\n };\n }\n return {status: 'error', message: error.message};\n });\n }\n}\n","import _ from 'lodash';\r\nimport {SensuQueryCtrl} from './query_ctrl';\r\n\r\n/**\r\n * Helper class for building field selectors.\r\n * This class should be refactored => no segments should be in `target` but directly in the query controller.\r\n */\r\nexport default class FieldSelector {\r\n fieldSegments: any[];\r\n\r\n fieldType: string;\r\n\r\n attributePath: string;\r\n\r\n alias: string;\r\n\r\n /**\r\n * Restores the segments based on the given parameters.\r\n */\r\n static restore = (ctrl: SensuQueryCtrl, segments: FieldSelector): FieldSelector => {\r\n const path = _(segments.fieldSegments)\r\n .map(segment => segment.value)\r\n .join('.');\r\n\r\n const selector: FieldSelector = new FieldSelector(ctrl, path);\r\n\r\n selector.alias = segments.alias;\r\n\r\n return selector;\r\n };\r\n\r\n constructor(ctrl: SensuQueryCtrl, initPath: string) {\r\n this.fieldSegments = _.map(initPath.split('.'), path =>\r\n ctrl.uiSegmentSrv.newKey(path)\r\n );\r\n this.refresh(ctrl);\r\n }\r\n\r\n /**\r\n * Refreshes the selectors UI elements - if a segment changes its value.\r\n */\r\n refresh = (ctrl: SensuQueryCtrl): void => {\r\n if (!ctrl.dataPreview || ctrl.dataPreview.length <= 0) {\r\n return;\r\n }\r\n let selection = ctrl.dataPreview[0];\r\n\r\n for (let i = 0; i < this.fieldSegments.length; i++) {\r\n const segment: any = this.fieldSegments[i];\r\n const value: string = segment.value;\r\n\r\n if (selection) {\r\n selection = _.get(selection, value);\r\n }\r\n\r\n if (value === '*') {\r\n this.fieldSegments = this.fieldSegments.slice(0, i + 1);\r\n }\r\n }\r\n\r\n if (selection === undefined) {\r\n this.fieldType = 'undefined';\r\n } else if (_.isPlainObject(selection)) {\r\n this.fieldSegments.push(ctrl.uiSegmentSrv.newKey('*'));\r\n this.fieldType = 'object';\r\n } else if (_.isArray(selection)) {\r\n this.fieldType = 'array';\r\n } else if (typeof selection === 'number') {\r\n this.fieldType = 'number';\r\n } else {\r\n this.fieldType = 'string';\r\n }\r\n\r\n this.attributePath = this.getPath();\r\n };\r\n\r\n /**\r\n * Returns the current attribute path of this selector.\r\n */\r\n getPath = (): string => {\r\n return _(this.fieldSegments)\r\n .map(segment => segment.value)\r\n .join('.');\r\n };\r\n}\r\n","import appEvents from 'grafana/app/core/app_events';\nimport {QueryCtrl} from 'grafana/app/plugins/sdk';\nimport _ from 'lodash';\n\nimport {\n ApiEndpoint,\n AggregationType,\n TextValue,\n GrafanaTarget,\n ClientSideFilter,\n ServerSideFilter,\n ServerSideFilterType,\n} from './types';\n\nimport FieldSelector from './FieldSelector';\nimport {AGGREGATION_TYPES, API_ENDPOINTS, QUERY_TYPES, FORMATS} from './constants';\nimport {targetToQueryString} from './utils/query_util';\nimport Sensu from './sensu/sensu';\nimport ConfigMigration from './utils/config_migration_util';\n\nexport class SensuQueryCtrl extends QueryCtrl {\n static templateUrl = 'partials/query.editor.html';\n\n // Will be stored by Grafana\n target: GrafanaTarget;\n\n // Constants\n readonly aggregationTypes: AggregationType[] = AGGREGATION_TYPES;\n readonly queryTypes: TextValue[] = QUERY_TYPES;\n readonly formats: TextValue[] = FORMATS;\n\n segmentAggregationTarget: any;\n dataPreview: any = {};\n dataPreviewBuffer: any[] = [];\n\n apiEndpoints: ApiEndpoint[] = API_ENDPOINTS; // used in the partial\n addFieldSegment: any;\n namespaceSegment: any;\n groupBySegment: any;\n\n clientFilterSegments: any[] = [];\n serverFilterSegments: any[] = [];\n\n /** @ngInject **/\n constructor($scope, $injector, private $q, public uiSegmentSrv, private templateSrv) {\n super($scope, $injector);\n\n // Migrate existing configurations to the latest model version\n ConfigMigration.migrate(this.target);\n\n const {clientSideFilters, serverSideFilters} = this.target;\n\n // restore client filter segments\n _(clientSideFilters)\n .map(this._createClientFilterSegments)\n .each(segmentArray => this.clientFilterSegments.push(segmentArray));\n\n this.clientFilterSegments.push([this.uiSegmentSrv.newPlusButton()]);\n\n //restore server filter segments\n _(serverSideFilters)\n .map(this._createServerFilterSegments)\n .each(segmentArray => this.serverFilterSegments.push(segmentArray));\n\n this.serverFilterSegments.push([this.uiSegmentSrv.newPlusButton()]);\n\n // create field selectors\n if (this.target.fieldSelectors === undefined) {\n this.target.fieldSelectors = [new FieldSelector(this, '*')];\n } else {\n this.target.fieldSelectors = _.map(this.target.fieldSelectors, selector =>\n FieldSelector.restore(this, selector)\n );\n }\n\n if (this.target.apiEndpoints === undefined) {\n this.target.apiEndpoints = API_ENDPOINTS[0].value;\n }\n\n if (this.target.queryType === undefined) {\n this.target.queryType = this.queryTypes[0].value;\n }\n\n if (this.target.format === undefined) {\n this.target.format = this.formats[0].value;\n }\n\n this.addFieldSegment = this.uiSegmentSrv.newPlusButton();\n\n if (this.target.aggregation !== undefined) {\n delete this.target.aggregation;\n }\n\n if (this.target.aggregationType === undefined) {\n this.target.aggregationType = AGGREGATION_TYPES[0].value;\n }\n\n if (this.target.aggregationRequiresTarget === undefined) {\n this.target.aggregationRequiresTarget = AGGREGATION_TYPES[0].requiresTarget;\n }\n\n if (this.target.aggregationField === undefined) {\n this.segmentAggregationTarget = this.uiSegmentSrv.newFake(\n 'select target attribute',\n 'value',\n 'query-segment-value'\n );\n } else {\n this.segmentAggregationTarget = this.uiSegmentSrv.newSegment({\n value: this.target.aggregationField,\n });\n }\n\n if (this.target.groupBy === undefined) {\n this.groupBySegment = this.uiSegmentSrv.newPlusButton();\n } else {\n this.groupBySegment = this.uiSegmentSrv.newSegment({\n value: this.target.groupBy,\n });\n }\n\n if (this.target.namespace === undefined) {\n this.target.namespace = 'default';\n }\n\n this.namespaceSegment = this.uiSegmentSrv.newSegment({value: this.target.namespace});\n\n appEvents.on('ds-request-response', this.onResponseReceived, $scope);\n this.panelCtrl.events.on('refresh', this.onRefresh, $scope);\n this.panelCtrl.events.on('data-received', this.onDataReceived, $scope);\n\n this.panelCtrl.refresh();\n }\n\n /**\n * Creates an array containg segments which represent a in-browser filter. The first segment represents the filter-key,\n * the second the operator and the third the filter-value.\n */\n _createClientFilterSegments = (filter: ClientSideFilter) => {\n const segmentArray = [\n this.uiSegmentSrv.newKey(filter.key),\n this.uiSegmentSrv.newOperator(filter.matcher),\n this.uiSegmentSrv.newKeyValue(filter.value),\n ];\n\n return segmentArray;\n };\n\n /**\n * Creates an array containg segments which represent a response filter (sever-side). The first segment represents the type\n * of the filer (labelSelector or fieldSelector), the second the filter-key, the third the operator and the fourth the filter-value.\n */\n _createServerFilterSegments = (filter: ServerSideFilter) => {\n const type =\n filter.type === ServerSideFilterType.FIELD ? 'fieldSelector' : 'labelSelector';\n\n const segmentArray = [\n this.uiSegmentSrv.newCondition(type),\n this.uiSegmentSrv.newKey(filter.key),\n this.uiSegmentSrv.newOperator(filter.matcher),\n this.uiSegmentSrv.newKeyValue(filter.value),\n ];\n\n return segmentArray;\n };\n\n /**\n * Returns the currently selected aggregation type.\n */\n getCurrentAggregationType = () => {\n return _.find(AGGREGATION_TYPES, {\n value: this.target.aggregationType,\n });\n };\n\n /**\n * Called if the aggregation field changes.\n */\n onAggregationFieldChange = () => {\n this.target.aggregationField = this.segmentAggregationTarget.value;\n this.panelCtrl.refresh();\n };\n\n /**\n * Called if the aggregation type changes.\n */\n onAggregationTypeChange = () => {\n this.target.aggregationRequiresTarget = this.getCurrentAggregationType().requiresTarget;\n this._resetAggregation();\n this.panelCtrl.refresh();\n };\n\n /**\n * Resets the aggregation options.\n */\n _resetAggregation = () => {\n delete this.target.aggregationAlias;\n delete this.target.aggregationField;\n\n this.removeGroupBy();\n\n this.segmentAggregationTarget = this.uiSegmentSrv.newFake(\n 'select target attribute',\n 'value',\n 'query-segment-value'\n );\n };\n\n /**\n * Returns selectable options (all existing keys) for the aggregation field segment.\n */\n getTargetOptions = () => {\n const options: string[] = this.getAllDeepKeys();\n const segments: any[] = _.map(options, option =>\n this.uiSegmentSrv.newSegment({value: option})\n );\n\n return this.$q.when(segments);\n };\n\n /**\n * Returns selectable options (all existing keys) for the group-by segment.\n */\n getGroupByOptions = () => {\n const options: string[] = this.getAllDeepKeys();\n const segments: any[] = _.map(options, option =>\n this.uiSegmentSrv.newSegment({value: option})\n );\n\n return this.$q.when(segments);\n };\n\n /**\n * Called when the user changes the groupBy attribute.\n */\n onGroupByChange = () => {\n this.target.groupBy = this.groupBySegment.value;\n this.panelCtrl.refresh();\n };\n\n /**\n * Removes the groupBy attribute.\n */\n removeGroupBy = () => {\n this.groupBySegment = this.uiSegmentSrv.newPlusButton();\n delete this.target.groupBy;\n delete this.target.groupAlias;\n this.panelCtrl.refresh();\n };\n\n /**\n * Returns selectable options for the namespace segment.\n */\n getNamespaceOptions = () => {\n return Sensu.query(this.datasource, {\n method: 'GET',\n url: '/namespaces',\n namespaces: [],\n limit: 0,\n responseFilters: [],\n })\n .then(result => {\n // get existing namespaces based on query result\n const namespaces = _.map(result, namespace => namespace.name);\n\n // add all option\n namespaces.unshift('*');\n\n // add template variables\n _.each(this.templateSrv.variables, variable =>\n namespaces.unshift('$' + variable.name)\n );\n\n return _.map(namespaces, option => this.uiSegmentSrv.newSegment({value: option}));\n })\n .catch(() => {\n return [];\n });\n };\n\n /**\n * Called of the namespace is changing.\n */\n onNamespaceChange = () => {\n this.target.namespace = this.namespaceSegment.value;\n this.panelCtrl.refresh();\n };\n\n /**\n * Resets the field and filter segments.\n */\n _reset = () => {\n this.target.fieldSelectors = [new FieldSelector(this, '*')];\n this.clientFilterSegments = [[this.uiSegmentSrv.newPlusButton()]];\n this.serverFilterSegments = [[this.uiSegmentSrv.newPlusButton()]];\n this._updateFilterTarget();\n };\n\n /**\n * Called when the api is changing.\n */\n onApiChange = () => {\n this._reset();\n this.panelCtrl.refresh();\n };\n\n /**\n * Called when the query type is changing.\n */\n onQueryTypeChange = () => {\n this._resetAggregation();\n this.panelCtrl.refresh();\n };\n\n /**\n * Removes the filter at the given index.\n */\n removeFilter = (index: number, isServerFilter: boolean) => {\n const targetArray = isServerFilter\n ? this.serverFilterSegments\n : this.clientFilterSegments;\n targetArray.splice(index, 1);\n this._updateFilterTarget();\n this.panelCtrl.refresh();\n };\n\n /**\n * Called when a filter is changing.\n */\n onFilterSegmentUpdate = (segment, parentIndex, index) => {\n if (segment.type === 'plus-button') {\n this._addClientFilterSegment(segment);\n return;\n }\n\n if (index == 2) {\n const segmentValue = segment.value;\n if (/\\/.*\\/\\w*/.test(segmentValue)) {\n this.clientFilterSegments[parentIndex][1] = this.uiSegmentSrv.newOperator('=~');\n }\n }\n\n this._updateFilterTarget();\n this.panelCtrl.refresh();\n };\n\n /**\n * Adds a new in-browser filter.\n */\n _addClientFilterSegment = (sourceSegment: any) => {\n const segmentArray: any[] = [\n this.uiSegmentSrv.newKey(sourceSegment.value),\n this.uiSegmentSrv.newOperator('=='),\n this.uiSegmentSrv.newFake('select filter value', 'value', 'query-segment-value'),\n ];\n\n this.clientFilterSegments.pop();\n this.clientFilterSegments.push(segmentArray);\n this.clientFilterSegments.push([this.uiSegmentSrv.newPlusButton()]);\n };\n\n /**\n * Adds a new response filter.\n */\n _addServerFilterSegment = (sourceSegment: any) => {\n const segmentArray: any[] = [\n this.uiSegmentSrv.newCondition(sourceSegment.value),\n this.uiSegmentSrv.newFake('select filter key', 'value', 'query-segment-value'),\n this.uiSegmentSrv.newOperator('=='),\n this.uiSegmentSrv.newFake('select filter value', 'value', 'query-segment-value'),\n ];\n\n this.serverFilterSegments.pop();\n this.serverFilterSegments.push(segmentArray);\n this.serverFilterSegments.push([this.uiSegmentSrv.newPlusButton()]);\n };\n\n /**\n * Called when a response filter configuration is changed.\n *\n * @param segment the segment which has been changed\n */\n onServerFilterSegmentUpdate = segment => {\n if (segment.type === 'plus-button') {\n this._addServerFilterSegment(segment);\n return;\n }\n\n this._updateFilterTarget();\n this.panelCtrl.refresh();\n };\n\n /**\n * Returns selectable options for filter segments.\n */\n getFilterSegmentOptions = (segment, parentIndex, index) => {\n let segments: any[] = [];\n\n if (segment.type === 'operator') {\n segments = this.uiSegmentSrv.newOperators(['==', '=~', '!=', '!~', '<', '>']);\n } else if (this.dataPreview && this.dataPreview.length > 0) {\n let options: string[] = [];\n if (index === 0) {\n options = this.getAllDeepKeys();\n } else if (index === 2) {\n const filterKey = this.clientFilterSegments[parentIndex][0].value;\n options = _(this.dataPreview)\n .map(data => _.get(data, filterKey))\n .uniq()\n .value();\n\n _.each(this.templateSrv.variables, variable =>\n options.unshift('/$' + variable.name + '/')\n );\n }\n segments = _.map(options, option => this.uiSegmentSrv.newSegment(String(option)));\n }\n\n return this.$q.when(segments);\n };\n\n /**\n * The segments which represents the specified filters will not be persisted and passed to the data source.\n * Instead, an object is created which represents the filters which is passed to the data source and\n * persisted by Grafana. Calling this method syncs the object (target) and updates its value to match the\n * segments' values specified by the user.\n */\n _updateFilterTarget = () => {\n const target = this.target;\n\n // update client filters\n const clientFilters = _(this.clientFilterSegments)\n .filter(segmentArray => segmentArray.length === 3)\n .filter(segmentArray => !segmentArray[2].fake)\n .map(segmentArray => {\n return {\n key: segmentArray[0].value,\n matcher: segmentArray[1].value,\n value: segmentArray[2].value,\n };\n })\n .value();\n\n target.clientSideFilters = clientFilters;\n\n // update server filters\n const serverFilters = _(this.serverFilterSegments)\n .filter(segmentArray => segmentArray.length === 4)\n .filter(segmentArray => !segmentArray[1].fake && !segmentArray[3].fake)\n .map(segmentArray => {\n let type;\n switch (segmentArray[0].value) {\n case 'fieldSelector':\n type = ServerSideFilterType.FIELD;\n break;\n case 'labelSelector':\n type = ServerSideFilterType.LABEL;\n break;\n default:\n return {};\n }\n\n return {\n key: segmentArray[1].value,\n matcher: segmentArray[2].value,\n value: segmentArray[3].value,\n type,\n };\n })\n .filter(filter => filter.type !== undefined)\n .value();\n\n target.serverSideFilters = serverFilters;\n };\n\n /**\n * Returns all existing keys of the current data preview.\n */\n getAllDeepKeys = () => {\n return _.flatMap(this.combineKeys(this.dataPreview[0]), e => e);\n };\n\n /**\n * Returns selectable options for the field segments.\n */\n getFieldSelectorOptions = (segment, parentIndex, index) => {\n let segments: any[] = [];\n\n if (this.dataPreview && this.dataPreview.length > 0) {\n let options: string[] = [];\n\n let currentSelection: any = this.dataPreview[0];\n\n if (index > 0) {\n for (let i = 0; i < index; i++) {\n const fieldSegment = this.target.fieldSelectors[parentIndex].fieldSegments[i];\n currentSelection = _.get(currentSelection, fieldSegment.value);\n }\n }\n\n options = _.concat(options, ['*']);\n options = _.concat(options, Object.keys(currentSelection));\n\n options.sort();\n\n segments = _.map(options, option => this.uiSegmentSrv.newSegment({value: option}));\n }\n\n return this.$q.when(segments);\n };\n\n /**\n * Called if a field segment is changed.\n */\n onFieldSelectorSegmentUpdate = (segment, parentIndex) => {\n if (segment == this.addFieldSegment) {\n this.target.fieldSelectors.push(new FieldSelector(this, segment.value));\n this.addFieldSegment = this.uiSegmentSrv.newPlusButton();\n } else {\n this.target.fieldSelectors[parentIndex].refresh(this);\n }\n\n this.panelCtrl.refresh();\n };\n\n /**\n * Removes the field selector on the specified index.\n */\n removeField = index => {\n this.target.fieldSelectors.splice(index, 1);\n this.panelCtrl.refresh();\n };\n\n /**\n * Called if an alias is changing.\n */\n onAliasChange = () => {\n this.panelCtrl.refresh();\n };\n\n combineKeys = object => {\n const keys: string[] = Object.keys(object);\n\n return _.flatMap(keys, key => {\n if (_.isPlainObject(object[key])) {\n return _.map(this.combineKeys(object[key]), nestedKeys => {\n return key + '.' + nestedKeys;\n });\n } else {\n return key;\n }\n });\n };\n\n /**\n * Returns the currently selected api endpoint.\n */\n _getCurrentApi = () => {\n return _.find(API_ENDPOINTS, {value: this.target.apiEndpoints});\n };\n\n getServerFilterOptions = (segment, parentIndex) => {\n if (segment.type === 'operator') {\n return this.$q.when(\n this.uiSegmentSrv.newOperators(['==', '!=', 'in', 'notin', 'matches'])\n );\n } else if (segment.type === 'plus-button' || segment.type === 'condition') {\n return this.$q.when(\n _.map(['fieldSelector', 'labelSelector'], value =>\n this.uiSegmentSrv.newSegment({value})\n )\n );\n }\n\n const options: string[] = _.map(\n this.templateSrv.variables,\n variable => '\"$' + variable.name + '\"'\n );\n\n const filterType = this.serverFilterSegments[parentIndex][0].value;\n\n if (filterType === 'fieldSelector') {\n const currentApi = this._getCurrentApi();\n if (currentApi) {\n currentApi.fieldSelectors.forEach(field => options.push(field));\n }\n }\n\n const segments = _.map(options, option =>\n this.uiSegmentSrv.newSegment(new String(option))\n );\n\n return this.$q.when(segments);\n };\n\n onDataReceived = () => {\n if (this.dataPreviewBuffer.length > 0) {\n // this is done so that we get the response from all querys. otherwise the last query could override the\n // data which we need\n //\n // TODO only store the data related to the current query\n this.dataPreview = _.flatten(this.dataPreviewBuffer);\n this.dataPreviewBuffer = [];\n }\n };\n\n /**\n * Called when a request is finished. The requests data is stored and used as a data preview which is basis for auto completions.\n */\n onResponseReceived = response => {\n if (!response.config.url.endsWith('/auth')) {\n this.dataPreviewBuffer.push(response.data);\n }\n };\n\n onRefresh = () => {\n //TODO\n this.dataPreview = {};\n };\n\n /**\n * Returns a string representation of the current query configuration.\n */\n getCollapsedText() {\n return targetToQueryString(this.target);\n }\n}\n","import {InstanceSettings} from './types';\r\n\r\n/**\r\n * Controller responsible for the configuration ui.\r\n */\r\nexport class SensuConfigCtrl {\r\n static templateUrl = 'partials/config.html';\r\n\r\n // the current datasource settings\r\n current: InstanceSettings;\r\n\r\n /** @ngInject **/\r\n constructor($scope) {\r\n $scope.$watch(\r\n () => this.current.url,\r\n value => (this.current.jsonData.currentUrl = value)\r\n );\r\n $scope.$watch(\r\n () => this.current.basicAuth,\r\n value => {\r\n if (value) {\r\n this.current.jsonData.useApiKey = false;\r\n }\r\n }\r\n );\r\n }\r\n\r\n /**\r\n * When the \"Use API Key\" option is toggled.\r\n */\r\n onUseApiKeyToggle = () => {\r\n const current = this.current;\r\n if (current.jsonData.useApiKey) {\r\n current.basicAuth = false;\r\n this.resetApiKey();\r\n }\r\n };\r\n\r\n /**\r\n * Resets the currely set API key.\r\n */\r\n resetApiKey = () => {\r\n this.current.secureJsonFields.apiKey = false;\r\n this.current.secureJsonData = this.current.secureJsonData || {};\r\n this.current.secureJsonData.apiKey = '';\r\n };\r\n}\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/src/datasource.ts b/src/datasource.ts index 66e3bce..94422cc 100644 --- a/src/datasource.ts +++ b/src/datasource.ts @@ -102,6 +102,7 @@ export default class SensuDatasource { */ query(queryOptions) { const queryTargets = _(queryOptions.targets) + .filter(target => !target.hide) .map(ConfigMigration.migrate) .map(target => this.prepareQuery(target, queryOptions)) .value();