setting.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. // Copyright 2014 Unknwon
  2. // Copyright 2014 Torkel Ödegaard
  3. package setting
  4. import (
  5. "bytes"
  6. "fmt"
  7. "net/http"
  8. "net/url"
  9. "os"
  10. "path"
  11. "path/filepath"
  12. "regexp"
  13. "runtime"
  14. "strings"
  15. "time"
  16. "github.com/go-macaron/session"
  17. "github.com/grafana/grafana/pkg/log"
  18. "github.com/grafana/grafana/pkg/util"
  19. ini "gopkg.in/ini.v1"
  20. )
  21. type Scheme string
  22. const (
  23. HTTP Scheme = "http"
  24. HTTPS Scheme = "https"
  25. SOCKET Scheme = "socket"
  26. DEFAULT_HTTP_ADDR string = "0.0.0.0"
  27. )
  28. const (
  29. DEV = "development"
  30. PROD = "production"
  31. TEST = "test"
  32. APP_NAME = "Grafana"
  33. APP_NAME_ENTERPRISE = "Grafana Enterprise"
  34. )
  35. var (
  36. ERR_TEMPLATE_NAME = "error"
  37. )
  38. var (
  39. // App settings.
  40. Env = DEV
  41. AppUrl string
  42. AppSubUrl string
  43. InstanceName string
  44. // build
  45. BuildVersion string
  46. BuildCommit string
  47. BuildBranch string
  48. BuildStamp int64
  49. IsEnterprise bool
  50. ApplicationName string
  51. // packaging
  52. Packaging = "unknown"
  53. // Paths
  54. HomePath string
  55. PluginsPath string
  56. CustomInitPath = "conf/custom.ini"
  57. // Log settings.
  58. LogConfigs []util.DynMap
  59. // Http server options
  60. Protocol Scheme
  61. Domain string
  62. HttpAddr, HttpPort string
  63. SshPort int
  64. CertFile, KeyFile string
  65. SocketPath string
  66. RouterLogging bool
  67. DataProxyLogging bool
  68. DataProxyTimeout int
  69. StaticRootPath string
  70. EnableGzip bool
  71. EnforceDomain bool
  72. // Security settings.
  73. SecretKey string
  74. DisableGravatar bool
  75. EmailCodeValidMinutes int
  76. DataProxyWhiteList map[string]bool
  77. DisableBruteForceLoginProtection bool
  78. CookieSecure bool
  79. CookieSameSite http.SameSite
  80. // Snapshots
  81. ExternalSnapshotUrl string
  82. ExternalSnapshotName string
  83. ExternalEnabled bool
  84. SnapShotRemoveExpired bool
  85. // Dashboard history
  86. DashboardVersionsToKeep int
  87. // User settings
  88. AllowUserSignUp bool
  89. AllowUserOrgCreate bool
  90. AutoAssignOrg bool
  91. AutoAssignOrgId int
  92. AutoAssignOrgRole string
  93. VerifyEmailEnabled bool
  94. LoginHint string
  95. DefaultTheme string
  96. DisableLoginForm bool
  97. DisableSignoutMenu bool
  98. SignoutRedirectUrl string
  99. ExternalUserMngLinkUrl string
  100. ExternalUserMngLinkName string
  101. ExternalUserMngInfo string
  102. OAuthAutoLogin bool
  103. ViewersCanEdit bool
  104. // Http auth
  105. AdminUser string
  106. AdminPassword string
  107. LoginCookieName string
  108. LoginMaxLifetimeDays int
  109. AnonymousEnabled bool
  110. AnonymousOrgName string
  111. AnonymousOrgRole string
  112. // Auth proxy settings
  113. AuthProxyEnabled bool
  114. AuthProxyHeaderName string
  115. AuthProxyHeaderProperty string
  116. AuthProxyAutoSignUp bool
  117. AuthProxyLdapSyncTtl int
  118. AuthProxyWhitelist string
  119. AuthProxyHeaders map[string]string
  120. // Basic Auth
  121. BasicAuthEnabled bool
  122. // Plugin settings
  123. PluginAppsSkipVerifyTLS bool
  124. // Session settings.
  125. SessionOptions session.Options
  126. SessionConnMaxLifetime int64
  127. // Global setting objects.
  128. Raw *ini.File
  129. ConfRootPath string
  130. IsWindows bool
  131. // for logging purposes
  132. configFiles []string
  133. appliedCommandLineProperties []string
  134. appliedEnvOverrides []string
  135. ReportingEnabled bool
  136. CheckForUpdates bool
  137. GoogleAnalyticsId string
  138. GoogleTagManagerId string
  139. // LDAP
  140. LdapEnabled bool
  141. LdapConfigFile string
  142. LdapAllowSignup = true
  143. // QUOTA
  144. Quota QuotaSettings
  145. // Alerting
  146. AlertingEnabled bool
  147. ExecuteAlerts bool
  148. AlertingRenderLimit int
  149. AlertingErrorOrTimeout string
  150. AlertingNoDataOrNullValues string
  151. // Explore UI
  152. ExploreEnabled bool
  153. // logger
  154. logger log.Logger
  155. // Grafana.NET URL
  156. GrafanaComUrl string
  157. // S3 temp image store
  158. S3TempImageStoreBucketUrl string
  159. S3TempImageStoreAccessKey string
  160. S3TempImageStoreSecretKey string
  161. ImageUploadProvider string
  162. )
  163. // TODO move all global vars to this struct
  164. type Cfg struct {
  165. Raw *ini.File
  166. // HTTP Server Settings
  167. AppUrl string
  168. AppSubUrl string
  169. // Paths
  170. ProvisioningPath string
  171. DataPath string
  172. LogsPath string
  173. // SMTP email settings
  174. Smtp SmtpSettings
  175. // Rendering
  176. ImagesDir string
  177. PhantomDir string
  178. RendererUrl string
  179. RendererCallbackUrl string
  180. RendererLimit int
  181. RendererLimitAlerting int
  182. // Security
  183. DisableBruteForceLoginProtection bool
  184. CookieSecure bool
  185. CookieSameSite http.SameSite
  186. TempDataLifetime time.Duration
  187. MetricsEndpointEnabled bool
  188. MetricsEndpointBasicAuthUsername string
  189. MetricsEndpointBasicAuthPassword string
  190. EnableAlphaPanels bool
  191. DisableSanitizeHtml bool
  192. EnterpriseLicensePath string
  193. // Auth
  194. LoginCookieName string
  195. LoginMaxInactiveLifetimeDays int
  196. LoginMaxLifetimeDays int
  197. TokenRotationIntervalMinutes int
  198. // User
  199. EditorsCanOwn bool
  200. }
  201. type CommandLineArgs struct {
  202. Config string
  203. HomePath string
  204. Args []string
  205. }
  206. func init() {
  207. IsWindows = runtime.GOOS == "windows"
  208. logger = log.New("settings")
  209. }
  210. func parseAppUrlAndSubUrl(section *ini.Section) (string, string) {
  211. appUrl := section.Key("root_url").MustString("http://localhost:3000/")
  212. if appUrl[len(appUrl)-1] != '/' {
  213. appUrl += "/"
  214. }
  215. // Check if has app suburl.
  216. url, err := url.Parse(appUrl)
  217. if err != nil {
  218. log.Fatal(4, "Invalid root_url(%s): %s", appUrl, err)
  219. }
  220. appSubUrl := strings.TrimSuffix(url.Path, "/")
  221. return appUrl, appSubUrl
  222. }
  223. func ToAbsUrl(relativeUrl string) string {
  224. return AppUrl + relativeUrl
  225. }
  226. func shouldRedactKey(s string) bool {
  227. uppercased := strings.ToUpper(s)
  228. return strings.Contains(uppercased, "PASSWORD") || strings.Contains(uppercased, "SECRET") || strings.Contains(uppercased, "PROVIDER_CONFIG")
  229. }
  230. func shouldRedactURLKey(s string) bool {
  231. uppercased := strings.ToUpper(s)
  232. return strings.Contains(uppercased, "DATABASE_URL")
  233. }
  234. func applyEnvVariableOverrides(file *ini.File) error {
  235. appliedEnvOverrides = make([]string, 0)
  236. for _, section := range file.Sections() {
  237. for _, key := range section.Keys() {
  238. sectionName := strings.ToUpper(strings.Replace(section.Name(), ".", "_", -1))
  239. keyName := strings.ToUpper(strings.Replace(key.Name(), ".", "_", -1))
  240. envKey := fmt.Sprintf("GF_%s_%s", sectionName, keyName)
  241. envValue := os.Getenv(envKey)
  242. if len(envValue) > 0 {
  243. key.SetValue(envValue)
  244. if shouldRedactKey(envKey) {
  245. envValue = "*********"
  246. }
  247. if shouldRedactURLKey(envKey) {
  248. u, err := url.Parse(envValue)
  249. if err != nil {
  250. return fmt.Errorf("could not parse environment variable. key: %s, value: %s. error: %v", envKey, envValue, err)
  251. }
  252. ui := u.User
  253. if ui != nil {
  254. _, exists := ui.Password()
  255. if exists {
  256. u.User = url.UserPassword(ui.Username(), "-redacted-")
  257. envValue = u.String()
  258. }
  259. }
  260. }
  261. appliedEnvOverrides = append(appliedEnvOverrides, fmt.Sprintf("%s=%s", envKey, envValue))
  262. }
  263. }
  264. }
  265. return nil
  266. }
  267. func applyCommandLineDefaultProperties(props map[string]string, file *ini.File) {
  268. appliedCommandLineProperties = make([]string, 0)
  269. for _, section := range file.Sections() {
  270. for _, key := range section.Keys() {
  271. keyString := fmt.Sprintf("default.%s.%s", section.Name(), key.Name())
  272. value, exists := props[keyString]
  273. if exists {
  274. key.SetValue(value)
  275. if shouldRedactKey(keyString) {
  276. value = "*********"
  277. }
  278. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  279. }
  280. }
  281. }
  282. }
  283. func applyCommandLineProperties(props map[string]string, file *ini.File) {
  284. for _, section := range file.Sections() {
  285. sectionName := section.Name() + "."
  286. if section.Name() == ini.DEFAULT_SECTION {
  287. sectionName = ""
  288. }
  289. for _, key := range section.Keys() {
  290. keyString := sectionName + key.Name()
  291. value, exists := props[keyString]
  292. if exists {
  293. appliedCommandLineProperties = append(appliedCommandLineProperties, fmt.Sprintf("%s=%s", keyString, value))
  294. key.SetValue(value)
  295. }
  296. }
  297. }
  298. }
  299. func getCommandLineProperties(args []string) map[string]string {
  300. props := make(map[string]string)
  301. for _, arg := range args {
  302. if !strings.HasPrefix(arg, "cfg:") {
  303. continue
  304. }
  305. trimmed := strings.TrimPrefix(arg, "cfg:")
  306. parts := strings.Split(trimmed, "=")
  307. if len(parts) != 2 {
  308. log.Fatal(3, "Invalid command line argument. argument: %v", arg)
  309. return nil
  310. }
  311. props[parts[0]] = parts[1]
  312. }
  313. return props
  314. }
  315. func makeAbsolute(path string, root string) string {
  316. if filepath.IsAbs(path) {
  317. return path
  318. }
  319. return filepath.Join(root, path)
  320. }
  321. func evalEnvVarExpression(value string) string {
  322. regex := regexp.MustCompile(`\${(\w+)}`)
  323. return regex.ReplaceAllStringFunc(value, func(envVar string) string {
  324. envVar = strings.TrimPrefix(envVar, "${")
  325. envVar = strings.TrimSuffix(envVar, "}")
  326. envValue := os.Getenv(envVar)
  327. // if env variable is hostname and it is empty use os.Hostname as default
  328. if envVar == "HOSTNAME" && envValue == "" {
  329. envValue, _ = os.Hostname()
  330. }
  331. return envValue
  332. })
  333. }
  334. func evalConfigValues(file *ini.File) {
  335. for _, section := range file.Sections() {
  336. for _, key := range section.Keys() {
  337. key.SetValue(evalEnvVarExpression(key.Value()))
  338. }
  339. }
  340. }
  341. func loadSpecifedConfigFile(configFile string, masterFile *ini.File) error {
  342. if configFile == "" {
  343. configFile = filepath.Join(HomePath, CustomInitPath)
  344. // return without error if custom file does not exist
  345. if !pathExists(configFile) {
  346. return nil
  347. }
  348. }
  349. userConfig, err := ini.Load(configFile)
  350. if err != nil {
  351. return fmt.Errorf("Failed to parse %v, %v", configFile, err)
  352. }
  353. userConfig.BlockMode = false
  354. for _, section := range userConfig.Sections() {
  355. for _, key := range section.Keys() {
  356. if key.Value() == "" {
  357. continue
  358. }
  359. defaultSec, err := masterFile.GetSection(section.Name())
  360. if err != nil {
  361. defaultSec, _ = masterFile.NewSection(section.Name())
  362. }
  363. defaultKey, err := defaultSec.GetKey(key.Name())
  364. if err != nil {
  365. defaultKey, _ = defaultSec.NewKey(key.Name(), key.Value())
  366. }
  367. defaultKey.SetValue(key.Value())
  368. }
  369. }
  370. configFiles = append(configFiles, configFile)
  371. return nil
  372. }
  373. func (cfg *Cfg) loadConfiguration(args *CommandLineArgs) (*ini.File, error) {
  374. var err error
  375. // load config defaults
  376. defaultConfigFile := path.Join(HomePath, "conf/defaults.ini")
  377. configFiles = append(configFiles, defaultConfigFile)
  378. // check if config file exists
  379. if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
  380. fmt.Println("Grafana-server Init Failed: Could not find config defaults, make sure homepath command line parameter is set or working directory is homepath")
  381. os.Exit(1)
  382. }
  383. // load defaults
  384. parsedFile, err := ini.Load(defaultConfigFile)
  385. if err != nil {
  386. fmt.Println(fmt.Sprintf("Failed to parse defaults.ini, %v", err))
  387. os.Exit(1)
  388. return nil, err
  389. }
  390. parsedFile.BlockMode = false
  391. // command line props
  392. commandLineProps := getCommandLineProperties(args.Args)
  393. // load default overrides
  394. applyCommandLineDefaultProperties(commandLineProps, parsedFile)
  395. // load specified config file
  396. err = loadSpecifedConfigFile(args.Config, parsedFile)
  397. if err != nil {
  398. cfg.initLogging(parsedFile)
  399. log.Fatal(3, err.Error())
  400. }
  401. // apply environment overrides
  402. err = applyEnvVariableOverrides(parsedFile)
  403. if err != nil {
  404. return nil, err
  405. }
  406. // apply command line overrides
  407. applyCommandLineProperties(commandLineProps, parsedFile)
  408. // evaluate config values containing environment variables
  409. evalConfigValues(parsedFile)
  410. // update data path and logging config
  411. cfg.DataPath = makeAbsolute(parsedFile.Section("paths").Key("data").String(), HomePath)
  412. cfg.initLogging(parsedFile)
  413. return parsedFile, err
  414. }
  415. func pathExists(path string) bool {
  416. _, err := os.Stat(path)
  417. if err == nil {
  418. return true
  419. }
  420. if os.IsNotExist(err) {
  421. return false
  422. }
  423. return false
  424. }
  425. func setHomePath(args *CommandLineArgs) {
  426. if args.HomePath != "" {
  427. HomePath = args.HomePath
  428. return
  429. }
  430. HomePath, _ = filepath.Abs(".")
  431. // check if homepath is correct
  432. if pathExists(filepath.Join(HomePath, "conf/defaults.ini")) {
  433. return
  434. }
  435. // try down one path
  436. if pathExists(filepath.Join(HomePath, "../conf/defaults.ini")) {
  437. HomePath = filepath.Join(HomePath, "../")
  438. }
  439. }
  440. var skipStaticRootValidation = false
  441. func validateStaticRootPath() error {
  442. if skipStaticRootValidation {
  443. return nil
  444. }
  445. if _, err := os.Stat(path.Join(StaticRootPath, "build")); err != nil {
  446. logger.Error("Failed to detect generated javascript files in public/build")
  447. }
  448. return nil
  449. }
  450. func NewCfg() *Cfg {
  451. return &Cfg{
  452. Raw: ini.Empty(),
  453. }
  454. }
  455. func (cfg *Cfg) Load(args *CommandLineArgs) error {
  456. setHomePath(args)
  457. iniFile, err := cfg.loadConfiguration(args)
  458. if err != nil {
  459. return err
  460. }
  461. cfg.Raw = iniFile
  462. // Temporary keep global, to make refactor in steps
  463. Raw = cfg.Raw
  464. ApplicationName = APP_NAME
  465. if IsEnterprise {
  466. ApplicationName = APP_NAME_ENTERPRISE
  467. }
  468. Env = iniFile.Section("").Key("app_mode").MustString("development")
  469. InstanceName = iniFile.Section("").Key("instance_name").MustString("unknown_instance_name")
  470. PluginsPath = makeAbsolute(iniFile.Section("paths").Key("plugins").String(), HomePath)
  471. cfg.ProvisioningPath = makeAbsolute(iniFile.Section("paths").Key("provisioning").String(), HomePath)
  472. server := iniFile.Section("server")
  473. AppUrl, AppSubUrl = parseAppUrlAndSubUrl(server)
  474. cfg.AppUrl = AppUrl
  475. cfg.AppSubUrl = AppSubUrl
  476. Protocol = HTTP
  477. if server.Key("protocol").MustString("http") == "https" {
  478. Protocol = HTTPS
  479. CertFile = server.Key("cert_file").String()
  480. KeyFile = server.Key("cert_key").String()
  481. }
  482. if server.Key("protocol").MustString("http") == "socket" {
  483. Protocol = SOCKET
  484. SocketPath = server.Key("socket").String()
  485. }
  486. Domain = server.Key("domain").MustString("localhost")
  487. HttpAddr = server.Key("http_addr").MustString(DEFAULT_HTTP_ADDR)
  488. HttpPort = server.Key("http_port").MustString("3000")
  489. RouterLogging = server.Key("router_logging").MustBool(false)
  490. EnableGzip = server.Key("enable_gzip").MustBool(false)
  491. EnforceDomain = server.Key("enforce_domain").MustBool(false)
  492. StaticRootPath = makeAbsolute(server.Key("static_root_path").String(), HomePath)
  493. if err := validateStaticRootPath(); err != nil {
  494. return err
  495. }
  496. // read data proxy settings
  497. dataproxy := iniFile.Section("dataproxy")
  498. DataProxyLogging = dataproxy.Key("logging").MustBool(false)
  499. DataProxyTimeout = dataproxy.Key("timeout").MustInt(30)
  500. // read security settings
  501. security := iniFile.Section("security")
  502. SecretKey = security.Key("secret_key").String()
  503. DisableGravatar = security.Key("disable_gravatar").MustBool(true)
  504. cfg.DisableBruteForceLoginProtection = security.Key("disable_brute_force_login_protection").MustBool(false)
  505. DisableBruteForceLoginProtection = cfg.DisableBruteForceLoginProtection
  506. CookieSecure = security.Key("cookie_secure").MustBool(false)
  507. cfg.CookieSecure = CookieSecure
  508. samesiteString := security.Key("cookie_samesite").MustString("lax")
  509. validSameSiteValues := map[string]http.SameSite{
  510. "lax": http.SameSiteLaxMode,
  511. "strict": http.SameSiteStrictMode,
  512. "none": http.SameSiteDefaultMode,
  513. }
  514. if samesite, ok := validSameSiteValues[samesiteString]; ok {
  515. CookieSameSite = samesite
  516. cfg.CookieSameSite = CookieSameSite
  517. } else {
  518. CookieSameSite = http.SameSiteLaxMode
  519. cfg.CookieSameSite = CookieSameSite
  520. }
  521. // read snapshots settings
  522. snapshots := iniFile.Section("snapshots")
  523. ExternalSnapshotUrl = snapshots.Key("external_snapshot_url").String()
  524. ExternalSnapshotName = snapshots.Key("external_snapshot_name").String()
  525. ExternalEnabled = snapshots.Key("external_enabled").MustBool(true)
  526. SnapShotRemoveExpired = snapshots.Key("snapshot_remove_expired").MustBool(true)
  527. // read dashboard settings
  528. dashboards := iniFile.Section("dashboards")
  529. DashboardVersionsToKeep = dashboards.Key("versions_to_keep").MustInt(20)
  530. // read data source proxy white list
  531. DataProxyWhiteList = make(map[string]bool)
  532. for _, hostAndIp := range util.SplitString(security.Key("data_source_proxy_whitelist").String()) {
  533. DataProxyWhiteList[hostAndIp] = true
  534. }
  535. // admin
  536. AdminUser = security.Key("admin_user").String()
  537. AdminPassword = security.Key("admin_password").String()
  538. // users
  539. users := iniFile.Section("users")
  540. AllowUserSignUp = users.Key("allow_sign_up").MustBool(true)
  541. AllowUserOrgCreate = users.Key("allow_org_create").MustBool(true)
  542. AutoAssignOrg = users.Key("auto_assign_org").MustBool(true)
  543. AutoAssignOrgId = users.Key("auto_assign_org_id").MustInt(1)
  544. AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Viewer"})
  545. VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
  546. LoginHint = users.Key("login_hint").String()
  547. DefaultTheme = users.Key("default_theme").String()
  548. ExternalUserMngLinkUrl = users.Key("external_manage_link_url").String()
  549. ExternalUserMngLinkName = users.Key("external_manage_link_name").String()
  550. ExternalUserMngInfo = users.Key("external_manage_info").String()
  551. ViewersCanEdit = users.Key("viewers_can_edit").MustBool(false)
  552. cfg.EditorsCanOwn = users.Key("editors_can_own").MustBool(false)
  553. // auth
  554. auth := iniFile.Section("auth")
  555. LoginCookieName = auth.Key("login_cookie_name").MustString("grafana_session")
  556. cfg.LoginCookieName = LoginCookieName
  557. cfg.LoginMaxInactiveLifetimeDays = auth.Key("login_maximum_inactive_lifetime_days").MustInt(7)
  558. LoginMaxLifetimeDays = auth.Key("login_maximum_lifetime_days").MustInt(30)
  559. cfg.LoginMaxLifetimeDays = LoginMaxLifetimeDays
  560. cfg.TokenRotationIntervalMinutes = auth.Key("token_rotation_interval_minutes").MustInt(10)
  561. if cfg.TokenRotationIntervalMinutes < 2 {
  562. cfg.TokenRotationIntervalMinutes = 2
  563. }
  564. DisableLoginForm = auth.Key("disable_login_form").MustBool(false)
  565. DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false)
  566. OAuthAutoLogin = auth.Key("oauth_auto_login").MustBool(false)
  567. SignoutRedirectUrl = auth.Key("signout_redirect_url").String()
  568. // anonymous access
  569. AnonymousEnabled = iniFile.Section("auth.anonymous").Key("enabled").MustBool(false)
  570. AnonymousOrgName = iniFile.Section("auth.anonymous").Key("org_name").String()
  571. AnonymousOrgRole = iniFile.Section("auth.anonymous").Key("org_role").String()
  572. // auth proxy
  573. authProxy := iniFile.Section("auth.proxy")
  574. AuthProxyEnabled = authProxy.Key("enabled").MustBool(false)
  575. AuthProxyHeaderName = authProxy.Key("header_name").String()
  576. AuthProxyHeaderProperty = authProxy.Key("header_property").String()
  577. AuthProxyAutoSignUp = authProxy.Key("auto_sign_up").MustBool(true)
  578. AuthProxyLdapSyncTtl = authProxy.Key("ldap_sync_ttl").MustInt()
  579. AuthProxyWhitelist = authProxy.Key("whitelist").String()
  580. AuthProxyHeaders = make(map[string]string)
  581. for _, propertyAndHeader := range util.SplitString(authProxy.Key("headers").String()) {
  582. split := strings.SplitN(propertyAndHeader, ":", 2)
  583. if len(split) == 2 {
  584. AuthProxyHeaders[split[0]] = split[1]
  585. }
  586. }
  587. // basic auth
  588. authBasic := iniFile.Section("auth.basic")
  589. BasicAuthEnabled = authBasic.Key("enabled").MustBool(true)
  590. // global plugin settings
  591. PluginAppsSkipVerifyTLS = iniFile.Section("plugins").Key("app_tls_skip_verify_insecure").MustBool(false)
  592. // Rendering
  593. renderSec := iniFile.Section("rendering")
  594. cfg.RendererUrl = renderSec.Key("server_url").String()
  595. cfg.RendererCallbackUrl = renderSec.Key("callback_url").String()
  596. if cfg.RendererCallbackUrl == "" {
  597. cfg.RendererCallbackUrl = AppUrl
  598. } else {
  599. if cfg.RendererCallbackUrl[len(cfg.RendererCallbackUrl)-1] != '/' {
  600. cfg.RendererCallbackUrl += "/"
  601. }
  602. _, err := url.Parse(cfg.RendererCallbackUrl)
  603. if err != nil {
  604. log.Fatal(4, "Invalid callback_url(%s): %s", cfg.RendererCallbackUrl, err)
  605. }
  606. }
  607. cfg.ImagesDir = filepath.Join(cfg.DataPath, "png")
  608. cfg.PhantomDir = filepath.Join(HomePath, "tools/phantomjs")
  609. cfg.TempDataLifetime = iniFile.Section("paths").Key("temp_data_lifetime").MustDuration(time.Second * 3600 * 24)
  610. cfg.MetricsEndpointEnabled = iniFile.Section("metrics").Key("enabled").MustBool(true)
  611. cfg.MetricsEndpointBasicAuthUsername = iniFile.Section("metrics").Key("basic_auth_username").String()
  612. cfg.MetricsEndpointBasicAuthPassword = iniFile.Section("metrics").Key("basic_auth_password").String()
  613. analytics := iniFile.Section("analytics")
  614. ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
  615. CheckForUpdates = analytics.Key("check_for_updates").MustBool(true)
  616. GoogleAnalyticsId = analytics.Key("google_analytics_ua_id").String()
  617. GoogleTagManagerId = analytics.Key("google_tag_manager_id").String()
  618. ldapSec := iniFile.Section("auth.ldap")
  619. LdapEnabled = ldapSec.Key("enabled").MustBool(false)
  620. LdapConfigFile = ldapSec.Key("config_file").String()
  621. LdapAllowSignup = ldapSec.Key("allow_sign_up").MustBool(true)
  622. alerting := iniFile.Section("alerting")
  623. AlertingEnabled = alerting.Key("enabled").MustBool(true)
  624. ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true)
  625. AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5)
  626. AlertingErrorOrTimeout = alerting.Key("error_or_timeout").MustString("alerting")
  627. AlertingNoDataOrNullValues = alerting.Key("nodata_or_nullvalues").MustString("no_data")
  628. explore := iniFile.Section("explore")
  629. ExploreEnabled = explore.Key("enabled").MustBool(true)
  630. panels := iniFile.Section("panels")
  631. cfg.EnableAlphaPanels = panels.Key("enable_alpha").MustBool(false)
  632. cfg.DisableSanitizeHtml = panels.Key("disable_sanitize_html").MustBool(false)
  633. cfg.readSessionConfig()
  634. cfg.readSmtpSettings()
  635. cfg.readQuotaSettings()
  636. if VerifyEmailEnabled && !cfg.Smtp.Enabled {
  637. log.Warn("require_email_validation is enabled but smtp is disabled")
  638. }
  639. // check old key name
  640. GrafanaComUrl = iniFile.Section("grafana_net").Key("url").MustString("")
  641. if GrafanaComUrl == "" {
  642. GrafanaComUrl = iniFile.Section("grafana_com").Key("url").MustString("https://grafana.com")
  643. }
  644. imageUploadingSection := iniFile.Section("external_image_storage")
  645. ImageUploadProvider = imageUploadingSection.Key("provider").MustString("")
  646. enterprise := iniFile.Section("enterprise")
  647. cfg.EnterpriseLicensePath = enterprise.Key("license_path").MustString(filepath.Join(cfg.DataPath, "license.jwt"))
  648. return nil
  649. }
  650. func (cfg *Cfg) readSessionConfig() {
  651. sec := cfg.Raw.Section("session")
  652. SessionOptions = session.Options{}
  653. SessionOptions.Provider = sec.Key("provider").In("memory", []string{"memory", "file", "redis", "mysql", "postgres", "memcache"})
  654. SessionOptions.ProviderConfig = strings.Trim(sec.Key("provider_config").String(), "\" ")
  655. SessionOptions.CookieName = sec.Key("cookie_name").MustString("grafana_sess")
  656. SessionOptions.CookiePath = AppSubUrl
  657. SessionOptions.Secure = sec.Key("cookie_secure").MustBool()
  658. SessionOptions.Gclifetime = cfg.Raw.Section("session").Key("gc_interval_time").MustInt64(86400)
  659. SessionOptions.Maxlifetime = cfg.Raw.Section("session").Key("session_life_time").MustInt64(86400)
  660. SessionOptions.IDLength = 16
  661. if SessionOptions.Provider == "file" {
  662. SessionOptions.ProviderConfig = makeAbsolute(SessionOptions.ProviderConfig, cfg.DataPath)
  663. os.MkdirAll(path.Dir(SessionOptions.ProviderConfig), os.ModePerm)
  664. }
  665. if SessionOptions.CookiePath == "" {
  666. SessionOptions.CookiePath = "/"
  667. }
  668. SessionConnMaxLifetime = cfg.Raw.Section("session").Key("conn_max_lifetime").MustInt64(14400)
  669. }
  670. func (cfg *Cfg) initLogging(file *ini.File) {
  671. // split on comma
  672. logModes := strings.Split(file.Section("log").Key("mode").MustString("console"), ",")
  673. // also try space
  674. if len(logModes) == 1 {
  675. logModes = strings.Split(file.Section("log").Key("mode").MustString("console"), " ")
  676. }
  677. cfg.LogsPath = makeAbsolute(file.Section("paths").Key("logs").String(), HomePath)
  678. log.ReadLoggingConfig(logModes, cfg.LogsPath, file)
  679. }
  680. func (cfg *Cfg) LogConfigSources() {
  681. var text bytes.Buffer
  682. for _, file := range configFiles {
  683. logger.Info("Config loaded from", "file", file)
  684. }
  685. if len(appliedCommandLineProperties) > 0 {
  686. for _, prop := range appliedCommandLineProperties {
  687. logger.Info("Config overridden from command line", "arg", prop)
  688. }
  689. }
  690. if len(appliedEnvOverrides) > 0 {
  691. text.WriteString("\tEnvironment variables used:\n")
  692. for _, prop := range appliedEnvOverrides {
  693. logger.Info("Config overridden from Environment variable", "var", prop)
  694. }
  695. }
  696. logger.Info("Path Home", "path", HomePath)
  697. logger.Info("Path Data", "path", cfg.DataPath)
  698. logger.Info("Path Logs", "path", cfg.LogsPath)
  699. logger.Info("Path Plugins", "path", PluginsPath)
  700. logger.Info("Path Provisioning", "path", cfg.ProvisioningPath)
  701. logger.Info("App mode " + Env)
  702. }