grafana/pkg/setting/setting.go

773 lines
22 KiB
Go
Raw Normal View History

2014-10-05 09:50:04 -05:00
// Copyright 2014 Unknwon
// Copyright 2014 Torkel Ödegaard
2014-10-04 06:33:20 -05:00
package setting
import (
"bytes"
"fmt"
2014-10-04 06:33:20 -05:00
"net/url"
"os"
"path"
"path/filepath"
"regexp"
2014-10-04 06:33:20 -05:00
"runtime"
"strings"
"gopkg.in/ini.v1"
2014-10-05 09:50:04 -05:00
"github.com/go-macaron/session"
"time"
2015-02-05 03:37:13 -06:00
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/util"
2014-10-04 06:33:20 -05:00
)
type Scheme string
const (
HTTP Scheme = "http"
HTTPS Scheme = "https"
SOCKET Scheme = "socket"
DEFAULT_HTTP_ADDR string = "0.0.0.0"
2014-10-04 06:33:20 -05:00
)
2014-12-16 05:04:08 -06:00
const (
DEV string = "development"
PROD string = "production"
TEST string = "test"
)
2014-10-04 06:33:20 -05:00
var (
// App settings.
Remove redundancy in variable declarations (golint) This commit fixes the following golint warnings: pkg/api/avatar/avatar.go:229:12: should omit type *http.Client from declaration of var client; it will be inferred from the right-hand side pkg/login/brute_force_login_protection.go:13:26: should omit type time.Duration from declaration of var loginAttemptsWindow; it will be inferred from the right-hand side pkg/metrics/graphitebridge/graphite.go:58:26: should omit type []string from declaration of var metricCategoryPrefix; it will be inferred from the right-hand side pkg/metrics/graphitebridge/graphite.go:69:22: should omit type []string from declaration of var trimMetricPrefix; it will be inferred from the right-hand side pkg/models/alert.go:37:36: should omit type error from declaration of var ErrCannotChangeStateOnPausedAlert; it will be inferred from the right-hand side pkg/models/alert.go:38:36: should omit type error from declaration of var ErrRequiresNewState; it will be inferred from the right-hand side pkg/models/datasource.go:61:28: should omit type map[string]bool from declaration of var knownDatasourcePlugins; it will be inferred from the right-hand side pkg/plugins/update_checker.go:16:13: should omit type http.Client from declaration of var httpClient; it will be inferred from the right-hand side pkg/services/alerting/engine.go:103:24: should omit type time.Duration from declaration of var unfinishedWorkTimeout; it will be inferred from the right-hand side pkg/services/alerting/engine.go:105:19: should omit type time.Duration from declaration of var alertTimeout; it will be inferred from the right-hand side pkg/services/alerting/engine.go:106:19: should omit type int from declaration of var alertMaxAttempts; it will be inferred from the right-hand side pkg/services/alerting/notifier.go:143:23: should omit type map[string]*NotifierPlugin from declaration of var notifierFactories; it will be inferred from the right-hand side pkg/services/alerting/rule.go:136:24: should omit type map[string]ConditionFactory from declaration of var conditionFactories; it will be inferred from the right-hand side pkg/services/alerting/conditions/evaluator.go:12:15: should omit type []string from declaration of var defaultTypes; it will be inferred from the right-hand side pkg/services/alerting/conditions/evaluator.go:13:15: should omit type []string from declaration of var rangedTypes; it will be inferred from the right-hand side pkg/services/alerting/notifiers/opsgenie.go:44:19: should omit type string from declaration of var opsgenieAlertURL; it will be inferred from the right-hand side pkg/services/alerting/notifiers/pagerduty.go:43:23: should omit type string from declaration of var pagerdutyEventApiUrl; it will be inferred from the right-hand side pkg/services/alerting/notifiers/telegram.go:21:17: should omit type string from declaration of var telegramApiUrl; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:11:24: should omit type string from declaration of var simpleDashboardConfig; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:12:24: should omit type string from declaration of var oldVersion; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:13:24: should omit type string from declaration of var brokenConfigs; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/file_reader.go:22:30: should omit type time.Duration from declaration of var checkDiskForChangesInterval; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/file_reader.go:24:23: should omit type error from declaration of var ErrFolderNameMissing; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:15:34: should omit type string from declaration of var twoDatasourcesConfig; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:16:34: should omit type string from declaration of var twoDatasourcesConfigPurgeOthers; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:17:34: should omit type string from declaration of var doubleDatasourcesConfig; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:18:34: should omit type string from declaration of var allProperties; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:19:34: should omit type string from declaration of var versionZero; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:20:34: should omit type string from declaration of var brokenYaml; it will be inferred from the right-hand side pkg/services/sqlstore/stats.go:16:25: should omit type time.Duration from declaration of var activeUserTimeLimit; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/mysql_dialect.go:69:14: should omit type bool from declaration of var hasLen1; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/mysql_dialect.go:70:14: should omit type bool from declaration of var hasLen2; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/postgres_dialect.go:95:14: should omit type bool from declaration of var hasLen1; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/postgres_dialect.go:96:14: should omit type bool from declaration of var hasLen2; it will be inferred from the right-hand side pkg/setting/setting.go:42:15: should omit type string from declaration of var Env; it will be inferred from the right-hand side pkg/setting/setting.go:161:18: should omit type bool from declaration of var LdapAllowSignup; it will be inferred from the right-hand side pkg/setting/setting.go:473:30: should omit type bool from declaration of var skipStaticRootValidation; it will be inferred from the right-hand side pkg/tsdb/interval.go:14:21: should omit type time.Duration from declaration of var defaultMinInterval; it will be inferred from the right-hand side pkg/tsdb/interval.go:15:21: should omit type time.Duration from declaration of var year; it will be inferred from the right-hand side pkg/tsdb/interval.go:16:21: should omit type time.Duration from declaration of var day; it will be inferred from the right-hand side pkg/tsdb/cloudwatch/credentials.go:26:24: should omit type map[string]cache from declaration of var awsCredentialCache; it will be inferred from the right-hand side pkg/tsdb/influxdb/query.go:15:27: should omit type *regexp.Regexp from declaration of var regexpOperatorPattern; it will be inferred from the right-hand side pkg/tsdb/influxdb/query.go:16:27: should omit type *regexp.Regexp from declaration of var regexpMeasurementPattern; it will be inferred from the right-hand side pkg/tsdb/mssql/mssql_test.go:25:14: should omit type string from declaration of var serverIP; it will be inferred from the right-hand side
2018-04-27 15:14:36 -05:00
Env = DEV
AppUrl string
AppSubUrl string
InstanceName string
2014-10-04 06:33:20 -05:00
// build
BuildVersion string
BuildCommit string
BuildStamp int64
IsEnterprise bool
ApplicationName string
// Paths
LogsPath string
HomePath string
DataPath string
PluginsPath string
CustomInitPath = "conf/custom.ini"
2014-10-04 06:33:20 -05:00
// Log settings.
LogModes []string
2015-04-19 02:29:08 -05:00
LogConfigs []util.DynMap
2014-10-04 06:33:20 -05:00
// Http server options
Protocol Scheme
Domain string
HttpAddr, HttpPort string
SshPort int
CertFile, KeyFile string
SocketPath string
2014-10-05 09:50:04 -05:00
RouterLogging bool
2017-01-11 09:51:46 -06:00
DataProxyLogging bool
2014-10-05 09:50:04 -05:00
StaticRootPath string
EnableGzip bool
EnforceDomain bool
2014-10-05 09:50:04 -05:00
// Security settings.
2018-01-26 03:41:41 -06:00
SecretKey string
LogInRememberDays int
CookieUserName string
CookieRememberName string
DisableGravatar bool
EmailCodeValidMinutes int
DataProxyWhiteList map[string]bool
DisableBruteForceLoginProtection bool
// Snapshots
ExternalSnapshotUrl string
ExternalSnapshotName string
ExternalEnabled bool
SnapShotRemoveExpired bool
// Dashboard history
DashboardVersionsToKeep int
// User settings
2017-07-31 07:39:33 -05:00
AllowUserSignUp bool
AllowUserOrgCreate bool
AutoAssignOrg bool
AutoAssignOrgId int
2017-07-31 07:39:33 -05:00
AutoAssignOrgRole string
VerifyEmailEnabled bool
LoginHint string
DefaultTheme string
DisableLoginForm bool
DisableSignoutMenu bool
SignoutRedirectUrl string
2017-07-31 07:39:33 -05:00
ExternalUserMngLinkUrl string
ExternalUserMngLinkName string
ExternalUserMngInfo string
ViewersCanEdit bool
// Http auth
2015-01-27 08:45:27 -06:00
AdminUser string
AdminPassword string
AnonymousEnabled bool
AnonymousOrgName string
AnonymousOrgRole string
// Auth proxy settings
AuthProxyEnabled bool
AuthProxyHeaderName string
AuthProxyHeaderProperty string
AuthProxyAutoSignUp bool
AuthProxyLdapSyncTtl int
AuthProxyWhitelist string
AuthProxyHeaders map[string]string
// Basic Auth
BasicAuthEnabled bool
// Plugin settings
PluginAppsSkipVerifyTLS bool
2014-10-05 09:50:04 -05:00
// Session settings.
SessionOptions session.Options
SessionConnMaxLifetime int64
2014-10-04 06:33:20 -05:00
// Global setting objects.
Raw *ini.File
2014-10-04 06:33:20 -05:00
ConfRootPath string
IsWindows bool
2014-10-06 14:31:54 -05:00
// for logging purposes
configFiles []string
appliedCommandLineProperties []string
appliedEnvOverrides []string
2015-03-22 14:14:00 -05:00
ReportingEnabled bool
CheckForUpdates bool
GoogleAnalyticsId string
GoogleTagManagerId string
2015-06-04 02:34:42 -05:00
// LDAP
LdapEnabled bool
LdapConfigFile string
Remove redundancy in variable declarations (golint) This commit fixes the following golint warnings: pkg/api/avatar/avatar.go:229:12: should omit type *http.Client from declaration of var client; it will be inferred from the right-hand side pkg/login/brute_force_login_protection.go:13:26: should omit type time.Duration from declaration of var loginAttemptsWindow; it will be inferred from the right-hand side pkg/metrics/graphitebridge/graphite.go:58:26: should omit type []string from declaration of var metricCategoryPrefix; it will be inferred from the right-hand side pkg/metrics/graphitebridge/graphite.go:69:22: should omit type []string from declaration of var trimMetricPrefix; it will be inferred from the right-hand side pkg/models/alert.go:37:36: should omit type error from declaration of var ErrCannotChangeStateOnPausedAlert; it will be inferred from the right-hand side pkg/models/alert.go:38:36: should omit type error from declaration of var ErrRequiresNewState; it will be inferred from the right-hand side pkg/models/datasource.go:61:28: should omit type map[string]bool from declaration of var knownDatasourcePlugins; it will be inferred from the right-hand side pkg/plugins/update_checker.go:16:13: should omit type http.Client from declaration of var httpClient; it will be inferred from the right-hand side pkg/services/alerting/engine.go:103:24: should omit type time.Duration from declaration of var unfinishedWorkTimeout; it will be inferred from the right-hand side pkg/services/alerting/engine.go:105:19: should omit type time.Duration from declaration of var alertTimeout; it will be inferred from the right-hand side pkg/services/alerting/engine.go:106:19: should omit type int from declaration of var alertMaxAttempts; it will be inferred from the right-hand side pkg/services/alerting/notifier.go:143:23: should omit type map[string]*NotifierPlugin from declaration of var notifierFactories; it will be inferred from the right-hand side pkg/services/alerting/rule.go:136:24: should omit type map[string]ConditionFactory from declaration of var conditionFactories; it will be inferred from the right-hand side pkg/services/alerting/conditions/evaluator.go:12:15: should omit type []string from declaration of var defaultTypes; it will be inferred from the right-hand side pkg/services/alerting/conditions/evaluator.go:13:15: should omit type []string from declaration of var rangedTypes; it will be inferred from the right-hand side pkg/services/alerting/notifiers/opsgenie.go:44:19: should omit type string from declaration of var opsgenieAlertURL; it will be inferred from the right-hand side pkg/services/alerting/notifiers/pagerduty.go:43:23: should omit type string from declaration of var pagerdutyEventApiUrl; it will be inferred from the right-hand side pkg/services/alerting/notifiers/telegram.go:21:17: should omit type string from declaration of var telegramApiUrl; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:11:24: should omit type string from declaration of var simpleDashboardConfig; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:12:24: should omit type string from declaration of var oldVersion; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:13:24: should omit type string from declaration of var brokenConfigs; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/file_reader.go:22:30: should omit type time.Duration from declaration of var checkDiskForChangesInterval; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/file_reader.go:24:23: should omit type error from declaration of var ErrFolderNameMissing; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:15:34: should omit type string from declaration of var twoDatasourcesConfig; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:16:34: should omit type string from declaration of var twoDatasourcesConfigPurgeOthers; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:17:34: should omit type string from declaration of var doubleDatasourcesConfig; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:18:34: should omit type string from declaration of var allProperties; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:19:34: should omit type string from declaration of var versionZero; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:20:34: should omit type string from declaration of var brokenYaml; it will be inferred from the right-hand side pkg/services/sqlstore/stats.go:16:25: should omit type time.Duration from declaration of var activeUserTimeLimit; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/mysql_dialect.go:69:14: should omit type bool from declaration of var hasLen1; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/mysql_dialect.go:70:14: should omit type bool from declaration of var hasLen2; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/postgres_dialect.go:95:14: should omit type bool from declaration of var hasLen1; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/postgres_dialect.go:96:14: should omit type bool from declaration of var hasLen2; it will be inferred from the right-hand side pkg/setting/setting.go:42:15: should omit type string from declaration of var Env; it will be inferred from the right-hand side pkg/setting/setting.go:161:18: should omit type bool from declaration of var LdapAllowSignup; it will be inferred from the right-hand side pkg/setting/setting.go:473:30: should omit type bool from declaration of var skipStaticRootValidation; it will be inferred from the right-hand side pkg/tsdb/interval.go:14:21: should omit type time.Duration from declaration of var defaultMinInterval; it will be inferred from the right-hand side pkg/tsdb/interval.go:15:21: should omit type time.Duration from declaration of var year; it will be inferred from the right-hand side pkg/tsdb/interval.go:16:21: should omit type time.Duration from declaration of var day; it will be inferred from the right-hand side pkg/tsdb/cloudwatch/credentials.go:26:24: should omit type map[string]cache from declaration of var awsCredentialCache; it will be inferred from the right-hand side pkg/tsdb/influxdb/query.go:15:27: should omit type *regexp.Regexp from declaration of var regexpOperatorPattern; it will be inferred from the right-hand side pkg/tsdb/influxdb/query.go:16:27: should omit type *regexp.Regexp from declaration of var regexpMeasurementPattern; it will be inferred from the right-hand side pkg/tsdb/mssql/mssql_test.go:25:14: should omit type string from declaration of var serverIP; it will be inferred from the right-hand side
2018-04-27 15:14:36 -05:00
LdapAllowSignup = true
2015-07-10 04:10:48 -05:00
2015-09-10 12:47:33 -05:00
// QUOTA
Quota QuotaSettings
// Alerting
AlertingEnabled bool
ExecuteAlerts bool
AlertingErrorOrTimeout string
AlertingNoDataOrNullValues string
2018-04-27 04:39:14 -05:00
// Explore UI
ExploreEnabled bool
// logger
logger log.Logger
// Grafana.NET URL
GrafanaComUrl string
// S3 temp image store
S3TempImageStoreBucketUrl string
S3TempImageStoreAccessKey string
S3TempImageStoreSecretKey string
ImageUploadProvider string
2014-10-04 06:33:20 -05:00
)
type Cfg struct {
Raw *ini.File
// Paths
ProvisioningPath string
// SMTP email settings
Smtp SmtpSettings
// Rendering
ImagesDir string
PhantomDir string
RendererUrl string
RendererCallbackUrl string
RendererLimit int
RendererLimitAlerting int
DisableBruteForceLoginProtection bool
TempDataLifetime time.Duration
MetricsEndpointEnabled bool
}
type CommandLineArgs struct {
Config string
HomePath string
Args []string
}
2014-10-04 06:33:20 -05:00
func init() {
IsWindows = runtime.GOOS == "windows"
logger = log.New("settings")
2015-01-01 08:29:10 -06:00
}
2014-10-04 06:33:20 -05:00
func parseAppUrlAndSubUrl(section *ini.Section) (string, string) {
appUrl := section.Key("root_url").MustString("http://localhost:3000/")
if appUrl[len(appUrl)-1] != '/' {
appUrl += "/"
}
// Check if has app suburl.
2015-01-30 07:21:32 -06:00
url, err := url.Parse(appUrl)
if err != nil {
log.Fatal(4, "Invalid root_url(%s): %s", appUrl, err)
}
appSubUrl := strings.TrimSuffix(url.Path, "/")
return appUrl, appSubUrl
}
func ToAbsUrl(relativeUrl string) string {
return AppUrl + relativeUrl
}
func shouldRedactKey(s string) bool {
uppercased := strings.ToUpper(s)
2016-08-27 02:50:35 -05:00
return strings.Contains(uppercased, "PASSWORD") || strings.Contains(uppercased, "SECRET") || strings.Contains(uppercased, "PROVIDER_CONFIG")
}
func shouldRedactURLKey(s string) bool {
uppercased := strings.ToUpper(s)
return strings.Contains(uppercased, "DATABASE_URL")
}
func applyEnvVariableOverrides(file *ini.File) error {
appliedEnvOverrides = make([]string, 0)
for _, section := range file.Sections() {
for _, key := range section.Keys() {
sectionName := strings.ToUpper(strings.Replace(section.Name(), ".", "_", -1))
keyName := strings.ToUpper(strings.Replace(key.Name(), ".", "_", -1))
envKey := fmt.Sprintf("GF_%s_%s", sectionName, keyName)
envValue := os.Getenv(envKey)
if len(envValue) > 0 {
key.SetValue(envValue)
if shouldRedactKey(envKey) {
envValue = "*********"
}
if shouldRedactURLKey(envKey) {
u, err := url.Parse(envValue)
if err != nil {
return fmt.Errorf("could not parse environment variable. key: %s, value: %s. error: %v", envKey, envValue, err)
}
ui := u.User
if ui != nil {
_, exists := ui.Password()
if exists {
u.User = url.UserPassword(ui.Username(), "-redacted-")
envValue = u.String()
}
}
}
appliedEnvOverrides = append(appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, envValue))
}
}
}
return nil
}
func applyCommandLineDefaultProperties(props map[string]string, file *ini.File) {
appliedCommandLineProperties = make([]string, 0)
for _, section := range file.Sections() {
for _, key := range section.Keys() {
keyString := fmt.Sprintf("default.%s.%s", section.Name(), key.Name())
value, exists := props[keyString]
if exists {
key.SetValue(value)
if shouldRedactKey(keyString) {
value = "*********"
}
appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
}
}
}
}
func applyCommandLineProperties(props map[string]string, file *ini.File) {
for _, section := range file.Sections() {
sectionName := section.Name() + "."
if section.Name() == ini.DEFAULT_SECTION {
sectionName = ""
}
for _, key := range section.Keys() {
keyString := sectionName + key.Name()
value, exists := props[keyString]
if exists {
appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
key.SetValue(value)
}
}
}
}
func getCommandLineProperties(args []string) map[string]string {
props := make(map[string]string)
2014-10-04 06:33:20 -05:00
for _, arg := range args {
if !strings.HasPrefix(arg, "cfg:") {
continue
}
trimmed := strings.TrimPrefix(arg, "cfg:")
parts := strings.Split(trimmed, "=")
if len(parts) != 2 {
2018-08-28 15:26:47 -05:00
log.Fatal(3, "Invalid command line argument. argument: %v", arg)
return nil
}
props[parts[0]] = parts[1]
}
return props
}
func makeAbsolute(path string, root string) string {
if filepath.IsAbs(path) {
return path
}
return filepath.Join(root, path)
}
func evalEnvVarExpression(value string) string {
regex := regexp.MustCompile(`\${(\w+)}`)
return regex.ReplaceAllStringFunc(value, func(envVar string) string {
envVar = strings.TrimPrefix(envVar, "${")
envVar = strings.TrimSuffix(envVar, "}")
envValue := os.Getenv(envVar)
// if env variable is hostname and it is empty use os.Hostname as default
if envVar == "HOSTNAME" && envValue == "" {
envValue, _ = os.Hostname()
}
return envValue
})
}
func evalConfigValues(file *ini.File) {
for _, section := range file.Sections() {
for _, key := range section.Keys() {
key.SetValue(evalEnvVarExpression(key.Value()))
}
}
}
func loadSpecifedConfigFile(configFile string, masterFile *ini.File) error {
if configFile == "" {
configFile = filepath.Join(HomePath, CustomInitPath)
// return without error if custom file does not exist
if !pathExists(configFile) {
return nil
}
}
userConfig, err := ini.Load(configFile)
if err != nil {
return fmt.Errorf("Failed to parse %v, %v", configFile, err)
}
userConfig.BlockMode = false
for _, section := range userConfig.Sections() {
for _, key := range section.Keys() {
if key.Value() == "" {
continue
}
defaultSec, err := masterFile.GetSection(section.Name())
if err != nil {
defaultSec, _ = masterFile.NewSection(section.Name())
}
defaultKey, err := defaultSec.GetKey(key.Name())
if err != nil {
defaultKey, _ = defaultSec.NewKey(key.Name(), key.Value())
}
defaultKey.SetValue(key.Value())
}
}
configFiles = append(configFiles, configFile)
return nil
}
func loadConfiguration(args *CommandLineArgs) (*ini.File, error) {
var err error
// load config defaults
defaultConfigFile := path.Join(HomePath, "conf/defaults.ini")
configFiles = append(configFiles, defaultConfigFile)
// check if config file exists
if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
fmt.Println("Grafana-server Init Failed: Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath")
os.Exit(1)
}
// load defaults
parsedFile, err := ini.Load(defaultConfigFile)
if err != nil {
fmt.Println(fmt.Sprintf("Failed to parse defaults.ini, %v", err))
os.Exit(1)
return nil, err
}
parsedFile.BlockMode = false
// command line props
commandLineProps := getCommandLineProperties(args.Args)
// load default overrides
applyCommandLineDefaultProperties(commandLineProps, parsedFile)
// load specified config file
err = loadSpecifedConfigFile(args.Config, parsedFile)
if err != nil {
initLogging(parsedFile)
log.Fatal(3, err.Error())
}
2014-10-04 06:33:20 -05:00
// apply environment overrides
err = applyEnvVariableOverrides(parsedFile)
if err != nil {
return nil, err
}
// apply command line overrides
applyCommandLineProperties(commandLineProps, parsedFile)
// evaluate config values containing environment variables
evalConfigValues(parsedFile)
// update data path and logging config
DataPath = makeAbsolute(parsedFile.Section("paths").Key("data").String(), HomePath)
initLogging(parsedFile)
return parsedFile, err
}
func pathExists(path string) bool {
_, err := os.Stat(path)
if err == nil {
return true
}
if os.IsNotExist(err) {
return false
}
return false
}
func setHomePath(args *CommandLineArgs) {
if args.HomePath != "" {
HomePath = args.HomePath
return
}
HomePath, _ = filepath.Abs(".")
// check if homepath is correct
if pathExists(filepath.Join(HomePath, "conf/defaults.ini")) {
return
}
// try down one path
if pathExists(filepath.Join(HomePath, "../conf/defaults.ini")) {
HomePath = filepath.Join(HomePath, "../")
}
}
Remove redundancy in variable declarations (golint) This commit fixes the following golint warnings: pkg/api/avatar/avatar.go:229:12: should omit type *http.Client from declaration of var client; it will be inferred from the right-hand side pkg/login/brute_force_login_protection.go:13:26: should omit type time.Duration from declaration of var loginAttemptsWindow; it will be inferred from the right-hand side pkg/metrics/graphitebridge/graphite.go:58:26: should omit type []string from declaration of var metricCategoryPrefix; it will be inferred from the right-hand side pkg/metrics/graphitebridge/graphite.go:69:22: should omit type []string from declaration of var trimMetricPrefix; it will be inferred from the right-hand side pkg/models/alert.go:37:36: should omit type error from declaration of var ErrCannotChangeStateOnPausedAlert; it will be inferred from the right-hand side pkg/models/alert.go:38:36: should omit type error from declaration of var ErrRequiresNewState; it will be inferred from the right-hand side pkg/models/datasource.go:61:28: should omit type map[string]bool from declaration of var knownDatasourcePlugins; it will be inferred from the right-hand side pkg/plugins/update_checker.go:16:13: should omit type http.Client from declaration of var httpClient; it will be inferred from the right-hand side pkg/services/alerting/engine.go:103:24: should omit type time.Duration from declaration of var unfinishedWorkTimeout; it will be inferred from the right-hand side pkg/services/alerting/engine.go:105:19: should omit type time.Duration from declaration of var alertTimeout; it will be inferred from the right-hand side pkg/services/alerting/engine.go:106:19: should omit type int from declaration of var alertMaxAttempts; it will be inferred from the right-hand side pkg/services/alerting/notifier.go:143:23: should omit type map[string]*NotifierPlugin from declaration of var notifierFactories; it will be inferred from the right-hand side pkg/services/alerting/rule.go:136:24: should omit type map[string]ConditionFactory from declaration of var conditionFactories; it will be inferred from the right-hand side pkg/services/alerting/conditions/evaluator.go:12:15: should omit type []string from declaration of var defaultTypes; it will be inferred from the right-hand side pkg/services/alerting/conditions/evaluator.go:13:15: should omit type []string from declaration of var rangedTypes; it will be inferred from the right-hand side pkg/services/alerting/notifiers/opsgenie.go:44:19: should omit type string from declaration of var opsgenieAlertURL; it will be inferred from the right-hand side pkg/services/alerting/notifiers/pagerduty.go:43:23: should omit type string from declaration of var pagerdutyEventApiUrl; it will be inferred from the right-hand side pkg/services/alerting/notifiers/telegram.go:21:17: should omit type string from declaration of var telegramApiUrl; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:11:24: should omit type string from declaration of var simpleDashboardConfig; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:12:24: should omit type string from declaration of var oldVersion; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/config_reader_test.go:13:24: should omit type string from declaration of var brokenConfigs; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/file_reader.go:22:30: should omit type time.Duration from declaration of var checkDiskForChangesInterval; it will be inferred from the right-hand side pkg/services/provisioning/dashboards/file_reader.go:24:23: should omit type error from declaration of var ErrFolderNameMissing; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:15:34: should omit type string from declaration of var twoDatasourcesConfig; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:16:34: should omit type string from declaration of var twoDatasourcesConfigPurgeOthers; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:17:34: should omit type string from declaration of var doubleDatasourcesConfig; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:18:34: should omit type string from declaration of var allProperties; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:19:34: should omit type string from declaration of var versionZero; it will be inferred from the right-hand side pkg/services/provisioning/datasources/config_reader_test.go:20:34: should omit type string from declaration of var brokenYaml; it will be inferred from the right-hand side pkg/services/sqlstore/stats.go:16:25: should omit type time.Duration from declaration of var activeUserTimeLimit; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/mysql_dialect.go:69:14: should omit type bool from declaration of var hasLen1; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/mysql_dialect.go:70:14: should omit type bool from declaration of var hasLen2; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/postgres_dialect.go:95:14: should omit type bool from declaration of var hasLen1; it will be inferred from the right-hand side pkg/services/sqlstore/migrator/postgres_dialect.go:96:14: should omit type bool from declaration of var hasLen2; it will be inferred from the right-hand side pkg/setting/setting.go:42:15: should omit type string from declaration of var Env; it will be inferred from the right-hand side pkg/setting/setting.go:161:18: should omit type bool from declaration of var LdapAllowSignup; it will be inferred from the right-hand side pkg/setting/setting.go:473:30: should omit type bool from declaration of var skipStaticRootValidation; it will be inferred from the right-hand side pkg/tsdb/interval.go:14:21: should omit type time.Duration from declaration of var defaultMinInterval; it will be inferred from the right-hand side pkg/tsdb/interval.go:15:21: should omit type time.Duration from declaration of var year; it will be inferred from the right-hand side pkg/tsdb/interval.go:16:21: should omit type time.Duration from declaration of var day; it will be inferred from the right-hand side pkg/tsdb/cloudwatch/credentials.go:26:24: should omit type map[string]cache from declaration of var awsCredentialCache; it will be inferred from the right-hand side pkg/tsdb/influxdb/query.go:15:27: should omit type *regexp.Regexp from declaration of var regexpOperatorPattern; it will be inferred from the right-hand side pkg/tsdb/influxdb/query.go:16:27: should omit type *regexp.Regexp from declaration of var regexpMeasurementPattern; it will be inferred from the right-hand side pkg/tsdb/mssql/mssql_test.go:25:14: should omit type string from declaration of var serverIP; it will be inferred from the right-hand side
2018-04-27 15:14:36 -05:00
var skipStaticRootValidation = false
func validateStaticRootPath() error {
if skipStaticRootValidation {
return nil
}
if _, err := os.Stat(path.Join(StaticRootPath, "build")); err != nil {
logger.Error("Failed to detect generated javascript files in public/build")
}
return nil
}
func NewCfg() *Cfg {
return &Cfg{
Raw: ini.Empty(),
}
}
func (cfg *Cfg) Load(args *CommandLineArgs) error {
setHomePath(args)
iniFile, err := loadConfiguration(args)
if err != nil {
return err
}
cfg.Raw = iniFile
// Temporary keep global, to make refactor in steps
Raw = cfg.Raw
ApplicationName = "Grafana"
if IsEnterprise {
ApplicationName += " Enterprise"
}
Env = iniFile.Section("").Key("app_mode").MustString("development")
InstanceName = iniFile.Section("").Key("instance_name").MustString("unknown_instance_name")
PluginsPath = makeAbsolute(iniFile.Section("paths").Key("plugins").String(), HomePath)
cfg.ProvisioningPath = makeAbsolute(iniFile.Section("paths").Key("provisioning").String(), HomePath)
server := iniFile.Section("server")
AppUrl, AppSubUrl = parseAppUrlAndSubUrl(server)
2014-10-04 06:33:20 -05:00
Protocol = HTTP
if server.Key("protocol").MustString("http") == "https" {
2014-10-04 06:33:20 -05:00
Protocol = HTTPS
CertFile = server.Key("cert_file").String()
KeyFile = server.Key("cert_key").String()
2014-10-04 06:33:20 -05:00
}
if server.Key("protocol").MustString("http") == "socket" {
Protocol = SOCKET
SocketPath = server.Key("socket").String()
}
Domain = server.Key("domain").MustString("localhost")
HttpAddr = server.Key("http_addr").MustString(DEFAULT_HTTP_ADDR)
HttpPort = server.Key("http_port").MustString("3000")
RouterLogging = server.Key("router_logging").MustBool(false)
EnableGzip = server.Key("enable_gzip").MustBool(false)
EnforceDomain = server.Key("enforce_domain").MustBool(false)
StaticRootPath = makeAbsolute(server.Key("static_root_path").String(), HomePath)
if err := validateStaticRootPath(); err != nil {
return err
}
// read data proxy settings
dataproxy := iniFile.Section("dataproxy")
DataProxyLogging = dataproxy.Key("logging").MustBool(false)
// read security settings
security := iniFile.Section("security")
SecretKey = security.Key("secret_key").String()
LogInRememberDays = security.Key("login_remember_days").MustInt()
CookieUserName = security.Key("cookie_username").String()
CookieRememberName = security.Key("cookie_remember_name").String()
DisableGravatar = security.Key("disable_gravatar").MustBool(true)
cfg.DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false)
DisableBruteForceLoginProtection = cfg.DisableBruteForceLoginProtection
// read snapshots settings
snapshots := iniFile.Section("snapshots")
ExternalSnapshotUrl = snapshots.Key("external_snapshot_url").String()
ExternalSnapshotName = snapshots.Key("external_snapshot_name").String()
ExternalEnabled = snapshots.Key("external_enabled").MustBool(true)
SnapShotRemoveExpired = snapshots.Key("snapshot_remove_expired").MustBool(true)
// read dashboard settings
dashboards := iniFile.Section("dashboards")
DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
// read data source proxy white list
DataProxyWhiteList = make(map[string]bool)
for _, hostAndIp := range util.SplitString(security.Key("data_source_proxy_whitelist").String()) {
DataProxyWhiteList[hostAndIp] = true
}
2015-01-27 08:45:27 -06:00
// admin
AdminUser = security.Key("admin_user").String()
AdminPassword = security.Key("admin_password").String()
users := iniFile.Section("users")
AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true)
AutoAssignOrg = users.Key("auto_assign_org").MustBool(true)
AutoAssignOrgId = users.Key("auto_assign_org_id").MustInt(1)
AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
2015-08-20 13:15:36 -05:00
LoginHint = users.Key("login_hint").String()
DefaultTheme = users.Key("default_theme").String()
2017-07-31 07:39:33 -05:00
ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
ExternalUserMngInfo = users.Key("external_manage_info").String()
ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
// auth
auth := iniFile.Section("auth")
DisableLoginForm = auth.Key("disable_login_form").MustBool(false)
DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false)
SignoutRedirectUrl = auth.Key("signout_redirect_url").String()
2015-01-27 08:45:27 -06:00
// anonymous access
AnonymousEnabled = iniFile.Section("auth.anonymous").Key("enabled").MustBool(false)
AnonymousOrgName = iniFile.Section("auth.anonymous").Key("org_name").String()
AnonymousOrgRole = iniFile.Section("auth.anonymous").Key("org_role").String()
// auth proxy
authProxy := iniFile.Section("auth.proxy")
AuthProxyEnabled = authProxy.Key("enabled").MustBool(false)
AuthProxyHeaderName = authProxy.Key("header_name").String()
AuthProxyHeaderProperty = authProxy.Key("header_property").String()
AuthProxyAutoSignUp = authProxy.Key("auto_sign_up").MustBool(true)
AuthProxyLdapSyncTtl = authProxy.Key("ldap_sync_ttl").MustInt()
AuthProxyWhitelist = authProxy.Key("whitelist").String()
AuthProxyHeaders = make(map[string]string)
for _, propertyAndHeader := range util.SplitString(authProxy.Key("headers").String()) {
split := strings.SplitN(propertyAndHeader, ":", 2)
if len(split) == 2 {
AuthProxyHeaders[split[0]] = split[1]
}
}
// basic auth
authBasic := iniFile.Section("auth.basic")
2015-06-30 05:14:13 -05:00
BasicAuthEnabled = authBasic.Key("enabled").MustBool(true)
// global plugin settings
PluginAppsSkipVerifyTLS = iniFile.Section("plugins").Key("app_tls_skip_verify_insecure").MustBool(false)
// Rendering
renderSec := iniFile.Section("rendering")
cfg.RendererLimit = renderSec.Key("concurrent_limit").MustInt(10)
cfg.RendererLimitAlerting = renderSec.Key("concurrent_limit").MustInt(5)
cfg.RendererUrl = renderSec.Key("server_url").String()
improve remote image rendering (#13102) * improve remote image rendering - determine "domain" during Init() so we are not re-parsing settings on every request - if using http-mode via a rednererUrl, then use the AppUrl for the page that the renderer loads. When in http-mode the renderer is likely running on another server so trying to use the localhost or even the specific IP:PORT grafana is listening on wont work. - apply the request timeout via a context rather then directly on the http client. - use a global http client so we can take advantage of connection re-use - log and handle errors better. * ensure imagesDir exists * allow users to define callback_url for remote rendering - allow users to define the url that a remote rendering service should use for connecting back to the grafana instance. By default the "root_url" is used. * improve remote image rendering - determine "domain" during Init() so we are not re-parsing settings on every request - if using http-mode via a rednererUrl, then use the AppUrl for the page that the renderer loads. When in http-mode the renderer is likely running on another server so trying to use the localhost or even the specific IP:PORT grafana is listening on wont work. - apply the request timeout via a context rather then directly on the http client. - use a global http client so we can take advantage of connection re-use - log and handle errors better. * ensure imagesDir exists * allow users to define callback_url for remote rendering - allow users to define the url that a remote rendering service should use for connecting back to the grafana instance. By default the "root_url" is used. * rendering: fixed issue with renderKey where userId and orgId was in mixed up, added test for RenderCallbackUrl reading logic
2018-09-04 06:42:55 -05:00
cfg.RendererCallbackUrl = renderSec.Key("callback_url").String()
if cfg.RendererCallbackUrl == "" {
cfg.RendererCallbackUrl = AppUrl
} else {
if cfg.RendererCallbackUrl[len(cfg.RendererCallbackUrl)-1] != '/' {
cfg.RendererCallbackUrl += "/"
}
_, err := url.Parse(cfg.RendererCallbackUrl)
if err != nil {
log.Fatal(4, "Invalid callback_url(%s): %s", cfg.RendererCallbackUrl, err)
}
}
cfg.ImagesDir = filepath.Join(DataPath, "png")
cfg.PhantomDir = filepath.Join(HomePath, "tools/phantomjs")
cfg.TempDataLifetime = iniFile.Section("paths").Key("temp_data_lifetime").MustDuration(time.Second * 3600 * 24)
cfg.MetricsEndpointEnabled = iniFile.Section("metrics").Key("enabled").MustBool(true)
2014-11-14 10:13:33 -06:00
analytics := iniFile.Section("analytics")
2015-03-27 11:13:44 -05:00
ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
CheckForUpdates = analytics.Key("check_for_updates").MustBool(true)
2015-03-27 11:13:44 -05:00
GoogleAnalyticsId = analytics.Key("google_analytics_ua_id").String()
GoogleTagManagerId = analytics.Key("google_tag_manager_id").String()
2015-03-22 14:14:00 -05:00
ldapSec := iniFile.Section("auth.ldap")
2015-06-04 02:34:42 -05:00
LdapEnabled = ldapSec.Key("enabled").MustBool(false)
LdapConfigFile = ldapSec.Key("config_file").String()
LdapAllowSignup = ldapSec.Key("allow_sign_up").MustBool(true)
2015-06-04 02:34:42 -05:00
alerting := iniFile.Section("alerting")
AlertingEnabled = alerting.Key("enabled").MustBool(true)
ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true)
AlertingErrorOrTimeout = alerting.Key("error_or_timeout").MustString("alerting")
AlertingNoDataOrNullValues = alerting.Key("nodata_or_nullvalues").MustString("no_data")
explore := iniFile.Section("explore")
ExploreEnabled = explore.Key("enabled").MustBool(false)
2018-04-27 04:39:14 -05:00
cfg.readSessionConfig()
cfg.readSmtpSettings()
cfg.readQuotaSettings()
if VerifyEmailEnabled && !cfg.Smtp.Enabled {
2017-12-28 08:51:15 -06:00
log.Warn("require_email_validation is enabled but smtp is disabled")
}
// check old key name
GrafanaComUrl = iniFile.Section("grafana_net").Key("url").MustString("")
if GrafanaComUrl == "" {
GrafanaComUrl = iniFile.Section("grafana_com").Key("url").MustString("https://grafana.com")
}
imageUploadingSection := iniFile.Section("external_image_storage")
ImageUploadProvider = imageUploadingSection.Key("provider").MustString("")
return nil
}
2014-12-30 03:28:27 -06:00
func (cfg *Cfg) readSessionConfig() {
sec := cfg.Raw.Section("session")
2014-12-30 03:28:27 -06:00
SessionOptions = session.Options{}
2015-12-08 07:35:09 -06:00
SessionOptions.Provider = sec.Key("provider").In("memory", []string{"memory", "file", "redis", "mysql", "postgres", "memcache"})
SessionOptions.ProviderConfig = strings.Trim(sec.Key("provider_config").String(), "\" ")
SessionOptions.CookieName = sec.Key("cookie_name").MustString("grafana_sess")
2014-12-30 03:28:27 -06:00
SessionOptions.CookiePath = AppSubUrl
SessionOptions.Secure = sec.Key("cookie_secure").MustBool()
SessionOptions.Gclifetime = cfg.Raw.Section("session").Key("gc_interval_time").MustInt64(86400)
SessionOptions.Maxlifetime = cfg.Raw.Section("session").Key("session_life_time").MustInt64(86400)
SessionOptions.IDLength = 16
2014-12-30 03:28:27 -06:00
if SessionOptions.Provider == "file" {
SessionOptions.ProviderConfig = makeAbsolute(SessionOptions.ProviderConfig, DataPath)
2014-12-30 03:28:27 -06:00
os.MkdirAll(path.Dir(SessionOptions.ProviderConfig), os.ModePerm)
2014-10-05 09:50:04 -05:00
}
if SessionOptions.CookiePath == "" {
SessionOptions.CookiePath = "/"
}
SessionConnMaxLifetime = cfg.Raw.Section("session").Key("conn_max_lifetime").MustInt64(14400)
2014-10-05 09:50:04 -05:00
}
func initLogging(file *ini.File) {
2016-06-07 05:11:41 -05:00
// split on comma
LogModes = strings.Split(file.Section("log").Key("mode").MustString("console"), ",")
2016-06-07 05:11:41 -05:00
// also try space
if len(LogModes) == 1 {
LogModes = strings.Split(file.Section("log").Key("mode").MustString("console"), " ")
}
LogsPath = makeAbsolute(file.Section("paths").Key("logs").String(), HomePath)
log.ReadLoggingConfig(LogModes, LogsPath, file)
}
func (cfg *Cfg) LogConfigSources() {
var text bytes.Buffer
for _, file := range configFiles {
logger.Info("Config loaded from", "file", file)
}
if len(appliedCommandLineProperties) > 0 {
for _, prop := range appliedCommandLineProperties {
logger.Info("Config overridden from command line", "arg", prop)
}
}
if len(appliedEnvOverrides) > 0 {
text.WriteString("\tEnvironment variables used:\n")
for _, prop := range appliedEnvOverrides {
logger.Info("Config overridden from Environment variable", "var", prop)
}
}
logger.Info("Path Home", "path", HomePath)
logger.Info("Path Data", "path", DataPath)
logger.Info("Path Logs", "path", LogsPath)
logger.Info("Path Plugins", "path", PluginsPath)
logger.Info("Path Provisioning", "path", cfg.ProvisioningPath)
logger.Info("App mode " + Env)
}