mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into create-annotations
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
## Minor Enchancements
|
## Minor Enchancements
|
||||||
|
|
||||||
* **Prometheus**: Make Prometheus query field a textarea [#7663](https://github.com/grafana/grafana/issues/7663), thx [@hagen1778](https://github.com/hagen1778)
|
* **Prometheus**: Make Prometheus query field a textarea [#7663](https://github.com/grafana/grafana/issues/7663), thx [@hagen1778](https://github.com/hagen1778)
|
||||||
|
* **Prometheus**: Step parameter changed semantics to min step to reduce the load on Prometheus and rendering in browser [#8073](https://github.com/grafana/grafana/pull/8073), thx [@bobrik](https://github.com/bobrik)
|
||||||
* **Templating**: Should not be possible to create self-referencing (recursive) template variable definitions [#7614](https://github.com/grafana/grafana/issues/7614) thx [@thuck](https://github.com/thuck)
|
* **Templating**: Should not be possible to create self-referencing (recursive) template variable definitions [#7614](https://github.com/grafana/grafana/issues/7614) thx [@thuck](https://github.com/thuck)
|
||||||
* **Cloudwatch**: Correctly obtain IAM roles within ECS container tasks [#7892](https://github.com/grafana/grafana/issues/7892) thx [@gomlgs](https://github.com/gomlgs)
|
* **Cloudwatch**: Correctly obtain IAM roles within ECS container tasks [#7892](https://github.com/grafana/grafana/issues/7892) thx [@gomlgs](https://github.com/gomlgs)
|
||||||
* **Units**: New number format: Scientific notation [#7781](https://github.com/grafana/grafana/issues/7781) thx [@cadnce](https://github.com/cadnce)
|
* **Units**: New number format: Scientific notation [#7781](https://github.com/grafana/grafana/issues/7781) thx [@cadnce](https://github.com/cadnce)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func New(logger string, ctx ...interface{}) Logger {
|
|||||||
func Trace(format string, v ...interface{}) {
|
func Trace(format string, v ...interface{}) {
|
||||||
var message string
|
var message string
|
||||||
if len(v) > 0 {
|
if len(v) > 0 {
|
||||||
message = fmt.Sprintf(format, v)
|
message = fmt.Sprintf(format, v...)
|
||||||
} else {
|
} else {
|
||||||
message = format
|
message = format
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ func Trace(format string, v ...interface{}) {
|
|||||||
func Debug(format string, v ...interface{}) {
|
func Debug(format string, v ...interface{}) {
|
||||||
var message string
|
var message string
|
||||||
if len(v) > 0 {
|
if len(v) > 0 {
|
||||||
message = fmt.Sprintf(format, v)
|
message = fmt.Sprintf(format, v...)
|
||||||
} else {
|
} else {
|
||||||
message = format
|
message = format
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ func Debug2(message string, v ...interface{}) {
|
|||||||
func Info(format string, v ...interface{}) {
|
func Info(format string, v ...interface{}) {
|
||||||
var message string
|
var message string
|
||||||
if len(v) > 0 {
|
if len(v) > 0 {
|
||||||
message = fmt.Sprintf(format, v)
|
message = fmt.Sprintf(format, v...)
|
||||||
} else {
|
} else {
|
||||||
message = format
|
message = format
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ func Info2(message string, v ...interface{}) {
|
|||||||
func Warn(format string, v ...interface{}) {
|
func Warn(format string, v ...interface{}) {
|
||||||
var message string
|
var message string
|
||||||
if len(v) > 0 {
|
if len(v) > 0 {
|
||||||
message = fmt.Sprintf(format, v)
|
message = fmt.Sprintf(format, v...)
|
||||||
} else {
|
} else {
|
||||||
message = format
|
message = format
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ func Warn2(message string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Error(skip int, format string, v ...interface{}) {
|
func Error(skip int, format string, v ...interface{}) {
|
||||||
Root.Error(fmt.Sprintf(format, v))
|
Root.Error(fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Error2(message string, v ...interface{}) {
|
func Error2(message string, v ...interface{}) {
|
||||||
@@ -96,7 +96,7 @@ func Error2(message string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Critical(skip int, format string, v ...interface{}) {
|
func Critical(skip int, format string, v ...interface{}) {
|
||||||
Root.Crit(fmt.Sprintf(format, v))
|
Root.Crit(fmt.Sprintf(format, v...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Fatal(skip int, format string, v ...interface{}) {
|
func Fatal(skip int, format string, v ...interface{}) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initContextWithAuthProxy(ctx *Context) bool {
|
func initContextWithAuthProxy(ctx *Context, orgId int64) bool {
|
||||||
if !setting.AuthProxyEnabled {
|
if !setting.AuthProxyEnabled {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,7 @@ func initContextWithAuthProxy(ctx *Context) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
query := getSignedInUserQueryForProxyAuth(proxyHeaderValue)
|
query := getSignedInUserQueryForProxyAuth(proxyHeaderValue)
|
||||||
|
query.OrgId = orgId
|
||||||
if err := bus.Dispatch(query); err != nil {
|
if err := bus.Dispatch(query); err != nil {
|
||||||
if err != m.ErrUserNotFound {
|
if err != m.ErrUserNotFound {
|
||||||
ctx.Handle(500, "Failed to find user specified in auth proxy header", err)
|
ctx.Handle(500, "Failed to find user specified in auth proxy header", err)
|
||||||
@@ -46,7 +47,7 @@ func initContextWithAuthProxy(ctx *Context) bool {
|
|||||||
ctx.Handle(500, "Failed to create user specified in auth proxy header", err)
|
ctx.Handle(500, "Failed to create user specified in auth proxy header", err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
query = &m.GetSignedInUserQuery{UserId: cmd.Result.Id}
|
query = &m.GetSignedInUserQuery{UserId: cmd.Result.Id, OrgId: orgId}
|
||||||
if err := bus.Dispatch(query); err != nil {
|
if err := bus.Dispatch(query); err != nil {
|
||||||
ctx.Handle(500, "Failed find user after creation", err)
|
ctx.Handle(500, "Failed find user after creation", err)
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -39,6 +39,12 @@ func GetContextHandler() macaron.Handler {
|
|||||||
Logger: log.New("context"),
|
Logger: log.New("context"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orgId := int64(0)
|
||||||
|
orgIdHeader := ctx.Req.Header.Get("X-Grafana-Org-Id")
|
||||||
|
if orgIdHeader != "" {
|
||||||
|
orgId, _ = strconv.ParseInt(orgIdHeader, 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
// the order in which these are tested are important
|
// the order in which these are tested are important
|
||||||
// look for api key in Authorization header first
|
// look for api key in Authorization header first
|
||||||
// then init session and look for userId in session
|
// then init session and look for userId in session
|
||||||
@@ -46,9 +52,9 @@ func GetContextHandler() macaron.Handler {
|
|||||||
// then test if anonymous access is enabled
|
// then test if anonymous access is enabled
|
||||||
if initContextWithRenderAuth(ctx) ||
|
if initContextWithRenderAuth(ctx) ||
|
||||||
initContextWithApiKey(ctx) ||
|
initContextWithApiKey(ctx) ||
|
||||||
initContextWithBasicAuth(ctx) ||
|
initContextWithBasicAuth(ctx, orgId) ||
|
||||||
initContextWithAuthProxy(ctx) ||
|
initContextWithAuthProxy(ctx, orgId) ||
|
||||||
initContextWithUserSessionCookie(ctx) ||
|
initContextWithUserSessionCookie(ctx, orgId) ||
|
||||||
initContextWithAnonymousUser(ctx) {
|
initContextWithAnonymousUser(ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,18 +74,18 @@ func initContextWithAnonymousUser(ctx *Context) bool {
|
|||||||
if err := bus.Dispatch(&orgQuery); err != nil {
|
if err := bus.Dispatch(&orgQuery); err != nil {
|
||||||
log.Error(3, "Anonymous access organization error: '%s': %s", setting.AnonymousOrgName, err)
|
log.Error(3, "Anonymous access organization error: '%s': %s", setting.AnonymousOrgName, err)
|
||||||
return false
|
return false
|
||||||
} else {
|
|
||||||
ctx.IsSignedIn = false
|
|
||||||
ctx.AllowAnonymous = true
|
|
||||||
ctx.SignedInUser = &m.SignedInUser{}
|
|
||||||
ctx.OrgRole = m.RoleType(setting.AnonymousOrgRole)
|
|
||||||
ctx.OrgId = orgQuery.Result.Id
|
|
||||||
ctx.OrgName = orgQuery.Result.Name
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.IsSignedIn = false
|
||||||
|
ctx.AllowAnonymous = true
|
||||||
|
ctx.SignedInUser = &m.SignedInUser{}
|
||||||
|
ctx.OrgRole = m.RoleType(setting.AnonymousOrgRole)
|
||||||
|
ctx.OrgId = orgQuery.Result.Id
|
||||||
|
ctx.OrgName = orgQuery.Result.Name
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func initContextWithUserSessionCookie(ctx *Context) bool {
|
func initContextWithUserSessionCookie(ctx *Context, orgId int64) bool {
|
||||||
// initialize session
|
// initialize session
|
||||||
if err := ctx.Session.Start(ctx); err != nil {
|
if err := ctx.Session.Start(ctx); err != nil {
|
||||||
ctx.Logger.Error("Failed to start session", "error", err)
|
ctx.Logger.Error("Failed to start session", "error", err)
|
||||||
@@ -91,15 +97,15 @@ func initContextWithUserSessionCookie(ctx *Context) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
query := m.GetSignedInUserQuery{UserId: userId}
|
query := m.GetSignedInUserQuery{UserId: userId, OrgId: orgId}
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
ctx.Logger.Error("Failed to get user with id", "userId", userId)
|
ctx.Logger.Error("Failed to get user with id", "userId", userId)
|
||||||
return false
|
return false
|
||||||
} else {
|
|
||||||
ctx.SignedInUser = query.Result
|
|
||||||
ctx.IsSignedIn = true
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.SignedInUser = query.Result
|
||||||
|
ctx.IsSignedIn = true
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func initContextWithApiKey(ctx *Context) bool {
|
func initContextWithApiKey(ctx *Context) bool {
|
||||||
@@ -114,30 +120,31 @@ func initContextWithApiKey(ctx *Context) bool {
|
|||||||
ctx.JsonApiErr(401, "Invalid API key", err)
|
ctx.JsonApiErr(401, "Invalid API key", err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch key
|
// fetch key
|
||||||
keyQuery := m.GetApiKeyByNameQuery{KeyName: decoded.Name, OrgId: decoded.OrgId}
|
keyQuery := m.GetApiKeyByNameQuery{KeyName: decoded.Name, OrgId: decoded.OrgId}
|
||||||
if err := bus.Dispatch(&keyQuery); err != nil {
|
if err := bus.Dispatch(&keyQuery); err != nil {
|
||||||
ctx.JsonApiErr(401, "Invalid API key", err)
|
ctx.JsonApiErr(401, "Invalid API key", err)
|
||||||
return true
|
return true
|
||||||
} else {
|
}
|
||||||
apikey := keyQuery.Result
|
|
||||||
|
|
||||||
// validate api key
|
apikey := keyQuery.Result
|
||||||
if !apikeygen.IsValid(decoded, apikey.Key) {
|
|
||||||
ctx.JsonApiErr(401, "Invalid API key", err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.IsSignedIn = true
|
// validate api key
|
||||||
ctx.SignedInUser = &m.SignedInUser{}
|
if !apikeygen.IsValid(decoded, apikey.Key) {
|
||||||
ctx.OrgRole = apikey.Role
|
ctx.JsonApiErr(401, "Invalid API key", err)
|
||||||
ctx.ApiKeyId = apikey.Id
|
|
||||||
ctx.OrgId = apikey.OrgId
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.IsSignedIn = true
|
||||||
|
ctx.SignedInUser = &m.SignedInUser{}
|
||||||
|
ctx.OrgRole = apikey.Role
|
||||||
|
ctx.ApiKeyId = apikey.Id
|
||||||
|
ctx.OrgId = apikey.OrgId
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func initContextWithBasicAuth(ctx *Context) bool {
|
func initContextWithBasicAuth(ctx *Context, orgId int64) bool {
|
||||||
|
|
||||||
if !setting.BasicAuthEnabled {
|
if !setting.BasicAuthEnabled {
|
||||||
return false
|
return false
|
||||||
@@ -168,15 +175,15 @@ func initContextWithBasicAuth(ctx *Context) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
query := m.GetSignedInUserQuery{UserId: user.Id}
|
query := m.GetSignedInUserQuery{UserId: user.Id, OrgId: orgId}
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
ctx.JsonApiErr(401, "Authentication error", err)
|
ctx.JsonApiErr(401, "Authentication error", err)
|
||||||
return true
|
return true
|
||||||
} else {
|
|
||||||
ctx.SignedInUser = query.Result
|
|
||||||
ctx.IsSignedIn = true
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.SignedInUser = query.Result
|
||||||
|
ctx.IsSignedIn = true
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle handles and logs error by given status.
|
// Handle handles and logs error by given status.
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ type GetSignedInUserQuery struct {
|
|||||||
UserId int64
|
UserId int64
|
||||||
Login string
|
Login string
|
||||||
Email string
|
Email string
|
||||||
|
OrgId int64
|
||||||
Result *SignedInUser
|
Result *SignedInUser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package sqlstore
|
package sqlstore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -273,7 +274,7 @@ func SetUsingOrg(cmd *m.SetUsingOrgCommand) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !valid {
|
if !valid {
|
||||||
return fmt.Errorf("user does not belong ot org")
|
return fmt.Errorf("user does not belong to org")
|
||||||
}
|
}
|
||||||
|
|
||||||
return inTransaction(func(sess *xorm.Session) error {
|
return inTransaction(func(sess *xorm.Session) error {
|
||||||
@@ -319,19 +320,24 @@ func GetUserOrgList(query *m.GetUserOrgListQuery) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetSignedInUser(query *m.GetSignedInUserQuery) error {
|
func GetSignedInUser(query *m.GetSignedInUserQuery) error {
|
||||||
|
orgId := "u.org_id"
|
||||||
|
if query.OrgId > 0 {
|
||||||
|
orgId = strconv.FormatInt(query.OrgId, 10)
|
||||||
|
}
|
||||||
|
|
||||||
var rawSql = `SELECT
|
var rawSql = `SELECT
|
||||||
u.id as user_id,
|
u.id as user_id,
|
||||||
u.is_admin as is_grafana_admin,
|
u.is_admin as is_grafana_admin,
|
||||||
u.email as email,
|
u.email as email,
|
||||||
u.login as login,
|
u.login as login,
|
||||||
u.name as name,
|
u.name as name,
|
||||||
u.help_flags1 as help_flags1,
|
u.help_flags1 as help_flags1,
|
||||||
org.name as org_name,
|
org.name as org_name,
|
||||||
org_user.role as org_role,
|
org_user.role as org_role,
|
||||||
org.id as org_id
|
org.id as org_id
|
||||||
FROM ` + dialect.Quote("user") + ` as u
|
FROM ` + dialect.Quote("user") + ` as u
|
||||||
LEFT OUTER JOIN org_user on org_user.org_id = u.org_id and org_user.user_id = u.id
|
LEFT OUTER JOIN org_user on org_user.org_id = ` + orgId + ` and org_user.user_id = u.id
|
||||||
LEFT OUTER JOIN org on org.id = u.org_id `
|
LEFT OUTER JOIN org on org.id = org_user.org_id `
|
||||||
|
|
||||||
sess := x.Table("user")
|
sess := x.Table("user")
|
||||||
if query.UserId > 0 {
|
if query.UserId > 0 {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ export class BackendSrv {
|
|||||||
inFlightRequests = {};
|
inFlightRequests = {};
|
||||||
HTTP_REQUEST_CANCELLED = -1;
|
HTTP_REQUEST_CANCELLED = -1;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(private $http, private alertSrv, private $rootScope, private $q, private $timeout) {
|
constructor(private $http, private alertSrv, private $rootScope, private $q, private $timeout, private contextSrv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
get(url, params?) {
|
get(url, params?) {
|
||||||
@@ -63,12 +63,18 @@ export class BackendSrv {
|
|||||||
|
|
||||||
request(options) {
|
request(options) {
|
||||||
options.retry = options.retry || 0;
|
options.retry = options.retry || 0;
|
||||||
var requestIsLocal = options.url.indexOf('/') === 0;
|
var requestIsLocal = !options.url.match(/^http/);
|
||||||
var firstAttempt = options.retry === 0;
|
var firstAttempt = options.retry === 0;
|
||||||
|
|
||||||
if (requestIsLocal && !options.hasSubUrl) {
|
if (requestIsLocal) {
|
||||||
options.url = config.appSubUrl + options.url;
|
if (this.contextSrv.user && this.contextSrv.user.orgId) {
|
||||||
options.hasSubUrl = true;
|
options.headers = options.headers || {};
|
||||||
|
options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.url.indexOf("/") === 0) {
|
||||||
|
options.url = options.url.substring(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.$http(options).then(results => {
|
return this.$http(options).then(results => {
|
||||||
@@ -125,16 +131,23 @@ export class BackendSrv {
|
|||||||
this.addCanceler(requestId, canceler);
|
this.addCanceler(requestId, canceler);
|
||||||
}
|
}
|
||||||
|
|
||||||
var requestIsLocal = options.url.indexOf('/') === 0;
|
var requestIsLocal = !options.url.match(/^http/);
|
||||||
var firstAttempt = options.retry === 0;
|
var firstAttempt = options.retry === 0;
|
||||||
|
|
||||||
if (requestIsLocal && !options.hasSubUrl && options.retry === 0) {
|
if (requestIsLocal) {
|
||||||
options.url = config.appSubUrl + options.url;
|
if (this.contextSrv.user && this.contextSrv.user.orgId) {
|
||||||
}
|
options.headers = options.headers || {};
|
||||||
|
options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId;
|
||||||
|
}
|
||||||
|
|
||||||
if (requestIsLocal && options.headers && options.headers.Authorization) {
|
if (options.url.indexOf("/") === 0) {
|
||||||
options.headers['X-DS-Authorization'] = options.headers.Authorization;
|
options.url = options.url.substring(1);
|
||||||
delete options.headers.Authorization;
|
}
|
||||||
|
|
||||||
|
if (options.headers && options.headers.Authorization) {
|
||||||
|
options.headers['X-DS-Authorization'] = options.headers.Authorization;
|
||||||
|
delete options.headers.Authorization;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.$http(options).catch(err => {
|
return this.$http(options).catch(err => {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
var intervalFactor = target.intervalFactor || 1;
|
var intervalFactor = target.intervalFactor || 1;
|
||||||
target.step = query.step = this.calculateInterval(interval, intervalFactor);
|
target.step = query.step = this.calculateInterval(interval, intervalFactor);
|
||||||
var range = Math.ceil(end - start);
|
var range = Math.ceil(end - start);
|
||||||
target.step = query.step = this.adjustStep(query.step, range);
|
target.step = query.step = this.adjustStep(query.step, this.intervalSeconds(options.interval), range);
|
||||||
queries.push(query);
|
queries.push(query);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,13 +122,13 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.adjustStep = function(step, range) {
|
this.adjustStep = function(step, autoStep, range) {
|
||||||
// Prometheus drop query if range/step > 11000
|
// Prometheus drop query if range/step > 11000
|
||||||
// calibrate step if it is too big
|
// calibrate step if it is too big
|
||||||
if (step !== 0 && range / step > 11000) {
|
if (step !== 0 && range / step > 11000) {
|
||||||
return Math.ceil(range / 11000);
|
return Math.ceil(range / 11000);
|
||||||
}
|
}
|
||||||
return step;
|
return Math.max(step, autoStep);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.performTimeSeriesQuery = function(query, start, end) {
|
this.performTimeSeriesQuery = function(query, start, end) {
|
||||||
@@ -189,7 +189,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
var end = this.getPrometheusTime(options.range.to, true);
|
var end = this.getPrometheusTime(options.range.to, true);
|
||||||
var query = {
|
var query = {
|
||||||
expr: interpolated,
|
expr: interpolated,
|
||||||
step: this.adjustStep(kbn.interval_to_seconds(step), Math.ceil(end - start)) + 's'
|
step: this.adjustStep(kbn.interval_to_seconds(step), 0, Math.ceil(end - start)) + 's'
|
||||||
};
|
};
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -229,6 +229,10 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.calculateInterval = function(interval, intervalFactor) {
|
this.calculateInterval = function(interval, intervalFactor) {
|
||||||
|
return Math.ceil(this.intervalSeconds(interval) * intervalFactor);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.intervalSeconds = function(interval) {
|
||||||
var m = interval.match(durationSplitRegexp);
|
var m = interval.match(durationSplitRegexp);
|
||||||
var dur = moment.duration(parseInt(m[1]), m[2]);
|
var dur = moment.duration(parseInt(m[1]), m[2]);
|
||||||
var sec = dur.asSeconds();
|
var sec = dur.asSeconds();
|
||||||
@@ -236,7 +240,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
sec = 1;
|
sec = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math.ceil(sec * intervalFactor);
|
return sec;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.transformMetricData = function(md, options, start, end) {
|
this.transformMetricData = function(md, options, start, end) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</input>
|
</input>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label width-5">Step</label>
|
<label class="gf-form-label">Min step</label>
|
||||||
<input type="text" class="gf-form-input max-width-5" ng-model="ctrl.target.interval"
|
<input type="text" class="gf-form-input max-width-5" ng-model="ctrl.target.interval"
|
||||||
data-placement="right"
|
data-placement="right"
|
||||||
spellcheck='false'
|
spellcheck='false'
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class GettingStartedPanelCtrl extends PanelCtrl {
|
|||||||
icon: 'icon-gf icon-gf-users',
|
icon: 'icon-gf icon-gf-users',
|
||||||
href: 'org/users?gettingstarted',
|
href: 'org/users?gettingstarted',
|
||||||
check: () => {
|
check: () => {
|
||||||
return this.backendSrv.get('api/org/users').then(res => {
|
return this.backendSrv.get('/api/org/users').then(res => {
|
||||||
return res.length > 1;
|
return res.length > 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ class GettingStartedPanelCtrl extends PanelCtrl {
|
|||||||
icon: 'icon-gf icon-gf-apps',
|
icon: 'icon-gf icon-gf-apps',
|
||||||
href: 'https://grafana.com/plugins?utm_source=grafana_getting_started',
|
href: 'https://grafana.com/plugins?utm_source=grafana_getting_started',
|
||||||
check: () => {
|
check: () => {
|
||||||
return this.backendSrv.get('api/plugins', {embedded: 0, core: 0}).then(plugins => {
|
return this.backendSrv.get('/api/plugins', {embedded: 0, core: 0}).then(plugins => {
|
||||||
return plugins.length > 0;
|
return plugins.length > 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user