瀏覽代碼

Progress on influxdb and templated queries/variables, #613

Torkel Ödegaard 11 年之前
父節點
當前提交
2dc4434a49

+ 9 - 0
src/app/components/kbn.js

@@ -652,5 +652,14 @@ function($, _, moment) {
     }
   };
 
+  kbn.stringToJsRegex = function(str) {
+    if (str[0] !== '/') {
+      return new RegExp(str);
+    }
+
+    var match = str.match(new RegExp('^/(.*?)/(g?i?m?y?)$'));
+    return new RegExp(match[1], match[2]);
+  };
+
   return kbn;
 });

+ 1 - 2
src/app/components/timeSeries.js

@@ -15,8 +15,7 @@ function (_, kbn) {
     if (!aliasOrRegex) { return false; }
 
     if (aliasOrRegex[0] === '/') {
-      var match = aliasOrRegex.match(new RegExp('^/(.*?)/(g?i?m?y?)$'));
-      var regex = new RegExp(match[1], match[2]);
+      var regex = kbn.stringToJsRegex(aliasOrRegex);
       return seriesAlias.match(regex) != null;
     }
 

+ 9 - 8
src/app/controllers/templateEditorCtrl.js

@@ -7,7 +7,7 @@ function (angular, _) {
 
   var module = angular.module('grafana.controllers');
 
-  module.controller('TemplateEditorCtrl', function($scope, datasourceSrv, templateSrv, templateValuesSrv) {
+  module.controller('TemplateEditorCtrl', function($scope, datasourceSrv, templateSrv, templateValuesSrv, alertSrv) {
 
     var replacementDefaults = {
       type: 'query',
@@ -38,7 +38,10 @@ function (angular, _) {
     };
 
     $scope.runQuery = function() {
-      templateValuesSrv.updateOptions($scope.current);
+      return templateValuesSrv.updateOptions($scope.current).then(function() {
+      }, function(err) {
+        alertSrv.set('Templating', 'Failed to run query for variable values: ' + err.message, 'error');
+      });
     };
 
     $scope.edit = function(variable) {
@@ -54,9 +57,10 @@ function (angular, _) {
     };
 
     $scope.update = function() {
-      templateValuesSrv.updateOptions($scope.current);
-      $scope.reset();
-      $scope.editor.index = 0;
+      $scope.runQuery().then(function() {
+        $scope.reset();
+        $scope.editor.index = 0;
+      });
     };
 
     $scope.reset = function() {
@@ -68,9 +72,6 @@ function (angular, _) {
       if ($scope.current.type === 'time period') {
         $scope.current.query = '1m,10m,30m,1h,6h,12h,1d,7d,14d,30d';
       }
-      else {
-        $scope.current.query = '';
-      }
     };
 
     $scope.removeVariable = function(variable) {

+ 1 - 1
src/app/partials/templating_editor.html

@@ -113,7 +113,7 @@
 				<div class="editor-option">
 					<div class="editor-row">
 						<div class="editor-option" >
-							<label class="small">Variable values (first 20)</label>
+							<label class="small">Variable values (showing 20/{{current.options.length}})</label>
 							<ul class="grafana-options-list">
 								<li ng-repeat="option in current.options | limitTo: 20">
 									{{option.text}}

+ 1 - 0
src/app/services/dashboard/dashboardSrv.js

@@ -214,6 +214,7 @@ function (angular, $, kbn, _, moment) {
         for (i = 0 ; i < this.templating.list.length; i++) {
           var variable = this.templating.list[i];
           if (variable.datasource === void 0) { variable.datasource = null; }
+          if (variable.type === 'filter') { variable.type = 'query'; }
           if (variable.type === void 0) { variable.type = 'query'; }
           if (variable.allFormat === void 0) { variable.allFormat = 'Glob'; }
         }

+ 1 - 1
src/app/services/influxdb/influxdbDatasource.js

@@ -161,7 +161,7 @@ function (angular, _, kbn, InfluxSeries) {
       });
     };
 
-    InfluxDatasource.prototype.metricFindQuery = function (filterSrv, query) {
+    InfluxDatasource.prototype.metricFindQuery = function (query) {
       var interpolated;
       try {
         interpolated = templateSrv.replace(query);

+ 30 - 7
src/app/services/templateValuesSrv.js

@@ -2,9 +2,8 @@ define([
   'angular',
   'lodash',
   'kbn',
-  'store'
 ],
-function (angular, _) {
+function (angular, _, kbn) {
   'use strict';
 
   var module = angular.module('grafana.services');
@@ -30,7 +29,7 @@ function (angular, _) {
 
       templateSrv.updateTemplateData();
 
-      return this.applyFilterToOtherFilters(variable)
+      return this.updateOptionsInChildVariables(variable)
         .then(function() {
           if (!recursive) {
             $rootScope.$broadcast('refresh');
@@ -38,7 +37,7 @@ function (angular, _) {
         });
     };
 
-    this.applyFilterToOtherFilters = function(updatedVariable) {
+    this.updateOptionsInChildVariables = function(updatedVariable) {
       var promises = _.map(self.variables, function(otherVariable) {
         if (otherVariable === updatedVariable) {
           return;
@@ -63,9 +62,8 @@ function (angular, _) {
       var datasource = datasourceSrv.get(variable.datasource);
       return datasource.metricFindQuery(variable.query)
         .then(function (results) {
-          variable.options = _.map(results, function(node) {
-            return { text: node.text, value: node.text };
-          });
+
+          variable.options = self.metricNamesToVariableValues(variable, results);
 
           if (variable.includeAll) {
             self.addAllOption(variable);
@@ -84,6 +82,31 @@ function (angular, _) {
         });
     };
 
+    this.metricNamesToVariableValues = function(variable, metricNames) {
+      var regex, options, i, matches;
+      options = [];
+
+      if (variable.regex) {
+        regex = kbn.stringToJsRegex(variable.regex);
+      }
+
+      for (i = 0; i < metricNames.length; i++) {
+        var value = metricNames[i].text;
+
+        if (regex) {
+          matches = regex.exec(value);
+          if (!matches) { continue; }
+          if (matches.length > 1) {
+            value = matches[1];
+          }
+        }
+
+        options.push({text: value, value: value});
+      }
+
+      return options;
+    };
+
     this.addAllOption = function(variable) {
       var allValue = '';
       switch(variable.allFormat) {

+ 130 - 7
src/test/specs/templateValuesSrv-specs.js

@@ -8,26 +8,27 @@ define([
   describe('templateValuesSrv', function() {
     var _templateValuesSrv;
     var _dashboard;
+    var _datasourceSrv = {};
+    var _q;
+    var _rootScope;
 
     beforeEach(module('grafana.services'));
     beforeEach(module(function($provide) {
-      $provide.value('datasourceSrv', {});
+      $provide.value('datasourceSrv', _datasourceSrv);
       $provide.value('templateSrv', {
         updateTemplateData: function() {}
       });
       _dashboard = dashboardMock.create();
     }));
 
-    beforeEach(inject(function(templateValuesSrv) {
+    beforeEach(inject(function(templateValuesSrv, $rootScope, $q) {
       _templateValuesSrv = templateValuesSrv;
+      _rootScope = $rootScope;
+      _q = $q;
     }));
 
     describe('update time period variable options', function() {
-      var variable = {
-        type: 'time period',
-        query: 'auto,1s,2h,5h,1d',
-        name: 'test'
-      };
+      var variable = { type: 'time period', query: 'auto,1s,2h,5h,1d', name: 'test' };
 
       beforeEach(function() {
         _templateValuesSrv.updateOptions(variable);
@@ -40,6 +41,128 @@ define([
       });
     });
 
+    function describeUpdateVariable(desc, fn) {
+      describe(desc, function() {
+        var ctx = {};
+        ctx.setup = function(setupFn) {
+         ctx.setupFn = setupFn;
+        };
+
+        beforeEach(function() {
+          ctx.setupFn();
+          var ds = {};
+          ds.metricFindQuery = sinon.stub().returns(_q.when(ctx.queryResult));
+          _datasourceSrv.get = sinon.stub().returns(ds);
+
+          _templateValuesSrv.updateOptions(ctx.variable);
+          _rootScope.$digest();
+        });
+
+        fn(ctx);
+      });
+    }
+
+    describeUpdateVariable('time period variable ', function(ctx) {
+      ctx.setup(function() {
+        ctx.variable = { type: 'time period', query: 'auto,1s,2h,5h,1d', name: 'test' };
+      });
+
+      it('should update options array', function() {
+        expect(ctx.variable.options.length).to.be(5);
+        expect(ctx.variable.options[1].text).to.be('1s');
+        expect(ctx.variable.options[1].value).to.be('1s');
+      });
+    });
+
+    describeUpdateVariable('basic query variable', function(ctx) {
+      ctx.setup(function() {
+        ctx.variable = { type: 'query', query: 'apps.*', name: 'test' };
+        ctx.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
+      });
+
+      it('should update options array', function() {
+        expect(ctx.variable.options.length).to.be(2);
+        expect(ctx.variable.options[0].text).to.be('backend1');
+        expect(ctx.variable.options[0].value).to.be('backend1');
+        expect(ctx.variable.options[1].value).to.be('backend2');
+      });
+
+      it('should select first option as value', function() {
+        expect(ctx.variable.current.value).to.be('backend1');
+      });
+    });
+
+    describeUpdateVariable('and existing value still exists in options', function(ctx) {
+      ctx.setup(function() {
+        ctx.variable = { type: 'query', query: 'apps.*', name: 'test' };
+        ctx.variable.current = { value: 'backend2'};
+        ctx.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
+      });
+
+      it('should keep variable value', function() {
+        expect(ctx.variable.current.value).to.be('backend2');
+      });
+    });
+
+    describeUpdateVariable('and regex pattern exists', function(ctx) {
+      ctx.setup(function() {
+        ctx.variable = { type: 'query', query: 'apps.*', name: 'test' };
+        ctx.variable.regex = '/apps.*(backend_[0-9]+)/';
+        ctx.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
+      });
+
+      it('should extract and use match group', function() {
+        expect(ctx.variable.options[0].value).to.be('backend_01');
+      });
+    });
+
+    describeUpdateVariable('and regex pattern exists and no match', function(ctx) {
+      ctx.setup(function() {
+        ctx.variable = { type: 'query', query: 'apps.*', name: 'test' };
+        ctx.variable.regex = '/apps.*(backendasd[0-9]+)/';
+        ctx.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
+      });
+
+      it('should not add non matching items', function() {
+        expect(ctx.variable.options.length).to.be(0);
+      });
+    });
+
+   describeUpdateVariable('regex pattern without slashes', function(ctx) {
+      ctx.setup(function() {
+        ctx.variable = { type: 'query', query: 'apps.*', name: 'test' };
+        ctx.variable.regex = 'backend_01';
+        ctx.queryResult = [{text: 'apps.backend.backend_01.counters.req'}, {text: 'apps.backend.backend_02.counters.req'}];
+      });
+
+      it('should return matches options', function() {
+        expect(ctx.variable.options.length).to.be(1);
+      });
+    });
+
+    describeUpdateVariable('and existing value still exists in options', function(ctx) {
+      ctx.setup(function() {
+        ctx.variable = { type: 'query', query: 'apps.*', name: 'test' };
+        ctx.variable.current = { value: 'backend2'};
+        ctx.queryResult = [{text: 'backend1'}, {text: 'backend2'}];
+      });
+
+      it('should keep variable value', function() {
+        expect(ctx.variable.current.value).to.be('backend2');
+      });
+    });
+
+    describeUpdateVariable('with include All glob syntax', function(ctx) {
+      ctx.setup(function() {
+        ctx.variable = { type: 'query', query: 'apps.*', name: 'test', includeAll: true, allFormat: 'Glob' };
+        ctx.queryResult = [{text: 'backend1'}, {text: 'backend2'}, { text: 'backend3'}];
+      });
+
+      it('should add All Glob option', function() {
+        expect(ctx.variable.options[0].value).to.be('{backend1,backend2,backend3}');
+      });
+    });
+
   });
 
 });