Ver código fonte

Merge branch 'master' into alerting_definitions

bergquist 9 anos atrás
pai
commit
ba5978abd3

+ 13 - 0
CHANGELOG.md

@@ -1,3 +1,16 @@
+# 3.0.0-beta6 (unreleased)
+
+### Enhancements
+* **Singlestat**: Support for gauges in singlestat panel. closes [#3688](https://github.com/grafana/grafana/pull/3688)
+
+### Bug fixes
+* **InfluxDB 0.12**: Fixed issue templating and `show tag values` query only returning tags for first measurement,  fixes [#4726](https://github.com/grafana/grafana/issues/4726)
+* **Templating**: Fixed issue with regex formating when matching multiple values, fixes [#4755](https://github.com/grafana/grafana/issues/4755)
+* **Templating**: Fixed issue with custom all value and escaping, fixes [#4736](https://github.com/grafana/grafana/issues/4736)
+* **Dashlist**: Fixed issue dashboard list panel and caching tags, fixes [#4768](https://github.com/grafana/grafana/issues/4768)
+* **Graph**: Fixed issue with unneeded scrollbar in legend for Firefox, fixes [#4760](https://github.com/grafana/grafana/issues/4760)
+* **Table panel**: Fixed issue table panel formating string array properties, fixes [#4791](https://github.com/grafana/grafana/issues/4791)
+
 # 3.0.0-beta5 (2016-04-15)
 
 ### Bug fixes

+ 1 - 1
package.json

@@ -54,7 +54,7 @@
     "phantomjs-prebuilt": "^2.1.3",
     "reflect-metadata": "0.1.2",
     "rxjs": "5.0.0-beta.4",
-    "sass-lint": "^1.5.0",
+    "sass-lint": "^1.6.0",
     "systemjs": "0.19.24"
   },
   "engines": {

+ 2 - 2
pkg/api/cloudwatch/metrics.go

@@ -56,7 +56,7 @@ func init() {
 			"HbaseBackupFailed", "MostRecentBackupDuration", "TimeSinceLastSuccessfulBackup"},
 		"AWS/ES":       {"ClusterStatus.green", "ClusterStatus.yellow", "ClusterStatus.red", "Nodes", "SearchableDocuments", "DeletedDocuments", "CPUUtilization", "FreeStorageSpace", "JVMMemoryPressure", "AutomatedSnapshotFailure", "MasterCPUUtilization", "MasterFreeStorageSpace", "MasterJVMMemoryPressure", "ReadLatency", "WriteLatency", "ReadThroughput", "WriteThroughput", "DiskQueueLength", "ReadIOPS", "WriteIOPS"},
 		"AWS/Events":   {"Invocations", "FailedInvocations", "TriggeredRules", "MatchedEvents", "ThrottledRules"},
-		"AWS/Kinesis":  {"PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "IncomingBytes", "IncomingRecords", "GetRecords.Bytes", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Success"},
+		"AWS/Kinesis":  {"GetRecords.Bytes", "GetRecords.IteratorAge", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Records", "GetRecords.Success", "IncomingBytes", "IncomingRecords", "PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "ReadProvisionedThroughputExceeded", "WriteProvisionedThroughputExceeded", "IteratorAgeMilliseconds", "OutgoingBytes", "OutgoingRecords"},
 		"AWS/Lambda":   {"Invocations", "Errors", "Duration", "Throttles"},
 		"AWS/Logs":     {"IncomingBytes", "IncomingLogEvents", "ForwardedBytes", "ForwardedLogEvents", "DeliveryErrors", "DeliveryThrottling"},
 		"AWS/ML":       {"PredictCount", "PredictFailureCount"},
@@ -88,7 +88,7 @@ func init() {
 		"AWS/ElasticMapReduce": {"ClusterId", "JobFlowId", "JobId"},
 		"AWS/ES":               {},
 		"AWS/Events":           {"RuleName"},
-		"AWS/Kinesis":          {"StreamName"},
+		"AWS/Kinesis":          {"StreamName", "ShardID"},
 		"AWS/Lambda":           {"FunctionName"},
 		"AWS/Logs":             {"LogGroupName", "DestinationType", "FilterName"},
 		"AWS/ML":               {"MLModelId", "RequestMode"},

+ 4 - 0
pkg/api/dashboard_snapshot.go

@@ -21,6 +21,10 @@ func GetSharingOptions(c *middleware.Context) {
 }
 
 func CreateDashboardSnapshot(c *middleware.Context, cmd m.CreateDashboardSnapshotCommand) {
+	if cmd.Name == "" {
+		cmd.Name = "Unnamed snapshot"
+	}
+
 	if cmd.External {
 		// external snapshot ref requires key and delete key
 		if cmd.Key == "" || cmd.DeleteKey == "" {

+ 5 - 5
pkg/cmd/grafana-cli/commands/install_command.go

@@ -126,8 +126,8 @@ func downloadFile(pluginName, filePath, url string) (err error) {
 	defer func() {
 		if r := recover(); r != nil {
 			retryCount++
-			if retryCount == 1 {
-				log.Debug("\nFailed downloading. Will retry once.\n")
+			if retryCount < 3 {
+				fmt.Printf("\nFailed downloading. Will retry once.\n%v\n", r)
 				downloadFile(pluginName, filePath, url)
 			} else {
 				panic(r)
@@ -164,14 +164,14 @@ func downloadFile(pluginName, filePath, url string) (err error) {
 				return fmt.Errorf(permissionsDeniedMessage, newFile)
 			}
 
-			defer dst.Close()
 			src, err := zf.Open()
 			if err != nil {
-				log.Errorf("%v", err)
+				log.Errorf("Failed to extract file: %v", err)
 			}
-			defer src.Close()
 
 			io.Copy(dst, src)
+			dst.Close()
+			src.Close()
 		}
 	}
 

+ 3 - 8
pkg/cmd/grafana-cli/commands/remove_command.go

@@ -3,7 +3,7 @@ package commands
 import (
 	"errors"
 
-	"github.com/grafana/grafana/pkg/cmd/grafana-cli/log"
+	"fmt"
 	m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
 	services "github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
 )
@@ -15,22 +15,17 @@ func removeCommand(c CommandLine) error {
 	pluginPath := c.GlobalString("pluginsDir")
 	localPlugins := getPluginss(pluginPath)
 
-	log.Info("remove!\n")
-
 	plugin := c.Args().First()
-	log.Info("plugin: " + plugin + "\n")
 	if plugin == "" {
 		return errors.New("Missing plugin parameter")
 	}
 
-	log.Infof("plugins : \n%v\n", localPlugins)
-
 	for _, p := range localPlugins {
 		if p.Id == c.Args().First() {
-			log.Infof("removing plugin %s", p.Id)
 			removePlugin(pluginPath, p.Id)
+			return nil
 		}
 	}
 
-	return nil
+	return fmt.Errorf("Could not find plugin named %s", c.Args().First())
 }

+ 5 - 5
pkg/cmd/grafana-cli/main.go

@@ -8,7 +8,6 @@ import (
 	"github.com/codegangsta/cli"
 	"github.com/grafana/grafana/pkg/cmd/grafana-cli/commands"
 	"github.com/grafana/grafana/pkg/cmd/grafana-cli/log"
-	"strings"
 )
 
 var version = "master"
@@ -18,7 +17,7 @@ func getGrafanaPluginDir() string {
 	defaultNix := "/var/lib/grafana/plugins"
 
 	if currentOS == "windows" {
-		return "C:\\opt\\grafana\\plugins"
+		return "../data/plugins"
 	}
 
 	pwd, err := os.Getwd()
@@ -29,16 +28,17 @@ func getGrafanaPluginDir() string {
 	}
 
 	if isDevenvironment(pwd) {
-		return "../../../data/plugins"
+		return "../data/plugins"
 	}
 
 	return defaultNix
 }
 
 func isDevenvironment(pwd string) bool {
-	// if grafana-cli is executed from the cmd folder we can assume
+	// if ../conf/defaults.ini exists, grafana is not installed as package
 	// that its in development environment.
-	return strings.HasSuffix(pwd, "/pkg/cmd/grafana-cli")
+	_, err := os.Stat("../conf/defaults.ini")
+	return err == nil
 }
 
 func main() {

+ 1 - 1
pkg/models/dashboard_snapshot.go

@@ -45,7 +45,7 @@ type DashboardSnapshotDTO struct {
 
 type CreateDashboardSnapshotCommand struct {
 	Dashboard *simplejson.Json `json:"dashboard" binding:"Required"`
-	Name      string           `json:"name" binding:"Required"`
+	Name      string           `json:"name"`
 	Expires   int64            `json:"expires"`
 
 	// these are passed when storing an external snapshot ref

+ 1 - 1
public/app/features/dashboard/viewStateSrv.js

@@ -36,7 +36,7 @@ function (angular, _, $) {
         self.update(payload);
       });
 
-      $scope.onAppEvent('panel-instantiated', function(evt, payload) {
+      $scope.onAppEvent('panel-initialized', function(evt, payload) {
         self.registerPanel(payload.scope);
       });
 

+ 4 - 1
public/app/features/panel/panel_ctrl.ts

@@ -50,8 +50,11 @@ export class PanelCtrl {
   }
 
   init() {
-    this.publishAppEvent('panel-instantiated', {scope: this.$scope});
     this.calculatePanelHeight();
+
+    this.publishAppEvent('panel-initialized', {scope: this.$scope});
+    this.events.emit('panel-initialized');
+
     this.refresh();
   }
 

+ 5 - 1
public/app/features/templating/templateSrv.js

@@ -57,7 +57,7 @@ function (angular, _) {
           }
 
           var escapedValues = _.map(value, regexEscape);
-          return escapedValues.join('|');
+          return '(' + escapedValues.join('|') + ')';
         }
         case "lucene": {
           if (typeof value === 'string') {
@@ -152,6 +152,10 @@ function (angular, _) {
         value = variable.current.value;
         if (self.isAllValue(value)) {
           value = self.getAllValue(variable);
+          // skip formating of custom all values
+          if (variable.allValue) {
+            return value;
+          }
         }
 
         var res = self.formatValue(value, format, variable);

+ 0 - 5
public/app/features/templating/templateValuesSrv.js

@@ -294,11 +294,6 @@ function (angular, _, kbn) {
     };
 
     this.addAllOption = function(variable) {
-      if (variable.allValue) {
-        variable.options.unshift({text: 'All', value: variable.allValue});
-        return;
-      }
-
       variable.options.unshift({text: 'All', value: "$__all"});
     };
 

BIN
public/app/plugins/datasource/elasticsearch/img/logo_large.png


+ 7 - 0
public/app/plugins/datasource/graphite/gfunc.js

@@ -80,6 +80,13 @@ function (_, $) {
     category: categories.Calculate,
   });
 
+  addFuncDef({
+    name: 'stddevSeries',
+    params: optionalSeriesRefArgs,
+    defaultParams: [''],
+    category: categories.Calculate,
+  });
+
   addFuncDef({
     name: 'divideSeries',
     params: optionalSeriesRefArgs,

+ 3 - 1
public/app/plugins/datasource/influxdb/influx_query.ts

@@ -152,7 +152,9 @@ export default class InfluxQuery {
       if (interpolate) {
         value = this.templateSrv.replace(value, this.scopedVars);
       }
-      value = "'" + value.replace('\\', '\\\\') + "'";
+      if (isNaN(+value)) {
+        value = "'" + value.replace('\\', '\\\\') + "'";
+      }
     } else if (interpolate){
       value = this.templateSrv.replace(value, this.scopedVars, 'regex');
     }

+ 2 - 2
public/app/plugins/datasource/influxdb/query_builder.js

@@ -25,8 +25,8 @@ function (_) {
       }
     }
 
-    // quote value unless regex
-    if (operator !== '=~' && operator !== '!~') {
+    // quote value unless regex or number
+    if (operator !== '=~' && operator !== '!~' && isNaN(+value)) {
       value = "'" + value + "'";
     }
 

+ 21 - 9
public/app/plugins/datasource/influxdb/response_parser.ts

@@ -12,17 +12,29 @@ export default class ResponseParser {
       return [];
     }
 
-    var series = influxResults.series[0];
-    return _.map(series.values, (value) => {
-      if (_.isArray(value)) {
-        if (query.toLowerCase().indexOf('show tag values') >= 0) {
-          return { text: (value[1] || value[0]) };
+    var influxdb11format = query.toLowerCase().indexOf('show tag values') >= 0;
+
+    var res = {};
+    _.each(influxResults.series, serie => {
+      _.each(serie.values, value => {
+        if (_.isArray(value)) {
+          if (influxdb11format) {
+            addUnique(res, value[1] || value[0]);
+          } else {
+            addUnique(res, value[0]);
+          }
         } else {
-          return { text: value[0] };
+          addUnique(res, value);
         }
-      } else {
-        return { text: value };
-      }
+      });
+    });
+
+    return _.map(res, value => {
+      return { text: value};
     });
   }
 }
+
+function addUnique(arr, value) {
+  arr[value] = value;
+}

+ 17 - 9
public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts

@@ -38,7 +38,7 @@ describe("influxdb response parser", () => {
               {
                 "name": "hostnameTagValues",
                 "columns": ["hostname"],
-                "values": [ ["server1"], ["server2"] ]
+                "values": [ ["server1"], ["server2"], ["server2"] ]
               }
             ]
           }
@@ -54,7 +54,7 @@ describe("influxdb response parser", () => {
       });
     });
 
-    describe("response from 0.11.0", () => {
+    describe("response from 0.12.0", () => {
       var response = {
         "results": [
            {
@@ -62,8 +62,19 @@ describe("influxdb response parser", () => {
                {
                  "name": "cpu",
                  "columns": [ "key", "value"],
-                 "values": [ [ "source", "site" ], [ "source", "api" ] ]
-               }
+                 "values": [
+                   [ "source", "site" ],
+                   [ "source", "api" ]
+                 ]
+               },
+               {
+                 "name": "logins",
+                 "columns": [ "key", "value"],
+                 "values": [
+                   [ "source", "site" ],
+                   [ "source", "webapi"]
+                 ]
+               },
              ]
            }
         ]
@@ -72,15 +83,12 @@ describe("influxdb response parser", () => {
       var result = this.parser.parse(query, response);
 
       it("should get two responses", () => {
-        expect(_.size(result)).to.be(2);
+        expect(_.size(result)).to.be(3);
         expect(result[0].text).to.be('site');
         expect(result[1].text).to.be('api');
+        expect(result[2].text).to.be('webapi');
       });
     });
-
-
-
-
   });
 
   describe("SHOW FIELD response", () => {

+ 11 - 12
public/app/plugins/panel/dashlist/module.ts

@@ -5,27 +5,26 @@ import config from 'app/core/config';
 import {PanelCtrl} from 'app/plugins/sdk';
 import {impressions} from 'app/features/dashboard/impression_store';
 
- // Set and populate defaults
-var panelDefaults = {
-  query: '',
-  limit: 10,
-  tags: [],
-  recent: false,
-  search: false,
-  starred: true,
-  headings: true,
-};
-
 class DashListCtrl extends PanelCtrl {
   static templateUrl = 'module.html';
 
   groups: any[];
   modes: any[];
 
+  panelDefaults = {
+    query: '',
+    limit: 10,
+    tags: [],
+    recent: false,
+    search: false,
+    starred: true,
+    headings: true,
+  };
+
   /** @ngInject */
   constructor($scope, $injector, private backendSrv) {
     super($scope, $injector);
-    _.defaults(this.panel, panelDefaults);
+    _.defaults(this.panel, this.panelDefaults);
 
     if (this.panel.tag) {
       this.panel.tags = [this.panel.tag];

+ 1 - 1
public/app/plugins/panel/graph/graph.js

@@ -73,7 +73,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
             var legendSeries = _.filter(data, function(series) {
               return series.hideFromLegend(panel.legend) === false;
             });
-            var total = 23 + (22 * legendSeries.length);
+            var total = 23 + (21 * legendSeries.length);
             return Math.min(total, Math.floor(panelHeight/2));
           } else {
             return 26;

+ 1 - 1
public/app/plugins/panel/table/renderer.ts

@@ -30,7 +30,7 @@ export class TableRenderer {
     }
 
     if (_.isArray(v)) {
-      v = v.join(',&nbsp;');
+      v = v.join(', ');
     }
 
     return v;

+ 14 - 12
public/sass/components/_dropdown.scss

@@ -67,18 +67,20 @@
   }
 
   // Links within the dropdown menu
-  > li > a {
-    display: block;
-    padding: 3px 20px 3px 15px;
-    clear: both;
-    font-weight: normal;
-    line-height: $line-height-base;
-    color: $dropdownLinkColor;
-    white-space: nowrap;
-
-    i {
-      padding-right: 5px;
-      color: $link-color-disabled;
+  > li {
+      > a {
+      display: block;
+      padding: 3px 20px 3px 15px;
+      clear: both;
+      font-weight: normal;
+      line-height: $line-height-base;
+      color: $dropdownLinkColor;
+      white-space: nowrap;
+
+      i {
+        padding-right: 5px;
+        color: $link-color-disabled;
+      }
     }
   }
 }

+ 2 - 1
public/sass/components/_panel_graph.scss

@@ -85,7 +85,8 @@
 }
 
 .graph-legend-table {
-  overflow-y: scroll;
+  overflow-y: auto;
+  overflow-x: hidden;
 
   .graph-legend-series {
     display: table-row;

+ 1 - 1
public/test/core/utils/emitter_specs.ts

@@ -24,7 +24,7 @@ describe("Emitter", () => {
       expect(sub2Called).to.be(true);
     });
 
-    it.only('should handle errors', () => {
+    it('should handle errors', () => {
       var events = new Emitter();
       var sub1Called = 0;
       var sub2Called = 0;

+ 6 - 1
public/test/specs/templateSrv-specs.js

@@ -99,6 +99,11 @@ define([
         var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
         expect(target).to.be('this.*.filters');
       });
+
+      it('should not escape custom all value', function() {
+        var target = _templateSrv.replace('this.$test', {}, 'regex');
+        expect(target).to.be('this.*');
+      });
     });
 
     describe('lucene format', function() {
@@ -127,7 +132,7 @@ define([
 
       it('multi value and regex format should render regex string', function() {
         var result = _templateSrv.formatValue(['test.','test2'], 'regex');
-        expect(result).to.be('test\\.|test2');
+        expect(result).to.be('(test\\.|test2)');
       });
 
       it('multi value and pipe should render pipe string', function() {

+ 1 - 1
public/test/specs/templateValuesSrv-specs.js

@@ -280,7 +280,7 @@ define([
       });
 
       it('should add All option with custom value', function() {
-        expect(scenario.variable.options[0].value).to.be('*');
+        expect(scenario.variable.options[0].value).to.be('$__all');
       });
     });
 

+ 14 - 1
tasks/default_task.js

@@ -25,6 +25,19 @@ module.exports = function(grunt) {
     'typescript:build'
   ]);
 
-  grunt.registerTask('test', ['default', 'karma:test']);
+  grunt.registerTask('test', ['default', 'karma:test', 'no-only-tests']);
 
+  grunt.registerTask('no-only-tests', function() {
+    var files = grunt.file.expand('public/**/*_specs\.ts', 'public/**/*_specs\.js');
+
+    files.forEach(function(spec) {
+      var rows = grunt.file.read(spec).split('\n');
+      rows.forEach(function(row) {
+        if (row.indexOf('.only(') > 0) {
+          grunt.log.errorlns(row);
+          grunt.fail.warn('found only statement in test: ' + spec)
+        }
+      });
+    });
+  });
 };