Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d2836657c4 |
@@ -8,29 +8,68 @@ import (
|
||||
|
||||
const defaultDataProxyRowLimit = int64(1000000)
|
||||
|
||||
type ProxySettings struct {
|
||||
SendUserHeader bool
|
||||
Logging bool
|
||||
Timeout int
|
||||
DialTimeout int
|
||||
KeepAlive int
|
||||
TLSHandshakeTimeout int
|
||||
ExpectContinueTimeout int
|
||||
MaxConnsPerHost int
|
||||
MaxIdleConns int
|
||||
IdleConnTimeout int
|
||||
ResponseLimit int64
|
||||
RowLimit int64
|
||||
UserAgent string
|
||||
}
|
||||
|
||||
func readDataProxySettings(iniFile *ini.File, cfg *Cfg) error {
|
||||
dataproxy := iniFile.Section("dataproxy")
|
||||
cfg.SendUserHeader = dataproxy.Key("send_user_header").MustBool(false)
|
||||
cfg.DataProxyLogging = dataproxy.Key("logging").MustBool(false)
|
||||
cfg.DataProxyTimeout = dataproxy.Key("timeout").MustInt(30)
|
||||
cfg.DataProxyDialTimeout = dataproxy.Key("dialTimeout").MustInt(10)
|
||||
cfg.DataProxyKeepAlive = dataproxy.Key("keep_alive_seconds").MustInt(30)
|
||||
cfg.DataProxyTLSHandshakeTimeout = dataproxy.Key("tls_handshake_timeout_seconds").MustInt(10)
|
||||
cfg.DataProxyExpectContinueTimeout = dataproxy.Key("expect_continue_timeout_seconds").MustInt(1)
|
||||
cfg.DataProxyMaxConnsPerHost = dataproxy.Key("max_conns_per_host").MustInt(0)
|
||||
cfg.DataProxyMaxIdleConns = dataproxy.Key("max_idle_connections").MustInt()
|
||||
cfg.DataProxyIdleConnTimeout = dataproxy.Key("idle_conn_timeout_seconds").MustInt(90)
|
||||
cfg.ResponseLimit = dataproxy.Key("response_limit").MustInt64(0)
|
||||
cfg.DataProxyRowLimit = dataproxy.Key("row_limit").MustInt64(defaultDataProxyRowLimit)
|
||||
cfg.DataProxyUserAgent = dataproxy.Key("user_agent").String()
|
||||
proxy := ReadDataProxySettings(iniFile)
|
||||
|
||||
if cfg.DataProxyUserAgent == "" {
|
||||
cfg.DataProxyUserAgent = fmt.Sprintf("Grafana/%s", BuildVersion)
|
||||
}
|
||||
|
||||
if cfg.DataProxyRowLimit <= 0 {
|
||||
cfg.DataProxyRowLimit = defaultDataProxyRowLimit
|
||||
}
|
||||
cfg.SendUserHeader = proxy.SendUserHeader
|
||||
cfg.DataProxyLogging = proxy.Logging
|
||||
cfg.DataProxyTimeout = proxy.Timeout
|
||||
cfg.DataProxyDialTimeout = proxy.DialTimeout
|
||||
cfg.DataProxyKeepAlive = proxy.KeepAlive
|
||||
cfg.DataProxyTLSHandshakeTimeout = proxy.TLSHandshakeTimeout
|
||||
cfg.DataProxyExpectContinueTimeout = proxy.ExpectContinueTimeout
|
||||
cfg.DataProxyMaxConnsPerHost = proxy.MaxConnsPerHost
|
||||
cfg.DataProxyMaxIdleConns = proxy.MaxIdleConns
|
||||
cfg.DataProxyIdleConnTimeout = proxy.IdleConnTimeout
|
||||
cfg.ResponseLimit = proxy.ResponseLimit
|
||||
cfg.DataProxyRowLimit = proxy.RowLimit
|
||||
cfg.DataProxyUserAgent = proxy.UserAgent
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ReadDataProxySettings(iniFile *ini.File) ProxySettings {
|
||||
section := iniFile.Section("dataproxy")
|
||||
|
||||
proxy := ProxySettings{
|
||||
SendUserHeader: section.Key("send_user_header").MustBool(false),
|
||||
Logging: section.Key("logging").MustBool(false),
|
||||
Timeout: section.Key("timeout").MustInt(30),
|
||||
DialTimeout: section.Key("dialTimeout").MustInt(10),
|
||||
KeepAlive: section.Key("keep_alive_seconds").MustInt(30),
|
||||
TLSHandshakeTimeout: section.Key("tls_handshake_timeout_seconds").MustInt(10),
|
||||
ExpectContinueTimeout: section.Key("expect_continue_timeout_seconds").MustInt(1),
|
||||
MaxConnsPerHost: section.Key("max_conns_per_host").MustInt(0),
|
||||
MaxIdleConns: section.Key("max_idle_connections").MustInt(),
|
||||
IdleConnTimeout: section.Key("idle_conn_timeout_seconds").MustInt(90),
|
||||
ResponseLimit: section.Key("response_limit").MustInt64(0),
|
||||
RowLimit: section.Key("row_limit").MustInt64(defaultDataProxyRowLimit),
|
||||
UserAgent: section.Key("user_agent").String(),
|
||||
}
|
||||
|
||||
if proxy.UserAgent == "" {
|
||||
proxy.UserAgent = fmt.Sprintf("Grafana/%s", BuildVersion)
|
||||
}
|
||||
|
||||
if proxy.RowLimit <= 0 {
|
||||
proxy.RowLimit = defaultDataProxyRowLimit
|
||||
}
|
||||
|
||||
return proxy
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func TestReadDataProxySettings(t *testing.T) {
|
||||
t.Run("should use default values when ini is empty", func(t *testing.T) {
|
||||
f := ini.Empty()
|
||||
proxy := ReadDataProxySettings(f)
|
||||
|
||||
assertDataProxyDefaults(t, proxy)
|
||||
})
|
||||
|
||||
t.Run("should use default values when section exists with no values", func(t *testing.T) {
|
||||
f := ini.Empty()
|
||||
_, err := f.NewSection("dataproxy")
|
||||
require.NoError(t, err)
|
||||
|
||||
proxy := ReadDataProxySettings(f)
|
||||
|
||||
assertDataProxyDefaults(t, proxy)
|
||||
})
|
||||
|
||||
t.Run("should use custom values when section has overrides", func(t *testing.T) {
|
||||
iniFile := `
|
||||
[dataproxy]
|
||||
send_user_header = true
|
||||
logging = true
|
||||
timeout = 60
|
||||
dialTimeout = 20
|
||||
keep_alive_seconds = 60
|
||||
tls_handshake_timeout_seconds = 20
|
||||
expect_continue_timeout_seconds = 2
|
||||
max_conns_per_host = 100
|
||||
max_idle_connections = 50
|
||||
idle_conn_timeout_seconds = 120
|
||||
response_limit = 5242880
|
||||
row_limit = 500000
|
||||
user_agent = CustomAgent/1.0
|
||||
`
|
||||
f, err := ini.Load([]byte(iniFile))
|
||||
require.NoError(t, err)
|
||||
|
||||
proxy := ReadDataProxySettings(f)
|
||||
|
||||
assert.True(t, proxy.SendUserHeader)
|
||||
assert.True(t, proxy.Logging)
|
||||
assert.Equal(t, 60, proxy.Timeout)
|
||||
assert.Equal(t, 20, proxy.DialTimeout)
|
||||
assert.Equal(t, 60, proxy.KeepAlive)
|
||||
assert.Equal(t, 20, proxy.TLSHandshakeTimeout)
|
||||
assert.Equal(t, 2, proxy.ExpectContinueTimeout)
|
||||
assert.Equal(t, 100, proxy.MaxConnsPerHost)
|
||||
assert.Equal(t, 50, proxy.MaxIdleConns)
|
||||
assert.Equal(t, 120, proxy.IdleConnTimeout)
|
||||
assert.Equal(t, int64(5242880), proxy.ResponseLimit)
|
||||
assert.Equal(t, int64(500000), proxy.RowLimit)
|
||||
assert.Equal(t, "CustomAgent/1.0", proxy.UserAgent)
|
||||
})
|
||||
|
||||
t.Run("should set default row limit when row_limit is zero", func(t *testing.T) {
|
||||
iniFile := `
|
||||
[dataproxy]
|
||||
row_limit = 0
|
||||
`
|
||||
f, err := ini.Load([]byte(iniFile))
|
||||
require.NoError(t, err)
|
||||
|
||||
proxy := ReadDataProxySettings(f)
|
||||
|
||||
assert.Equal(t, defaultDataProxyRowLimit, proxy.RowLimit)
|
||||
})
|
||||
|
||||
t.Run("should set default row limit when row_limit is negative", func(t *testing.T) {
|
||||
iniFile := `
|
||||
[dataproxy]
|
||||
row_limit = -100
|
||||
`
|
||||
f, err := ini.Load([]byte(iniFile))
|
||||
require.NoError(t, err)
|
||||
|
||||
proxy := ReadDataProxySettings(f)
|
||||
|
||||
assert.Equal(t, defaultDataProxyRowLimit, proxy.RowLimit)
|
||||
})
|
||||
}
|
||||
|
||||
func assertDataProxyDefaults(t *testing.T, proxy ProxySettings) {
|
||||
t.Helper()
|
||||
|
||||
assert.False(t, proxy.SendUserHeader)
|
||||
assert.False(t, proxy.Logging)
|
||||
assert.Equal(t, 30, proxy.Timeout)
|
||||
assert.Equal(t, 10, proxy.DialTimeout)
|
||||
assert.Equal(t, 30, proxy.KeepAlive)
|
||||
assert.Equal(t, 10, proxy.TLSHandshakeTimeout)
|
||||
assert.Equal(t, 1, proxy.ExpectContinueTimeout)
|
||||
assert.Equal(t, 0, proxy.MaxConnsPerHost)
|
||||
assert.Equal(t, 0, proxy.MaxIdleConns)
|
||||
assert.Equal(t, 90, proxy.IdleConnTimeout)
|
||||
assert.Equal(t, int64(0), proxy.ResponseLimit)
|
||||
assert.Equal(t, defaultDataProxyRowLimit, proxy.RowLimit)
|
||||
|
||||
// UserAgent should match "Grafana/{version}" pattern
|
||||
assert.Regexp(t, regexp.MustCompile(`^Grafana/.*`), proxy.UserAgent)
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package setting
|
||||
|
||||
import "gopkg.in/ini.v1"
|
||||
|
||||
type OrgQuota struct {
|
||||
User int64 `target:"org_user"`
|
||||
DataSource int64 `target:"data_source"`
|
||||
@@ -32,34 +34,42 @@ type QuotaSettings struct {
|
||||
}
|
||||
|
||||
func (cfg *Cfg) readQuotaSettings() {
|
||||
iniFile := cfg.Raw
|
||||
quota := ReadQuotaSettings(iniFile)
|
||||
// set global defaults.
|
||||
quota := cfg.Raw.Section("quota")
|
||||
cfg.Quota.Enabled = quota.Key("enabled").MustBool(false)
|
||||
cfg.Quota = quota
|
||||
}
|
||||
|
||||
func ReadQuotaSettings(iniFile *ini.File) QuotaSettings {
|
||||
section := iniFile.Section("quota")
|
||||
var quota QuotaSettings
|
||||
quota.Enabled = section.Key("enabled").MustBool(false)
|
||||
|
||||
// per ORG Limits
|
||||
cfg.Quota.Org = OrgQuota{
|
||||
User: quota.Key("org_user").MustInt64(10),
|
||||
DataSource: quota.Key("org_data_source").MustInt64(10),
|
||||
Dashboard: quota.Key("org_dashboard").MustInt64(10),
|
||||
ApiKey: quota.Key("org_api_key").MustInt64(10),
|
||||
AlertRule: quota.Key("org_alert_rule").MustInt64(100),
|
||||
quota.Org = OrgQuota{
|
||||
User: section.Key("org_user").MustInt64(10),
|
||||
DataSource: section.Key("org_data_source").MustInt64(10),
|
||||
Dashboard: section.Key("org_dashboard").MustInt64(10),
|
||||
ApiKey: section.Key("org_api_key").MustInt64(10),
|
||||
AlertRule: section.Key("org_alert_rule").MustInt64(100),
|
||||
}
|
||||
|
||||
// per User limits
|
||||
cfg.Quota.User = UserQuota{
|
||||
Org: quota.Key("user_org").MustInt64(10),
|
||||
quota.User = UserQuota{
|
||||
Org: section.Key("user_org").MustInt64(10),
|
||||
}
|
||||
|
||||
// Global Limits
|
||||
cfg.Quota.Global = GlobalQuota{
|
||||
User: quota.Key("global_user").MustInt64(-1),
|
||||
Org: quota.Key("global_org").MustInt64(-1),
|
||||
DataSource: quota.Key("global_data_source").MustInt64(-1),
|
||||
Dashboard: quota.Key("global_dashboard").MustInt64(-1),
|
||||
ApiKey: quota.Key("global_api_key").MustInt64(-1),
|
||||
Session: quota.Key("global_session").MustInt64(-1),
|
||||
File: quota.Key("global_file").MustInt64(-1),
|
||||
AlertRule: quota.Key("global_alert_rule").MustInt64(-1),
|
||||
Correlations: quota.Key("global_correlations").MustInt64(-1),
|
||||
quota.Global = GlobalQuota{
|
||||
User: section.Key("global_user").MustInt64(-1),
|
||||
Org: section.Key("global_org").MustInt64(-1),
|
||||
DataSource: section.Key("global_data_source").MustInt64(-1),
|
||||
Dashboard: section.Key("global_dashboard").MustInt64(-1),
|
||||
ApiKey: section.Key("global_api_key").MustInt64(-1),
|
||||
Session: section.Key("global_session").MustInt64(-1),
|
||||
File: section.Key("global_file").MustInt64(-1),
|
||||
AlertRule: section.Key("global_alert_rule").MustInt64(-1),
|
||||
Correlations: section.Key("global_correlations").MustInt64(-1),
|
||||
}
|
||||
return quota
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func TestReadQuotaSettings(t *testing.T) {
|
||||
t.Run("should use custom values when section has overrides", func(t *testing.T) {
|
||||
iniFile := `
|
||||
[quota]
|
||||
enabled = true
|
||||
|
||||
# Org quotas
|
||||
org_user = 20
|
||||
org_data_source = 30
|
||||
org_dashboard = 40
|
||||
org_api_key = 50
|
||||
org_alert_rule = 200
|
||||
|
||||
# User quotas
|
||||
user_org = 5
|
||||
|
||||
# Global quotas
|
||||
global_user = 1000
|
||||
global_org = 500
|
||||
global_data_source = 2000
|
||||
global_dashboard = 3000
|
||||
global_api_key = 100
|
||||
global_session = 10000
|
||||
global_file = 500
|
||||
global_alert_rule = 5000
|
||||
global_correlations = 250
|
||||
`
|
||||
f, err := ini.Load([]byte(iniFile))
|
||||
require.NoError(t, err)
|
||||
|
||||
quota := ReadQuotaSettings(f)
|
||||
|
||||
// Enabled should be true
|
||||
assert.True(t, quota.Enabled)
|
||||
|
||||
// Org quotas should have custom values
|
||||
assert.Equal(t, int64(20), quota.Org.User)
|
||||
assert.Equal(t, int64(30), quota.Org.DataSource)
|
||||
assert.Equal(t, int64(40), quota.Org.Dashboard)
|
||||
assert.Equal(t, int64(50), quota.Org.ApiKey)
|
||||
assert.Equal(t, int64(200), quota.Org.AlertRule)
|
||||
|
||||
// User quotas should have custom values
|
||||
assert.Equal(t, int64(5), quota.User.Org)
|
||||
|
||||
// Global quotas should have custom values
|
||||
assert.Equal(t, int64(1000), quota.Global.User)
|
||||
assert.Equal(t, int64(500), quota.Global.Org)
|
||||
assert.Equal(t, int64(2000), quota.Global.DataSource)
|
||||
assert.Equal(t, int64(3000), quota.Global.Dashboard)
|
||||
assert.Equal(t, int64(100), quota.Global.ApiKey)
|
||||
assert.Equal(t, int64(10000), quota.Global.Session)
|
||||
assert.Equal(t, int64(500), quota.Global.File)
|
||||
assert.Equal(t, int64(5000), quota.Global.AlertRule)
|
||||
assert.Equal(t, int64(250), quota.Global.Correlations)
|
||||
})
|
||||
|
||||
t.Run("should use default values when ini is empty", func(t *testing.T) {
|
||||
f := ini.Empty()
|
||||
quota := ReadQuotaSettings(f)
|
||||
|
||||
assertDefaults(t, quota)
|
||||
})
|
||||
|
||||
t.Run("should use default values when section exists with no values", func(t *testing.T) {
|
||||
f := ini.Empty()
|
||||
_, err := f.NewSection("quota")
|
||||
require.NoError(t, err)
|
||||
|
||||
quota := ReadQuotaSettings(f)
|
||||
|
||||
assertDefaults(t, quota)
|
||||
})
|
||||
}
|
||||
|
||||
func assertDefaults(t *testing.T, quota QuotaSettings) {
|
||||
t.Helper()
|
||||
|
||||
// Enabled should be false by default
|
||||
assert.False(t, quota.Enabled)
|
||||
|
||||
// Org quotas should have default values
|
||||
assert.Equal(t, int64(10), quota.Org.User)
|
||||
assert.Equal(t, int64(10), quota.Org.DataSource)
|
||||
assert.Equal(t, int64(10), quota.Org.Dashboard)
|
||||
assert.Equal(t, int64(10), quota.Org.ApiKey)
|
||||
assert.Equal(t, int64(100), quota.Org.AlertRule)
|
||||
|
||||
// User quotas should have default values
|
||||
assert.Equal(t, int64(10), quota.User.Org)
|
||||
|
||||
// Global quotas should have default values (-1 means unlimited)
|
||||
assert.Equal(t, int64(-1), quota.Global.User)
|
||||
assert.Equal(t, int64(-1), quota.Global.Org)
|
||||
assert.Equal(t, int64(-1), quota.Global.DataSource)
|
||||
assert.Equal(t, int64(-1), quota.Global.Dashboard)
|
||||
assert.Equal(t, int64(-1), quota.Global.ApiKey)
|
||||
assert.Equal(t, int64(-1), quota.Global.Session)
|
||||
assert.Equal(t, int64(-1), quota.Global.File)
|
||||
assert.Equal(t, int64(-1), quota.Global.AlertRule)
|
||||
assert.Equal(t, int64(-1), quota.Global.Correlations)
|
||||
}
|
||||
Reference in New Issue
Block a user