2014-10-05 22:50:04 +08:00
// Copyright 2014 Unknwon
// Copyright 2014 Torkel Ödegaard
2014-10-04 19:33:20 +08:00
package setting
import (
2015-04-09 18:16:59 +08:00
"bytes"
2015-02-12 20:31:41 +08:00
"fmt"
2014-10-04 19:33:20 +08:00
"net/url"
"os"
"path"
"path/filepath"
2015-04-09 18:16:59 +08:00
"regexp"
2014-10-04 19:33:20 +08:00
"runtime"
"strings"
2015-01-27 17:09:54 +08:00
"gopkg.in/ini.v1"
2014-10-05 22:50:04 +08:00
2017-01-11 21:00:49 +08:00
"github.com/go-macaron/session"
2015-02-05 17:37:13 +08:00
"github.com/grafana/grafana/pkg/log"
2015-04-19 15:14:50 +08:00
"github.com/grafana/grafana/pkg/util"
2014-10-04 19:33:20 +08:00
)
type Scheme string
const (
2016-11-23 22:35:43 +08:00
HTTP Scheme = "http"
HTTPS Scheme = "https"
2017-04-27 14:54:21 +08:00
SOCKET Scheme = "socket"
2016-11-23 22:35:43 +08:00
DEFAULT_HTTP_ADDR string = "0.0.0.0"
2014-10-04 19:33:20 +08:00
)
2014-12-16 19:04:08 +08:00
const (
DEV string = "development"
PROD string = "production"
TEST string = "test"
)
2014-10-04 19:33:20 +08:00
var (
// App settings.
2018-04-28 04:14:36 +08:00
Env = DEV
2016-06-02 20:32:17 +08:00
AppUrl string
AppSubUrl string
InstanceName string
2014-10-04 19:33:20 +08:00
2015-01-05 17:46:58 +08:00
// build
2018-04-27 19:41:58 +08:00
BuildVersion string
BuildCommit string
BuildStamp int64
Enterprise bool
ApplicationName string
2015-01-05 17:46:58 +08:00
2015-04-09 18:16:59 +08:00
// Paths
2018-05-01 21:51:15 +08:00
LogsPath string
HomePath string
DataPath string
PluginsPath string
CustomInitPath = "conf/custom.ini"
2015-04-09 18:16:59 +08:00
2014-10-04 19:33:20 +08:00
// Log settings.
2015-04-09 18:16:59 +08:00
LogModes [ ] string
2015-04-19 15:29:08 +08:00
LogConfigs [ ] util . DynMap
2014-10-04 19:33:20 +08:00
// Http server options
Protocol Scheme
Domain string
HttpAddr , HttpPort string
SshPort int
CertFile , KeyFile string
2017-04-27 14:54:21 +08:00
SocketPath string
2014-10-05 22:50:04 +08:00
RouterLogging bool
2017-01-11 23:51:46 +08:00
DataProxyLogging bool
2014-10-05 22:50:04 +08:00
StaticRootPath string
2015-01-14 17:34:14 +08:00
EnableGzip bool
2015-05-05 17:21:06 +08:00
EnforceDomain bool
2014-10-05 22:50:04 +08:00
2015-01-27 17:09:54 +08:00
// Security settings.
2018-01-26 17:41:41 +08:00
SecretKey string
LogInRememberDays int
CookieUserName string
CookieRememberName string
DisableGravatar bool
EmailCodeValidMinutes int
DataProxyWhiteList map [ string ] bool
DisableBruteForceLoginProtection bool
2015-01-27 17:09:54 +08:00
2015-10-14 22:39:57 +08:00
// Snapshots
2016-09-23 22:56:12 +08:00
ExternalSnapshotUrl string
ExternalSnapshotName string
ExternalEnabled bool
SnapShotRemoveExpired bool
2015-10-14 22:39:57 +08:00
2017-11-14 18:34:27 +08:00
// Dashboard history
DashboardVersionsToKeep int
2015-03-11 23:19:29 +08:00
// User settings
2017-07-31 20:39:33 +08:00
AllowUserSignUp bool
AllowUserOrgCreate bool
AutoAssignOrg bool
AutoAssignOrgRole string
VerifyEmailEnabled bool
LoginHint string
DefaultTheme string
DisableLoginForm bool
DisableSignoutMenu bool
ExternalUserMngLinkUrl string
ExternalUserMngLinkName string
ExternalUserMngInfo string
2017-12-14 01:53:42 +08:00
ViewersCanEdit bool
2015-01-27 22:14:53 +08:00
2015-01-07 23:37:24 +08:00
// Http auth
2015-01-27 22:45:27 +08:00
AdminUser string
AdminPassword string
2015-02-24 03:07:49 +08:00
AnonymousEnabled bool
AnonymousOrgName string
AnonymousOrgRole string
2015-01-07 23:37:24 +08:00
2015-05-01 17:55:59 +08:00
// Auth proxy settings
AuthProxyEnabled bool
AuthProxyHeaderName string
AuthProxyHeaderProperty string
AuthProxyAutoSignUp bool
2016-02-23 21:22:28 +08:00
AuthProxyLdapSyncTtl int
AuthProxyWhitelist string
2018-05-07 16:39:16 +08:00
AuthProxyHeaders map [ string ] string
2015-05-01 17:55:59 +08:00
2015-06-30 15:37:52 +08:00
// Basic Auth
BasicAuthEnabled bool
2017-09-28 18:10:59 +08:00
// Plugin settings
PluginAppsSkipVerifyTLS bool
2014-10-05 22:50:04 +08:00
// Session settings.
2018-03-16 04:23:33 +08:00
SessionOptions session . Options
SessionConnMaxLifetime int64
2014-10-04 19:33:20 +08:00
// Global setting objects.
2018-04-30 22:21:04 +08:00
Raw * ini . File
2014-10-04 19:33:20 +08:00
ConfRootPath string
IsWindows bool
2014-10-07 03:31:54 +08:00
// PhantomJs Rendering
2016-09-29 03:06:00 +08:00
ImagesDir string
PhantomDir string
2015-03-03 17:18:24 +08:00
2015-04-09 18:16:59 +08:00
// for logging purposes
configFiles [ ] string
appliedCommandLineProperties [ ] string
appliedEnvOverrides [ ] string
2015-03-23 03:14:00 +08:00
2015-08-21 15:30:39 +08:00
ReportingEnabled bool
2016-04-12 00:21:48 +08:00
CheckForUpdates bool
2015-08-21 15:30:39 +08:00
GoogleAnalyticsId string
GoogleTagManagerId string
2015-06-04 15:34:42 +08:00
// LDAP
2016-10-07 14:49:58 +08:00
LdapEnabled bool
LdapConfigFile string
2018-04-28 04:14:36 +08:00
LdapAllowSignup = true
2015-07-10 17:10:48 +08:00
2015-09-11 01:47:33 +08:00
// QUOTA
Quota QuotaSettings
2016-04-29 20:35:58 +08:00
// Alerting
2017-01-25 20:32:26 +08:00
AlertingEnabled bool
2017-01-20 23:43:29 +08:00
ExecuteAlerts bool
2016-06-07 19:31:56 +08:00
2018-04-27 17:39:14 +08:00
// Explore UI
ExploreEnabled bool
2016-06-07 15:29:47 +08:00
// logger
logger log . Logger
2016-06-16 14:06:43 +08:00
2016-05-27 19:52:19 +08:00
// Grafana.NET URL
2017-05-22 20:56:50 +08:00
GrafanaComUrl string
2016-07-30 19:36:21 +08:00
// S3 temp image store
S3TempImageStoreBucketUrl string
S3TempImageStoreAccessKey string
S3TempImageStoreSecretKey string
2016-08-10 23:27:39 +08:00
ImageUploadProvider string
2014-10-04 19:33:20 +08:00
)
2018-04-30 22:21:04 +08:00
type Cfg struct {
Raw * ini . File
2018-05-01 21:51:15 +08:00
// Paths
ProvisioningPath string
2018-04-30 22:21:04 +08:00
// SMTP email settings
Smtp SmtpSettings
ImagesDir string
DisableBruteForceLoginProtection bool
}
2015-04-08 20:10:04 +08:00
type CommandLineArgs struct {
2015-04-12 15:15:49 +08:00
Config string
HomePath string
Args [ ] string
2015-04-08 20:10:04 +08:00
}
2014-10-04 19:33:20 +08:00
func init ( ) {
IsWindows = runtime . GOOS == "windows"
2016-06-07 15:29:47 +08:00
logger = log . New ( "settings" )
2015-01-01 22:29:10 +08:00
}
2014-10-04 19:33:20 +08:00
2015-01-27 17:09:54 +08: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 21:21:32 +08:00
url , err := url . Parse ( appUrl )
2015-01-27 17:09:54 +08:00
if err != nil {
log . Fatal ( 4 , "Invalid root_url(%s): %s" , appUrl , err )
}
appSubUrl := strings . TrimSuffix ( url . Path , "/" )
return appUrl , appSubUrl
}
2015-02-06 21:17:40 +08:00
func ToAbsUrl ( relativeUrl string ) string {
2015-02-04 18:35:59 +08:00
return AppUrl + relativeUrl
}
2016-03-02 02:50:45 +08:00
func shouldRedactKey ( s string ) bool {
uppercased := strings . ToUpper ( s )
2016-08-27 15:50:35 +08:00
return strings . Contains ( uppercased , "PASSWORD" ) || strings . Contains ( uppercased , "SECRET" ) || strings . Contains ( uppercased , "PROVIDER_CONFIG" )
2016-03-02 02:50:45 +08:00
}
2016-06-29 00:37:59 +08:00
func shouldRedactURLKey ( s string ) bool {
uppercased := strings . ToUpper ( s )
return strings . Contains ( uppercased , "DATABASE_URL" )
}
2018-04-30 22:21:04 +08:00
func applyEnvVariableOverrides ( file * ini . File ) error {
2015-04-09 18:16:59 +08:00
appliedEnvOverrides = make ( [ ] string , 0 )
2018-04-30 22:21:04 +08:00
for _ , section := range file . Sections ( ) {
2015-02-12 20:31:41 +08:00
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 )
2016-03-02 02:50:45 +08:00
if shouldRedactKey ( envKey ) {
2015-12-04 17:38:27 +08:00
envValue = "*********"
}
2016-06-29 00:37:59 +08:00
if shouldRedactURLKey ( envKey ) {
2018-03-29 00:03:33 +08:00
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 )
}
2016-06-29 00:37:59 +08:00
ui := u . User
if ui != nil {
_ , exists := ui . Password ( )
if exists {
u . User = url . UserPassword ( ui . Username ( ) , "-redacted-" )
envValue = u . String ( )
}
}
}
2015-04-09 18:16:59 +08:00
appliedEnvOverrides = append ( appliedEnvOverrides , fmt . Sprintf ( "%s=%s" , envKey , envValue ) )
2015-02-12 20:31:41 +08:00
}
}
}
2018-03-29 00:03:33 +08:00
return nil
2015-02-12 18:55:55 +08:00
}
2018-04-30 22:21:04 +08:00
func applyCommandLineDefaultProperties ( props map [ string ] string , file * ini . File ) {
2015-04-09 18:16:59 +08:00
appliedCommandLineProperties = make ( [ ] string , 0 )
2018-04-30 22:21:04 +08:00
for _ , section := range file . Sections ( ) {
2015-04-09 18:16:59 +08:00
for _ , key := range section . Keys ( ) {
keyString := fmt . Sprintf ( "default.%s.%s" , section . Name ( ) , key . Name ( ) )
value , exists := props [ keyString ]
if exists {
key . SetValue ( value )
2016-03-02 02:50:45 +08:00
if shouldRedactKey ( keyString ) {
2015-12-04 17:38:27 +08:00
value = "*********"
}
2015-04-09 18:16:59 +08:00
appliedCommandLineProperties = append ( appliedCommandLineProperties , fmt . Sprintf ( "%s=%s" , keyString , value ) )
}
2015-04-09 02:31:42 +08:00
}
}
}
2018-04-30 22:21:04 +08:00
func applyCommandLineProperties ( props map [ string ] string , file * ini . File ) {
for _ , section := range file . Sections ( ) {
2017-10-02 02:02:25 +08:00
sectionName := section . Name ( ) + "."
if section . Name ( ) == ini . DEFAULT_SECTION {
sectionName = ""
}
2015-04-09 18:16:59 +08:00
for _ , key := range section . Keys ( ) {
2017-10-02 02:02:25 +08:00
keyString := sectionName + key . Name ( )
2015-04-09 18:16:59 +08:00
value , exists := props [ keyString ]
if exists {
appliedCommandLineProperties = append ( appliedCommandLineProperties , fmt . Sprintf ( "%s=%s" , keyString , value ) )
2017-10-02 02:02:25 +08:00
key . SetValue ( value )
2015-04-09 18:16:59 +08:00
}
}
}
}
2015-02-16 05:57:49 +08:00
2015-04-09 18:16:59 +08:00
func getCommandLineProperties ( args [ ] string ) map [ string ] string {
props := make ( map [ string ] string )
2014-10-04 19:33:20 +08:00
2015-04-09 18:16:59 +08:00
for _ , arg := range args {
if ! strings . HasPrefix ( arg , "cfg:" ) {
continue
}
trimmed := strings . TrimPrefix ( arg , "cfg:" )
parts := strings . Split ( trimmed , "=" )
if len ( parts ) != 2 {
log . Fatal ( 3 , "Invalid command line argument" , arg )
return nil
2015-01-27 17:09:54 +08:00
}
2015-01-05 14:59:18 +08:00
2015-04-09 18:16:59 +08:00
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 )
2016-06-02 20:32:17 +08:00
2017-06-05 20:20:34 +08:00
// if env variable is hostname and it is empty use os.Hostname as default
2016-06-02 20:32:17 +08:00
if envVar == "HOSTNAME" && envValue == "" {
envValue , _ = os . Hostname ( )
}
2015-04-09 18:16:59 +08:00
return envValue
} )
}
2018-04-30 22:21:04 +08:00
func evalConfigValues ( file * ini . File ) {
for _ , section := range file . Sections ( ) {
2015-04-09 18:16:59 +08:00
for _ , key := range section . Keys ( ) {
key . SetValue ( evalEnvVarExpression ( key . Value ( ) ) )
}
}
}
2018-04-30 22:21:04 +08:00
func loadSpecifedConfigFile ( configFile string , masterFile * ini . File ) error {
2015-04-12 15:15:49 +08:00
if configFile == "" {
2016-09-08 19:22:30 +08:00
configFile = filepath . Join ( HomePath , CustomInitPath )
2015-04-12 15:15:49 +08:00
// return without error if custom file does not exist
if ! pathExists ( configFile ) {
2016-07-01 07:37:06 +08:00
return nil
2015-04-12 15:15:49 +08:00
}
}
2015-04-10 16:58:32 +08:00
userConfig , err := ini . Load ( configFile )
if err != nil {
2016-07-01 07:37:06 +08:00
return fmt . Errorf ( "Failed to parse %v, %v" , configFile , err )
2015-04-10 16:58:32 +08:00
}
2016-11-29 00:55:18 +08:00
userConfig . BlockMode = false
2015-04-10 16:58:32 +08:00
for _ , section := range userConfig . Sections ( ) {
for _ , key := range section . Keys ( ) {
if key . Value ( ) == "" {
continue
}
2018-04-30 22:21:04 +08:00
defaultSec , err := masterFile . GetSection ( section . Name ( ) )
2015-04-10 16:58:32 +08:00
if err != nil {
2018-04-30 22:21:04 +08:00
defaultSec , _ = masterFile . NewSection ( section . Name ( ) )
2015-04-10 16:58:32 +08:00
}
defaultKey , err := defaultSec . GetKey ( key . Name ( ) )
if err != nil {
2015-11-19 23:50:17 +08:00
defaultKey , _ = defaultSec . NewKey ( key . Name ( ) , key . Value ( ) )
2015-04-10 16:58:32 +08:00
}
defaultKey . SetValue ( key . Value ( ) )
}
}
configFiles = append ( configFiles , configFile )
2016-07-01 07:37:06 +08:00
return nil
2015-04-10 16:58:32 +08:00
}
2018-04-30 22:21:04 +08:00
func loadConfiguration ( args * CommandLineArgs ) ( * ini . File , error ) {
2015-04-09 18:16:59 +08:00
var err error
// load config defaults
defaultConfigFile := path . Join ( HomePath , "conf/defaults.ini" )
configFiles = append ( configFiles , defaultConfigFile )
2016-12-06 14:36:10 +08:00
// 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
2018-04-30 22:21:04 +08:00
parsedFile , err := ini . Load ( defaultConfigFile )
2015-04-09 18:16:59 +08:00
if err != nil {
2016-12-06 14:36:10 +08:00
fmt . Println ( fmt . Sprintf ( "Failed to parse defaults.ini, %v" , err ) )
os . Exit ( 1 )
2018-04-30 22:21:04 +08:00
return nil , err
2015-04-09 18:16:59 +08:00
}
2018-04-30 22:21:04 +08:00
parsedFile . BlockMode = false
2016-11-18 23:43:08 +08:00
2015-04-09 18:16:59 +08:00
// command line props
commandLineProps := getCommandLineProperties ( args . Args )
// load default overrides
2018-04-30 22:21:04 +08:00
applyCommandLineDefaultProperties ( commandLineProps , parsedFile )
2015-04-09 18:16:59 +08:00
// load specified config file
2018-04-30 22:21:04 +08:00
err = loadSpecifedConfigFile ( args . Config , parsedFile )
2016-07-01 07:37:06 +08:00
if err != nil {
2018-04-30 22:21:04 +08:00
initLogging ( parsedFile )
2016-07-01 07:37:06 +08:00
log . Fatal ( 3 , err . Error ( ) )
}
2014-10-04 19:33:20 +08:00
2015-04-09 18:16:59 +08:00
// apply environment overrides
2018-04-30 22:21:04 +08:00
err = applyEnvVariableOverrides ( parsedFile )
2018-03-29 00:03:33 +08:00
if err != nil {
2018-04-30 22:21:04 +08:00
return nil , err
2018-03-29 00:03:33 +08:00
}
2015-04-09 18:16:59 +08:00
// apply command line overrides
2018-04-30 22:21:04 +08:00
applyCommandLineProperties ( commandLineProps , parsedFile )
2015-04-08 20:10:04 +08:00
2015-04-09 18:16:59 +08:00
// evaluate config values containing environment variables
2018-04-30 22:21:04 +08:00
evalConfigValues ( parsedFile )
2015-05-14 16:15:46 +08:00
// update data path and logging config
2018-04-30 22:21:04 +08:00
DataPath = makeAbsolute ( parsedFile . Section ( "paths" ) . Key ( "data" ) . String ( ) , HomePath )
initLogging ( parsedFile )
2018-03-29 00:03:33 +08:00
2018-04-30 22:21:04 +08:00
return parsedFile , err
2015-04-09 18:16:59 +08:00
}
2015-04-12 15:15:49 +08:00
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 , "../" )
}
}
2018-04-28 04:14:36 +08:00
var skipStaticRootValidation = false
2015-09-11 14:58:45 +08:00
func validateStaticRootPath ( ) error {
if skipStaticRootValidation {
return nil
2015-09-10 19:34:32 +08:00
}
2017-10-02 02:02:25 +08:00
if _ , err := os . Stat ( path . Join ( StaticRootPath , "build" ) ) ; err != nil {
logger . Error ( "Failed to detect generated javascript files in public/build" )
2015-09-10 19:34:32 +08:00
}
2017-10-02 02:02:25 +08:00
return nil
2015-09-10 19:34:32 +08:00
}
2018-04-30 22:21:04 +08:00
func NewCfg ( ) * Cfg {
return & Cfg { }
}
func ( cfg * Cfg ) Load ( args * CommandLineArgs ) error {
2015-04-12 15:15:49 +08:00
setHomePath ( args )
2018-04-30 22:21:04 +08:00
iniFile , err := loadConfiguration ( args )
2018-03-29 00:03:33 +08:00
if err != nil {
return err
}
2015-04-09 18:16:59 +08:00
2018-04-30 22:21:04 +08:00
cfg . Raw = iniFile
// Temporary keep global, to make refactor in steps
Raw = cfg . Raw
2018-04-27 19:41:58 +08:00
ApplicationName = "Grafana"
if Enterprise {
ApplicationName += " Enterprise"
}
2018-04-30 22:21:04 +08:00
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 )
2018-05-01 21:51:15 +08:00
cfg . ProvisioningPath = makeAbsolute ( iniFile . Section ( "paths" ) . Key ( "provisioning" ) . String ( ) , HomePath )
2018-04-30 22:21:04 +08:00
server := iniFile . Section ( "server" )
2015-01-27 17:09:54 +08:00
AppUrl , AppSubUrl = parseAppUrlAndSubUrl ( server )
2014-10-04 19:33:20 +08:00
Protocol = HTTP
2015-01-27 17:09:54 +08:00
if server . Key ( "protocol" ) . MustString ( "http" ) == "https" {
2014-10-04 19:33:20 +08:00
Protocol = HTTPS
2015-01-27 17:09:54 +08:00
CertFile = server . Key ( "cert_file" ) . String ( )
2015-03-12 02:44:31 +08:00
KeyFile = server . Key ( "cert_key" ) . String ( )
2014-10-04 19:33:20 +08:00
}
2017-04-27 14:54:21 +08:00
if server . Key ( "protocol" ) . MustString ( "http" ) == "socket" {
Protocol = SOCKET
SocketPath = server . Key ( "socket" ) . String ( )
}
2015-01-27 17:09:54 +08:00
Domain = server . Key ( "domain" ) . MustString ( "localhost" )
2016-11-23 22:35:43 +08:00
HttpAddr = server . Key ( "http_addr" ) . MustString ( DEFAULT_HTTP_ADDR )
2015-01-27 17:09:54 +08:00
HttpPort = server . Key ( "http_port" ) . MustString ( "3000" )
RouterLogging = server . Key ( "router_logging" ) . MustBool ( false )
2017-01-16 19:43:59 +08:00
2015-01-27 17:09:54 +08:00
EnableGzip = server . Key ( "enable_gzip" ) . MustBool ( false )
2015-05-05 17:21:06 +08:00
EnforceDomain = server . Key ( "enforce_domain" ) . MustBool ( false )
2015-09-11 14:58:45 +08:00
StaticRootPath = makeAbsolute ( server . Key ( "static_root_path" ) . String ( ) , HomePath )
if err := validateStaticRootPath ( ) ; err != nil {
return err
}
2015-01-27 17:09:54 +08:00
2017-01-16 19:43:59 +08:00
// read data proxy settings
2018-04-30 22:21:04 +08:00
dataproxy := iniFile . Section ( "dataproxy" )
2017-01-16 19:43:59 +08:00
DataProxyLogging = dataproxy . Key ( "logging" ) . MustBool ( false )
2015-09-09 23:21:25 +08:00
// read security settings
2018-04-30 22:21:04 +08:00
security := iniFile . Section ( "security" )
2015-01-27 17:09:54 +08:00
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 ( )
2015-05-01 14:40:13 +08:00
DisableGravatar = security . Key ( "disable_gravatar" ) . MustBool ( true )
2018-04-30 22:21:04 +08:00
cfg . DisableBruteForceLoginProtection = security . Key ( "disable_brute_force_login_protection" ) . MustBool ( false )
DisableBruteForceLoginProtection = cfg . DisableBruteForceLoginProtection
2015-05-01 14:40:13 +08:00
2015-10-14 22:39:57 +08:00
// read snapshots settings
2018-04-30 22:21:04 +08:00
snapshots := iniFile . Section ( "snapshots" )
2015-10-14 22:39:57 +08:00
ExternalSnapshotUrl = snapshots . Key ( "external_snapshot_url" ) . String ( )
ExternalSnapshotName = snapshots . Key ( "external_snapshot_name" ) . String ( )
ExternalEnabled = snapshots . Key ( "external_enabled" ) . MustBool ( true )
2016-09-23 22:56:12 +08:00
SnapShotRemoveExpired = snapshots . Key ( "snapshot_remove_expired" ) . MustBool ( true )
2015-10-14 22:39:57 +08:00
2017-11-14 18:34:27 +08:00
// read dashboard settings
2018-04-30 22:21:04 +08:00
dashboards := iniFile . Section ( "dashboards" )
2017-11-15 18:36:36 +08:00
DashboardVersionsToKeep = dashboards . Key ( "versions_to_keep" ) . MustInt ( 20 )
2017-11-14 18:34:27 +08:00
2015-09-09 23:21:25 +08:00
// read data source proxy white list
DataProxyWhiteList = make ( map [ string ] bool )
2017-04-25 15:14:29 +08:00
for _ , hostAndIp := range util . SplitString ( security . Key ( "data_source_proxy_whitelist" ) . String ( ) ) {
2015-09-09 23:21:25 +08:00
DataProxyWhiteList [ hostAndIp ] = true
}
2015-01-27 22:45:27 +08:00
// admin
AdminUser = security . Key ( "admin_user" ) . String ( )
AdminPassword = security . Key ( "admin_password" ) . String ( )
2018-04-30 22:21:04 +08:00
users := iniFile . Section ( "users" )
2015-03-11 23:19:29 +08:00
AllowUserSignUp = users . Key ( "allow_sign_up" ) . MustBool ( true )
AllowUserOrgCreate = users . Key ( "allow_org_create" ) . MustBool ( true )
AutoAssignOrg = users . Key ( "auto_assign_org" ) . MustBool ( true )
2017-12-14 01:53:42 +08:00
AutoAssignOrgRole = users . Key ( "auto_assign_org_role" ) . In ( "Editor" , [ ] string { "Editor" , "Admin" , "Viewer" } )
2015-08-31 17:35:07 +08:00
VerifyEmailEnabled = users . Key ( "verify_email_enabled" ) . MustBool ( false )
2015-08-21 02:15:36 +08:00
LoginHint = users . Key ( "login_hint" ) . String ( )
2016-05-12 20:11:10 +08:00
DefaultTheme = users . Key ( "default_theme" ) . String ( )
2017-07-31 20:39:33 +08:00
ExternalUserMngLinkUrl = users . Key ( "external_manage_link_url" ) . String ( )
ExternalUserMngLinkName = users . Key ( "external_manage_link_name" ) . String ( )
ExternalUserMngInfo = users . Key ( "external_manage_info" ) . String ( )
2017-12-14 01:53:42 +08:00
ViewersCanEdit = users . Key ( "viewers_can_edit" ) . MustBool ( false )
2016-09-28 21:27:08 +08:00
// auth
2018-04-30 22:21:04 +08:00
auth := iniFile . Section ( "auth" )
2016-09-28 21:27:08 +08:00
DisableLoginForm = auth . Key ( "disable_login_form" ) . MustBool ( false )
2017-03-29 17:33:28 +08:00
DisableSignoutMenu = auth . Key ( "disable_signout_menu" ) . MustBool ( false )
2015-01-27 22:14:53 +08:00
2015-01-27 22:45:27 +08:00
// anonymous access
2018-04-30 22:21:04 +08:00
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 ( )
2015-01-07 23:37:24 +08:00
2015-05-01 17:55:59 +08:00
// auth proxy
2018-04-30 22:21:04 +08:00
authProxy := iniFile . Section ( "auth.proxy" )
2015-05-01 17:55:59 +08:00
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 )
2016-02-23 21:22:28 +08:00
AuthProxyLdapSyncTtl = authProxy . Key ( "ldap_sync_ttl" ) . MustInt ( )
AuthProxyWhitelist = authProxy . Key ( "whitelist" ) . String ( )
2015-05-01 17:55:59 +08:00
2018-05-07 16:39:16 +08:00
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 ]
}
}
2016-02-23 21:22:28 +08:00
// basic auth
2018-04-30 22:21:04 +08:00
authBasic := iniFile . Section ( "auth.basic" )
2015-06-30 18:14:13 +08:00
BasicAuthEnabled = authBasic . Key ( "enabled" ) . MustBool ( true )
2015-06-30 15:37:52 +08:00
2017-09-28 18:10:59 +08:00
// global plugin settings
2018-04-30 22:21:04 +08:00
PluginAppsSkipVerifyTLS = iniFile . Section ( "plugins" ) . Key ( "app_tls_skip_verify_insecure" ) . MustBool ( false )
2017-09-28 18:10:59 +08:00
2014-10-07 03:31:54 +08:00
// PhantomJS rendering
2018-04-30 22:21:04 +08:00
cfg . ImagesDir = filepath . Join ( DataPath , "png" )
ImagesDir = cfg . ImagesDir
2018-01-25 18:05:59 +08:00
PhantomDir = filepath . Join ( HomePath , "tools/phantomjs" )
2014-11-15 00:13:33 +08:00
2018-04-30 22:21:04 +08:00
analytics := iniFile . Section ( "analytics" )
2015-03-28 00:13:44 +08:00
ReportingEnabled = analytics . Key ( "reporting_enabled" ) . MustBool ( true )
2016-04-12 00:21:48 +08:00
CheckForUpdates = analytics . Key ( "check_for_updates" ) . MustBool ( true )
2015-03-28 00:13:44 +08:00
GoogleAnalyticsId = analytics . Key ( "google_analytics_ua_id" ) . String ( )
2015-08-21 15:30:39 +08:00
GoogleTagManagerId = analytics . Key ( "google_tag_manager_id" ) . String ( )
2015-03-23 03:14:00 +08:00
2018-04-30 22:21:04 +08:00
ldapSec := iniFile . Section ( "auth.ldap" )
2015-06-04 15:34:42 +08:00
LdapEnabled = ldapSec . Key ( "enabled" ) . MustBool ( false )
2015-07-15 16:08:23 +08:00
LdapConfigFile = ldapSec . Key ( "config_file" ) . String ( )
2016-10-07 14:49:58 +08:00
LdapAllowSignup = ldapSec . Key ( "allow_sign_up" ) . MustBool ( true )
2015-06-04 15:34:42 +08:00
2018-04-30 22:21:04 +08:00
alerting := iniFile . Section ( "alerting" )
2017-01-25 20:32:26 +08:00
AlertingEnabled = alerting . Key ( "enabled" ) . MustBool ( true )
2016-10-10 19:09:16 +08:00
ExecuteAlerts = alerting . Key ( "execute_alerts" ) . MustBool ( true )
2016-04-29 20:35:58 +08:00
2018-04-30 22:21:04 +08:00
explore := iniFile . Section ( "explore" )
2018-04-27 21:35:46 +08:00
ExploreEnabled = explore . Key ( "enabled" ) . MustBool ( false )
2018-04-27 17:39:14 +08:00
2018-04-30 22:21:04 +08:00
cfg . readSessionConfig ( )
cfg . readSmtpSettings ( )
cfg . readQuotaSettings ( )
2015-08-31 17:35:07 +08:00
2018-04-30 22:21:04 +08:00
if VerifyEmailEnabled && ! cfg . Smtp . Enabled {
2017-12-28 22:51:15 +08:00
log . Warn ( "require_email_validation is enabled but smtp is disabled" )
2015-08-31 17:35:07 +08:00
}
2015-09-11 14:58:45 +08:00
2017-05-22 20:56:50 +08:00
// check old key name
2018-04-30 22:21:04 +08:00
GrafanaComUrl = iniFile . Section ( "grafana_net" ) . Key ( "url" ) . MustString ( "" )
2017-05-22 20:56:50 +08:00
if GrafanaComUrl == "" {
2018-04-30 22:21:04 +08:00
GrafanaComUrl = iniFile . Section ( "grafana_com" ) . Key ( "url" ) . MustString ( "https://grafana.com" )
2017-05-22 20:56:50 +08:00
}
2016-05-27 19:52:19 +08:00
2018-04-30 22:21:04 +08:00
imageUploadingSection := iniFile . Section ( "external_image_storage" )
2017-12-28 22:48:02 +08:00
ImageUploadProvider = imageUploadingSection . Key ( "provider" ) . MustString ( "" )
2015-09-11 14:58:45 +08:00
return nil
2015-01-15 21:44:15 +08:00
}
2014-12-30 17:28:27 +08:00
2018-04-30 22:21:04 +08:00
func ( cfg * Cfg ) readSessionConfig ( ) {
sec := cfg . Raw . Section ( "session" )
2014-12-30 17:28:27 +08:00
SessionOptions = session . Options { }
2015-12-08 21:35:09 +08:00
SessionOptions . Provider = sec . Key ( "provider" ) . In ( "memory" , [ ] string { "memory" , "file" , "redis" , "mysql" , "postgres" , "memcache" } )
2015-01-27 17:09:54 +08:00
SessionOptions . ProviderConfig = strings . Trim ( sec . Key ( "provider_config" ) . String ( ) , "\" " )
SessionOptions . CookieName = sec . Key ( "cookie_name" ) . MustString ( "grafana_sess" )
2014-12-30 17:28:27 +08:00
SessionOptions . CookiePath = AppSubUrl
2015-01-27 17:09:54 +08:00
SessionOptions . Secure = sec . Key ( "cookie_secure" ) . MustBool ( )
2018-04-30 22:21:04 +08:00
SessionOptions . Gclifetime = cfg . Raw . Section ( "session" ) . Key ( "gc_interval_time" ) . MustInt64 ( 86400 )
SessionOptions . Maxlifetime = cfg . Raw . Section ( "session" ) . Key ( "session_life_time" ) . MustInt64 ( 86400 )
2015-04-08 01:21:14 +08:00
SessionOptions . IDLength = 16
2014-12-30 17:28:27 +08:00
if SessionOptions . Provider == "file" {
2015-04-09 18:16:59 +08:00
SessionOptions . ProviderConfig = makeAbsolute ( SessionOptions . ProviderConfig , DataPath )
2014-12-30 17:28:27 +08:00
os . MkdirAll ( path . Dir ( SessionOptions . ProviderConfig ) , os . ModePerm )
2014-10-05 22:50:04 +08:00
}
2015-04-08 14:59:12 +08:00
if SessionOptions . CookiePath == "" {
SessionOptions . CookiePath = "/"
}
2018-03-16 04:23:33 +08:00
2018-04-30 22:21:04 +08:00
SessionConnMaxLifetime = cfg . Raw . Section ( "session" ) . Key ( "conn_max_lifetime" ) . MustInt64 ( 14400 )
2014-10-05 22:50:04 +08:00
}
2015-03-03 17:18:24 +08:00
2018-04-30 22:21:04 +08:00
func initLogging ( file * ini . File ) {
2016-06-07 18:11:41 +08:00
// split on comma
2018-04-30 22:21:04 +08:00
LogModes = strings . Split ( file . Section ( "log" ) . Key ( "mode" ) . MustString ( "console" ) , "," )
2016-06-07 18:11:41 +08:00
// also try space
if len ( LogModes ) == 1 {
2018-04-30 22:21:04 +08:00
LogModes = strings . Split ( file . Section ( "log" ) . Key ( "mode" ) . MustString ( "console" ) , " " )
2015-03-03 17:18:24 +08:00
}
2018-04-30 22:21:04 +08:00
LogsPath = makeAbsolute ( file . Section ( "paths" ) . Key ( "logs" ) . String ( ) , HomePath )
log . ReadLoggingConfig ( LogModes , LogsPath , file )
2015-03-03 17:18:24 +08:00
}
2018-04-30 22:21:04 +08:00
func ( cfg * Cfg ) LogConfigSources ( ) {
2015-04-09 18:16:59 +08:00
var text bytes . Buffer
2016-06-07 15:29:47 +08:00
for _ , file := range configFiles {
logger . Info ( "Config loaded from" , "file" , file )
2015-03-03 17:18:24 +08:00
}
2015-04-09 18:16:59 +08:00
if len ( appliedCommandLineProperties ) > 0 {
2016-06-07 15:29:47 +08:00
for _ , prop := range appliedCommandLineProperties {
2017-06-05 20:20:34 +08:00
logger . Info ( "Config overridden from command line" , "arg" , prop )
2015-04-09 18:16:59 +08:00
}
}
if len ( appliedEnvOverrides ) > 0 {
text . WriteString ( "\tEnvironment variables used:\n" )
2016-06-07 15:29:47 +08:00
for _ , prop := range appliedEnvOverrides {
2017-06-05 20:20:34 +08:00
logger . Info ( "Config overridden from Environment variable" , "var" , prop )
2015-04-09 18:16:59 +08:00
}
}
2016-06-07 15:29:47 +08:00
logger . Info ( "Path Home" , "path" , HomePath )
logger . Info ( "Path Data" , "path" , DataPath )
logger . Info ( "Path Logs" , "path" , LogsPath )
logger . Info ( "Path Plugins" , "path" , PluginsPath )
2018-05-01 21:51:15 +08:00
logger . Info ( "Path Provisioning" , "path" , cfg . ProvisioningPath )
2017-10-02 02:02:25 +08:00
logger . Info ( "App mode " + Env )
2015-03-03 17:18:24 +08:00
}