mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
added regular expression queries and esVersion service+directive+filter to allow a given element to require a specified elasticsearch version
This commit is contained in:
parent
cfceadc87d
commit
c6b1503950
@ -10,13 +10,15 @@ function (angular, config, _) {
|
|||||||
var module = angular.module('kibana.controllers');
|
var module = angular.module('kibana.controllers');
|
||||||
|
|
||||||
module.controller('DashCtrl', function(
|
module.controller('DashCtrl', function(
|
||||||
$scope, $route, ejsResource, fields, dashboard, alertSrv, panelMove) {
|
$scope, $route, ejsResource, fields, dashboard, alertSrv, panelMove, esVersion) {
|
||||||
|
|
||||||
|
$scope.requiredElasticSearchVersion = ">=0.20.5";
|
||||||
|
|
||||||
$scope.editor = {
|
$scope.editor = {
|
||||||
index: 0
|
index: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
// For moving stuff around the dashboard. Needs better names
|
// For moving stuff around the dashboard.
|
||||||
$scope.panelMove = panelMove;
|
|
||||||
$scope.panelMoveDrop = panelMove.onDrop;
|
$scope.panelMoveDrop = panelMove.onDrop;
|
||||||
$scope.panelMoveStart = panelMove.onStart;
|
$scope.panelMoveStart = panelMove.onStart;
|
||||||
$scope.panelMoveStop = panelMove.onStop;
|
$scope.panelMoveStop = panelMove.onStop;
|
||||||
@ -24,16 +26,18 @@ function (angular, config, _) {
|
|||||||
$scope.panelMoveOut = panelMove.onOut;
|
$scope.panelMoveOut = panelMove.onOut;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.config = config;
|
$scope.config = config;
|
||||||
// Make underscore.js available to views
|
// Make stuff, including underscore.js available to views
|
||||||
$scope._ = _;
|
$scope._ = _;
|
||||||
$scope.dashboard = dashboard;
|
$scope.dashboard = dashboard;
|
||||||
$scope.dashAlerts = alertSrv;
|
$scope.dashAlerts = alertSrv;
|
||||||
|
$scope.esVersion = esVersion;
|
||||||
|
|
||||||
|
// Clear existing alerts
|
||||||
alertSrv.clearAll();
|
alertSrv.clearAll();
|
||||||
|
|
||||||
// Provide a global list of all see fields
|
// Provide a global list of all seen fields
|
||||||
$scope.fields = fields;
|
$scope.fields = fields;
|
||||||
$scope.reset_row();
|
$scope.reset_row();
|
||||||
|
|
||||||
|
@ -7,5 +7,6 @@ define([
|
|||||||
'./ngBlur',
|
'./ngBlur',
|
||||||
'./ngModelOnBlur',
|
'./ngModelOnBlur',
|
||||||
'./tip',
|
'./tip',
|
||||||
'./confirmClick'
|
'./confirmClick',
|
||||||
|
'./esVersion'
|
||||||
], function () {});
|
], function () {});
|
25
src/app/directives/esVersion.js
Normal file
25
src/app/directives/esVersion.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
Only show an element if it meets an Elasticsearch version requirement
|
||||||
|
*/
|
||||||
|
|
||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'app',
|
||||||
|
],
|
||||||
|
function (angular) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular
|
||||||
|
.module('kibana.directives')
|
||||||
|
.directive('esVersion', function(esVersion) {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function(scope, elem, attr) {
|
||||||
|
if(!esVersion.is(attr.esVersion)) {
|
||||||
|
console.log('hiding');
|
||||||
|
elem.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
@ -24,6 +24,18 @@ define(['angular', 'jquery', 'underscore', 'moment'], function (angular, $, _, m
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
Filter an array of objects by elasticsearch version requirements
|
||||||
|
*/
|
||||||
|
module.filter('esVersion', function(esVersion) {
|
||||||
|
return function(items, require) {
|
||||||
|
var ret = _.filter(items,function(qt) {
|
||||||
|
return esVersion.is(qt[require]) ? true : false;
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
module.filter('slice', function() {
|
module.filter('slice', function() {
|
||||||
return function(arr, start, end) {
|
return function(arr, start, end) {
|
||||||
if(!_.isUndefined(arr)) {
|
if(!_.isUndefined(arr)) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="panel-query-meta row-fluid" style="width:170px">
|
<div class="panel-query-meta row-fluid" style="width:220px">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.input-query-alias {
|
.input-query-alias {
|
||||||
@ -10,12 +10,19 @@
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
<a class="close" ng-click="render();dismiss();" href="">×</a>
|
<a class="close" ng-click="render();dismiss();" href="">×</a>
|
||||||
<i ng-click="toggle_pin(id);dismiss();" class="small pointer icon-pushpin"></i>
|
<label class="strong small ">Query Alias <button class="btn btn-mini" ng-class="{active:querySrv.list[id].pin}" ng-click="toggle_pin(id);dismiss();" class="pointer"><i class="icon-pushpin"></i></button></label>
|
||||||
<label class="strong small ">Query Alias</label>
|
|
||||||
<form>
|
<form>
|
||||||
<input class="input-medium input-query-alias" type="text" ng-model="querySrv.list[id].alias" placeholder='Alias...' />
|
<input class="input-large input-query-alias" type="text" ng-model="querySrv.list[id].alias" placeholder='Alias...' />
|
||||||
<div>
|
<div>
|
||||||
<i ng-repeat="color in querySrv.colors" class="pointer" ng-class="{'icon-circle-blank':querySrv.list[id].color == color,'icon-circle':querySrv.list[id].color != color}" ng-style="{color:color}" ng-click="querySrv.list[id].color = color;render();"> </i>
|
<i ng-repeat="color in querySrv.colors" class="pointer" ng-class="{'icon-circle-blank':querySrv.list[id].color == color,'icon-circle':querySrv.list[id].color != color}" ng-style="{color:color}" ng-click="querySrv.list[id].color = color;render();"> </i>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<label class="small">Query type</label>
|
||||||
|
<select ng-change="dismiss();" class="input-small" ng-model="querySrv.list[id].type">
|
||||||
|
<option ng-repeat="type in querySrv.queryTypes|esVersion:'require'">{{type.name}}</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
@ -2,10 +2,12 @@
|
|||||||
<div ng-repeat="id in (unPinnedQueries = (querySrv.ids|pinnedQuery:false))" ng-class="{'short-query': unPinnedQueries.length>1}">
|
<div ng-repeat="id in (unPinnedQueries = (querySrv.ids|pinnedQuery:false))" ng-class="{'short-query': unPinnedQueries.length>1}">
|
||||||
<form class="form-search" style="position:relative;margin-bottom:5px;" ng-submit="refresh()">
|
<form class="form-search" style="position:relative;margin-bottom:5px;" ng-submit="refresh()">
|
||||||
<span class="begin-query">
|
<span class="begin-query">
|
||||||
<i class="icon-circle pointer" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="rightTop" ng-style="{color: querySrv.list[id].color}"></i>
|
<i class="icon-circle pointer" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="bottomLeft" ng-style="{color: querySrv.list[id].color}"></i>
|
||||||
<i class="icon-remove-sign pointer remove-query" ng-show="querySrv.ids.length > 1" ng-click="querySrv.remove(id);refresh()"></i>
|
<i class="icon-remove-sign pointer remove-query" ng-show="querySrv.ids.length > 1" ng-click="querySrv.remove(id);refresh()"></i>
|
||||||
</span>
|
</span>
|
||||||
<input class="search-query panel-query" ng-class="{ 'input-block-level': unPinnedQueries.length==1, 'last-query': $last, 'has-remove': querySrv.ids.length > 1 }" bs-typeahead="panel.history" data-min-length=0 data-items=100 type="text" ng-model="querySrv.list[id].query" />
|
<span>
|
||||||
|
<input class="search-query panel-query" ng-class="{ 'input-block-level': unPinnedQueries.length==1, 'last-query': $last, 'has-remove': querySrv.ids.length > 1 }" bs-typeahead="panel.history" data-min-length=0 data-items=100 type="text" ng-model="querySrv.list[id].query" />
|
||||||
|
</span>
|
||||||
<span class="end-query">
|
<span class="end-query">
|
||||||
<i class="icon-search pointer" ng-click="refresh()" ng-show="$last"></i>
|
<i class="icon-search pointer" ng-click="refresh()" ng-show="$last"></i>
|
||||||
<i class="icon-plus pointer" ng-click="querySrv.set({})" ng-show="$last"></i>
|
<i class="icon-plus pointer" ng-click="querySrv.set({})" ng-show="$last"></i>
|
||||||
@ -13,9 +15,9 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:inline-block" ng-repeat="id in querySrv.ids|pinnedQuery:true">
|
<div style="display:inline-block" ng-repeat="id in querySrv.ids|pinnedQuery:true">
|
||||||
<span class="pointer" ng-show="$first" ng-click="panel.pinned = !panel.pinned"><small class="pins">Pinned</small> <i ng-class="{'icon-caret-right':panel.pinned,'icon-caret-left':!panel.pinned}"></i></span>
|
<span class="pointer" ng-show="$first" ng-click="panel.pinned = !panel.pinned"><span class="pins">Pinned</span> <i ng-class="{'icon-caret-right':panel.pinned,'icon-caret-left':!panel.pinned}"></i></span>
|
||||||
<span ng-show="panel.pinned" class="pinned badge">
|
<span ng-show="panel.pinned" class="badge pinned">
|
||||||
<i class="icon-circle pointer" ng-style="{color: querySrv.list[id].color}" data-unique="1" bs-popover="'app/panels/query/meta.html'"></i><span bs-tooltip="querySrv.list[id].query"> {{querySrv.list[id].alias || querySrv.list[id].query}}</span>
|
<i class="icon-circle pointer" ng-style="{color: querySrv.list[id].color}" data-unique="1" bs-popover="'app/panels/query/meta.html'" data-placement="bottomLeft"></i><span bs-tooltip="querySrv.list[id].query"> {{querySrv.list[id].alias || querySrv.list[id].query}}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span style="display:inline-block" ng-show="unPinnedQueries.length == 0">
|
<span style="display:inline-block" ng-show="unPinnedQueries.length == 0">
|
||||||
|
@ -6,6 +6,7 @@ define([
|
|||||||
'./kbnIndex',
|
'./kbnIndex',
|
||||||
'./querySrv',
|
'./querySrv',
|
||||||
'./timer',
|
'./timer',
|
||||||
'./panelMove'
|
'./panelMove',
|
||||||
|
'./esVersion'
|
||||||
],
|
],
|
||||||
function () {});
|
function () {});
|
150
src/app/services/esVersion.js
Normal file
150
src/app/services/esVersion.js
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'underscore',
|
||||||
|
'config'
|
||||||
|
],
|
||||||
|
function (angular, _, config) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var module = angular.module('kibana.services');
|
||||||
|
|
||||||
|
module.service('esVersion', function($http, alertSrv) {
|
||||||
|
|
||||||
|
this.versions = [];
|
||||||
|
|
||||||
|
// save a reference to this
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.init = function() {
|
||||||
|
getVersions();
|
||||||
|
};
|
||||||
|
|
||||||
|
var getVersions = function() {
|
||||||
|
var nodeInfo = $http({
|
||||||
|
url: config.elasticsearch + '/_nodes',
|
||||||
|
method: "GET"
|
||||||
|
}).error(function(data, status) {
|
||||||
|
if(status === 0) {
|
||||||
|
alertSrv.set('Error',"Could not contact Elasticsearch at "+config.elasticsearch+
|
||||||
|
". Please ensure that Elasticsearch is reachable from your system." ,'error');
|
||||||
|
} else {
|
||||||
|
alertSrv.set('Error',"Could not reach "+config.elasticsearch+"/_nodes. If you"+
|
||||||
|
" are using a proxy, ensure it is configured correctly",'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return nodeInfo.then(function(p) {
|
||||||
|
_.each(p.data.nodes, function(v) {
|
||||||
|
self.versions.push(v.version.split('-')[0]);
|
||||||
|
});
|
||||||
|
self.versions = sortVersions(_.uniq(self.versions));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the max version in this cluster
|
||||||
|
this.max = function() {
|
||||||
|
return _.last(self.versions);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return the lowest version in the cluster
|
||||||
|
this.min = function() {
|
||||||
|
return _.first(self.versions);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sort versions from lowest to highest
|
||||||
|
var sortVersions = function(versions) {
|
||||||
|
var _versions = _.clone(versions),
|
||||||
|
_r = [];
|
||||||
|
|
||||||
|
while(_r.length < versions.length) {
|
||||||
|
var _h = "0";
|
||||||
|
/*jshint -W083 */
|
||||||
|
_.each(_versions,function(v){
|
||||||
|
if(self.compare(_h,v)) {
|
||||||
|
_h = v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_versions = _.without(_versions,_h);
|
||||||
|
_r.push(_h);
|
||||||
|
}
|
||||||
|
return _r.reverse();
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Takes a version string with one of the following optional comparison prefixes: >,>=,<.<=
|
||||||
|
and evaluates if the cluster meets the requirement. If the prefix is omitted exact match
|
||||||
|
is assumed
|
||||||
|
*/
|
||||||
|
this.is = function(equation) {
|
||||||
|
var _v = equation,
|
||||||
|
_cf;
|
||||||
|
|
||||||
|
if(_v.charAt(0) === '>') {
|
||||||
|
_cf = _v.charAt(1) === '=' ? self.gte(_v.slice(2)) : self.gt(_v.slice(1));
|
||||||
|
} else if (_v.charAt(0) === '<') {
|
||||||
|
_cf = _v.charAt(1) === '=' ? self.lte(_v.slice(2)) : self.lt(_v.slice(1));
|
||||||
|
} else {
|
||||||
|
_cf = self.eq(_v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cf;
|
||||||
|
};
|
||||||
|
|
||||||
|
// check if lowest version in cluster = `version`
|
||||||
|
this.eq = function(version) {
|
||||||
|
return version === self.min() ? true : false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// version > lowest version in cluster?
|
||||||
|
this.gt = function(version) {
|
||||||
|
return version === self.min() ? false : self.gte(version);
|
||||||
|
};
|
||||||
|
|
||||||
|
// version < highest version in cluster?
|
||||||
|
this.lt = function(version) {
|
||||||
|
return version === self.max() ? false : self.lte(version);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the lowest version in the cluster is >= to `version`
|
||||||
|
this.gte = function(version) {
|
||||||
|
return self.compare(version,self.min());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the highest version in the cluster is <= to `version`
|
||||||
|
this.lte = function(version) {
|
||||||
|
return self.compare(self.max(),version);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determine if a specific version is greater than or equal to another
|
||||||
|
this.compare = function (required,installed) {
|
||||||
|
var a = installed.split('.');
|
||||||
|
var b = required.split('.');
|
||||||
|
var i;
|
||||||
|
|
||||||
|
for (i = 0; i < a.length; ++i) {
|
||||||
|
a[i] = Number(a[i]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < b.length; ++i) {
|
||||||
|
b[i] = Number(b[i]);
|
||||||
|
}
|
||||||
|
if (a.length === 2) {
|
||||||
|
a[2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a[0] > b[0]){return true;}
|
||||||
|
if (a[0] < b[0]){return false;}
|
||||||
|
|
||||||
|
if (a[1] > b[1]){return true;}
|
||||||
|
if (a[1] < b[1]){return false;}
|
||||||
|
|
||||||
|
if (a[2] > b[2]){return true;}
|
||||||
|
if (a[2] < b[2]){return false;}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -39,6 +39,12 @@ function (angular, _, config) {
|
|||||||
"#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" //7
|
"#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" //7
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Define the query types and the version of elasticsearch they were first available in
|
||||||
|
this.queryTypes = [
|
||||||
|
{name:'lucene',require:">=0.17.0"},
|
||||||
|
{name:'regex',require:">=0.90.3"}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
// Save a reference to this
|
// Save a reference to this
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -104,6 +110,8 @@ function (angular, _, config) {
|
|||||||
{
|
{
|
||||||
case 'lucene':
|
case 'lucene':
|
||||||
return ejs.QueryStringQuery(q.query || '*');
|
return ejs.QueryStringQuery(q.query || '*');
|
||||||
|
case 'regex':
|
||||||
|
return ejs.RegexpQuery('_all',q.query);
|
||||||
default:
|
default:
|
||||||
return _.isUndefined(q.query) ? false : ejs.QueryStringQuery(q.query || '*');
|
return _.isUndefined(q.query) ? false : ejs.QueryStringQuery(q.query || '*');
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
<body ng-cloak>
|
<body ng-cloak>
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" ng-href="css/bootstrap.{{dashboard.current.style||'dark'}}.min.css">
|
<link rel="stylesheet" ng-href="css/bootstrap.{{dashboard.current.style||'dark'}}.min.css">
|
||||||
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
|
||||||
<link rel="stylesheet" href="css/font-awesome.min.css">
|
<link rel="stylesheet" href="css/font-awesome.min.css">
|
||||||
|
Loading…
Reference in New Issue
Block a user