Merge pull request #12712 from grafana/cp-5.2.2

Cherry-picks for 5.2.2
This commit is contained in:
Marcus Efraimsson
2018-07-25 13:17:28 +02:00
committed by GitHub
17 changed files with 157 additions and 60 deletions
+3 -1
View File
@@ -60,7 +60,8 @@ datasources:
url: localhost:5432
database: grafana
user: grafana
password: password
secureJsonData:
password: password
jsonData:
sslmode: "disable"
@@ -71,3 +72,4 @@ datasources:
authType: credentials
defaultRegion: eu-west-2
+1 -1
View File
@@ -4,7 +4,7 @@
"company": "Grafana Labs"
},
"name": "grafana",
"version": "5.2.1",
"version": "5.2.2",
"repository": {
"type": "git",
"url": "http://github.com/grafana/grafana.git"
+4 -4
View File
@@ -50,7 +50,7 @@ func TestAlertRuleExtraction(t *testing.T) {
So(err, ShouldBeNil)
Convey("Extractor should not modify the original json", func() {
dashJson, err := simplejson.NewJson([]byte(json))
dashJson, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
dash := m.NewDashboardFromJson(dashJson)
@@ -79,7 +79,7 @@ func TestAlertRuleExtraction(t *testing.T) {
Convey("Parsing and validating dashboard containing graphite alerts", func() {
dashJson, err := simplejson.NewJson([]byte(json))
dashJson, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
dash := m.NewDashboardFromJson(dashJson)
@@ -143,7 +143,7 @@ func TestAlertRuleExtraction(t *testing.T) {
panelWithoutId, err := ioutil.ReadFile("./test-data/panels-missing-id.json")
So(err, ShouldBeNil)
dashJson, err := simplejson.NewJson([]byte(panelWithoutId))
dashJson, err := simplejson.NewJson(panelWithoutId)
So(err, ShouldBeNil)
dash := m.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1)
@@ -159,7 +159,7 @@ func TestAlertRuleExtraction(t *testing.T) {
panelWithIdZero, err := ioutil.ReadFile("./test-data/panel-with-id-0.json")
So(err, ShouldBeNil)
dashJson, err := simplejson.NewJson([]byte(panelWithIdZero))
dashJson, err := simplejson.NewJson(panelWithIdZero)
So(err, ShouldBeNil)
dash := m.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1)
@@ -32,7 +32,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
So(json.Get("size").MustInt(500), ShouldEqual, 0)
So(json.Get("sort").Interface(), ShouldBeNil)
@@ -81,7 +81,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
So(json.Get("size").MustInt(0), ShouldEqual, 200)
@@ -124,7 +124,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
scriptFields, err := json.Get("script_fields").Map()
@@ -163,7 +163,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
So(json.Get("aggs").MustMap(), ShouldHaveLength, 2)
@@ -200,7 +200,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
So(json.Get("aggs").MustMap(), ShouldHaveLength, 1)
@@ -251,7 +251,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
topAggOne := json.GetPath("aggs", "1")
@@ -300,7 +300,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
topAgg := json.GetPath("aggs", "1")
@@ -364,7 +364,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
termsAgg := json.GetPath("aggs", "1")
@@ -419,7 +419,7 @@ func TestSearchRequest(t *testing.T) {
Convey("When marshal to JSON should generate correct json", func() {
body, err := json.Marshal(sr)
So(err, ShouldBeNil)
json, err := simplejson.NewJson([]byte(body))
json, err := simplejson.NewJson(body)
So(err, ShouldBeNil)
scriptFields, err := json.Get("script_fields").Map()
+4 -4
View File
@@ -525,7 +525,7 @@ func TestMSSQL(t *testing.T) {
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 1)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float64(float32(tInitial.Unix())))*1e3)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float32(tInitial.Unix()))*1e3)
})
Convey("When doing a metric query using epoch (float32 nullable) as time column and value column (float32 nullable) should return metric with time in milliseconds", func() {
@@ -547,7 +547,7 @@ func TestMSSQL(t *testing.T) {
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 1)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float64(float32(tInitial.Unix())))*1e3)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float32(tInitial.Unix()))*1e3)
})
Convey("When doing a metric query grouping by time and select metric column should return correct series", func() {
@@ -924,7 +924,7 @@ func TestMSSQL(t *testing.T) {
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0].(int64), ShouldEqual, int64(dt.Unix()*1000))
So(columns[0].(int64), ShouldEqual, dt.Unix()*1000)
})
Convey("When doing an annotation query with a time column in epoch second format (int) should return ms", func() {
@@ -954,7 +954,7 @@ func TestMSSQL(t *testing.T) {
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0].(int64), ShouldEqual, int64(dt.Unix()*1000))
So(columns[0].(int64), ShouldEqual, dt.Unix()*1000)
})
Convey("When doing an annotation query with a time column in epoch millisecond format should return ms", func() {
+5 -5
View File
@@ -132,8 +132,8 @@ func TestMySQL(t *testing.T) {
So(column[7].(float64), ShouldEqual, 1.11)
So(column[8].(float64), ShouldEqual, 2.22)
So(*column[9].(*float32), ShouldEqual, 3.33)
So(column[10].(time.Time), ShouldHappenWithin, time.Duration(10*time.Second), time.Now())
So(column[11].(time.Time), ShouldHappenWithin, time.Duration(10*time.Second), time.Now())
So(column[10].(time.Time), ShouldHappenWithin, 10*time.Second, time.Now())
So(column[11].(time.Time), ShouldHappenWithin, 10*time.Second, time.Now())
So(column[12].(string), ShouldEqual, "11:11:11")
So(column[13].(int64), ShouldEqual, 2018)
So(*column[14].(*[]byte), ShouldHaveSameTypeAs, []byte{1})
@@ -571,7 +571,7 @@ func TestMySQL(t *testing.T) {
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 1)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float64(float32(tInitial.Unix())))*1e3)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float32(tInitial.Unix()))*1e3)
})
Convey("When doing a metric query using epoch (float32 nullable) as time column and value column (float32 nullable) should return metric with time in milliseconds", func() {
@@ -593,7 +593,7 @@ func TestMySQL(t *testing.T) {
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 1)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float64(float32(tInitial.Unix())))*1e3)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float32(tInitial.Unix()))*1e3)
})
Convey("When doing a metric query grouping by time and select metric column should return correct series", func() {
@@ -810,7 +810,7 @@ func TestMySQL(t *testing.T) {
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0].(int64), ShouldEqual, int64(dt.Unix()*1000))
So(columns[0].(int64), ShouldEqual, dt.Unix()*1000)
})
Convey("When doing an annotation query with a time column in epoch millisecond format should return ms", func() {
+4 -4
View File
@@ -504,7 +504,7 @@ func TestPostgres(t *testing.T) {
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 1)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float64(float32(tInitial.Unix())))*1e3)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float32(tInitial.Unix()))*1e3)
})
Convey("When doing a metric query using epoch (float32 nullable) as time column and value column (float32 nullable) should return metric with time in milliseconds", func() {
@@ -526,7 +526,7 @@ func TestPostgres(t *testing.T) {
So(queryResult.Error, ShouldBeNil)
So(len(queryResult.Series), ShouldEqual, 1)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float64(float32(tInitial.Unix())))*1e3)
So(queryResult.Series[0].Points[0][1].Float64, ShouldEqual, float64(float32(tInitial.Unix()))*1e3)
})
Convey("When doing a metric query grouping by time and select metric column should return correct series", func() {
@@ -713,7 +713,7 @@ func TestPostgres(t *testing.T) {
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0].(int64), ShouldEqual, int64(dt.Unix()*1000))
So(columns[0].(int64), ShouldEqual, dt.Unix()*1000)
})
Convey("When doing an annotation query with a time column in epoch second format (int) should return ms", func() {
@@ -743,7 +743,7 @@ func TestPostgres(t *testing.T) {
columns := queryResult.Tables[0].Rows[0]
//Should be in milliseconds
So(columns[0].(int64), ShouldEqual, int64(dt.Unix()*1000))
So(columns[0].(int64), ShouldEqual, dt.Unix()*1000)
})
Convey("When doing an annotation query with a time column in epoch millisecond format should return ms", func() {
+1
View File
@@ -68,6 +68,7 @@ func (e *DefaultSqlEngine) InitEngine(driverName string, dsInfo *models.DataSour
engine.SetMaxOpenConns(10)
engine.SetMaxIdleConns(10)
engineCache.versions[dsInfo.Id] = dsInfo.Version
engineCache.cache[dsInfo.Id] = engine
e.XormEngine = engine
+14
View File
@@ -119,6 +119,20 @@ describe('TimeSeries', function() {
series.getFlotPairs('null');
expect(series.stats.avg).toBe(null);
});
it('calculates timeStep', function() {
series = new TimeSeries({
datapoints: [[null, 1], [null, 2], [null, 3]],
});
series.getFlotPairs('null');
expect(series.stats.timeStep).toBe(1);
series = new TimeSeries({
datapoints: [[0, 1530529290], [0, 1530529305], [0, 1530529320]],
});
series.getFlotPairs('null');
expect(series.stats.timeStep).toBe(15);
});
});
describe('When checking if ms resolution is needed', function() {
+9 -8
View File
@@ -41,20 +41,20 @@ function dashLink($compile, $sanitize, linkSrv) {
elem.html(template);
$compile(elem.contents())(scope);
var anchor = elem.find('a');
var icon = elem.find('i');
var span = elem.find('span');
function update() {
var linkInfo = linkSrv.getAnchorInfo(link);
const anchor = elem.find('a');
const span = elem.find('span');
span.text(linkInfo.title);
if (!link.asDropdown) {
anchor.attr('href', linkInfo.href);
sanitizeAnchor();
}
elem.find('a').attr('data-placement', 'bottom');
anchor.attr('data-placement', 'bottom');
// tooltip
elem.find('a').tooltip({
anchor.tooltip({
title: $sanitize(scope.link.tooltip),
html: true,
container: 'body',
@@ -62,12 +62,13 @@ function dashLink($compile, $sanitize, linkSrv) {
}
function sanitizeAnchor() {
const anchor = elem.find('a');
const anchorSanitized = $sanitize(anchor.parent().html());
anchor.parent().html(anchorSanitized);
}
icon.attr('class', 'fa fa-fw ' + scope.link.icon);
anchor.attr('target', scope.link.target);
elem.find('i').attr('class', 'fa fa-fw ' + scope.link.icon);
elem.find('a').attr('target', scope.link.target);
// fix for menus on the far right
if (link.asDropdown && scope.$last) {
@@ -222,7 +222,7 @@ class MetricsPanelCtrl extends PanelCtrl {
// and add built in variables interval and interval_ms
var scopedVars = Object.assign({}, this.panel.scopedVars, {
__interval: { text: this.interval, value: this.interval },
__interval_ms: { text: this.intervalMs, value: this.intervalMs },
__interval_ms: { text: String(this.intervalMs), value: String(this.intervalMs) },
});
var metricsQuery = {
+1 -1
View File
@@ -56,7 +56,7 @@ System.config({
css: 'vendor/plugin-css/css.js',
},
meta: {
'plugin*': {
'/*': {
esModule: true,
authorization: true,
loader: 'plugin-loader',
@@ -162,8 +162,8 @@ export class PrometheusDatasource {
format: activeTargets[index].format,
step: queries[index].step,
legendFormat: activeTargets[index].legendFormat,
start: start,
end: end,
start: queries[index].start,
end: queries[index].end,
query: queries[index].expr,
responseListLength: responseList.length,
responseIndex: index,
@@ -196,7 +196,7 @@ export class PrometheusDatasource {
interval = adjustedInterval;
scopedVars = Object.assign({}, options.scopedVars, {
__interval: { text: interval + 's', value: interval + 's' },
__interval_ms: { text: interval * 1000, value: interval * 1000 },
__interval_ms: { text: String(interval * 1000), value: String(interval * 1000) },
});
}
query.step = interval;
@@ -68,7 +68,7 @@ describe('PrometheusDatasource', () => {
ctx.query = {
range: { from: moment(1443454528000), to: moment(1443454528000) },
targets: [{ expr: 'test{job="testjob"}', format: 'heatmap', legendFormat: '{{le}}' }],
interval: '60s',
interval: '1s',
};
});
@@ -452,7 +452,7 @@ describe('PrometheusDatasource', function() {
interval: '10s',
scopedVars: {
__interval: { text: '10s', value: '10s' },
__interval_ms: { text: 10 * 1000, value: 10 * 1000 },
__interval_ms: { text: String(10 * 1000), value: String(10 * 1000) },
},
};
var urlExpected =
@@ -463,8 +463,8 @@ describe('PrometheusDatasource', function() {
expect(query.scopedVars.__interval.text).to.be('10s');
expect(query.scopedVars.__interval.value).to.be('10s');
expect(query.scopedVars.__interval_ms.text).to.be(10 * 1000);
expect(query.scopedVars.__interval_ms.value).to.be(10 * 1000);
expect(query.scopedVars.__interval_ms.text).to.be(String(10 * 1000));
expect(query.scopedVars.__interval_ms.value).to.be(String(10 * 1000));
});
it('should be min interval when it is greater than auto interval', function() {
var query = {
@@ -479,7 +479,7 @@ describe('PrometheusDatasource', function() {
interval: '5s',
scopedVars: {
__interval: { text: '5s', value: '5s' },
__interval_ms: { text: 5 * 1000, value: 5 * 1000 },
__interval_ms: { text: String(5 * 1000), value: String(5 * 1000) },
},
};
var urlExpected =
@@ -490,8 +490,8 @@ describe('PrometheusDatasource', function() {
expect(query.scopedVars.__interval.text).to.be('5s');
expect(query.scopedVars.__interval.value).to.be('5s');
expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000);
expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
expect(query.scopedVars.__interval_ms.text).to.be(String(5 * 1000));
expect(query.scopedVars.__interval_ms.value).to.be(String(5 * 1000));
});
it('should account for intervalFactor', function() {
var query = {
@@ -507,7 +507,7 @@ describe('PrometheusDatasource', function() {
interval: '10s',
scopedVars: {
__interval: { text: '10s', value: '10s' },
__interval_ms: { text: 10 * 1000, value: 10 * 1000 },
__interval_ms: { text: String(10 * 1000), value: String(10 * 1000) },
},
};
var urlExpected =
@@ -518,8 +518,8 @@ describe('PrometheusDatasource', function() {
expect(query.scopedVars.__interval.text).to.be('10s');
expect(query.scopedVars.__interval.value).to.be('10s');
expect(query.scopedVars.__interval_ms.text).to.be(10 * 1000);
expect(query.scopedVars.__interval_ms.value).to.be(10 * 1000);
expect(query.scopedVars.__interval_ms.text).to.be(String(10 * 1000));
expect(query.scopedVars.__interval_ms.value).to.be(String(10 * 1000));
});
it('should be interval * intervalFactor when greater than min interval', function() {
var query = {
@@ -535,7 +535,7 @@ describe('PrometheusDatasource', function() {
interval: '5s',
scopedVars: {
__interval: { text: '5s', value: '5s' },
__interval_ms: { text: 5 * 1000, value: 5 * 1000 },
__interval_ms: { text: String(5 * 1000), value: String(5 * 1000) },
},
};
var urlExpected =
@@ -546,8 +546,8 @@ describe('PrometheusDatasource', function() {
expect(query.scopedVars.__interval.text).to.be('5s');
expect(query.scopedVars.__interval.value).to.be('5s');
expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000);
expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
expect(query.scopedVars.__interval_ms.text).to.be(String(5 * 1000));
expect(query.scopedVars.__interval_ms.value).to.be(String(5 * 1000));
});
it('should be min interval when greater than interval * intervalFactor', function() {
var query = {
@@ -563,7 +563,7 @@ describe('PrometheusDatasource', function() {
interval: '5s',
scopedVars: {
__interval: { text: '5s', value: '5s' },
__interval_ms: { text: 5 * 1000, value: 5 * 1000 },
__interval_ms: { text: String(5 * 1000), value: String(5 * 1000) },
},
};
var urlExpected =
@@ -574,8 +574,8 @@ describe('PrometheusDatasource', function() {
expect(query.scopedVars.__interval.text).to.be('5s');
expect(query.scopedVars.__interval.value).to.be('5s');
expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000);
expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
expect(query.scopedVars.__interval_ms.text).to.be(String(5 * 1000));
expect(query.scopedVars.__interval_ms.value).to.be(String(5 * 1000));
});
it('should be determined by the 11000 data points limit, accounting for intervalFactor', function() {
var query = {
@@ -590,7 +590,7 @@ describe('PrometheusDatasource', function() {
interval: '5s',
scopedVars: {
__interval: { text: '5s', value: '5s' },
__interval_ms: { text: 5 * 1000, value: 5 * 1000 },
__interval_ms: { text: String(5 * 1000), value: String(5 * 1000) },
},
};
var end = 7 * 24 * 60 * 60;
@@ -609,8 +609,8 @@ describe('PrometheusDatasource', function() {
expect(query.scopedVars.__interval.text).to.be('5s');
expect(query.scopedVars.__interval.value).to.be('5s');
expect(query.scopedVars.__interval_ms.text).to.be(5 * 1000);
expect(query.scopedVars.__interval_ms.value).to.be(5 * 1000);
expect(query.scopedVars.__interval_ms.text).to.be(String(5 * 1000));
expect(query.scopedVars.__interval_ms.value).to.be(String(5 * 1000));
});
});
});
@@ -127,4 +127,82 @@ describe('Prometheus Result Transformer', () => {
]);
});
});
describe('When resultFormat is time series', () => {
it('should transform matrix into timeseries', () => {
const response = {
status: 'success',
data: {
resultType: 'matrix',
result: [
{
metric: { __name__: 'test', job: 'testjob' },
values: [[0, '10'], [1, '10'], [2, '0']],
},
],
},
};
let result = [];
let options = {
format: 'timeseries',
start: 0,
end: 2,
};
ctx.resultTransformer.transform(result, { data: response }, options);
expect(result).toEqual([{ target: 'test{job="testjob"}', datapoints: [[10, 0], [10, 1000], [0, 2000]] }]);
});
it('should fill timeseries with null values', () => {
const response = {
status: 'success',
data: {
resultType: 'matrix',
result: [
{
metric: { __name__: 'test', job: 'testjob' },
values: [[1, '10'], [2, '0']],
},
],
},
};
let result = [];
let options = {
format: 'timeseries',
step: 1,
start: 0,
end: 2,
};
ctx.resultTransformer.transform(result, { data: response }, options);
expect(result).toEqual([{ target: 'test{job="testjob"}', datapoints: [[null, 0], [10, 1000], [0, 2000]] }]);
});
it('should align null values with step', () => {
const response = {
status: 'success',
data: {
resultType: 'matrix',
result: [
{
metric: { __name__: 'test', job: 'testjob' },
values: [[4, '10'], [8, '10']],
},
],
},
};
let result = [];
let options = {
format: 'timeseries',
step: 2,
start: 0,
end: 8,
};
ctx.resultTransformer.transform(result, { data: response }, options);
expect(result).toEqual([
{ target: 'test{job="testjob"}', datapoints: [[null, 0], [null, 2000], [10, 4000], [null, 6000], [10, 8000]] },
]);
});
});
});
+1
View File
@@ -16,6 +16,7 @@ div.flot-text {
height: 100%;
&--solo {
margin: 0;
.panel-container {
border: none;
z-index: $zindex-sidemenu + 1;