Commit 931bece1 by Torkel Ödegaard

Merge branch 'master' into ui-new-red-green-blue

parents 96281516 c13e302c
......@@ -2,6 +2,7 @@
### Minor
* **Pushover**: Adds support for images in pushover notifier [#10780](https://github.com/grafana/grafana/issues/10780), thx [@jpenalbae](https://github.com/jpenalbae)
* **Graphite/InfluxDB/OpenTSDB**: Fix always take dashboard timezone into consideration when handle custom time ranges [#15284](https://github.com/grafana/grafana/issues/15284)
* **Stackdriver**: Template variables in filters using globbing format [#15182](https://github.com/grafana/grafana/issues/15182)
* **Cloudwatch**: Add `resource_arns` template variable query function [#8207](https://github.com/grafana/grafana/issues/8207), thx [@jeroenvollenbrock](https://github.com/jeroenvollenbrock)
* **Cloudwatch**: Add AWS/Neptune metrics [#14231](https://github.com/grafana/grafana/issues/14231), thx [@tcpatterson](https://github.com/tcpatterson)
......@@ -12,6 +13,7 @@
* **Annotations**: Support PATCH verb in annotations http api [#12546](https://github.com/grafana/grafana/issues/12546), thx [@SamuelToh](https://github.com/SamuelToh)
* **Templating**: Add json formatting to variable interpolation [#15291](https://github.com/grafana/grafana/issues/15291), thx [@mtanda](https://github.com/mtanda)
* **Login**: Anonymous usage stats for token auth [#15288](https://github.com/grafana/grafana/issues/15288)
* **Alerting**: Fixes crash bug when alert notifier folders are missing [#15295](https://github.com/grafana/grafana/issues/15295)
### 6.0.0-beta1 fixes
......@@ -95,7 +97,7 @@
* **Stackdriver**: Fixes issue with data proxy and Authorization header [#14262](https://github.com/grafana/grafana/issues/14262)
* **Units**: fixedUnit for Flow:l/min and mL/min [#14294](https://github.com/grafana/grafana/issues/14294), thx [@flopp999](https://github.com/flopp999).
* **Logging**: Fix for issue where data proxy logged a secret when debug logging was enabled, now redacted. [#14319](https://github.com/grafana/grafana/issues/14319)
* **InfluxDB**: Add support for alerting on InfluxDB queries that use the cumulative_sum function. [#14314](https://github.com/grafana/grafana/pull/14314), thx [@nitti](https://github.com/nitti)
* TSDB**: Fix always take dashboard timezone into consideration when handle custom time ranges**: Add support for alerting on InfluxDB queries that use the cumulative_sum function. [#14314](https://github.com/grafana/grafana/pull/14314), thx [@nitti](https://github.com/nitti)
* **Plugins**: Panel plugins should no receive the panel-initialized event again as usual.
* **Embedded Graphs**: Iframe graph panels should now work as usual. [#14284](https://github.com/grafana/grafana/issues/14284)
* **Postgres**: Improve PostgreSQL Query Editor if using different Schemas, [#14313](
......@@ -1030,7 +1032,7 @@ Pull Request: [#8472](https://github.com/grafana/grafana/pull/8472)
* **Docs**: Added some details about Sessions in Postgres [#7694](https://github.com/grafana/grafana/pull/7694) thx [@rickard-von-essen](https://github.com/rickard-von-essen)
* **Influxdb**: Allow commas in template variables [#7681](https://github.com/grafana/grafana/issues/7681) thx [@thuck](https://github.com/thuck)
* **Cloudwatch**: stop using deprecated session.New() [#7736](https://github.com/grafana/grafana/issues/7736) thx [@mtanda](https://github.com/mtanda)
* **OpenTSDB**: Pass dropcounter rate option if no max counter and no reset value or reset value as 0 is specified [#7743](https://github.com/grafana/grafana/pull/7743) thx [@r4um](https://github.com/r4um)
*TSDB**: Fix always take dashboard timezone into consideration when handle custom time ranges**: Pass dropcounter rate option if no max counter and no reset value or reset value as 0 is specified [#7743](https://github.com/grafana/grafana/pull/7743) thx [@r4um](https://github.com/r4um)
* **Templating**: support full resolution for $interval variable [#7696](https://github.com/grafana/grafana/pull/7696) thx [@mtanda](https://github.com/mtanda)
* **Elasticsearch**: Unique Count on string fields in ElasticSearch [#3536](https://github.com/grafana/grafana/issues/3536), thx [@pyro2927](https://github.com/pyro2927)
* **Templating**: Data source template variable that refers to other variable in regex filter [#6365](https://github.com/grafana/grafana/issues/6365) thx [@rlodge](https://github.com/rlodge)
......
......@@ -64,6 +64,7 @@ RUN mkdir -p "$GF_PATHS_HOME/.aws" && \
useradd -r -u $GF_UID -g grafana grafana && \
mkdir -p "$GF_PATHS_PROVISIONING/datasources" \
"$GF_PATHS_PROVISIONING/dashboards" \
"$GF_PATHS_PROVISIONING/notifiers" \
"$GF_PATHS_LOGS" \
"$GF_PATHS_PLUGINS" \
"$GF_PATHS_DATA" && \
......
......@@ -31,11 +31,16 @@ case "$1" in
cp /usr/share/grafana/conf/ldap.toml /etc/grafana/ldap.toml
fi
if [ ! -f $PROVISIONING_CFG_DIR ]; then
if [ ! -d $PROVISIONING_CFG_DIR ]; then
mkdir -p $PROVISIONING_CFG_DIR/dashboards $PROVISIONING_CFG_DIR/datasources
cp /usr/share/grafana/conf/provisioning/dashboards/sample.yaml $PROVISIONING_CFG_DIR/dashboards/sample.yaml
cp /usr/share/grafana/conf/provisioning/datasources/sample.yaml $PROVISIONING_CFG_DIR/datasources/sample.yaml
fi
fi
if [ ! -d $PROVISIONING_CFG_DIR/notifiers ]; then
mkdir -p $PROVISIONING_CFG_DIR/notifiers
cp /usr/share/grafana/conf/provisioning/notifiers/sample.yaml $PROVISIONING_CFG_DIR/notifiers/sample.yaml
fi
# configuration files should not be modifiable by grafana user, as this can be a security issue
chown -Rh root:$GRAFANA_GROUP /etc/grafana/*
......
......@@ -39,6 +39,7 @@ RUN mkdir -p "$GF_PATHS_HOME/.aws" && \
useradd -r -u $GF_UID -g grafana grafana && \
mkdir -p "$GF_PATHS_PROVISIONING/datasources" \
"$GF_PATHS_PROVISIONING/dashboards" \
"$GF_PATHS_PROVISIONING/notifiers" \
"$GF_PATHS_LOGS" \
"$GF_PATHS_PLUGINS" \
"$GF_PATHS_DATA" && \
......
......@@ -45,11 +45,16 @@ if [ $1 -eq 1 ] ; then
cp /usr/share/grafana/conf/ldap.toml /etc/grafana/ldap.toml
fi
if [ ! -f $PROVISIONING_CFG_DIR ]; then
if [ ! -d $PROVISIONING_CFG_DIR ]; then
mkdir -p $PROVISIONING_CFG_DIR/dashboards $PROVISIONING_CFG_DIR/datasources
cp /usr/share/grafana/conf/provisioning/dashboards/sample.yaml $PROVISIONING_CFG_DIR/dashboards/sample.yaml
cp /usr/share/grafana/conf/provisioning/datasources/sample.yaml $PROVISIONING_CFG_DIR/datasources/sample.yaml
fi
fi
if [ ! -d $PROVISIONING_CFG_DIR/notifiers ]; then
mkdir -p $PROVISIONING_CFG_DIR/notifiers
cp /usr/share/grafana/conf/provisioning/notifiers/sample.yaml $PROVISIONING_CFG_DIR/notifiers/sample.yaml
fi
# Set user permissions on /var/log/grafana, /var/lib/grafana
mkdir -p /var/log/grafana /var/lib/grafana
......
......@@ -54,7 +54,7 @@ func NewDataSourceProxy(ds *m.DataSource, plugin *plugins.DataSourcePlugin, ctx
func newHTTPClient() httpClient {
return &http.Client{
Timeout: time.Duration(setting.DataProxyTimeout) * time.Second,
Timeout: 30 * time.Second,
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
}
}
......
......@@ -59,15 +59,15 @@ func (uss *UsageStatsService) sendUsageStats(oauthProviders map[string]bool) {
metrics["stats.provisioned_dashboards.count"] = statsQuery.Result.ProvisionedDashboards
metrics["stats.snapshots.count"] = statsQuery.Result.Snapshots
metrics["stats.teams.count"] = statsQuery.Result.Teams
metrics["stats.total_sessions.count"] = statsQuery.Result.Sessions
metrics["stats.total_auth_token.count"] = statsQuery.Result.AuthTokens
userCount := statsQuery.Result.Users
avgSessionsPerUser := statsQuery.Result.Sessions
avgAuthTokensPerUser := statsQuery.Result.AuthTokens
if userCount != 0 {
avgSessionsPerUser = avgSessionsPerUser / userCount
avgAuthTokensPerUser = avgAuthTokensPerUser / userCount
}
metrics["stats.avg_sessions_per_user.count"] = avgSessionsPerUser
metrics["stats.avg_auth_token_per_user.count"] = avgAuthTokensPerUser
dsStats := models.GetDataSourceStatsQuery{}
if err := uss.Bus.Dispatch(&dsStats); err != nil {
......
......@@ -45,7 +45,7 @@ func TestMetrics(t *testing.T) {
ProvisionedDashboards: 12,
Snapshots: 13,
Teams: 14,
Sessions: 15,
AuthTokens: 15,
}
getSystemStatsQuery = query
return nil
......@@ -229,8 +229,8 @@ func TestMetrics(t *testing.T) {
So(metrics.Get("stats.provisioned_dashboards.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.ProvisionedDashboards)
So(metrics.Get("stats.snapshots.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Snapshots)
So(metrics.Get("stats.teams.count").MustInt(), ShouldEqual, getSystemStatsQuery.Result.Teams)
So(metrics.Get("stats.total_sessions.count").MustInt64(), ShouldEqual, 15)
So(metrics.Get("stats.avg_sessions_per_user.count").MustInt64(), ShouldEqual, 5)
So(metrics.Get("stats.total_auth_token.count").MustInt64(), ShouldEqual, 15)
So(metrics.Get("stats.avg_auth_token_per_user.count").MustInt64(), ShouldEqual, 5)
So(metrics.Get("stats.ds."+models.DS_ES+".count").MustInt(), ShouldEqual, 9)
So(metrics.Get("stats.ds."+models.DS_PROMETHEUS+".count").MustInt(), ShouldEqual, 10)
......
......@@ -8,6 +8,8 @@ import (
"net/http"
"sync"
"time"
"github.com/grafana/grafana/pkg/setting"
)
type proxyTransportCache struct {
......@@ -57,7 +59,7 @@ func (ds *DataSource) GetHttpTransport() (*http.Transport, error) {
TLSClientConfig: tlsConfig,
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 30 * time.Second,
Timeout: time.Duration(setting.DataProxyTimeout) * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).Dial,
......
......@@ -15,7 +15,7 @@ type SystemStats struct {
FolderPermissions int64
Folders int64
ProvisionedDashboards int64
Sessions int64
AuthTokens int64
}
type DataSourceStats struct {
......
......@@ -59,7 +59,7 @@ func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) {
files, err := ioutil.ReadDir(cr.path)
if err != nil {
cr.log.Error("can't read dashboard provisioning files from directory", "path", cr.path)
cr.log.Error("can't read dashboard provisioning files from directory", "path", cr.path, "error", err)
return dashboards, nil
}
......
......@@ -19,7 +19,7 @@ func (cr *configReader) readConfig(path string) ([]*DatasourcesAsConfig, error)
files, err := ioutil.ReadDir(path)
if err != nil {
cr.log.Error("can't read datasource provisioning files from directory", "path", path)
cr.log.Error("can't read datasource provisioning files from directory", "path", path, "error", err)
return datasources, nil
}
......
......@@ -23,7 +23,7 @@ func (cr *configReader) readConfig(path string) ([]*notificationsAsConfig, error
files, err := ioutil.ReadDir(path)
if err != nil {
cr.log.Error("Can't read alert notification provisioning files from directory", "path", path)
cr.log.Error("Can't read alert notification provisioning files from directory", "path", path, "error", err)
return notifications, nil
}
......
......@@ -75,7 +75,7 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error {
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_provisioning") + `) AS provisioned_dashboards,`)
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_snapshot") + `) AS snapshots,`)
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("team") + `) AS teams,`)
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("user_auth_token") + `) AS sessions`)
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("user_auth_token") + `) AS auth_tokens`)
var stats m.SystemStats
_, err := x.SQL(sb.GetSqlString(), sb.params...).Get(&stats)
......
......@@ -68,7 +68,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
// handle plugin loading & changing of plugin type
if (!this.state.plugin || this.state.plugin.id !== pluginId) {
const plugin = config.panels[pluginId] || getPanelPluginNotFound(pluginId);
let plugin = config.panels[pluginId] || getPanelPluginNotFound(pluginId);
// remember if this is from an angular panel
const fromAngularPanel = this.state.angularPanel != null;
......@@ -81,10 +81,15 @@ export class DashboardPanel extends PureComponent<Props, State> {
}
if (plugin.exports) {
this.setState({ plugin: plugin, angularPanel: null });
this.setState({ plugin, angularPanel: null });
} else {
plugin.exports = await importPluginModule(plugin.module);
this.setState({ plugin: plugin, angularPanel: null });
try {
plugin.exports = await importPluginModule(plugin.module);
} catch (e) {
plugin = getPanelPluginNotFound(pluginId);
}
this.setState({ plugin, angularPanel: null });
}
}
}
......
......@@ -31,8 +31,8 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
this.query = function(options) {
const graphOptions = {
from: this.translateTime(options.rangeRaw.from, false),
until: this.translateTime(options.rangeRaw.to, true),
from: this.translateTime(options.rangeRaw.from, false, options.timezone),
until: this.translateTime(options.rangeRaw.to, true, options.timezone),
targets: options.targets,
format: options.format,
cacheTimeout: options.cacheTimeout || this.cacheTimeout,
......@@ -165,9 +165,9 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
method: 'GET',
url:
'/events/get_data?from=' +
this.translateTime(options.range.from, false) +
this.translateTime(options.range.from, false, options.timezone) +
'&until=' +
this.translateTime(options.range.to, true) +
this.translateTime(options.range.to, true, options.timezone) +
tags,
});
} catch (err) {
......@@ -179,7 +179,7 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
return templateSrv.variableExists(target.target);
};
this.translateTime = (date, roundUp) => {
this.translateTime = (date, roundUp, timezone) => {
if (_.isString(date)) {
if (date === 'now') {
return 'now';
......@@ -189,7 +189,7 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
date = date.replace('M', 'mon');
return date;
}
date = dateMath.parse(date, roundUp);
date = dateMath.parse(date, roundUp, timezone);
}
// graphite' s from filter is exclusive
......@@ -255,8 +255,8 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
};
if (options.range) {
httpOptions.params.from = this.translateTime(options.range.from, false);
httpOptions.params.until = this.translateTime(options.range.to, true);
httpOptions.params.from = this.translateTime(options.range.from, false, options.timezone);
httpOptions.params.until = this.translateTime(options.range.to, true, options.timezone);
}
return this.doGraphiteRequest(httpOptions).then(results => {
......@@ -280,8 +280,8 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
};
if (options.range) {
httpOptions.params.from = this.translateTime(options.range.from, false);
httpOptions.params.until = this.translateTime(options.range.to, true);
httpOptions.params.from = this.translateTime(options.range.from, false, options.timezone);
httpOptions.params.until = this.translateTime(options.range.to, true, options.timezone);
}
return this.doGraphiteRequest(httpOptions).then(results => {
......@@ -305,8 +305,8 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
};
if (options.range) {
httpOptions.params.from = this.translateTime(options.range.from, false);
httpOptions.params.until = this.translateTime(options.range.to, true);
httpOptions.params.from = this.translateTime(options.range.from, false, options.timezone);
httpOptions.params.until = this.translateTime(options.range.to, true, options.timezone);
}
return this.doGraphiteRequest(httpOptions).then(results => {
......@@ -343,8 +343,8 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
httpOptions.params.limit = options.limit;
}
if (options.range) {
httpOptions.params.from = this.translateTime(options.range.from, false);
httpOptions.params.until = this.translateTime(options.range.to, true);
httpOptions.params.from = this.translateTime(options.range.from, false, options.timezone);
httpOptions.params.until = this.translateTime(options.range.to, true, options.timezone);
}
return this.doGraphiteRequest(httpOptions).then(results => {
......@@ -379,8 +379,8 @@ export function GraphiteDatasource(this: any, instanceSettings, $q, backendSrv,
httpOptions.params.limit = options.limit;
}
if (options.range) {
httpOptions.params.from = this.translateTime(options.range.from, false);
httpOptions.params.until = this.translateTime(options.range.to, true);
httpOptions.params.from = this.translateTime(options.range.from, false, options.timezone);
httpOptions.params.until = this.translateTime(options.range.to, true, options.timezone);
}
return this.doGraphiteRequest(httpOptions).then(results => {
......
......@@ -127,7 +127,7 @@ export default class InfluxDatasource {
});
}
const timeFilter = this.getTimeFilter({ rangeRaw: options.rangeRaw });
const timeFilter = this.getTimeFilter({ rangeRaw: options.rangeRaw, timezone: options.timezone });
let query = options.annotation.query.replace('$timeFilter', timeFilter);
query = this.templateSrv.replace(query, null, 'regex');
......@@ -184,7 +184,7 @@ export default class InfluxDatasource {
}
if (options && options.range) {
const timeFilter = this.getTimeFilter({ rangeRaw: options.range });
const timeFilter = this.getTimeFilter({ rangeRaw: options.range, timezone: options.timezone });
query = query.replace('$timeFilter', timeFilter);
}
......@@ -291,8 +291,8 @@ export default class InfluxDatasource {
}
getTimeFilter(options) {
const from = this.getInfluxTime(options.rangeRaw.from, false);
const until = this.getInfluxTime(options.rangeRaw.to, true);
const from = this.getInfluxTime(options.rangeRaw.from, false, options.timezone);
const until = this.getInfluxTime(options.rangeRaw.to, true, options.timezone);
const fromIsAbsolute = from[from.length - 1] === 'ms';
if (until === 'now()' && !fromIsAbsolute) {
......@@ -302,7 +302,7 @@ export default class InfluxDatasource {
return 'time >= ' + from + ' and time <= ' + until;
}
getInfluxTime(date, roundUp) {
getInfluxTime(date, roundUp, timezone) {
if (_.isString(date)) {
if (date === 'now') {
return 'now()';
......@@ -314,7 +314,7 @@ export default class InfluxDatasource {
const unit = parts[2];
return 'now() - ' + amount + unit;
}
date = dateMath.parse(date, roundUp);
date = dateMath.parse(date, roundUp, timezone);
}
return date.valueOf() + 'ms';
......
......@@ -33,8 +33,8 @@ export default class OpenTsDatasource {
// Called once per panel (graph)
query(options) {
const start = this.convertToTSDBTime(options.rangeRaw.from, false);
const end = this.convertToTSDBTime(options.rangeRaw.to, true);
const start = this.convertToTSDBTime(options.rangeRaw.from, false, options.timezone);
const end = this.convertToTSDBTime(options.rangeRaw.to, true, options.timezone);
const qs = [];
_.each(options.targets, target => {
......@@ -86,8 +86,8 @@ export default class OpenTsDatasource {
}
annotationQuery(options) {
const start = this.convertToTSDBTime(options.rangeRaw.from, false);
const end = this.convertToTSDBTime(options.rangeRaw.to, true);
const start = this.convertToTSDBTime(options.rangeRaw.from, false, options.timezone);
const end = this.convertToTSDBTime(options.rangeRaw.to, true, options.timezone);
const qs = [];
const eventList = [];
......@@ -484,12 +484,12 @@ export default class OpenTsDatasource {
});
}
convertToTSDBTime(date, roundUp) {
convertToTSDBTime(date, roundUp, timezone) {
if (date === 'now') {
return null;
}
date = dateMath.parse(date, roundUp);
date = dateMath.parse(date, roundUp, timezone);
return date.valueOf();
}
}
......@@ -71,7 +71,7 @@ $page-bg: $gray-7;
$body-color: $gray-1;
$text-color: $gray-1;
$text-color-strong: $dark-2;
$text-color-weak: $gray-3;
$text-color-weak: $gray-2;
$text-color-faint: $gray-4;
$text-color-emphasis: $dark-5;
......
......@@ -124,7 +124,7 @@ input[type='text'].tight-form-func-param {
&--disabled {
.query-keyword {
color: darken($blue, 20%);
color: $text-color-weak;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment